@agentclientprotocol/claude-agent-acp 0.94.0 → 0.94.1-preview.10
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/README.md +21 -9
- package/dist/acp-agent.d.ts +39 -3
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +196 -67
- package/dist/acp-subagents.d.ts +2 -1
- package/dist/acp-subagents.d.ts.map +1 -1
- package/dist/air-extension.d.ts +5 -0
- package/dist/air-extension.d.ts.map +1 -1
- package/dist/air-extension.js +5 -0
- package/dist/async-tasks.d.ts +19 -0
- package/dist/async-tasks.d.ts.map +1 -1
- package/dist/async-tasks.js +52 -0
- package/dist/clear-context-coordinator.d.ts +1 -0
- package/dist/clear-context-coordinator.d.ts.map +1 -1
- package/dist/clear-context-coordinator.js +1 -0
- package/dist/index.js +2 -3
- package/dist/native-subagents.d.ts +64 -0
- package/dist/native-subagents.d.ts.map +1 -1
- package/dist/native-subagents.js +224 -9
- package/dist/permissions/options/shared.d.ts +3 -0
- package/dist/permissions/options/shared.d.ts.map +1 -1
- package/dist/permissions/options/tools.js +1 -1
- package/dist/serve.d.ts +19 -11
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +26 -18
- package/dist/session-index/activity.d.ts +4 -0
- package/dist/session-index/activity.d.ts.map +1 -1
- package/dist/session-index/activity.js +16 -0
- package/dist/session-index/background-tasks.d.ts +69 -0
- package/dist/session-index/background-tasks.d.ts.map +1 -0
- package/dist/session-index/background-tasks.js +173 -0
- package/dist/session-index/service.d.ts +2 -0
- package/dist/session-index/service.d.ts.map +1 -1
- package/dist/session-index/service.js +6 -1
- package/dist/session-index/session-index.d.ts +14 -0
- package/dist/session-index/session-index.d.ts.map +1 -1
- package/dist/session-index/session-index.js +25 -2
- package/dist/session-index/transcript-scan.d.ts +8 -1
- package/dist/session-index/transcript-scan.d.ts.map +1 -1
- package/dist/session-index/transcript-scan.js +22 -1
- package/dist/session-titles.d.ts +44 -16
- package/dist/session-titles.d.ts.map +1 -1
- package/dist/session-titles.js +89 -27
- package/dist/subagent-replay.d.ts +21 -1
- package/dist/subagent-replay.d.ts.map +1 -1
- package/dist/subagent-replay.js +51 -3
- package/dist/task-notifications.d.ts +30 -0
- package/dist/task-notifications.d.ts.map +1 -0
- package/dist/task-notifications.js +62 -0
- package/package.json +1 -1
package/dist/serve.d.ts
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
import * as v2 from "@agentclientprotocol/sdk/experimental/v2
|
|
1
|
+
import * as v2 from "@agentclientprotocol/sdk/experimental/v2";
|
|
2
2
|
import { type ClaudeAcpAgent, type Logger } from "./acp-agent.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* With `experimentalV2`, the connection goes through {@link acpProtocolRouter}.
|
|
7
|
-
* Without it, the adapter serves ACP v1 alone and never routes by protocol
|
|
8
|
-
* version, exactly as before.
|
|
4
|
+
* The ACP versions that the adapter serves: `v1` or `v2` alone, or both with
|
|
5
|
+
* `auto`, where the client's `initialize` picks the version.
|
|
9
6
|
*/
|
|
7
|
+
export type AcpProtocols = "auto" | "v1" | "v2";
|
|
8
|
+
/**
|
|
9
|
+
* Reads `CLAUDE_AGENT_ACP_PROTOCOL`: unset, empty, or `auto` serves both
|
|
10
|
+
* versions, and `v1` or `v2` serves that version alone. Throws on any other
|
|
11
|
+
* value, so that a typo such as `CLAUDE_AGENT_ACP_PROTOCOL=1` fails at startup
|
|
12
|
+
* instead of silently serving both.
|
|
13
|
+
*/
|
|
14
|
+
export declare function acpProtocolsFromEnv(value: string | undefined): AcpProtocols;
|
|
15
|
+
/** Serves ACP on stdio through {@link acpProtocolRouter}. */
|
|
10
16
|
export declare function serveAcp(logger: Logger | undefined, options: {
|
|
11
|
-
|
|
17
|
+
protocols: AcpProtocols;
|
|
12
18
|
}): {
|
|
13
19
|
closed: Promise<void>;
|
|
14
20
|
dispose(): Promise<void>;
|
|
15
21
|
};
|
|
16
22
|
/**
|
|
17
23
|
* Routes a connection to the protocol version that the client negotiates in
|
|
18
|
-
* `initialize
|
|
19
|
-
*
|
|
20
|
-
*
|
|
24
|
+
* `initialize`. With `auto`, a client that requests version 2 or later gets
|
|
25
|
+
* the draft ACP v2, and every other client gets ACP v1. With `v1`, a v2
|
|
26
|
+
* client is negotiated down to v1. With `v2`, the router rejects the
|
|
27
|
+
* `initialize` of a v1 client as an unsupported protocol version. `onAgent`
|
|
28
|
+
* receives the agent of the connection once the router has opened it.
|
|
21
29
|
*/
|
|
22
|
-
export declare function acpProtocolRouter(logger: Logger | undefined, onAgent: (agent: ClaudeAcpAgent) => void): v2.AgentProtocolRouter;
|
|
30
|
+
export declare function acpProtocolRouter(logger: Logger | undefined, onAgent: (agent: ClaudeAcpAgent) => void, protocols?: AcpProtocols): v2.AgentProtocolRouter;
|
|
23
31
|
//# sourceMappingURL=serve.d.ts.map
|
package/dist/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,EAAc,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAI9E;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAM3E;AAED,6DAA6D;AAC7D,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE;IAAE,SAAS,EAAE,YAAY,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAkBrD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,EACxC,SAAS,GAAE,YAAqB,GAC/B,EAAE,CAAC,mBAAmB,CAKxB"}
|
package/dist/serve.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as v2 from "@agentclientprotocol/sdk/experimental/v2/unstable";
|
|
1
|
+
import * as v2 from "@agentclientprotocol/sdk/experimental/v2";
|
|
3
2
|
import { v1AgentApp } from "./acp-agent.js";
|
|
4
3
|
import { nodeToWebReadable, nodeToWebWritable } from "./utils.js";
|
|
5
4
|
import { v2AgentApp } from "./v2/agent.js";
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* version, exactly as before.
|
|
6
|
+
* Reads `CLAUDE_AGENT_ACP_PROTOCOL`: unset, empty, or `auto` serves both
|
|
7
|
+
* versions, and `v1` or `v2` serves that version alone. Throws on any other
|
|
8
|
+
* value, so that a typo such as `CLAUDE_AGENT_ACP_PROTOCOL=1` fails at startup
|
|
9
|
+
* instead of silently serving both.
|
|
12
10
|
*/
|
|
11
|
+
export function acpProtocolsFromEnv(value) {
|
|
12
|
+
if (value === undefined || value === "")
|
|
13
|
+
return "auto";
|
|
14
|
+
if (value === "auto" || value === "v1" || value === "v2")
|
|
15
|
+
return value;
|
|
16
|
+
throw new Error(`CLAUDE_AGENT_ACP_PROTOCOL must be "auto", "v1", or "v2", not ${JSON.stringify(value)}`);
|
|
17
|
+
}
|
|
18
|
+
/** Serves ACP on stdio through {@link acpProtocolRouter}. */
|
|
13
19
|
export function serveAcp(logger, options) {
|
|
14
20
|
const output = nodeToWebWritable(process.stdout);
|
|
15
21
|
const input = nodeToWebReadable(process.stdin);
|
|
@@ -19,9 +25,7 @@ export function serveAcp(logger, options) {
|
|
|
19
25
|
const onAgent = (created) => {
|
|
20
26
|
agent = created;
|
|
21
27
|
};
|
|
22
|
-
const { closed } = options.
|
|
23
|
-
? acpProtocolRouter(logger, onAgent).connect(v2.ndJsonStream(output, input))
|
|
24
|
-
: v1AgentApp(logger, onAgent).connect(ndJsonStream(output, input));
|
|
28
|
+
const { closed } = acpProtocolRouter(logger, onAgent, options.protocols).connect(v2.ndJsonStream(output, input));
|
|
25
29
|
return {
|
|
26
30
|
closed,
|
|
27
31
|
dispose: async () => {
|
|
@@ -31,13 +35,17 @@ export function serveAcp(logger, options) {
|
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
33
37
|
* Routes a connection to the protocol version that the client negotiates in
|
|
34
|
-
* `initialize
|
|
35
|
-
*
|
|
36
|
-
*
|
|
38
|
+
* `initialize`. With `auto`, a client that requests version 2 or later gets
|
|
39
|
+
* the draft ACP v2, and every other client gets ACP v1. With `v1`, a v2
|
|
40
|
+
* client is negotiated down to v1. With `v2`, the router rejects the
|
|
41
|
+
* `initialize` of a v1 client as an unsupported protocol version. `onAgent`
|
|
42
|
+
* receives the agent of the connection once the router has opened it.
|
|
37
43
|
*/
|
|
38
|
-
export function acpProtocolRouter(logger, onAgent) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
.withV1(v1AgentApp(logger, onAgent))
|
|
42
|
-
|
|
44
|
+
export function acpProtocolRouter(logger, onAgent, protocols = "auto") {
|
|
45
|
+
const router = v2.agentProtocolRouter();
|
|
46
|
+
if (protocols !== "v2")
|
|
47
|
+
router.withV1(v1AgentApp(logger, onAgent));
|
|
48
|
+
if (protocols !== "v1")
|
|
49
|
+
router.withV2(v2AgentApp(logger, onAgent));
|
|
50
|
+
return router;
|
|
43
51
|
}
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
* - an interactive CLI that is not driven by an SDK holds it, and its registry
|
|
12
12
|
* status is newer than the transcript: the registry status (an idle one is
|
|
13
13
|
* `error` after such a turn);
|
|
14
|
+
* - a turn that ended with an open background task is `running`, also after
|
|
15
|
+
* 10 minutes: Claude Code wakes the session again when the task ends. The
|
|
16
|
+
* wait ends when the registry status is `idle`, because a task can end
|
|
17
|
+
* without a transcript record (a stop in the task UI);
|
|
14
18
|
* - otherwise the transcript tail: a finished turn is `idle` (`error` after
|
|
15
19
|
* an API error), an unfinished turn written in the last 10 minutes is
|
|
16
20
|
* `running`, and anything else has no known state.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../src/session-index/activity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../src/session-index/activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,iBAAiB,GAAG,OAAO,CAAC;AAE7E,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;gEAE4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAuCF,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,eAAe,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,eAAe,GAAG,SAAS,CAwC9B;AAED;;eAEe;AACf,wBAAgB,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG/E"}
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
* - an interactive CLI that is not driven by an SDK holds it, and its registry
|
|
12
12
|
* status is newer than the transcript: the registry status (an idle one is
|
|
13
13
|
* `error` after such a turn);
|
|
14
|
+
* - a turn that ended with an open background task is `running`, also after
|
|
15
|
+
* 10 minutes: Claude Code wakes the session again when the task ends. The
|
|
16
|
+
* wait ends when the registry status is `idle`, because a task can end
|
|
17
|
+
* without a transcript record (a stop in the task UI);
|
|
14
18
|
* - otherwise the transcript tail: a finished turn is `idle` (`error` after
|
|
15
19
|
* an API error), an unfinished turn written in the last 10 minutes is
|
|
16
20
|
* `running`, and anything else has no known state.
|
|
@@ -41,6 +45,14 @@ function usesRegistryStatus(record, transcriptMtimeMs) {
|
|
|
41
45
|
record.statusUpdatedAt !== undefined &&
|
|
42
46
|
record.statusUpdatedAt > transcriptMtimeMs);
|
|
43
47
|
}
|
|
48
|
+
/** Whether the last turn ended while a background task of the session is
|
|
49
|
+
* open. */
|
|
50
|
+
function waitsForBackgroundTasks(facts) {
|
|
51
|
+
if (facts.turnState !== "finished")
|
|
52
|
+
return false;
|
|
53
|
+
const openTasks = facts.backgroundTasks?.open ?? [];
|
|
54
|
+
return openTasks.length > 0;
|
|
55
|
+
}
|
|
44
56
|
function iso(ms) {
|
|
45
57
|
return ms === undefined || !Number.isFinite(ms) ? undefined : new Date(ms).toISOString();
|
|
46
58
|
}
|
|
@@ -69,6 +81,10 @@ export function deriveActivity(input) {
|
|
|
69
81
|
if (state === "idle" && failed)
|
|
70
82
|
state = "error";
|
|
71
83
|
}
|
|
84
|
+
else if (waitsForBackgroundTasks(facts) && live.status !== "idle") {
|
|
85
|
+
// Claude Code wakes the session again when an open task ends.
|
|
86
|
+
state = "running";
|
|
87
|
+
}
|
|
72
88
|
else if (failed) {
|
|
73
89
|
state = "error";
|
|
74
90
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The background tasks of a session that did not end yet, from its transcript.
|
|
3
|
+
*
|
|
4
|
+
* A Claude Code session can start a background shell command or a background
|
|
5
|
+
* sub-agent and end its turn at once. When the task ends, Claude Code wakes
|
|
6
|
+
* the session with a `<task-notification>` input for a short turn. So a turn
|
|
7
|
+
* end with an open task is no end of the work: the session list keeps such a
|
|
8
|
+
* session `running` (see `activity.ts`).
|
|
9
|
+
*
|
|
10
|
+
* The records, as Claude Code 2.1.299 writes them, in the rules of AIR's
|
|
11
|
+
* native Claude provider:
|
|
12
|
+
*
|
|
13
|
+
* - a tool result opens a task when its `toolUseResult` has a
|
|
14
|
+
* `backgroundTaskId` (a shell command), or `isAsync: true` with an
|
|
15
|
+
* `agentId` (a sub-agent);
|
|
16
|
+
* - a task closes when its notification reaches the session: as a user
|
|
17
|
+
* record, or as a `queue-operation` `remove` when a running turn takes it
|
|
18
|
+
* in. A notification that waits in the queue (`enqueue`) keeps the task
|
|
19
|
+
* open, because the session still runs a turn for it;
|
|
20
|
+
* - only a notification with a `<status>` closes a task. A notification
|
|
21
|
+
* without one comes while the task still runs: the check-in of a quiet
|
|
22
|
+
* shell ("is still running after …", since Claude Code 2.1.303) or a
|
|
23
|
+
* `Monitor` event;
|
|
24
|
+
* - a `TaskStop` result closes the task of its `toolUseResult.task_id`:
|
|
25
|
+
* Claude Code writes no notification for it. The result does not name its
|
|
26
|
+
* tool, so its `tool_use_id` must match a `TaskStop` call. A `task_id` in
|
|
27
|
+
* the result of another tool keeps the task open;
|
|
28
|
+
* - a resumed CLI writes a `stopped` notification for each task of the
|
|
29
|
+
* previous process;
|
|
30
|
+
* - a sidechain record belongs to a sub-agent and opens or closes no task of
|
|
31
|
+
* the session.
|
|
32
|
+
*
|
|
33
|
+
* A background shell that does not end, for example a dev server, keeps its
|
|
34
|
+
* task open, so its session stays `running` while the CLI holds it.
|
|
35
|
+
*
|
|
36
|
+
* A task that a sub-agent starts is not seen. Its start record is only in the
|
|
37
|
+
* transcript of the sub-agent, so the session can be `idle` while the
|
|
38
|
+
* sub-agent waits for it.
|
|
39
|
+
*/
|
|
40
|
+
export type BackgroundTasks = {
|
|
41
|
+
/** The ids of the tasks that started and did not end, in start order. */
|
|
42
|
+
open: string[];
|
|
43
|
+
/** The `tool_use` ids of the `TaskStop` calls without a result. */
|
|
44
|
+
stopCalls: string[];
|
|
45
|
+
/** Whether the sets hold the records of the whole file. A set from the
|
|
46
|
+
* tail window only does not know a task that started before it. */
|
|
47
|
+
complete: boolean;
|
|
48
|
+
};
|
|
49
|
+
/** The task that a `<task-notification>` input ends: only an input that
|
|
50
|
+
* starts with the tag, after whitespace, as AIR's `TaskNotification` reads
|
|
51
|
+
* it. Only a notification with a `<status>` ends a task (see
|
|
52
|
+
* `taskNotificationsOf`). */
|
|
53
|
+
export declare function endedTaskId(input: string | undefined): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The tasks of the lines of `text`, applied on the tasks `after`.
|
|
56
|
+
*
|
|
57
|
+
* `after` can be what an earlier scan found for a shorter copy of the file,
|
|
58
|
+
* and `text` can repeat records of that copy. The result is still the same:
|
|
59
|
+
* the last record that opens or closes a task decides, and `text` holds the
|
|
60
|
+
* last records.
|
|
61
|
+
*/
|
|
62
|
+
export declare function backgroundTasksOf(text: string, options: {
|
|
63
|
+
complete: boolean;
|
|
64
|
+
after?: BackgroundTasks;
|
|
65
|
+
}): BackgroundTasks;
|
|
66
|
+
/** The tasks of the first `size` bytes of `filePath`, from all its records.
|
|
67
|
+
* Reads the whole file, so only for a session that a live process holds. */
|
|
68
|
+
export declare function searchBackgroundTasks(filePath: string, size: number): Promise<BackgroundTasks>;
|
|
69
|
+
//# sourceMappingURL=background-tasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background-tasks.d.ts","sourceRoot":"","sources":["../../src/session-index/background-tasks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAMH,MAAM,MAAM,eAAe,GAAG;IAC5B,yEAAyE;IACzE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mEAAmE;IACnE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;wEACoE;IACpE,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AA6DF;;;8BAG8B;AAC9B,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGzE;AAyED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,GACtD,eAAe,CAIjB;AAED;6EAC6E;AAC7E,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC,CAO1B"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The background tasks of a session that did not end yet, from its transcript.
|
|
3
|
+
*
|
|
4
|
+
* A Claude Code session can start a background shell command or a background
|
|
5
|
+
* sub-agent and end its turn at once. When the task ends, Claude Code wakes
|
|
6
|
+
* the session with a `<task-notification>` input for a short turn. So a turn
|
|
7
|
+
* end with an open task is no end of the work: the session list keeps such a
|
|
8
|
+
* session `running` (see `activity.ts`).
|
|
9
|
+
*
|
|
10
|
+
* The records, as Claude Code 2.1.299 writes them, in the rules of AIR's
|
|
11
|
+
* native Claude provider:
|
|
12
|
+
*
|
|
13
|
+
* - a tool result opens a task when its `toolUseResult` has a
|
|
14
|
+
* `backgroundTaskId` (a shell command), or `isAsync: true` with an
|
|
15
|
+
* `agentId` (a sub-agent);
|
|
16
|
+
* - a task closes when its notification reaches the session: as a user
|
|
17
|
+
* record, or as a `queue-operation` `remove` when a running turn takes it
|
|
18
|
+
* in. A notification that waits in the queue (`enqueue`) keeps the task
|
|
19
|
+
* open, because the session still runs a turn for it;
|
|
20
|
+
* - only a notification with a `<status>` closes a task. A notification
|
|
21
|
+
* without one comes while the task still runs: the check-in of a quiet
|
|
22
|
+
* shell ("is still running after …", since Claude Code 2.1.303) or a
|
|
23
|
+
* `Monitor` event;
|
|
24
|
+
* - a `TaskStop` result closes the task of its `toolUseResult.task_id`:
|
|
25
|
+
* Claude Code writes no notification for it. The result does not name its
|
|
26
|
+
* tool, so its `tool_use_id` must match a `TaskStop` call. A `task_id` in
|
|
27
|
+
* the result of another tool keeps the task open;
|
|
28
|
+
* - a resumed CLI writes a `stopped` notification for each task of the
|
|
29
|
+
* previous process;
|
|
30
|
+
* - a sidechain record belongs to a sub-agent and opens or closes no task of
|
|
31
|
+
* the session.
|
|
32
|
+
*
|
|
33
|
+
* A background shell that does not end, for example a dev server, keeps its
|
|
34
|
+
* task open, so its session stays `running` while the CLI holds it.
|
|
35
|
+
*
|
|
36
|
+
* A task that a sub-agent starts is not seen. Its start record is only in the
|
|
37
|
+
* transcript of the sub-agent, so the session can be `idle` while the
|
|
38
|
+
* sub-agent waits for it.
|
|
39
|
+
*/
|
|
40
|
+
import { createReadStream } from "node:fs";
|
|
41
|
+
import { createInterface } from "node:readline";
|
|
42
|
+
import { TASK_NOTIFICATION_TAG, taskNotificationsOf } from "../task-notifications.js";
|
|
43
|
+
const NOTIFICATION_TAG = `<${TASK_NOTIFICATION_TAG}>`;
|
|
44
|
+
/** Text that a line must hold to bear on a task, so that the other lines
|
|
45
|
+
* are not parsed. */
|
|
46
|
+
const TASK_MARKERS = ["backgroundTaskId", '"isAsync"', NOTIFICATION_TAG, "TaskStop", "task_id"];
|
|
47
|
+
function parseRecord(line) {
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(line);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function blocksOf(record) {
|
|
56
|
+
const content = record.message?.content;
|
|
57
|
+
return Array.isArray(content) ? content : [];
|
|
58
|
+
}
|
|
59
|
+
/** The input of a user record: its string content, else its first text
|
|
60
|
+
* block. */
|
|
61
|
+
function inputTextOf(record) {
|
|
62
|
+
const content = record.message?.content;
|
|
63
|
+
if (typeof content === "string")
|
|
64
|
+
return content;
|
|
65
|
+
return blocksOf(record).find((block) => block.type === "text")?.text;
|
|
66
|
+
}
|
|
67
|
+
/** The task that a `<task-notification>` input ends: only an input that
|
|
68
|
+
* starts with the tag, after whitespace, as AIR's `TaskNotification` reads
|
|
69
|
+
* it. Only a notification with a `<status>` ends a task (see
|
|
70
|
+
* `taskNotificationsOf`). */
|
|
71
|
+
export function endedTaskId(input) {
|
|
72
|
+
if (!input?.trimStart().startsWith(NOTIFICATION_TAG))
|
|
73
|
+
return undefined;
|
|
74
|
+
return taskNotificationsOf(input)[0]?.task_id;
|
|
75
|
+
}
|
|
76
|
+
/** The task that a tool result started: a background shell command, or an
|
|
77
|
+
* async sub-agent. */
|
|
78
|
+
function startedTaskId(record) {
|
|
79
|
+
if (record.type !== "user")
|
|
80
|
+
return undefined;
|
|
81
|
+
const result = record.toolUseResult;
|
|
82
|
+
if (result?.backgroundTaskId)
|
|
83
|
+
return result.backgroundTaskId;
|
|
84
|
+
if (result?.isAsync)
|
|
85
|
+
return result.agentId;
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
/** The task whose notification reached the session: as a user record, or
|
|
89
|
+
* as a queue `remove` when a running turn takes it in. */
|
|
90
|
+
function deliveredTaskId(record) {
|
|
91
|
+
if (record.type === "user")
|
|
92
|
+
return endedTaskId(inputTextOf(record));
|
|
93
|
+
if (record.type === "queue-operation" && record.operation === "remove") {
|
|
94
|
+
return endedTaskId(record.content);
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
/** Collects the tasks of the lines it is given, in file order. */
|
|
99
|
+
class TaskTracker {
|
|
100
|
+
open;
|
|
101
|
+
stopCalls;
|
|
102
|
+
constructor(after) {
|
|
103
|
+
this.open = new Set(after?.open);
|
|
104
|
+
this.stopCalls = new Set(after?.stopCalls);
|
|
105
|
+
}
|
|
106
|
+
add(line) {
|
|
107
|
+
const mayBearOnTask = TASK_MARKERS.some((marker) => line.includes(marker));
|
|
108
|
+
if (!mayBearOnTask)
|
|
109
|
+
return;
|
|
110
|
+
const record = parseRecord(line);
|
|
111
|
+
// A sidechain record belongs to a sub-agent, which receives the
|
|
112
|
+
// notifications of its own tasks.
|
|
113
|
+
if (!record || record.isSidechain)
|
|
114
|
+
return;
|
|
115
|
+
this.apply(record);
|
|
116
|
+
}
|
|
117
|
+
result({ complete }) {
|
|
118
|
+
return { open: [...this.open], stopCalls: [...this.stopCalls], complete };
|
|
119
|
+
}
|
|
120
|
+
apply(record) {
|
|
121
|
+
const started = startedTaskId(record);
|
|
122
|
+
if (started)
|
|
123
|
+
this.open.add(started);
|
|
124
|
+
const delivered = deliveredTaskId(record);
|
|
125
|
+
if (delivered)
|
|
126
|
+
this.open.delete(delivered);
|
|
127
|
+
this.applyTaskStop(record);
|
|
128
|
+
}
|
|
129
|
+
/** A `task_id` stops its task only in the result of a `TaskStop` call:
|
|
130
|
+
* another tool can give a `task_id` too. */
|
|
131
|
+
applyTaskStop(record) {
|
|
132
|
+
let isTaskStopResult = false;
|
|
133
|
+
for (const block of blocksOf(record)) {
|
|
134
|
+
if (block.type === "tool_use" && block.name === "TaskStop" && block.id) {
|
|
135
|
+
this.stopCalls.add(block.id);
|
|
136
|
+
}
|
|
137
|
+
const resultId = block.tool_use_id;
|
|
138
|
+
if (resultId && this.stopCalls.has(resultId)) {
|
|
139
|
+
this.stopCalls.delete(resultId);
|
|
140
|
+
isTaskStopResult = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const stopped = record.toolUseResult?.task_id;
|
|
144
|
+
if (isTaskStopResult && stopped)
|
|
145
|
+
this.open.delete(stopped);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The tasks of the lines of `text`, applied on the tasks `after`.
|
|
150
|
+
*
|
|
151
|
+
* `after` can be what an earlier scan found for a shorter copy of the file,
|
|
152
|
+
* and `text` can repeat records of that copy. The result is still the same:
|
|
153
|
+
* the last record that opens or closes a task decides, and `text` holds the
|
|
154
|
+
* last records.
|
|
155
|
+
*/
|
|
156
|
+
export function backgroundTasksOf(text, options) {
|
|
157
|
+
const tracker = new TaskTracker(options.after);
|
|
158
|
+
for (const line of text.split("\n"))
|
|
159
|
+
tracker.add(line);
|
|
160
|
+
return tracker.result({ complete: options.complete });
|
|
161
|
+
}
|
|
162
|
+
/** The tasks of the first `size` bytes of `filePath`, from all its records.
|
|
163
|
+
* Reads the whole file, so only for a session that a live process holds. */
|
|
164
|
+
export async function searchBackgroundTasks(filePath, size) {
|
|
165
|
+
const tracker = new TaskTracker();
|
|
166
|
+
if (size === 0)
|
|
167
|
+
return tracker.result({ complete: true });
|
|
168
|
+
const stream = createReadStream(filePath, { start: 0, end: size - 1, encoding: "utf8" });
|
|
169
|
+
const lines = createInterface({ input: stream, crlfDelay: Infinity });
|
|
170
|
+
for await (const line of lines)
|
|
171
|
+
tracker.add(line);
|
|
172
|
+
return tracker.result({ complete: true });
|
|
173
|
+
}
|
|
@@ -121,6 +121,8 @@ export declare class SessionIndexService {
|
|
|
121
121
|
private readonly now;
|
|
122
122
|
private readonly deleteSession;
|
|
123
123
|
constructor(deps: SessionIndexDeps);
|
|
124
|
+
/** Whether a live process holds the session, by the live registry. */
|
|
125
|
+
private isLive;
|
|
124
126
|
/** `session/list` of a `sessionIndex` client. `own` reports the sessions
|
|
125
127
|
* that this connection runs. */
|
|
126
128
|
list(params: ListSessionsRequest, own: (sessionId: string) => OwnSessionState | undefined): Promise<ListSessionsResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/session-index/service.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/session-index/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -327,11 +327,16 @@ export class SessionIndexService {
|
|
|
327
327
|
deleteSession;
|
|
328
328
|
constructor(deps) {
|
|
329
329
|
this.deps = deps;
|
|
330
|
-
this.index = new SessionIndex();
|
|
331
330
|
this.registry = deps.registry ?? new LiveSessionRegistry();
|
|
331
|
+
this.index = new SessionIndex({ isLive: (sessionId) => this.isLive(sessionId) });
|
|
332
332
|
this.now = deps.now ?? Date.now;
|
|
333
333
|
this.deleteSession = deps.deleteSession ?? ((id) => sdkDeleteSession(id));
|
|
334
334
|
}
|
|
335
|
+
/** Whether a live process holds the session, by the live registry. */
|
|
336
|
+
async isLive(sessionId) {
|
|
337
|
+
const live = await this.registry.snapshot();
|
|
338
|
+
return live.has(sessionId);
|
|
339
|
+
}
|
|
335
340
|
/** `session/list` of a `sessionIndex` client. `own` reports the sessions
|
|
336
341
|
* that this connection runs. */
|
|
337
342
|
async list(params, own) {
|
|
@@ -72,7 +72,14 @@ export type ListQuery = {
|
|
|
72
72
|
};
|
|
73
73
|
/** The title of the CLI's `custom-title.json` sidecar of a transcript. */
|
|
74
74
|
export declare function readSidecarTitle(filePath: string, sessionId: string): Promise<string | undefined>;
|
|
75
|
+
export type SessionIndexOptions = {
|
|
76
|
+
/** Whether a live process holds the session. Only for such a session the
|
|
77
|
+
* whole transcript is searched for its background tasks. */
|
|
78
|
+
isLive?: (sessionId: string) => Promise<boolean>;
|
|
79
|
+
};
|
|
75
80
|
export declare class SessionIndex {
|
|
81
|
+
private readonly options;
|
|
82
|
+
constructor(options?: SessionIndexOptions);
|
|
76
83
|
private readonly listings;
|
|
77
84
|
private readonly metadata;
|
|
78
85
|
/** The metadata reads in flight, by path: a list and a subscription that
|
|
@@ -212,6 +219,13 @@ export declare class SessionIndex {
|
|
|
212
219
|
private metadataOf;
|
|
213
220
|
private readAndCache;
|
|
214
221
|
private readMetadata;
|
|
222
|
+
/**
|
|
223
|
+
* `facts` with the background tasks of the whole transcript, when the
|
|
224
|
+
* tasks of its tail are not complete: a task can start before the tail.
|
|
225
|
+
* Only a finished turn of a live session waits for the tasks, so only
|
|
226
|
+
* then the whole transcript is read.
|
|
227
|
+
*/
|
|
228
|
+
private withAllBackgroundTasks;
|
|
215
229
|
/**
|
|
216
230
|
* The titles the SDK gives the listed transcript (`customTitle` and
|
|
217
231
|
* `summary` of its `getSessionInfo`), by the SDK's rule from the head and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-index.d.ts","sourceRoot":"","sources":["../../src/session-index/session-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAkBH,OAAO,EAeL,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"session-index.d.ts","sourceRoot":"","sources":["../../src/session-index/session-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ import { sanitizeTitle } from "../session-titles.js";
|
|
|
24
24
|
import { effectiveTitle, visibleTitle } from "./archive-title.js";
|
|
25
25
|
import { canonicalPath, encodeProjectPath, isExactProjectDir, isSessionId, normalizePath, pathAndAncestors, projectDirMatches, projectDirsOf, projectsRoot, sameProjectPath, } from "./project-dirs.js";
|
|
26
26
|
import { continuedInSessionId, hasHistory, isSidechainTranscript, lastTimestamp, readHeadTail, relocatedCwd, scanTranscriptFile, sdkTitles, tailCustomTitle, transcriptAgentName, transcriptProjectCwd, } from "./transcript-scan.js";
|
|
27
|
+
import { searchBackgroundTasks } from "./background-tasks.js";
|
|
27
28
|
import { DirListings, statFiles } from "./dir-listing.js";
|
|
28
29
|
import { isInLinkedWorktree, worktreeCounterparts } from "./worktrees.js";
|
|
29
30
|
export const DEFAULT_LIST_LIMIT = 50;
|
|
@@ -260,6 +261,10 @@ function scopeOf(paths) {
|
|
|
260
261
|
};
|
|
261
262
|
}
|
|
262
263
|
export class SessionIndex {
|
|
264
|
+
options;
|
|
265
|
+
constructor(options = {}) {
|
|
266
|
+
this.options = options;
|
|
267
|
+
}
|
|
263
268
|
listings = new DirListings();
|
|
264
269
|
metadata = new Lru(METADATA_CACHE_SIZE);
|
|
265
270
|
/** The metadata reads in flight, by path: a list and a subscription that
|
|
@@ -776,9 +781,10 @@ export class SessionIndex {
|
|
|
776
781
|
const headTail = await readHeadTail(candidate.filePath, candidate.size);
|
|
777
782
|
if (isSidechainTranscript(headTail.head))
|
|
778
783
|
return null;
|
|
779
|
-
const
|
|
780
|
-
if (!
|
|
784
|
+
const scanned = await scanTranscriptFile(candidate.filePath, candidate.size, headTail, previous, candidate.ino);
|
|
785
|
+
if (!scanned.hasMessages)
|
|
781
786
|
return null;
|
|
787
|
+
const facts = await this.withAllBackgroundTasks(candidate, scanned);
|
|
782
788
|
// The last relocation names the session's cwd, as the SDK reads it; the
|
|
783
789
|
// messages before it keep the old one.
|
|
784
790
|
const fileCwd = await this.recoverCwd(candidate.dirName, [
|
|
@@ -811,6 +817,23 @@ export class SessionIndex {
|
|
|
811
817
|
facts,
|
|
812
818
|
};
|
|
813
819
|
}
|
|
820
|
+
/**
|
|
821
|
+
* `facts` with the background tasks of the whole transcript, when the
|
|
822
|
+
* tasks of its tail are not complete: a task can start before the tail.
|
|
823
|
+
* Only a finished turn of a live session waits for the tasks, so only
|
|
824
|
+
* then the whole transcript is read.
|
|
825
|
+
*/
|
|
826
|
+
async withAllBackgroundTasks(candidate, facts) {
|
|
827
|
+
if (facts.turnState !== "finished")
|
|
828
|
+
return facts;
|
|
829
|
+
if (facts.backgroundTasks?.complete)
|
|
830
|
+
return facts;
|
|
831
|
+
const isLive = await this.options.isLive?.(candidate.sessionId);
|
|
832
|
+
if (!isLive)
|
|
833
|
+
return facts;
|
|
834
|
+
const backgroundTasks = await searchBackgroundTasks(candidate.filePath, candidate.size);
|
|
835
|
+
return { ...facts, backgroundTasks };
|
|
836
|
+
}
|
|
814
837
|
/**
|
|
815
838
|
* The titles the SDK gives the listed transcript (`customTitle` and
|
|
816
839
|
* `summary` of its `getSessionInfo`), by the SDK's rule from the head and
|
|
@@ -7,8 +7,12 @@
|
|
|
7
7
|
*
|
|
8
8
|
* A last message longer than the tail window leaves no message in it: then
|
|
9
9
|
* the tail window grows, up to {@link MAX_TAIL_SIZE}, until it holds one.
|
|
10
|
+
*
|
|
11
|
+
* The open background tasks come from the tail, on top of the tasks of an
|
|
12
|
+
* earlier scan (see `background-tasks.ts`).
|
|
10
13
|
*/
|
|
11
14
|
import * as fs from "node:fs/promises";
|
|
15
|
+
import { type BackgroundTasks } from "./background-tasks.js";
|
|
12
16
|
export type TurnState = "finished" | "unfinished";
|
|
13
17
|
export type TranscriptFacts = {
|
|
14
18
|
/** Time of the last user or assistant message in the tail, epoch ms. */
|
|
@@ -41,6 +45,9 @@ export type TranscriptFacts = {
|
|
|
41
45
|
* worktree and the session is in it), false when it says otherwise.
|
|
42
46
|
* Undefined when no such record was read. See {@link agentWorktreeOf}. */
|
|
43
47
|
agentWorktree?: boolean;
|
|
48
|
+
/** The background tasks that did not end. From the tail, on top of what
|
|
49
|
+
* an earlier scan found when the file only grew within the tail. */
|
|
50
|
+
backgroundTasks?: BackgroundTasks;
|
|
44
51
|
/** Whether the head or the tail holds a user or an assistant message. A
|
|
45
52
|
* transcript without one is a metadata-only stub. */
|
|
46
53
|
hasMessages: boolean;
|
|
@@ -59,7 +66,7 @@ declare const INHERITED_FACTS: readonly ["model", "tailCwd", "lastTurnEndedAt",
|
|
|
59
66
|
/** What an earlier scan of the same file found, at `size`. */
|
|
60
67
|
export type PreviousScan = {
|
|
61
68
|
size: number;
|
|
62
|
-
} & Pick<TranscriptFacts, "lastPromptAt" | "promptSearched" | (typeof INHERITED_FACTS)[number]>;
|
|
69
|
+
} & Pick<TranscriptFacts, "lastPromptAt" | "promptSearched" | "backgroundTasks" | (typeof INHERITED_FACTS)[number]>;
|
|
63
70
|
/** The first and the last 64 KB of the first `size` bytes of `filePath`:
|
|
64
71
|
* what was appended after the file was stat'ed is not read, so the result
|
|
65
72
|
* matches the size it is cached by. The tail is the head for a file that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-scan.d.ts","sourceRoot":"","sources":["../../src/session-index/transcript-scan.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"transcript-scan.d.ts","sourceRoot":"","sources":["../../src/session-index/transcript-scan.ts"],"names":[],"mappings":"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"}
|