@agent-deck/cli 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/muse-skills/agent-deck-playbooks/SKILL.md +0 -1
- package/dist/muse-skills/agent-deck-run/SKILL.md +28 -11
- package/dist/muse-skills/agent-deck-setup/SKILL.md +9 -5
- package/dist/run-detach.d.ts.map +1 -1
- package/dist/run-detach.js +6 -8
- package/dist/run-detach.js.map +1 -1
- package/dist/run-status.d.ts +1 -28
- package/dist/run-status.d.ts.map +1 -1
- package/dist/run-status.js +28 -242
- package/dist/run-status.js.map +1 -1
- package/dist/run.d.ts +10 -110
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +92 -323
- package/dist/run.js.map +1 -1
- package/package.json +3 -3
|
@@ -7,7 +7,6 @@ description: Use when a task matches a bound-deck playbook trigger, or when the
|
|
|
7
7
|
|
|
8
8
|
1. On task match: check `triggers` on `get_bound_deck`, then `get_playbook` before improvising. Playbook bodies live on the deck — do not mirror them into local skills.
|
|
9
9
|
|
|
10
|
-
<!-- Self-improvement blocks below are verbatim from GLOBAL_BODY in packages/cli/src/agent-harness.ts (NOT-427); keep in sync. -->
|
|
11
10
|
|
|
12
11
|
**When the user corrects your output** (the write trigger — no need to have called `get_playbook` earlier in the session):
|
|
13
12
|
|
|
@@ -1,19 +1,36 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-deck-run
|
|
3
|
-
description: Use when delegating a task to a local coding session on a named deck: brief it, launch it detached with agent-deck run, monitor it, review the result against the goal, and resume it with feedback until done.
|
|
3
|
+
description: "Use when delegating a task to a local coding session on a named deck: brief it, launch it detached with agent-deck run, monitor it, review the result against the goal, and resume it with feedback until done."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Agent Deck run (orchestrator)
|
|
7
7
|
|
|
8
8
|
You are the caller of a session, not the session. Follow the five steps below.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## 0. Check prerequisites first
|
|
11
11
|
|
|
12
|
-
You must be able to run shell commands on the machine where the coding tool is signed in; otherwise stop and tell the human you cannot use this skill.
|
|
12
|
+
You must be able to run shell commands on the machine where the coding tool is signed in; otherwise stop and tell the human you cannot use this skill. Then check, read-only, before writing any brief:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
agent-deck --version # >= 2.1.0
|
|
16
|
+
agent-deck status # Status: running
|
|
17
|
+
agent-deck deck list # the deck the user named exists
|
|
18
|
+
claude auth status # or: codex login status | cursor-agent status | muse --version
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If anything fails, stop and tell the human exactly what is missing and how to fix it (the `agent-deck-setup` skill lists the fixes). Do not start a run that will fail midway.
|
|
22
|
+
|
|
23
|
+
Bind the working folder once; `run` refuses an unbound folder ("No deck assigned in <dir>: run `agent-deck use <deck>` there first"):
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
cd <dir> && agent-deck use <deck> --client <client>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Leave the user's uncommitted changes alone; use a separate git worktree or branch when the repo is dirty.
|
|
13
30
|
|
|
14
31
|
## 1. Write the brief
|
|
15
32
|
|
|
16
|
-
Write the brief to a file. It must state the goal, the constraints, the definition of done, what the session must not do, and the tool profile the brief owner chose. Never put secrets in the brief.
|
|
33
|
+
Write the brief to a file. It must state the goal, the constraints, the definition of done, what the session must not do, and the tool profile the brief owner chose, and "if unclear, end your turn with the question". For code changes, the definition of done includes committing and pushing a named branch. Keep the user's decisions; label any number you had to assume as an assumption. Never put secrets in the brief.
|
|
17
34
|
|
|
18
35
|
## 2. Launch detached
|
|
19
36
|
|
|
@@ -25,11 +42,11 @@ agent-deck run <deck> --client <client> --cwd <dir> --prompt-file <brief-file> -
|
|
|
25
42
|
|
|
26
43
|
Supported `--client` values are `claude`, `codex`, `cursor`, `muse`; `agent-deck run --help` lists the clients. The examples use `claude`; substitute your client. Read the `runId`, pid, and log path from the `run <runId> detached: pid <pid> log <path>` line. If the launch fails closed on a deck binding mismatch, stop and report to the human instead of rebinding.
|
|
27
44
|
|
|
28
|
-
For per-client flags, resume ids, tool mappings, and trust behavior, see
|
|
45
|
+
For per-client flags, resume ids, tool mappings, and trust behavior, see `docs/DELEGATION.md` in the agent-deck repository.
|
|
29
46
|
|
|
30
47
|
## 3. Monitor
|
|
31
48
|
|
|
32
|
-
Poll until the state leaves `running`.
|
|
49
|
+
Poll until the state leaves `running`. Poll every 30 seconds: read-only runs typically take about 1–3 minutes, so a 30-second cadence catches the end within one interval without busy-polling.
|
|
33
50
|
|
|
34
51
|
```sh
|
|
35
52
|
agent-deck run status <runId>
|
|
@@ -39,11 +56,11 @@ agent-deck run log <runId> --tail 50
|
|
|
39
56
|
agent-deck run list
|
|
40
57
|
```
|
|
41
58
|
|
|
42
|
-
Read the `state` field (`running|ended|error|died`), the `sessionId`, and the log path. Stop rule: on `died` or `error`, stop polling, read the tail of the log for the failure, and report to the human.
|
|
59
|
+
Log lines look like `<ts> text|tool|result|end ...`; a finished run ends with `result success sessionId=<id> <final text>` and `end sessionId=<id>`. With `--json`, take the final answer from the `result` line's string `result` field (claude, codex, muse), not from the last `text` line; codex token usage is in a separate `usage` field. Read `text` lines for questions; answer from verified facts or ask the human. Read the `state` field (`running|ended|error|died`), the `sessionId`, and the log path. Stop rule: on `died` or `error`, stop polling, read the tail of the log for the failure, and report to the human.
|
|
43
60
|
|
|
44
61
|
## 4. Review
|
|
45
62
|
|
|
46
|
-
Judge the session's output against the goal and definition of done from step 1, not against the session's own summary. If it meets the goal, report to the human and stop.
|
|
63
|
+
Judge the session's output against the goal and definition of done from step 1, not against the session's own summary: open the real files, diff, tickets, or PR yourself. For code work, verify it landed: `git ls-remote origin <branch>` matches the session's commit. If it meets the goal, report to the human and stop.
|
|
47
64
|
|
|
48
65
|
## 5. Resume with feedback
|
|
49
66
|
|
|
@@ -53,13 +70,13 @@ Resume the same session with a feedback brief that quotes the gap found in step
|
|
|
53
70
|
agent-deck run <deck> --client <client> --cwd <dir> --prompt-file <feedback-file> --tools readonly --resume <sessionId> --detach
|
|
54
71
|
```
|
|
55
72
|
|
|
56
|
-
Repeat steps 3-5 until the goal is met
|
|
73
|
+
Repeat steps 3-5 until the goal is met, for at most 3 feedback rounds. If the goal is still not met after round 3, stop and bring the blocker to the human instead of resuming again.
|
|
57
74
|
|
|
58
75
|
### Corrections from a delegated run
|
|
59
|
-
- The party that observed and made the correction files it: the orchestrator files `propose_playbook_patch` on its own bound deck
|
|
76
|
+
- The party that observed and made the correction files it: the orchestrator files `propose_playbook_patch` on its own bound deck; the delegated session files only when a human corrects it directly.
|
|
60
77
|
- Evidence quotes the review gap as `user_feedback_excerpt` plus `runId`, `sessionId`, tool profile, and log path; no secrets in evidence.
|
|
61
78
|
- Clearly general lesson: `update` with `add_item` (or `create` when no playbook covers it); not yet general: `signal_only`.
|
|
62
|
-
- Cross-deck: `create`/`signal_only` land on the caller's bound deck and `get_playbook` reads only that deck
|
|
79
|
+
- Cross-deck: `create`/`signal_only` land on the caller's bound deck and `get_playbook` reads only that deck, so for a playbook on another deck file `signal_only` with the ids above.
|
|
63
80
|
|
|
64
81
|
## Hard rules
|
|
65
82
|
|
|
@@ -9,9 +9,11 @@ Treat setup as three separate layers: daemon health, host transport, then folder
|
|
|
9
9
|
|
|
10
10
|
1. Run `agent-deck status` and check `http://127.0.0.1:1110/health` (or `<mcp-url>/health`
|
|
11
11
|
from `.agent-deck/use.json` if present).
|
|
12
|
-
2. If the daemon is down, tell the user to run:
|
|
13
|
-
-
|
|
14
|
-
- `agent-deck
|
|
12
|
+
2. If agent-deck is missing, older than 2.1.0 (`agent-deck --version`), or the daemon is down, tell the user to run the matching fix:
|
|
13
|
+
- Not installed (macOS, Node.js 20+, npm): `npx @agent-deck/cli@latest install`, then `export PATH="$HOME/.local/bin:$PATH"` (managed install: launcher in `~/.local/bin`, versions under `~/.agent-deck/`).
|
|
14
|
+
- Outdated: `agent-deck upgrade` (`agent-deck upgrade --check` reports whether one is available).
|
|
15
|
+
- Daemon down: `agent-deck start --daemon`.
|
|
16
|
+
- `agent-deck doctor` prints any harness repair as `agent-deck setup --client <client>`; run it, then restart that host.
|
|
15
17
|
3. If the daemon is healthy but MCP tools are unavailable, repair the host transport:
|
|
16
18
|
- **Codex:** verify the Agent Deck plugin is installed, enabled, and current. Its bundled
|
|
17
19
|
`.mcp.json` must run `agent-deck mcp-launch`; reload or start a new task after changing
|
|
@@ -22,7 +24,9 @@ Treat setup as three separate layers: daemon health, host transport, then folder
|
|
|
22
24
|
that host.
|
|
23
25
|
4. Check the folder assignment reported by `agent-deck status`. If it is missing or legacy,
|
|
24
26
|
tell the user to run `agent-deck use <deck>` in that folder, then reload or retry MCP.
|
|
25
|
-
5.
|
|
27
|
+
5. For delegation (`agent-deck run`), the client CLI must also be installed and signed in. Check `claude auth status`, `codex login status`, `cursor-agent status`, or `muse --version`; if missing, point the user to the official install docs ([Claude Code](https://docs.anthropic.com/en/docs/claude-code/setup), [Codex](https://developers.openai.com/codex/cli), [Cursor CLI](https://cursor.com/docs/cli/installation); muse per its distribution) and its sign-in (`claude`, `codex login`, `cursor-agent login`, `muse login`).
|
|
28
|
+
6. If no deck exists (`agent-deck deck list`), the user creates one in the dashboard (`agent-deck open` → My Decks) or imports one: `agent-deck import <file>.agent-deck.json`.
|
|
29
|
+
7. Once transport and assignment are valid, use the session skill and require
|
|
26
30
|
`get_session_binding` followed by `get_bound_deck`.
|
|
27
|
-
|
|
31
|
+
8. Do not invent credentials, ports, or shell install pipelines. Keep guidance read-only;
|
|
28
32
|
the user executes install and setup commands.
|
package/dist/run-detach.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-detach.d.ts","sourceRoot":"","sources":["../src/run-detach.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAS,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"run-detach.d.ts","sourceRoot":"","sources":["../src/run-detach.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAS,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOjF,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,UAAU,EAChB,MAAM,OAAO,CAAC;AAEf,kFAAkF;AAClF,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAQjD,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAcD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,MAAM,EAAE,CA6BV;AAED,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG;IAC1C,qEAAqE;IACrE,OAAO,CAAC,EAAE,CACR,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,YAAY,KAClB,YAAY,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AA8BF,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,EAAE,UAAU,EACnB,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,MAAM,CAAC,CA8HjB"}
|
package/dist/run-detach.js
CHANGED
|
@@ -25,8 +25,8 @@ exports.startDetachedRun = startDetachedRun;
|
|
|
25
25
|
const node_child_process_1 = require("node:child_process");
|
|
26
26
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
27
27
|
const node_path_1 = __importDefault(require("node:path"));
|
|
28
|
+
const agent_run_1 = require("@agent-deck/backend/agent-run");
|
|
28
29
|
const daemon_logs_1 = require("./daemon-logs");
|
|
29
|
-
const paths_1 = require("./managed/paths");
|
|
30
30
|
const run_1 = require("./run");
|
|
31
31
|
/** Bounded starter return: never wait longer than this for the first log line. */
|
|
32
32
|
exports.DETACH_FIRST_LINE_TIMEOUT_MS = 5000;
|
|
@@ -118,11 +118,8 @@ async function startDetachedRun(originalArgs, options, deps = {}) {
|
|
|
118
118
|
console.error(prereq.error);
|
|
119
119
|
return 1;
|
|
120
120
|
}
|
|
121
|
-
const { deck } = prereq;
|
|
122
|
-
const
|
|
123
|
-
const runId = (0, run_1.newRunId)();
|
|
124
|
-
const logPath = options.log ?? node_path_1.default.join(homeDir, 'runs', runId, 'run.jsonl');
|
|
125
|
-
const metaPath = node_path_1.default.join(node_path_1.default.dirname(logPath), 'meta.json');
|
|
121
|
+
const { deck, resumedFrom } = prereq;
|
|
122
|
+
const { runId, logPath, metaPath } = (0, run_1.createCliRunService)(deps).allocate(options.log);
|
|
126
123
|
const outPath = resolveRunOutPath(logPath);
|
|
127
124
|
node_fs_1.default.mkdirSync(node_path_1.default.dirname(logPath), { recursive: true });
|
|
128
125
|
const childArgs = buildDetachedChildArgs(originalArgs, runId, logPath);
|
|
@@ -169,8 +166,9 @@ async function startDetachedRun(originalArgs, options, deps = {}) {
|
|
|
169
166
|
pid,
|
|
170
167
|
startedAt: new Date().toISOString(),
|
|
171
168
|
state: 'running',
|
|
169
|
+
...(resumedFrom ? { resumedFrom } : {}),
|
|
172
170
|
};
|
|
173
|
-
(0,
|
|
171
|
+
(0, agent_run_1.writeRunMeta)(metaPath, meta);
|
|
174
172
|
const deadline = Date.now() + timeoutMs;
|
|
175
173
|
for (;;) {
|
|
176
174
|
if (logHasFirstLine(logPath)) {
|
|
@@ -222,7 +220,7 @@ async function startDetachedRun(originalArgs, options, deps = {}) {
|
|
|
222
220
|
const current = JSON.parse(node_fs_1.default.readFileSync(metaPath, 'utf8'));
|
|
223
221
|
if (current.runId === runId && current.state === 'running') {
|
|
224
222
|
current.state = 'error';
|
|
225
|
-
(0,
|
|
223
|
+
(0, agent_run_1.writeRunMeta)(metaPath, current);
|
|
226
224
|
}
|
|
227
225
|
}
|
|
228
226
|
catch {
|
package/dist/run-detach.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-detach.js","sourceRoot":"","sources":["../src/run-detach.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"run-detach.js","sourceRoot":"","sources":["../src/run-detach.ts"],"names":[],"mappings":"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"}
|
package/dist/run-status.d.ts
CHANGED
|
@@ -1,35 +1,10 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type RunStatusInfo = {
|
|
3
|
-
runId: string;
|
|
4
|
-
deck: string;
|
|
5
|
-
client: string;
|
|
6
|
-
state: RunInspectState;
|
|
7
|
-
sessionId: string | null;
|
|
8
|
-
startedAt: string;
|
|
9
|
-
lastLogTs: string | null;
|
|
10
|
-
logPath: string;
|
|
11
|
-
};
|
|
1
|
+
export { collectRunStatus, isRunPidAlive, listRunInfos, type CollectedStatus, type RunInspectState, type RunStatusInfo, } from '@agent-deck/backend/agent-run';
|
|
12
2
|
export type RunInspectDeps = {
|
|
13
3
|
homeDir?: string;
|
|
14
4
|
/** Follow poll interval (tests only; default 100ms). */
|
|
15
5
|
followPollMs?: number;
|
|
16
6
|
};
|
|
17
7
|
export declare const RUN_LIST_DEFAULT_LIMIT = 20;
|
|
18
|
-
/**
|
|
19
|
-
* True when `pid` is alive and not obviously recycled: the runner process
|
|
20
|
-
* started before it wrote `startedAt`, so a live pid whose start time is
|
|
21
|
-
* well after `startedAt` must be a different process.
|
|
22
|
-
*/
|
|
23
|
-
export declare function isRunPidAlive(pid: number, startedAt: string): boolean;
|
|
24
|
-
export type CollectedStatus = {
|
|
25
|
-
found: false;
|
|
26
|
-
} | {
|
|
27
|
-
found: true;
|
|
28
|
-
info: RunStatusInfo;
|
|
29
|
-
warnings: string[];
|
|
30
|
-
corruptMeta: boolean;
|
|
31
|
-
};
|
|
32
|
-
export declare function collectRunStatus(runId: string, homeDir: string): CollectedStatus;
|
|
33
8
|
export declare function printRunStatusHelp(): void;
|
|
34
9
|
export declare function parseRunStatusArgs(args: string[]): {
|
|
35
10
|
runId: string;
|
|
@@ -56,7 +31,5 @@ export declare function parseRunListArgs(args: string[]): {
|
|
|
56
31
|
} | {
|
|
57
32
|
error: string;
|
|
58
33
|
};
|
|
59
|
-
export declare function listRunInfos(homeDir: string, limit: number): RunStatusInfo[];
|
|
60
34
|
export declare function runRunListCommand(args: string[], deps?: RunInspectDeps): Promise<number>;
|
|
61
|
-
export {};
|
|
62
35
|
//# sourceMappingURL=run-status.d.ts.map
|
package/dist/run-status.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-status.d.ts","sourceRoot":"","sources":["../src/run-status.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-status.d.ts","sourceRoot":"","sources":["../src/run-status.ts"],"names":[],"mappings":"AA4BA,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAwCzC,wBAAgB,kBAAkB,IAAI,IAAI,CASzC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAqBvG;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBhG;AAID,wBAAgB,eAAe,IAAI,IAAI,CAOtC;AAED,KAAK,aAAa,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAgCjF;AAwCD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAqE7F;AAID,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAuBrG;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B9F"}
|
package/dist/run-status.js
CHANGED
|
@@ -3,9 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.RUN_LIST_DEFAULT_LIMIT = void 0;
|
|
7
|
-
exports.isRunPidAlive = isRunPidAlive;
|
|
8
|
-
exports.collectRunStatus = collectRunStatus;
|
|
6
|
+
exports.RUN_LIST_DEFAULT_LIMIT = exports.listRunInfos = exports.isRunPidAlive = exports.collectRunStatus = void 0;
|
|
9
7
|
exports.printRunStatusHelp = printRunStatusHelp;
|
|
10
8
|
exports.parseRunStatusArgs = parseRunStatusArgs;
|
|
11
9
|
exports.runRunStatusCommand = runRunStatusCommand;
|
|
@@ -14,223 +12,30 @@ exports.parseRunLogArgs = parseRunLogArgs;
|
|
|
14
12
|
exports.runRunLogCommand = runRunLogCommand;
|
|
15
13
|
exports.printRunListHelp = printRunListHelp;
|
|
16
14
|
exports.parseRunListArgs = parseRunListArgs;
|
|
17
|
-
exports.listRunInfos = listRunInfos;
|
|
18
15
|
exports.runRunListCommand = runRunListCommand;
|
|
19
16
|
/**
|
|
20
17
|
* `agent-deck run status|log|list` — poll a run without parsing files (NOT-402).
|
|
21
18
|
*
|
|
22
|
-
* Reads the run record (`meta.json`) and JSONL log
|
|
23
|
-
* (
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
19
|
+
* Reads the run record (`meta.json`) and JSONL log through the shared run
|
|
20
|
+
* service (`@agent-deck/backend/agent-run`), so foreground, detached, and
|
|
21
|
+
* backend-started runs report the same state, including `died` for a
|
|
22
|
+
* `running` meta whose pid is gone. This file owns arg parsing, terminal
|
|
23
|
+
* formatting, and `--follow` polling.
|
|
27
24
|
*/
|
|
28
|
-
const node_child_process_1 = require("node:child_process");
|
|
29
25
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
30
|
-
const
|
|
26
|
+
const agent_run_1 = require("@agent-deck/backend/agent-run");
|
|
31
27
|
const paths_1 = require("./managed/paths");
|
|
32
|
-
const runtime_state_1 = require("./runtime-state");
|
|
33
28
|
const terminal_style_1 = require("./terminal-style");
|
|
29
|
+
// Run records and their reads live in the shared run service (NOT-479);
|
|
30
|
+
// re-exported so existing `from './run-status'` imports keep working.
|
|
31
|
+
var agent_run_2 = require("@agent-deck/backend/agent-run");
|
|
32
|
+
Object.defineProperty(exports, "collectRunStatus", { enumerable: true, get: function () { return agent_run_2.collectRunStatus; } });
|
|
33
|
+
Object.defineProperty(exports, "isRunPidAlive", { enumerable: true, get: function () { return agent_run_2.isRunPidAlive; } });
|
|
34
|
+
Object.defineProperty(exports, "listRunInfos", { enumerable: true, get: function () { return agent_run_2.listRunInfos; } });
|
|
34
35
|
exports.RUN_LIST_DEFAULT_LIMIT = 20;
|
|
35
|
-
function runsRoot(homeDir) {
|
|
36
|
-
return node_path_1.default.join(homeDir, 'runs');
|
|
37
|
-
}
|
|
38
|
-
function runPaths(homeDir, runId) {
|
|
39
|
-
const dir = node_path_1.default.join(runsRoot(homeDir), runId);
|
|
40
|
-
return { dir, metaPath: node_path_1.default.join(dir, 'meta.json'), logPath: node_path_1.default.join(dir, 'run.jsonl') };
|
|
41
|
-
}
|
|
42
36
|
function resolveHomeDir(deps) {
|
|
43
37
|
return deps?.homeDir ?? (0, paths_1.agentDeckHome)();
|
|
44
38
|
}
|
|
45
|
-
function readMetaFile(metaPath) {
|
|
46
|
-
let raw;
|
|
47
|
-
try {
|
|
48
|
-
raw = node_fs_1.default.readFileSync(metaPath, 'utf8');
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return { ok: false, reason: 'unreadable', partial: {} };
|
|
52
|
-
}
|
|
53
|
-
let parsed;
|
|
54
|
-
try {
|
|
55
|
-
parsed = JSON.parse(raw);
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return { ok: false, reason: 'invalid JSON', partial: {} };
|
|
59
|
-
}
|
|
60
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
61
|
-
return { ok: false, reason: 'not an object', partial: {} };
|
|
62
|
-
}
|
|
63
|
-
const partial = parsed;
|
|
64
|
-
if (typeof partial.runId !== 'string' ||
|
|
65
|
-
typeof partial.deck !== 'string' ||
|
|
66
|
-
typeof partial.client !== 'string' ||
|
|
67
|
-
typeof partial.startedAt !== 'string' ||
|
|
68
|
-
(partial.state !== 'running' && partial.state !== 'ended' && partial.state !== 'error')) {
|
|
69
|
-
return { ok: false, reason: 'missing required fields', partial };
|
|
70
|
-
}
|
|
71
|
-
return { ok: true, meta: partial };
|
|
72
|
-
}
|
|
73
|
-
function sessionOf(event) {
|
|
74
|
-
const value = event.sessionId;
|
|
75
|
-
return typeof value === 'string' && value ? value : null;
|
|
76
|
-
}
|
|
77
|
-
function readLogFile(logPath) {
|
|
78
|
-
const empty = {
|
|
79
|
-
exists: false,
|
|
80
|
-
events: [],
|
|
81
|
-
truncated: false,
|
|
82
|
-
lastTs: null,
|
|
83
|
-
lastSessionId: null,
|
|
84
|
-
sawEnd: false,
|
|
85
|
-
sawError: false,
|
|
86
|
-
};
|
|
87
|
-
let raw;
|
|
88
|
-
try {
|
|
89
|
-
raw = node_fs_1.default.readFileSync(logPath, 'utf8');
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return empty;
|
|
93
|
-
}
|
|
94
|
-
empty.exists = true;
|
|
95
|
-
if (!raw) {
|
|
96
|
-
return empty;
|
|
97
|
-
}
|
|
98
|
-
const endsWithNewline = raw.endsWith('\n');
|
|
99
|
-
const chunks = raw.split('\n');
|
|
100
|
-
// A trailing newline leaves an empty final chunk that is not a line.
|
|
101
|
-
const lines = endsWithNewline ? chunks.slice(0, -1) : chunks;
|
|
102
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
103
|
-
const line = lines[i];
|
|
104
|
-
const isLast = i === lines.length - 1;
|
|
105
|
-
if (!line) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
let parsed;
|
|
109
|
-
try {
|
|
110
|
-
parsed = JSON.parse(line);
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
// Only the last chunk of a file without a trailing newline can be a
|
|
114
|
-
// torn write; anything else is a corrupt line. Both are skipped.
|
|
115
|
-
void isLast;
|
|
116
|
-
empty.truncated = true;
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
if (!parsed || typeof parsed !== 'object' || typeof parsed.t !== 'string') {
|
|
120
|
-
empty.truncated = true;
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
const event = parsed;
|
|
124
|
-
empty.events.push({ raw: line, event });
|
|
125
|
-
if (typeof event.ts === 'string' && event.ts) {
|
|
126
|
-
empty.lastTs = event.ts;
|
|
127
|
-
}
|
|
128
|
-
const sessionId = sessionOf(event);
|
|
129
|
-
if (sessionId) {
|
|
130
|
-
empty.lastSessionId = sessionId;
|
|
131
|
-
}
|
|
132
|
-
if (event.t === 'end') {
|
|
133
|
-
empty.sawEnd = true;
|
|
134
|
-
}
|
|
135
|
-
else if (event.t === 'error') {
|
|
136
|
-
empty.sawError = true;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return empty;
|
|
140
|
-
}
|
|
141
|
-
/** Best-effort process start time via `ps`; null when unavailable. */
|
|
142
|
-
function getProcessStartTime(pid) {
|
|
143
|
-
try {
|
|
144
|
-
const out = (0, node_child_process_1.execFileSync)('ps', ['-o', 'lstart=', '-p', String(pid)], {
|
|
145
|
-
encoding: 'utf8',
|
|
146
|
-
timeout: 2000,
|
|
147
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
148
|
-
}).trim();
|
|
149
|
-
if (!out) {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
const parsed = new Date(out);
|
|
153
|
-
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* True when `pid` is alive and not obviously recycled: the runner process
|
|
161
|
-
* started before it wrote `startedAt`, so a live pid whose start time is
|
|
162
|
-
* well after `startedAt` must be a different process.
|
|
163
|
-
*/
|
|
164
|
-
function isRunPidAlive(pid, startedAt) {
|
|
165
|
-
if (!(0, runtime_state_1.isProcessAlive)(pid)) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
const procStart = getProcessStartTime(pid);
|
|
169
|
-
const runStart = new Date(startedAt);
|
|
170
|
-
if (!procStart || Number.isNaN(runStart.getTime())) {
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
// 2s tolerance for `ps` one-second resolution and clock skew.
|
|
174
|
-
return procStart.getTime() <= runStart.getTime() + 2000;
|
|
175
|
-
}
|
|
176
|
-
function effectiveState(meta) {
|
|
177
|
-
if (meta.state === 'ended' || meta.state === 'error') {
|
|
178
|
-
return meta.state;
|
|
179
|
-
}
|
|
180
|
-
return isRunPidAlive(meta.pid, meta.startedAt) ? 'running' : 'died';
|
|
181
|
-
}
|
|
182
|
-
function collectRunStatus(runId, homeDir) {
|
|
183
|
-
const { metaPath, logPath } = runPaths(homeDir, runId);
|
|
184
|
-
if (!node_fs_1.default.existsSync(metaPath)) {
|
|
185
|
-
return { found: false };
|
|
186
|
-
}
|
|
187
|
-
const metaRead = readMetaFile(metaPath);
|
|
188
|
-
const log = readLogFile(logPath);
|
|
189
|
-
const warnings = [];
|
|
190
|
-
if (metaRead.ok) {
|
|
191
|
-
const meta = metaRead.meta;
|
|
192
|
-
const sessionId = typeof meta.sessionId === 'string' && meta.sessionId ? meta.sessionId : log.lastSessionId;
|
|
193
|
-
if (log.truncated) {
|
|
194
|
-
warnings.push(`truncated log line in ${logPath} (ignored)`);
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
found: true,
|
|
198
|
-
corruptMeta: false,
|
|
199
|
-
warnings,
|
|
200
|
-
info: {
|
|
201
|
-
runId: meta.runId,
|
|
202
|
-
deck: meta.deck,
|
|
203
|
-
client: meta.client,
|
|
204
|
-
state: effectiveState(meta),
|
|
205
|
-
sessionId,
|
|
206
|
-
startedAt: meta.startedAt,
|
|
207
|
-
lastLogTs: log.lastTs,
|
|
208
|
-
logPath,
|
|
209
|
-
},
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
warnings.push(`meta.json is corrupt (${metaRead.reason}); showing log-derived info`);
|
|
213
|
-
if (log.truncated) {
|
|
214
|
-
warnings.push(`truncated log line in ${logPath} (ignored)`);
|
|
215
|
-
}
|
|
216
|
-
const partial = metaRead.partial;
|
|
217
|
-
return {
|
|
218
|
-
found: true,
|
|
219
|
-
corruptMeta: true,
|
|
220
|
-
warnings,
|
|
221
|
-
info: {
|
|
222
|
-
runId: typeof partial.runId === 'string' ? partial.runId : runId,
|
|
223
|
-
deck: typeof partial.deck === 'string' ? partial.deck : 'unknown',
|
|
224
|
-
client: typeof partial.client === 'string' ? partial.client : 'unknown',
|
|
225
|
-
state: 'error',
|
|
226
|
-
sessionId: (typeof partial.sessionId === 'string' && partial.sessionId ? partial.sessionId : null) ??
|
|
227
|
-
log.lastSessionId,
|
|
228
|
-
startedAt: typeof partial.startedAt === 'string' ? partial.startedAt : 'unknown',
|
|
229
|
-
lastLogTs: log.lastTs,
|
|
230
|
-
logPath,
|
|
231
|
-
},
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
39
|
function formatState(state, color) {
|
|
235
40
|
if (state === 'error' || state === 'died') {
|
|
236
41
|
return terminal_style_1.terminalStyle.error(state, color);
|
|
@@ -249,6 +54,9 @@ function printStatusHuman(info) {
|
|
|
249
54
|
if (info.sessionId) {
|
|
250
55
|
console.log(` session ${info.sessionId}`);
|
|
251
56
|
}
|
|
57
|
+
if (info.resumedFrom) {
|
|
58
|
+
console.log(` resumed from ${info.resumedFrom.runId} (--tools ${info.resumedFrom.tools})`);
|
|
59
|
+
}
|
|
252
60
|
console.log(` last log ${info.lastLogTs ?? 'never'}`);
|
|
253
61
|
console.log(` log ${info.logPath}`);
|
|
254
62
|
}
|
|
@@ -263,7 +71,8 @@ function printRunStatusHelp() {
|
|
|
263
71
|
agent-deck run status <runId> [--json]
|
|
264
72
|
|
|
265
73
|
Prints runId, deck, client, state (running|ended|error|died), sessionId when
|
|
266
|
-
known,
|
|
74
|
+
known, the origin run a resume continued (resumedFrom), startedAt, last log
|
|
75
|
+
line time, and the log path. A running meta whose
|
|
267
76
|
pid is no longer alive is reported as died. Exit 0 for any state; non-zero
|
|
268
77
|
only when the run id is unknown.`);
|
|
269
78
|
}
|
|
@@ -303,7 +112,7 @@ async function runRunStatusCommand(args, deps) {
|
|
|
303
112
|
console.error(parsed.error);
|
|
304
113
|
return 1;
|
|
305
114
|
}
|
|
306
|
-
const collected = collectRunStatus(parsed.runId, resolveHomeDir(deps));
|
|
115
|
+
const collected = (0, agent_run_1.collectRunStatus)(parsed.runId, resolveHomeDir(deps));
|
|
307
116
|
if (!collected.found) {
|
|
308
117
|
console.error(`Unknown run: ${parsed.runId}`);
|
|
309
118
|
return 1;
|
|
@@ -379,13 +188,13 @@ function formatLogHuman(event) {
|
|
|
379
188
|
const subtype = typeof event.subtype === 'string' ? event.subtype : '';
|
|
380
189
|
const result = event.result;
|
|
381
190
|
const rendered = typeof result === 'string' ? singleLine(result) : singleLine(JSON.stringify(result ?? null));
|
|
382
|
-
return `${ts} result ${subtype} sessionId=${
|
|
191
|
+
return `${ts} result ${subtype} sessionId=${(0, agent_run_1.logEventSessionId)(event) ?? 'unknown'}${rendered ? ` ${rendered}` : ''}`;
|
|
383
192
|
}
|
|
384
193
|
case 'end':
|
|
385
|
-
return `${ts} end sessionId=${
|
|
194
|
+
return `${ts} end sessionId=${(0, agent_run_1.logEventSessionId)(event) ?? 'unknown'}`;
|
|
386
195
|
case 'error': {
|
|
387
196
|
const message = typeof event.message === 'string' ? event.message : '';
|
|
388
|
-
return `${ts} error sessionId=${
|
|
197
|
+
return `${ts} error sessionId=${(0, agent_run_1.logEventSessionId)(event) ?? 'unknown'}${message ? ` ${singleLine(message)}` : ''}`;
|
|
389
198
|
}
|
|
390
199
|
default: {
|
|
391
200
|
// Runtime tolerance for a future/unknown `t` value that still parses.
|
|
@@ -410,19 +219,19 @@ async function runRunLogCommand(args, deps) {
|
|
|
410
219
|
return 1;
|
|
411
220
|
}
|
|
412
221
|
const homeDir = resolveHomeDir(deps);
|
|
413
|
-
const { metaPath, logPath } = runPaths(homeDir, parsed.runId);
|
|
222
|
+
const { metaPath, logPath } = (0, agent_run_1.runPaths)(homeDir, parsed.runId);
|
|
414
223
|
if (!node_fs_1.default.existsSync(metaPath)) {
|
|
415
224
|
console.error(`Unknown run: ${parsed.runId}`);
|
|
416
225
|
return 1;
|
|
417
226
|
}
|
|
418
|
-
const metaRead =
|
|
227
|
+
const metaRead = (0, agent_run_1.readRunMeta)(metaPath);
|
|
419
228
|
if (!metaRead.ok) {
|
|
420
229
|
console.warn(`Warning: meta.json is corrupt (${metaRead.reason}); showing the log anyway`);
|
|
421
230
|
}
|
|
422
231
|
const printEvent = (entry) => {
|
|
423
232
|
console.log(parsed.json ? entry.raw : formatLogHuman(entry.event));
|
|
424
233
|
};
|
|
425
|
-
let read =
|
|
234
|
+
let read = (0, agent_run_1.readRunLog)(logPath);
|
|
426
235
|
if (read.truncated) {
|
|
427
236
|
console.warn(`Warning: truncated log line in ${logPath} (ignored)`);
|
|
428
237
|
}
|
|
@@ -443,7 +252,7 @@ async function runRunLogCommand(args, deps) {
|
|
|
443
252
|
const pollMs = deps?.followPollMs ?? 100;
|
|
444
253
|
for (;;) {
|
|
445
254
|
await sleep(pollMs);
|
|
446
|
-
read =
|
|
255
|
+
read = (0, agent_run_1.readRunLog)(logPath);
|
|
447
256
|
if (read.truncated && !warnedTruncated) {
|
|
448
257
|
warnedTruncated = true;
|
|
449
258
|
console.warn(`Warning: truncated log line in ${logPath} (ignored)`);
|
|
@@ -459,7 +268,7 @@ async function runRunLogCommand(args, deps) {
|
|
|
459
268
|
}
|
|
460
269
|
}
|
|
461
270
|
// A run that died without an end/error line must still release followers.
|
|
462
|
-
const collected = collectRunStatus(parsed.runId, homeDir);
|
|
271
|
+
const collected = (0, agent_run_1.collectRunStatus)(parsed.runId, homeDir);
|
|
463
272
|
if (collected.found && collected.info.state !== 'running' && read.events.length >= printed) {
|
|
464
273
|
return 0;
|
|
465
274
|
}
|
|
@@ -500,29 +309,6 @@ function parseRunListArgs(args) {
|
|
|
500
309
|
}
|
|
501
310
|
return { json, limit };
|
|
502
311
|
}
|
|
503
|
-
function listRunInfos(homeDir, limit) {
|
|
504
|
-
let entries;
|
|
505
|
-
try {
|
|
506
|
-
entries = node_fs_1.default.readdirSync(runsRoot(homeDir));
|
|
507
|
-
}
|
|
508
|
-
catch {
|
|
509
|
-
return [];
|
|
510
|
-
}
|
|
511
|
-
const infos = [];
|
|
512
|
-
for (const runId of entries) {
|
|
513
|
-
const collected = collectRunStatus(runId, homeDir);
|
|
514
|
-
if (collected.found) {
|
|
515
|
-
infos.push(collected.info);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
infos.sort((a, b) => {
|
|
519
|
-
if (a.startedAt !== b.startedAt) {
|
|
520
|
-
return a.startedAt < b.startedAt ? 1 : -1;
|
|
521
|
-
}
|
|
522
|
-
return a.runId < b.runId ? 1 : -1;
|
|
523
|
-
});
|
|
524
|
-
return infos.slice(0, limit);
|
|
525
|
-
}
|
|
526
312
|
async function runRunListCommand(args, deps) {
|
|
527
313
|
const parsed = parseRunListArgs(args);
|
|
528
314
|
if ('error' in parsed) {
|
|
@@ -533,7 +319,7 @@ async function runRunListCommand(args, deps) {
|
|
|
533
319
|
console.error(parsed.error);
|
|
534
320
|
return 1;
|
|
535
321
|
}
|
|
536
|
-
const infos = listRunInfos(resolveHomeDir(deps), parsed.limit);
|
|
322
|
+
const infos = (0, agent_run_1.listRunInfos)(resolveHomeDir(deps), parsed.limit);
|
|
537
323
|
if (parsed.json) {
|
|
538
324
|
console.log(JSON.stringify(infos));
|
|
539
325
|
return 0;
|