@dynamicagents/plugins 0.11.1 → 0.13.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/README.md +59 -79
- package/dist/browser/index.d.ts +0 -2
- package/dist/browser/index.js +21 -27
- package/dist/claude-code/cards.d.ts +53 -0
- package/dist/claude-code/cards.js +272 -0
- package/dist/claude-code/config.d.ts +73 -31
- package/dist/claude-code/config.js +0 -2
- package/dist/claude-code/credentials.d.ts +21 -9
- package/dist/claude-code/credentials.js +43 -9
- package/dist/claude-code/egress.d.ts +15 -14
- package/dist/claude-code/egress.js +51 -14
- package/dist/claude-code/events.d.ts +153 -9
- package/dist/claude-code/events.js +289 -58
- package/dist/claude-code/github.d.ts +39 -0
- package/dist/claude-code/github.js +82 -0
- package/dist/claude-code/index.d.ts +24 -80
- package/dist/claude-code/index.js +19 -234
- package/dist/claude-code/model.d.ts +152 -0
- package/dist/claude-code/model.js +342 -0
- package/dist/claude-code/run.d.ts +283 -92
- package/dist/claude-code/run.js +620 -114
- package/dist/claude-code/session.d.ts +131 -0
- package/dist/claude-code/session.js +285 -0
- package/dist/claude-code/spec.d.ts +46 -0
- package/dist/claude-code/spec.js +83 -0
- package/dist/claude-code/verified.d.ts +15 -0
- package/dist/claude-code/verified.js +15 -0
- package/dist/computer/context.d.ts +19 -0
- package/dist/computer/context.js +222 -0
- package/dist/computer/file-lock.d.ts +5 -0
- package/dist/computer/file-lock.js +40 -0
- package/dist/computer/gate.d.ts +12 -12
- package/dist/computer/gate.js +12 -12
- package/dist/computer/index.d.ts +57 -255
- package/dist/computer/index.js +98 -1039
- package/dist/computer/paths.d.ts +47 -22
- package/dist/computer/paths.js +64 -49
- package/dist/computer/proxy.d.ts +45 -0
- package/dist/computer/proxy.js +234 -0
- package/dist/computer/render.d.ts +27 -38
- package/dist/computer/render.js +32 -65
- package/dist/computer/tools-exec.d.ts +3 -0
- package/dist/computer/tools-exec.js +268 -0
- package/dist/computer/tools-file.d.ts +12 -0
- package/dist/computer/tools-file.js +64 -0
- package/dist/computer/tools-grep.d.ts +3 -0
- package/dist/computer/tools-grep.js +129 -0
- package/dist/repo/checkout.d.ts +35 -6
- package/dist/repo/checkout.js +64 -6
- package/dist/repo/context.d.ts +135 -0
- package/dist/repo/context.js +582 -0
- package/dist/repo/index.d.ts +79 -57
- package/dist/repo/index.js +118 -1112
- package/dist/repo/tools-checks.d.ts +3 -0
- package/dist/repo/tools-checks.js +112 -0
- package/dist/repo/tools-clone.d.ts +4 -0
- package/dist/repo/tools-clone.js +192 -0
- package/dist/repo/tools-pr.d.ts +14 -0
- package/dist/repo/tools-pr.js +196 -0
- package/dist/repo/tools-review.d.ts +12 -0
- package/dist/repo/tools-review.js +393 -0
- package/dist/repo/tools-worktree.d.ts +4 -0
- package/dist/repo/tools-worktree.js +305 -0
- package/dist/repo/tools-worktrees.d.ts +12 -0
- package/dist/repo/tools-worktrees.js +48 -0
- package/dist/repo/url.d.ts +2 -2
- package/dist/repo/url.js +7 -7
- package/dist/scratch/index.d.ts +4 -4
- package/dist/scratch/index.js +12 -11
- package/dist/{computer → workspace}/advisory.d.ts +33 -20
- package/dist/{computer → workspace}/advisory.js +32 -7
- package/dist/workspace/ca-trust.d.ts +95 -0
- package/dist/workspace/ca-trust.js +312 -0
- package/dist/workspace/container-deps.d.ts +54 -0
- package/dist/workspace/container-deps.js +224 -0
- package/dist/workspace/container-fault.d.ts +38 -0
- package/dist/workspace/container-fault.js +73 -0
- package/dist/workspace/exec.d.ts +94 -0
- package/dist/workspace/exec.js +153 -0
- package/dist/workspace/format.d.ts +36 -0
- package/dist/workspace/format.js +57 -0
- package/dist/workspace/git-host.d.ts +79 -0
- package/dist/workspace/git-host.js +226 -0
- package/dist/workspace/git-identity.d.ts +57 -0
- package/dist/workspace/git-identity.js +147 -0
- package/dist/workspace/index.d.ts +43 -47
- package/dist/workspace/index.js +52 -112
- package/dist/workspace/install-job.d.ts +121 -0
- package/dist/workspace/install-job.js +866 -0
- package/dist/{computer → workspace}/install.d.ts +15 -19
- package/dist/{computer → workspace}/install.js +8 -11
- package/dist/workspace/object.d.ts +502 -0
- package/dist/workspace/object.js +1427 -0
- package/dist/workspace/open.d.ts +95 -0
- package/dist/workspace/open.js +63 -0
- package/dist/workspace/read.d.ts +16 -0
- package/dist/workspace/read.js +22 -0
- package/dist/workspace/shell.d.ts +45 -0
- package/dist/workspace/shell.js +80 -0
- package/dist/workspace/sync.d.ts +111 -0
- package/dist/workspace/sync.js +124 -0
- package/dist/workspace/wake.d.ts +19 -0
- package/dist/workspace/wake.js +10 -0
- package/package.json +28 -42
- package/dist/arc-agi/analysis.d.ts +0 -336
- package/dist/arc-agi/analysis.js +0 -829
- package/dist/arc-agi/client.d.ts +0 -82
- package/dist/arc-agi/client.js +0 -113
- package/dist/arc-agi/game-tools.d.ts +0 -25
- package/dist/arc-agi/game-tools.js +0 -26
- package/dist/arc-agi/index.d.ts +0 -42
- package/dist/arc-agi/index.js +0 -175
- package/dist/arc-agi/main-agent.d.ts +0 -27
- package/dist/arc-agi/main-agent.js +0 -65
- package/dist/arc-agi/recipe.d.ts +0 -51
- package/dist/arc-agi/recipe.js +0 -100
- package/dist/arc-agi/scorecard.d.ts +0 -118
- package/dist/arc-agi/scorecard.js +0 -163
- package/dist/arc-agi/soul.d.ts +0 -40
- package/dist/arc-agi/soul.js +0 -90
- package/dist/arc-agi/store.d.ts +0 -154
- package/dist/arc-agi/store.js +0 -216
- package/dist/arc-agi/tools.d.ts +0 -36
- package/dist/arc-agi/tools.js +0 -576
- package/dist/arc-agi/types.d.ts +0 -212
- package/dist/arc-agi/types.js +0 -19
- package/dist/claude-code/recipe.d.ts +0 -53
- package/dist/claude-code/recipe.js +0 -100
- package/dist/computer/read.d.ts +0 -137
- package/dist/computer/read.js +0 -203
- package/dist/recall/index.d.ts +0 -99
- package/dist/recall/index.js +0 -171
- package/dist/triage/index.d.ts +0 -355
- package/dist/triage/index.js +0 -302
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import type { AgentPlugin } from "@dynamicagents/core";
|
|
2
|
-
import type { CredentialStore, Lead } from "./credentials.js";
|
|
3
|
-
import { type DrainCursor, type DrainOutcome, type SessionRuntime } from "./run.js";
|
|
4
|
-
import { type ClaudeCodeConfig } from "./config.js";
|
|
5
1
|
/**
|
|
6
|
-
* `@dynamicagents/plugins/claude-code` —
|
|
2
|
+
* `@dynamicagents/plugins/claude-code` — sub-agents that run the Claude Code CLI.
|
|
7
3
|
*
|
|
8
4
|
* ## Why this exists
|
|
9
5
|
*
|
|
@@ -16,11 +12,12 @@ import { type ClaudeCodeConfig } from "./config.js";
|
|
|
16
12
|
*
|
|
17
13
|
* ## What it contributes, and what it does not
|
|
18
14
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
15
|
+
* **A writer's sub-agent spec, a model, and no plugin.** Claude Code brings its own
|
|
16
|
+
* tools, its own loop and its own context management, so there is nothing for
|
|
17
|
+
* an agent loop to drive: the session *is* the sub-agent's model —
|
|
18
|
+
* {@link claudeCodeModel} — and Think's recovery drives that. A host binds
|
|
19
|
+
* {@link CLAUDE_CODE_AGENT} to a `SubAgent` class whose `getModel()` returns
|
|
20
|
+
* one, and adds the `prepare` and `settle` that claim and release a workspace.
|
|
24
21
|
*
|
|
25
22
|
* ## The credential never enters the container
|
|
26
23
|
*
|
|
@@ -36,10 +33,9 @@ import { type ClaudeCodeConfig } from "./config.js";
|
|
|
36
33
|
*
|
|
37
34
|
* ## The 5-hour and weekly limits are routed around, not predicted
|
|
38
35
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* a cap on spend, only a gate on starting.
|
|
36
|
+
* **No budget gate, and one must not come back.** An estimate of spend is a
|
|
37
|
+
* guess about a bucket nobody can read, and it only moves when a run *ends* — so
|
|
38
|
+
* it caps nothing, it only refuses to start.
|
|
43
39
|
*
|
|
44
40
|
* The gateway sees Anthropic's actual response, which is the one place the
|
|
45
41
|
* bucket announces itself. So the credential is a **pool**: the first usable
|
|
@@ -56,72 +52,20 @@ import { type ClaudeCodeConfig } from "./config.js";
|
|
|
56
52
|
* policy is `{ mode: "http-gateway" }` and which supplies a
|
|
57
53
|
* {@link CredentialStore}. See the README.
|
|
58
54
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* and a fresh isolate picks up exactly where the last one stopped.
|
|
65
|
-
*/
|
|
66
|
-
export declare function claudeCodeSession(config: ClaudeCodeConfig): {
|
|
67
|
-
/**
|
|
68
|
-
* Spawn a session for one subtask and drain its first window.
|
|
69
|
-
*
|
|
70
|
-
* `subtaskId` namespaces the exec id. Subtasks are a concurrent fan-out, so
|
|
71
|
-
* two sessions in one workspace under one id would spawn over each other —
|
|
72
|
-
* see {@link execIdFor}.
|
|
73
|
-
*/
|
|
74
|
-
start(runtime: SessionRuntime, subtaskId: string | number, prompt: string, dir: string): Promise<DrainOutcome>;
|
|
75
|
-
/** Re-attach to a running session and drain one more window. */
|
|
76
|
-
resume(runtime: SessionRuntime, cursor: DrainCursor): Promise<DrainOutcome>;
|
|
77
|
-
/** Stop a session — `SIGTERM`, so its own process tree goes with it. */
|
|
78
|
-
stop(runtime: SessionRuntime, subtaskId: string | number): Promise<void>;
|
|
79
|
-
/**
|
|
80
|
-
* Is any credential usable right now, and if not, when?
|
|
81
|
-
*
|
|
82
|
-
* The same question {@link egress} answers per request, asked ahead of time
|
|
83
|
-
* so a host can decline to start a session it cannot pay for. That is not a
|
|
84
|
-
* micro-optimisation: an invocation carries an 18.7-27k-token cached prefix
|
|
85
|
-
* before it does anything, so starting one and letting the gateway refuse
|
|
86
|
-
* its first model call costs a container start and that prefix to learn what
|
|
87
|
-
* this returns for free — and reports it as a failed run rather than as a
|
|
88
|
-
* rate limit with a time on it.
|
|
89
|
-
*
|
|
90
|
-
* Reads only. Nothing here marks anything spent.
|
|
91
|
-
*/
|
|
92
|
-
credentials: (store: CredentialStore) => Promise<Lead>;
|
|
93
|
-
/**
|
|
94
|
-
* The `Fetcher` the workspace object installs as its egress policy.
|
|
95
|
-
*
|
|
96
|
-
* `store` is an **argument rather than a config field**, and that is the
|
|
97
|
-
* point: the credential pool's state belongs to whichever object has
|
|
98
|
-
* storage, and this same config object is also held by the parent's plugin
|
|
99
|
-
* list and by the subagent facet, neither of which has any. Making it a
|
|
100
|
-
* field would force both of them to invent one.
|
|
101
|
-
*/
|
|
102
|
-
egress: (store: CredentialStore) => {
|
|
103
|
-
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
104
|
-
connect(address: SocketAddress | string, options?: SocketOptions): Socket;
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
export type ClaudeCodeSession = ReturnType<typeof claudeCodeSession>;
|
|
108
|
-
/**
|
|
109
|
-
* The plugin.
|
|
110
|
-
*
|
|
111
|
-
* `subtaskType` and nothing else: no `toolFamilies`, because Claude Code's tools
|
|
112
|
-
* are its own, and no `capability` on the plugin, because a plugin declaring a
|
|
113
|
-
* subtask type puts its capability block on the **type** — declaring both makes
|
|
114
|
-
* the main agent read the same advice twice per round.
|
|
115
|
-
*/
|
|
116
|
-
export declare function claudeCode(config: ClaudeCodeConfig): AgentPlugin;
|
|
55
|
+
export { claudeCodeModel } from "./model.js";
|
|
56
|
+
export type { ClaudeCodeModelOptions, SessionEnd, SessionOutcome, SessionRecord, SessionWorkspace } from "./model.js";
|
|
57
|
+
export { claudeCodeSession } from "./session.js";
|
|
58
|
+
export type { ClaudeCodeSession, ResumeSession, StartSession } from "./session.js";
|
|
59
|
+
export { CLAUDE_CODE_AGENT, CLAUDE_CODE_WRITE_INPUT, type ClaudeCodeInput } from "./spec.js";
|
|
117
60
|
export { ANTHROPIC_HOST, claudeCodeEgress } from "./egress.js";
|
|
61
|
+
export { VERIFIED_CLAUDE_CODE_VERSION } from "./verified.js";
|
|
118
62
|
export type { EgressConfig } from "./egress.js";
|
|
119
|
-
export {
|
|
63
|
+
export { GITHUB_HOSTS, GITHUB_TOKEN_PLACEHOLDER } from "./github.js";
|
|
64
|
+
export { credentialPool, readRefusal, readRateLimitEvent } from "./credentials.js";
|
|
120
65
|
export type { CredentialPool, CredentialPoolConfig, CredentialState, CredentialStore, Lead, Refusal } from "./credentials.js";
|
|
121
|
-
export { buildLaunch, CLAUDE_EXEC_PREFIX, CREDENTIAL_PLACEHOLDER, execIdFor, freshCursor } from "./run.js";
|
|
122
|
-
export type { DrainCursor, DrainOutcome, Launch, LaunchOptions, SessionRuntime } from "./run.js";
|
|
123
|
-
export { parseStream, toProgress } from "./events.js";
|
|
124
|
-
export type { ClaudeCodeEvent, ClaudeCodeResult, ClaudeCodeUsage } from "./events.js";
|
|
125
|
-
export {
|
|
126
|
-
export {
|
|
127
|
-
export type { ClaudeCodeConfig, PermissionMode } from "./config.js";
|
|
66
|
+
export { buildLaunch, CLAUDE_EXEC_PREFIX, CREDENTIAL_PLACEHOLDER, execIdFor, followUpExecIdFor, freshCursor } from "./run.js";
|
|
67
|
+
export type { DrainCursor, DrainOptions, DrainOutcome, Launch, LaunchOptions, SessionRuntime } from "./run.js";
|
|
68
|
+
export { parseStream, toProgress, RATE_LIMIT_OK } from "./events.js";
|
|
69
|
+
export type { ClaudeCodeEvent, ClaudeCodeResult, ClaudeCodeUsage, RateLimitInfo } from "./events.js";
|
|
70
|
+
export { DEFAULT_PERMISSION_MODE, DEFAULT_TIMEOUT_MS } from "./config.js";
|
|
71
|
+
export type { ClaudeCodeConfig, EffortLevel, PermissionMode } from "./config.js";
|
|
@@ -1,63 +1,5 @@
|
|
|
1
|
-
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
-
if (value !== null && value !== void 0) {
|
|
3
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
-
var dispose, inner;
|
|
5
|
-
if (async) {
|
|
6
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
if (async) inner = dispose;
|
|
13
|
-
}
|
|
14
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
-
}
|
|
18
|
-
else if (async) {
|
|
19
|
-
env.stack.push({ async: true });
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
-
return function (env) {
|
|
25
|
-
function fail(e) {
|
|
26
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
-
env.hasError = true;
|
|
28
|
-
}
|
|
29
|
-
var r, s = 0;
|
|
30
|
-
function next() {
|
|
31
|
-
while (r = env.stack.pop()) {
|
|
32
|
-
try {
|
|
33
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
-
if (r.dispose) {
|
|
35
|
-
var result = r.dispose.call(r.value);
|
|
36
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
-
}
|
|
38
|
-
else s |= 1;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
fail(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
-
if (env.hasError) throw env.error;
|
|
46
|
-
}
|
|
47
|
-
return next();
|
|
48
|
-
};
|
|
49
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
-
var e = new Error(message);
|
|
51
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
-
});
|
|
53
|
-
import { definePlugin, PLUGIN_CONTRACT_VERSION } from "@dynamicagents/core";
|
|
54
|
-
import { claudeCodeEgress } from "./egress.js";
|
|
55
|
-
import { credentialPool } from "./credentials.js";
|
|
56
|
-
import { attachRun, drainRun, execIdFor, freshCursor, killRun, startRun } from "./run.js";
|
|
57
|
-
import { DEFAULT_TIMEOUT_MS, DEFAULT_WINDOW_MS } from "./config.js";
|
|
58
|
-
import { CLAUDE_CODE_SPEC, CLAUDE_CODE_TYPE, WORKSPACE_RUNTIME_KEY } from "./recipe.js";
|
|
59
1
|
/**
|
|
60
|
-
* `@dynamicagents/plugins/claude-code` —
|
|
2
|
+
* `@dynamicagents/plugins/claude-code` — sub-agents that run the Claude Code CLI.
|
|
61
3
|
*
|
|
62
4
|
* ## Why this exists
|
|
63
5
|
*
|
|
@@ -70,11 +12,12 @@ import { CLAUDE_CODE_SPEC, CLAUDE_CODE_TYPE, WORKSPACE_RUNTIME_KEY } from "./rec
|
|
|
70
12
|
*
|
|
71
13
|
* ## What it contributes, and what it does not
|
|
72
14
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
15
|
+
* **A writer's sub-agent spec, a model, and no plugin.** Claude Code brings its own
|
|
16
|
+
* tools, its own loop and its own context management, so there is nothing for
|
|
17
|
+
* an agent loop to drive: the session *is* the sub-agent's model —
|
|
18
|
+
* {@link claudeCodeModel} — and Think's recovery drives that. A host binds
|
|
19
|
+
* {@link CLAUDE_CODE_AGENT} to a `SubAgent` class whose `getModel()` returns
|
|
20
|
+
* one, and adds the `prepare` and `settle` that claim and release a workspace.
|
|
78
21
|
*
|
|
79
22
|
* ## The credential never enters the container
|
|
80
23
|
*
|
|
@@ -90,10 +33,9 @@ import { CLAUDE_CODE_SPEC, CLAUDE_CODE_TYPE, WORKSPACE_RUNTIME_KEY } from "./rec
|
|
|
90
33
|
*
|
|
91
34
|
* ## The 5-hour and weekly limits are routed around, not predicted
|
|
92
35
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* a cap on spend, only a gate on starting.
|
|
36
|
+
* **No budget gate, and one must not come back.** An estimate of spend is a
|
|
37
|
+
* guess about a bucket nobody can read, and it only moves when a run *ends* — so
|
|
38
|
+
* it caps nothing, it only refuses to start.
|
|
97
39
|
*
|
|
98
40
|
* The gateway sees Anthropic's actual response, which is the one place the
|
|
99
41
|
* bucket announces itself. So the credential is a **pool**: the first usable
|
|
@@ -110,170 +52,13 @@ import { CLAUDE_CODE_SPEC, CLAUDE_CODE_TYPE, WORKSPACE_RUNTIME_KEY } from "./rec
|
|
|
110
52
|
* policy is `{ mode: "http-gateway" }` and which supplies a
|
|
111
53
|
* {@link CredentialStore}. See the README.
|
|
112
54
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* The three calls a host's `executeChunk` needs and nothing else. State lives in
|
|
117
|
-
* the {@link DrainCursor} the caller persists between chunks, so this holds none
|
|
118
|
-
* and a fresh isolate picks up exactly where the last one stopped.
|
|
119
|
-
*/
|
|
120
|
-
export function claudeCodeSession(config) {
|
|
121
|
-
const windowMs = config.windowMs ?? DEFAULT_WINDOW_MS;
|
|
122
|
-
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
123
|
-
const launch = (prompt, dir) => ({
|
|
124
|
-
prompt,
|
|
125
|
-
dir,
|
|
126
|
-
...(config.model ? { model: config.model } : {}),
|
|
127
|
-
...(config.maxTurns === undefined ? {} : { maxTurns: config.maxTurns }),
|
|
128
|
-
...(config.maxSubagentDepth === undefined
|
|
129
|
-
? {}
|
|
130
|
-
: { maxSubagentDepth: config.maxSubagentDepth }),
|
|
131
|
-
...(config.maxConcurrentSubagents === undefined
|
|
132
|
-
? {}
|
|
133
|
-
: { maxConcurrentSubagents: config.maxConcurrentSubagents }),
|
|
134
|
-
// Forwarded only when set, so `buildLaunch` owns the default in one place
|
|
135
|
-
// rather than this line resolving it and the flag being written twice.
|
|
136
|
-
...(config.permissionMode ? { permissionMode: config.permissionMode } : {}),
|
|
137
|
-
...(config.env ? { env: config.env } : {})
|
|
138
|
-
});
|
|
139
|
-
return {
|
|
140
|
-
/**
|
|
141
|
-
* Spawn a session for one subtask and drain its first window.
|
|
142
|
-
*
|
|
143
|
-
* `subtaskId` namespaces the exec id. Subtasks are a concurrent fan-out, so
|
|
144
|
-
* two sessions in one workspace under one id would spawn over each other —
|
|
145
|
-
* see {@link execIdFor}.
|
|
146
|
-
*/
|
|
147
|
-
async start(runtime, subtaskId, prompt, dir) {
|
|
148
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
149
|
-
try {
|
|
150
|
-
const execId = execIdFor(subtaskId);
|
|
151
|
-
// `using`, so the attachment is released even when the drain throws.
|
|
152
|
-
const handle = __addDisposableResource(env_1, await startRun(runtime, {
|
|
153
|
-
...launch(prompt, dir),
|
|
154
|
-
execId,
|
|
155
|
-
timeoutMs
|
|
156
|
-
}), false);
|
|
157
|
-
return await drainRun(handle, freshCursor(execId), { windowMs });
|
|
158
|
-
}
|
|
159
|
-
catch (e_1) {
|
|
160
|
-
env_1.error = e_1;
|
|
161
|
-
env_1.hasError = true;
|
|
162
|
-
}
|
|
163
|
-
finally {
|
|
164
|
-
__disposeResources(env_1);
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
/** Re-attach to a running session and drain one more window. */
|
|
168
|
-
async resume(runtime, cursor) {
|
|
169
|
-
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
170
|
-
try {
|
|
171
|
-
const handle = __addDisposableResource(env_2, await attachRun(runtime, cursor), false);
|
|
172
|
-
return await drainRun(handle, cursor, { windowMs });
|
|
173
|
-
}
|
|
174
|
-
catch (e_2) {
|
|
175
|
-
env_2.error = e_2;
|
|
176
|
-
env_2.hasError = true;
|
|
177
|
-
}
|
|
178
|
-
finally {
|
|
179
|
-
__disposeResources(env_2);
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
/** Stop a session — `SIGTERM`, so its own process tree goes with it. */
|
|
183
|
-
async stop(runtime, subtaskId) {
|
|
184
|
-
await killRun(runtime, execIdFor(subtaskId));
|
|
185
|
-
},
|
|
186
|
-
/**
|
|
187
|
-
* Is any credential usable right now, and if not, when?
|
|
188
|
-
*
|
|
189
|
-
* The same question {@link egress} answers per request, asked ahead of time
|
|
190
|
-
* so a host can decline to start a session it cannot pay for. That is not a
|
|
191
|
-
* micro-optimisation: an invocation carries an 18.7-27k-token cached prefix
|
|
192
|
-
* before it does anything, so starting one and letting the gateway refuse
|
|
193
|
-
* its first model call costs a container start and that prefix to learn what
|
|
194
|
-
* this returns for free — and reports it as a failed run rather than as a
|
|
195
|
-
* rate limit with a time on it.
|
|
196
|
-
*
|
|
197
|
-
* Reads only. Nothing here marks anything spent.
|
|
198
|
-
*/
|
|
199
|
-
credentials: (store) => credentialPool({ credentials: config.credentials, store }).lead(),
|
|
200
|
-
/**
|
|
201
|
-
* The `Fetcher` the workspace object installs as its egress policy.
|
|
202
|
-
*
|
|
203
|
-
* `store` is an **argument rather than a config field**, and that is the
|
|
204
|
-
* point: the credential pool's state belongs to whichever object has
|
|
205
|
-
* storage, and this same config object is also held by the parent's plugin
|
|
206
|
-
* list and by the subagent facet, neither of which has any. Making it a
|
|
207
|
-
* field would force both of them to invent one.
|
|
208
|
-
*/
|
|
209
|
-
egress: (store) => claudeCodeEgress({
|
|
210
|
-
credentials: config.credentials,
|
|
211
|
-
store,
|
|
212
|
-
// Forwarded only when set. Defaulting it to `[]` here would turn "the
|
|
213
|
-
// host said nothing" into "Anthropic only", which is the one reading
|
|
214
|
-
// the three-way semantics exist to keep distinct.
|
|
215
|
-
...(config.restrictToHosts === undefined
|
|
216
|
-
? {}
|
|
217
|
-
: { restrictToHosts: config.restrictToHosts }),
|
|
218
|
-
label: CLAUDE_CODE_TYPE
|
|
219
|
-
})
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* The plugin.
|
|
224
|
-
*
|
|
225
|
-
* `subtaskType` and nothing else: no `toolFamilies`, because Claude Code's tools
|
|
226
|
-
* are its own, and no `capability` on the plugin, because a plugin declaring a
|
|
227
|
-
* subtask type puts its capability block on the **type** — declaring both makes
|
|
228
|
-
* the main agent read the same advice twice per round.
|
|
229
|
-
*/
|
|
230
|
-
export function claudeCode(config) {
|
|
231
|
-
// Read once at construction so a deployment that forgot the secret fails at DO
|
|
232
|
-
// start with a sentence naming this plugin, rather than at the first model
|
|
233
|
-
// call inside a subtask somebody is waiting on. The thunk is still what the
|
|
234
|
-
// gateway calls per request, so a rotation is picked up.
|
|
235
|
-
if (config.credentials().filter(Boolean).length === 0) {
|
|
236
|
-
throw new Error("claude-code: no credentials. Set at least one `claude setup-token` " +
|
|
237
|
-
"credential and pass it as " +
|
|
238
|
-
"`credentials: () => [env.CLAUDE_CODE_OAUTH_TOKEN_1]`.");
|
|
239
|
-
}
|
|
240
|
-
return definePlugin({
|
|
241
|
-
key: "claude-code",
|
|
242
|
-
contractVersion: PLUGIN_CONTRACT_VERSION,
|
|
243
|
-
subtaskType: CLAUDE_CODE_SPEC,
|
|
244
|
-
/**
|
|
245
|
-
* Hand each subtask the workspace its parent is working in.
|
|
246
|
-
*
|
|
247
|
-
* This runs on the **parent** — core dispatches `resolveRuntime` to the
|
|
248
|
-
* plugin that declared the subtask type, which is this one — so
|
|
249
|
-
* `workspaceName()` resolves here and would throw in the facet, where
|
|
250
|
-
* `callerKey()` is deliberately unavailable. Whatever this returns arrives
|
|
251
|
-
* at `executeChunk` as its `runtime` argument, and the host reads the name
|
|
252
|
-
* back out with {@link WORKSPACE_RUNTIME_KEY}.
|
|
253
|
-
*
|
|
254
|
-
* Without it a delegated session has no way to address the Durable Object
|
|
255
|
-
* holding the checkout it was told to work in — and it cannot be a subtask
|
|
256
|
-
* param instead, because those are rendered to the delegating model and a
|
|
257
|
-
* model-authored workspace name would let it name somebody else's.
|
|
258
|
-
*/
|
|
259
|
-
// Annotated rather than inferred: without it TypeScript narrows the
|
|
260
|
-
// plugin's runtime generic to this one key, which then fails to accept a
|
|
261
|
-
// plain `SubtaskRuntime` anywhere else.
|
|
262
|
-
resolveRuntime: async () => ({
|
|
263
|
-
[WORKSPACE_RUNTIME_KEY]: config.workspaceName()
|
|
264
|
-
})
|
|
265
|
-
// **No `requires.secrets`, and it is not an omission.** It named
|
|
266
|
-
// `CLAUDE_CODE_OAUTH_TOKEN` while there was exactly one credential with a
|
|
267
|
-
// name this package could know. The pool's entries are host-named — a
|
|
268
|
-
// deployment may call them anything and may have three — so there is no
|
|
269
|
-
// name left to declare. The property `requires` bought is kept by the
|
|
270
|
-
// `credentials()` check above, which is strictly better: it fails at DO
|
|
271
|
-
// start on the *value* being absent rather than on a name being unset.
|
|
272
|
-
});
|
|
273
|
-
}
|
|
55
|
+
export { claudeCodeModel } from "./model.js";
|
|
56
|
+
export { claudeCodeSession } from "./session.js";
|
|
57
|
+
export { CLAUDE_CODE_AGENT, CLAUDE_CODE_WRITE_INPUT } from "./spec.js";
|
|
274
58
|
export { ANTHROPIC_HOST, claudeCodeEgress } from "./egress.js";
|
|
275
|
-
export {
|
|
276
|
-
export {
|
|
277
|
-
export {
|
|
278
|
-
export {
|
|
279
|
-
export {
|
|
59
|
+
export { VERIFIED_CLAUDE_CODE_VERSION } from "./verified.js";
|
|
60
|
+
export { GITHUB_HOSTS, GITHUB_TOKEN_PLACEHOLDER } from "./github.js";
|
|
61
|
+
export { credentialPool, readRefusal, readRateLimitEvent } from "./credentials.js";
|
|
62
|
+
export { buildLaunch, CLAUDE_EXEC_PREFIX, CREDENTIAL_PLACEHOLDER, execIdFor, followUpExecIdFor, freshCursor } from "./run.js";
|
|
63
|
+
export { parseStream, toProgress, RATE_LIMIT_OK } from "./events.js";
|
|
64
|
+
export { DEFAULT_PERMISSION_MODE, DEFAULT_TIMEOUT_MS } from "./config.js";
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
import type { ArtifactEntryDetail } from "@dynamicagents/core/artifacts";
|
|
3
|
+
import type { ClaudeCodeConfig, PermissionMode } from "./config.js";
|
|
4
|
+
import type { ClaudeCodeResult, RateLimitInfo } from "./events.js";
|
|
5
|
+
import { type SessionRuntime } from "./run.js";
|
|
6
|
+
/**
|
|
7
|
+
* A Claude Code session as a sub-agent's **model**.
|
|
8
|
+
*
|
|
9
|
+
* Claude Code brings its own tools, its own loop and its own context, so there
|
|
10
|
+
* is nothing for Think to drive but the one call that runs it — and making that
|
|
11
|
+
* call the model is what puts the session under Think's recovery. A turn cut by
|
|
12
|
+
* an eviction or a deploy is continued; the continuation calls `doStream`
|
|
13
|
+
* again, and every step below it has already taken is stored, so it resumes
|
|
14
|
+
* where it was: the session is re-attached from its cursor, and a report
|
|
15
|
+
* already made is emitted again rather than made again.
|
|
16
|
+
*
|
|
17
|
+
* ## The report is the only text
|
|
18
|
+
*
|
|
19
|
+
* A run's result is what its assistant messages say, so narration streamed as
|
|
20
|
+
* text would become the result and bury the report. What the session says as
|
|
21
|
+
* it works goes to the parent as notes instead, through `note`. Nothing else is
|
|
22
|
+
* streamed at all: Think's stall watchdog is off, so a silent stream is not cut.
|
|
23
|
+
*/
|
|
24
|
+
/** The provider interface this implements, read off `ai` rather than imported. */
|
|
25
|
+
type LanguageModelV3 = Extract<LanguageModel, {
|
|
26
|
+
specificationVersion: "v3";
|
|
27
|
+
}>;
|
|
28
|
+
/** How one exec of a session ended. */
|
|
29
|
+
export interface SessionEnd {
|
|
30
|
+
exitCode: number;
|
|
31
|
+
/** Absent when the process died without ever emitting a `result` line. */
|
|
32
|
+
result?: ClaudeCodeResult;
|
|
33
|
+
/** Bounded, and only when there is no `result` to explain the exit. */
|
|
34
|
+
stderr?: string;
|
|
35
|
+
/** The subscription bucket as the client last reported it, if it did. */
|
|
36
|
+
rateLimit?: RateLimitInfo;
|
|
37
|
+
/**
|
|
38
|
+
* The Claude Code session id, from the `init` line by way of the drain's
|
|
39
|
+
* cursor — see {@link file://./run.ts DrainCursor.sessionId}.
|
|
40
|
+
*
|
|
41
|
+
* Here as well as on `result` because the sessions worth continuing are often
|
|
42
|
+
* the ones with no result: a session ended by its time limit, a cancel or a
|
|
43
|
+
* container rollout reports none, and this is then the only handle to the
|
|
44
|
+
* conversation it got half-way through.
|
|
45
|
+
*/
|
|
46
|
+
sessionId?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A session's handle, as the host is told it.
|
|
50
|
+
*
|
|
51
|
+
* Told **twice**: once with the id alone, as soon as the session's `init` line
|
|
52
|
+
* names it, and once with the session's end. The first call is what makes a
|
|
53
|
+
* session that is about to be killed resumable at all; the second says how the
|
|
54
|
+
* conversation it left stands.
|
|
55
|
+
*
|
|
56
|
+
* So a host keys its record on `sessionId` and keeps an `end` once it has one: a
|
|
57
|
+
* recovered turn can report the same id again without an end, and a record that
|
|
58
|
+
* let that erase the end would forget how the session finished.
|
|
59
|
+
*/
|
|
60
|
+
export interface SessionRecord {
|
|
61
|
+
sessionId: string;
|
|
62
|
+
/** Absent on the first call; the session's end on the second. */
|
|
63
|
+
end?: SessionEnd;
|
|
64
|
+
}
|
|
65
|
+
/** What a run amounted to, handed to `report`. */
|
|
66
|
+
export interface SessionOutcome {
|
|
67
|
+
/** The session's own end. */
|
|
68
|
+
session: SessionEnd;
|
|
69
|
+
/** The follow-up's end, when `followUp` asked for one. */
|
|
70
|
+
followUp?: SessionEnd;
|
|
71
|
+
}
|
|
72
|
+
/** The container a session runs in, released when the call that opened it ends. */
|
|
73
|
+
export interface SessionWorkspace extends Disposable {
|
|
74
|
+
readonly runtime: SessionRuntime;
|
|
75
|
+
}
|
|
76
|
+
export interface ClaudeCodeModelOptions {
|
|
77
|
+
config: ClaudeCodeConfig;
|
|
78
|
+
/**
|
|
79
|
+
* Opens the run's container — the workspace the run's `runtime()` names.
|
|
80
|
+
* Called again to re-attach after a cut stream, so each call should reach the
|
|
81
|
+
* object through a new stub rather than one held from the last.
|
|
82
|
+
*/
|
|
83
|
+
workspace: () => Promise<SessionWorkspace>;
|
|
84
|
+
/** The sub-agent's own storage, where every step's outcome is kept. */
|
|
85
|
+
storage: DurableObjectStorage;
|
|
86
|
+
/** The sub-agent's name, which is the run's id. The exec ids derive from it. */
|
|
87
|
+
runId: string;
|
|
88
|
+
/** The checkout. */
|
|
89
|
+
dir: string;
|
|
90
|
+
/**
|
|
91
|
+
* A JSON Schema the session's answer must match. Its `result` then carries
|
|
92
|
+
* the answer as `structured`, for `report` to read.
|
|
93
|
+
*/
|
|
94
|
+
jsonSchema?: Record<string, unknown>;
|
|
95
|
+
/**
|
|
96
|
+
* This run's mode, over {@link file://./config.ts ClaudeCodeConfig.permissionMode}.
|
|
97
|
+
*
|
|
98
|
+
* A planning run is a writing session under `plan` with a `jsonSchema`: it
|
|
99
|
+
* reads, edits nothing, and answers through `StructuredOutput` rather than an
|
|
100
|
+
* approval nobody is there to give. Carrying the plan out is a later run that
|
|
101
|
+
* resumes it with `fork` under the config's mode — the CLI takes a new
|
|
102
|
+
* `--permission-mode` on `--resume` — so the plan's own conversation stays
|
|
103
|
+
* whole for an edit.
|
|
104
|
+
*/
|
|
105
|
+
permissionMode?: PermissionMode;
|
|
106
|
+
/**
|
|
107
|
+
* A Claude Code conversation for this run to continue instead of starting one
|
|
108
|
+
* — see {@link file://./session.ts StartSession.resume}.
|
|
109
|
+
*
|
|
110
|
+
* Resolved by the host, in `prepare`, against whatever it recorded through
|
|
111
|
+
* {@link ClaudeCodeModelOptions.onSession}: which conversations exist in a
|
|
112
|
+
* workspace, and which of them a caller may continue, are the host's
|
|
113
|
+
* questions. The run's prompt is then the next user turn — its `brief` hook
|
|
114
|
+
* is the place to say what changed and nothing the session already holds.
|
|
115
|
+
*/
|
|
116
|
+
resume?: {
|
|
117
|
+
sessionId: string;
|
|
118
|
+
fork?: boolean;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Files one note on the parent's transcript: the sub-agent's `note`. A tool
|
|
122
|
+
* call, its result and the session's own start and end arrive with a card —
|
|
123
|
+
* see {@link file://./cards.ts Card}.
|
|
124
|
+
*/
|
|
125
|
+
note: (key: string, text: string, detail?: ArtifactEntryDetail) => Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* The session's handle, as soon as there is one and again when the session
|
|
128
|
+
* ends — see {@link SessionRecord}.
|
|
129
|
+
*
|
|
130
|
+
* Best-effort, like `note`: a throw is logged and the run goes on. Recording a
|
|
131
|
+
* handle is what makes a later run able to continue this conversation, and
|
|
132
|
+
* losing that is not worth losing the session over.
|
|
133
|
+
*/
|
|
134
|
+
onSession?: (record: SessionRecord) => Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* The session's prompt, from the task the parent sent. Defaults to the task.
|
|
137
|
+
*
|
|
138
|
+
* Runs once per run, before the session starts, and its answer is kept. A
|
|
139
|
+
* throw fails the run with its message — how a host refuses a run it cannot
|
|
140
|
+
* pay for, or has nothing to work in.
|
|
141
|
+
*/
|
|
142
|
+
brief?: (task: string) => Promise<string>;
|
|
143
|
+
/**
|
|
144
|
+
* One more turn for a session that ended, or `undefined`. Asked once; its
|
|
145
|
+
* answer is kept, so a resumed run does not ask again.
|
|
146
|
+
*/
|
|
147
|
+
followUp?: (session: SessionEnd) => Promise<string | undefined>;
|
|
148
|
+
/** The text the parent receives. Run once, and kept. */
|
|
149
|
+
report: (outcome: SessionOutcome) => Promise<string>;
|
|
150
|
+
}
|
|
151
|
+
export declare function claudeCodeModel(options: ClaudeCodeModelOptions): LanguageModelV3;
|
|
152
|
+
export {};
|