--- name: status description: Report the background assistant's current state read-only, from the heartbeat file and the task book under $JSC_HOME/assistant/. Heartbeat counts as fresh only when the file exists and its ts is less than 300 seconds old, and pid liveness is never checked. Print one table covering heartbeat freshness, last heartbeat time, cli, session, task count, and every task's state, title, next_run and fail_count, flagging each task whose fail_count is above zero. A missing heartbeat file prints 助理未運行 and still counts as a normal result rather than an error. Use when someone asks whether the assistant is running or what is queued; not for starting or stopping it, not for environment health checks (jsc-cli:doctor), and not for skill usage counts (jsc-log:stats). --- # status — assistant heartbeat and task book snapshot Read-only snapshot of the background assistant. This skill reads two paths and prints one table. It writes no file, writes no wiki page, calls no gate, and never starts or stops the assistant. No `tools/` script backs this skill. Two paths and one table stay below the extraction bar; re-evaluate when the assistant body itself lands. ## Data sources | Path | Format | Keys | | --- | --- | --- | | `$JSC_HOME/assistant/heartbeat` | plain text, one `key=value` per line | `ts` (epoch seconds), `pid`, `cli`, `session` | | `$JSC_HOME/assistant/tasks/{id}` | plain text, one `key=value` per line, one entry per file | `id`, `kind` (`check` or `todo`), `title`, `action`, `trigger`, `recur`, `repo`, `due`, `state` (`pending` / `done` / `paused`), `last_run`, `next_run`, `fail_count`, `origin` (`user` or `assistant`) | `$JSC_HOME` defaults to `~/.jsc`. **Freshness is time-based only.** The heartbeat is fresh when the file exists and `ts` is less than 300 seconds behind the current time. An older `ts` means the assistant is not running. Never test whether `pid` is alive: the five CLIs and the processes inside containers cannot see each other's pids, so a live-looking pid proves nothing and a missing one proves nothing either. Report `pid` as a hint for whoever has to find a blocking process, and give it no weight in the verdict. ## Steps 1. **Resolve the assistant directory.** Take `$JSC_HOME` from the environment; when it is unset or empty, use `~/.jsc`. Append `assistant/` to get the directory this skill reads. When that directory is absent or cannot be listed, print `助理未運行`, name the resolved path and the reason (the variable was unset and the default path does not exist, or the listing was denied), skip steps 2 to 6, and finish per step 7. Done when one absolute assistant directory path is recorded, or the not-running report naming that path is printed. 2. **Read the heartbeat.** Read `{assistant}/heartbeat` and split each line on its first `=`. Branch on the outcome. | Outcome | Do | | --- | --- | | File absent | Set heartbeat state to `不存在`, print `助理未運行`, continue at step 4 — the task book is still worth printing | | File unreadable (permission denied, I/O error) | Set heartbeat state to `不存在`, print `助理未運行`, name the error text as the reason, continue at step 4 | | File present, `ts` absent or not an integer | Set heartbeat state to `過期`, name the malformed value, continue at step 4 | | File present with an integer `ts` | Continue at step 3 | Done when the heartbeat state holds one of `不存在`, `過期`, or a pending verdict handed to step 3, and the values of `pid`, `cli` and `session` are recorded as read or as absent. 3. **Judge freshness.** Subtract `ts` from the current epoch seconds. A difference below 300 sets the state to `新鮮`; 300 or above sets it to `過期`. Done when the state is `新鮮` or `過期` and the age in seconds is recorded. 4. **Read the task book.** List the regular files directly under `{assistant}/tasks/` and parse each one as `key=value` lines. Branch on the outcome. | Outcome | Do | | --- | --- | | Directory absent | Report zero entries. This is a normal result, not an error | | Directory present, no files | Report zero entries | | A file cannot be read or holds no recognisable key | Keep it as one row, put the file name in the title column, name the read or parse error in that row, and carry on with the remaining files | | A key is missing from a readable file | Print `-` in that column | Done when every file under `tasks/` has produced exactly one row, or zero entries has been reported. 5. **Print the status table.** Lead with the heartbeat block — state (`新鮮` / `過期` / `不存在`), last heartbeat time rendered from `ts` in local time, `cli`, `session`, and the task count. Follow it with one row per task carrying `state`, `title`, `next_run` and `fail_count`, in the order the files were listed. Done when the heartbeat block holds all five values and the row count equals the task count reported in step 4. 6. **Flag the repeatedly failing tasks.** Append `已連續失敗 N 次` to every row whose `fail_count` is above 0, with `N` taken verbatim from the file. A broken entry that retries every round with nobody noticing is the reason this field exists, so let no such row leave the table unmarked. Done when every row with `fail_count` above 0 carries the marker and its number matches the file. 7. **Finish successfully.** `助理未運行`, an absent tasks directory and an empty tasks directory are normal results — never exit non-zero for any of them. Reserve a failure report for a condition none of the tables above covers, and state which path and which error produced it. Done when the report is printed and nothing under `$JSC_HOME` has been created, modified or deleted.