@dynamicagents/plugins 0.13.0 → 0.15.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 +14 -14
- package/dist/claude-code/cards.d.ts +4 -0
- package/dist/claude-code/cards.js +22 -0
- package/dist/claude-code/config.d.ts +10 -83
- package/dist/claude-code/config.js +0 -2
- package/dist/claude-code/credentials.d.ts +32 -50
- package/dist/claude-code/credentials.js +115 -74
- package/dist/claude-code/daemon/index.d.ts +24 -0
- package/dist/claude-code/daemon/index.js +203 -0
- package/dist/claude-code/egress.d.ts +35 -117
- package/dist/claude-code/egress.js +80 -325
- package/dist/claude-code/events.d.ts +14 -17
- package/dist/claude-code/events.js +19 -15
- package/dist/claude-code/harness-wire.d.ts +45 -0
- package/dist/claude-code/harness-wire.js +47 -0
- package/dist/claude-code/index.d.ts +19 -29
- package/dist/claude-code/index.js +17 -25
- package/dist/claude-code/language-model.d.ts +19 -0
- package/dist/claude-code/language-model.js +71 -0
- package/dist/claude-code/model.d.ts +77 -70
- package/dist/claude-code/model.js +328 -304
- package/dist/claude-code/placeholder.d.ts +12 -0
- package/dist/claude-code/placeholder.js +12 -0
- package/dist/claude-code/spec.d.ts +4 -4
- package/dist/claude-code/spec.js +4 -4
- package/dist/claude-code/verified.d.ts +1 -1
- package/dist/claude-code/verified.js +1 -1
- package/dist/computer/client.d.ts +88 -0
- package/dist/computer/client.js +6 -0
- package/dist/computer/context.d.ts +7 -7
- package/dist/computer/context.js +14 -18
- package/dist/computer/gate.d.ts +4 -23
- package/dist/computer/gate.js +1 -37
- package/dist/computer/index.d.ts +44 -43
- package/dist/computer/index.js +29 -50
- package/dist/computer/paths.d.ts +5 -27
- package/dist/computer/paths.js +7 -30
- package/dist/computer/proxy.d.ts +17 -31
- package/dist/computer/proxy.js +9 -44
- package/dist/computer/render.d.ts +3 -40
- package/dist/computer/render.js +3 -36
- package/dist/computer/sandbox.d.ts +55 -0
- package/dist/computer/sandbox.js +236 -0
- package/dist/computer/shell.d.ts +36 -0
- package/dist/computer/shell.js +41 -0
- package/dist/computer/tools-exec.js +3 -9
- package/dist/computer/tools-file.d.ts +1 -1
- package/dist/computer/tools-file.js +1 -1
- package/dist/{repo → repo-github}/checkout.d.ts +3 -4
- package/dist/{repo → repo-github}/checkout.js +3 -4
- package/dist/{repo → repo-github}/context.d.ts +14 -32
- package/dist/{repo → repo-github}/context.js +46 -81
- package/dist/{repo → repo-github}/index.d.ts +30 -13
- package/dist/{repo → repo-github}/index.js +25 -6
- package/dist/repo-github/mcp.d.ts +95 -0
- package/dist/repo-github/mcp.js +107 -0
- package/dist/repo-github/sandbox-egress.d.ts +68 -0
- package/dist/repo-github/sandbox-egress.js +272 -0
- package/dist/repo-github/sandbox-git.d.ts +30 -0
- package/dist/repo-github/sandbox-git.js +113 -0
- package/dist/{repo → repo-github}/tools-checks.js +43 -4
- package/dist/{repo → repo-github}/tools-clone.js +2 -21
- package/dist/{repo → repo-github}/tools-pr.d.ts +0 -1
- package/dist/{repo → repo-github}/tools-pr.js +85 -20
- package/dist/{repo → repo-github}/tools-review.d.ts +6 -0
- package/dist/{repo → repo-github}/tools-review.js +62 -176
- package/dist/{repo → repo-github}/url.d.ts +11 -0
- package/dist/{repo → repo-github}/url.js +12 -1
- package/dist/{workspace → sandbox}/advisory.d.ts +16 -35
- package/dist/{workspace → sandbox}/advisory.js +2 -29
- package/dist/sandbox/agent-exec.d.ts +31 -0
- package/dist/sandbox/agent-exec.js +62 -0
- package/dist/sandbox/ca-trust.d.ts +9 -0
- package/dist/sandbox/ca-trust.js +21 -0
- package/dist/sandbox/constants.d.ts +22 -0
- package/dist/sandbox/constants.js +22 -0
- package/dist/sandbox/daemon/composite.d.ts +9 -0
- package/dist/sandbox/daemon/composite.js +35 -0
- package/dist/sandbox/daemon/index.d.ts +47 -0
- package/dist/sandbox/daemon/index.js +116 -0
- package/dist/sandbox/egress.d.ts +81 -0
- package/dist/sandbox/egress.js +109 -0
- package/dist/sandbox/exec.d.ts +57 -0
- package/dist/sandbox/exec.js +52 -0
- package/dist/sandbox/format.d.ts +2 -0
- package/dist/sandbox/format.js +7 -0
- package/dist/sandbox/header.d.ts +50 -0
- package/dist/sandbox/header.js +94 -0
- package/dist/sandbox/index.d.ts +17 -0
- package/dist/sandbox/index.js +17 -0
- package/dist/{workspace/install.d.ts → sandbox/install-plan.d.ts} +10 -1
- package/dist/{workspace/install.js → sandbox/install-plan.js} +22 -4
- package/dist/sandbox/name.d.ts +27 -0
- package/dist/sandbox/name.js +32 -0
- package/dist/sandbox/object.d.ts +244 -0
- package/dist/sandbox/object.js +1139 -0
- package/dist/scratch/index.d.ts +1 -9
- package/dist/scratch/index.js +2 -18
- package/package.json +26 -22
- package/dist/claude-code/github.d.ts +0 -39
- package/dist/claude-code/github.js +0 -82
- package/dist/claude-code/run.d.ts +0 -474
- package/dist/claude-code/run.js +0 -901
- package/dist/claude-code/session.d.ts +0 -131
- package/dist/claude-code/session.js +0 -285
- package/dist/workspace/ca-trust.d.ts +0 -95
- package/dist/workspace/ca-trust.js +0 -312
- package/dist/workspace/container-deps.d.ts +0 -54
- package/dist/workspace/container-deps.js +0 -224
- package/dist/workspace/container-fault.d.ts +0 -38
- package/dist/workspace/container-fault.js +0 -73
- package/dist/workspace/exec.d.ts +0 -94
- package/dist/workspace/exec.js +0 -153
- package/dist/workspace/format.d.ts +0 -36
- package/dist/workspace/format.js +0 -57
- package/dist/workspace/git-host.d.ts +0 -79
- package/dist/workspace/git-host.js +0 -226
- package/dist/workspace/git-identity.d.ts +0 -57
- package/dist/workspace/git-identity.js +0 -147
- package/dist/workspace/index.d.ts +0 -49
- package/dist/workspace/index.js +0 -58
- package/dist/workspace/install-job.d.ts +0 -121
- package/dist/workspace/install-job.js +0 -866
- package/dist/workspace/object.d.ts +0 -502
- package/dist/workspace/object.js +0 -1427
- package/dist/workspace/open.d.ts +0 -95
- package/dist/workspace/open.js +0 -63
- package/dist/workspace/read.d.ts +0 -16
- package/dist/workspace/read.js +0 -22
- package/dist/workspace/shell.d.ts +0 -45
- package/dist/workspace/shell.js +0 -80
- package/dist/workspace/sync.d.ts +0 -111
- package/dist/workspace/sync.js +0 -124
- package/dist/workspace/wake.d.ts +0 -19
- package/dist/workspace/wake.js +0 -10
- /package/dist/{repo → repo-github}/tools-checks.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-clone.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-worktree.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-worktree.js +0 -0
- /package/dist/{repo → repo-github}/tools-worktrees.d.ts +0 -0
- /package/dist/{repo → repo-github}/tools-worktrees.js +0 -0
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import type { CredentialStore, Lead } from "./credentials.js";
|
|
2
|
-
import { type DrainCursor, type DrainOutcome, type DrainOptions, type SessionRuntime } from "./run.js";
|
|
3
|
-
import { type ClaudeCodeConfig, type PermissionMode } from "./config.js";
|
|
4
|
-
/**
|
|
5
|
-
* What continuing an interrupted conversation takes — see
|
|
6
|
-
* {@link file://./run.ts LaunchOptions.resume}.
|
|
7
|
-
*/
|
|
8
|
-
export interface ResumeSession {
|
|
9
|
-
sessionId: string;
|
|
10
|
-
/** Continue under a new id, leaving the original conversation whole. */
|
|
11
|
-
fork?: boolean;
|
|
12
|
-
}
|
|
13
|
-
/** What one session needs to be launched: see {@link ClaudeCodeSession.start}. */
|
|
14
|
-
export interface StartSession {
|
|
15
|
-
/** The whole of what this session is asked to do, or its next user turn. */
|
|
16
|
-
prompt: string;
|
|
17
|
-
/** The checkout. */
|
|
18
|
-
dir: string;
|
|
19
|
-
jsonSchema?: Record<string, unknown>;
|
|
20
|
-
/**
|
|
21
|
-
* This session's mode, over the config's — see
|
|
22
|
-
* {@link file://./model.ts ClaudeCodeModelOptions.permissionMode}.
|
|
23
|
-
*/
|
|
24
|
-
permissionMode?: PermissionMode;
|
|
25
|
-
/** A Claude Code conversation to continue rather than start. */
|
|
26
|
-
resume?: ResumeSession;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Bind a config to a workspace runtime: start, follow up, resume, stop.
|
|
30
|
-
*
|
|
31
|
-
* What `claudeCodeModel` drives a run with, and what a host's `settle` stops
|
|
32
|
-
* one with. State lives in the {@link DrainCursor} the caller stores, so this
|
|
33
|
-
* holds none and a fresh isolate picks up exactly where the last one stopped.
|
|
34
|
-
*
|
|
35
|
-
* ## Two senses of "resume", and they are not the same mechanism
|
|
36
|
-
*
|
|
37
|
-
* {@link ClaudeCodeSession.resume} re-attaches to a running **exec** — the
|
|
38
|
-
* process is alive in the container and a drain that was cut reads on from the
|
|
39
|
-
* cursor's sequence. Nothing about the conversation changes; this is plumbing.
|
|
40
|
-
*
|
|
41
|
-
* {@link StartSession.resume} continues a Claude Code **conversation** that has
|
|
42
|
-
* already ended, in a new process with a new exec: the session's transcript is
|
|
43
|
-
* read back into context and the prompt is the next user turn. Where that
|
|
44
|
-
* transcript lives — and so how long this is possible at all — is
|
|
45
|
-
* {@link file://./run.ts SESSION_CONFIG_DIR}.
|
|
46
|
-
*/
|
|
47
|
-
export declare function claudeCodeSession(config: ClaudeCodeConfig): {
|
|
48
|
-
/**
|
|
49
|
-
* Spawn a session for one run and drain it.
|
|
50
|
-
*
|
|
51
|
-
* `runId` namespaces the exec id. Runs are concurrent, so two sessions in
|
|
52
|
-
* one workspace under one id would spawn over each other — see
|
|
53
|
-
* {@link execIdFor}.
|
|
54
|
-
*
|
|
55
|
-
* `resume` continues a conversation on this session's **own** exec rather
|
|
56
|
-
* than on a second one: a run given a conversation to continue has no first
|
|
57
|
-
* session of its own, so there is nothing for a follow-up exec to follow.
|
|
58
|
-
*/
|
|
59
|
-
start(runtime: SessionRuntime, runId: string, options: StartSession, sinks?: DrainOptions): Promise<DrainOutcome>;
|
|
60
|
-
/**
|
|
61
|
-
* Give a finished writing session one more turn, and drain it.
|
|
62
|
-
*
|
|
63
|
-
* `sessionId` is the one the session reported — on its `result` line, or on
|
|
64
|
-
* its cursor when it ended without one. This runs in the workspace the
|
|
65
|
-
* session did, because that workspace's {@link file://./run.ts SESSION_CONFIG_DIR}
|
|
66
|
-
* is where the transcript it is continuing can be found. A drain cut short goes
|
|
67
|
-
* on through {@link resume} with the cursor it stored, like any other
|
|
68
|
-
* session's.
|
|
69
|
-
*
|
|
70
|
-
* Never forked: a follow-up is one more turn of the same conversation, which
|
|
71
|
-
* is exactly what a fork is for *not* doing. For the same reason it runs
|
|
72
|
-
* under the session's own `permissionMode`.
|
|
73
|
-
*/
|
|
74
|
-
followUp(runtime: SessionRuntime, runId: string, options: {
|
|
75
|
-
sessionId: string;
|
|
76
|
-
prompt: string;
|
|
77
|
-
dir: string;
|
|
78
|
-
permissionMode?: PermissionMode;
|
|
79
|
-
}, sinks?: DrainOptions): Promise<DrainOutcome>;
|
|
80
|
-
/**
|
|
81
|
-
* Re-attach to a running session and drain it to its end.
|
|
82
|
-
*
|
|
83
|
-
* **A session whose container was replaced is reported, not thrown.** The
|
|
84
|
-
* attachment is the first thing to notice a replacement, and the caller is a
|
|
85
|
-
* recovered turn with a cursor it will happily keep presenting: a throw here
|
|
86
|
-
* retries the same dead id until the recoveries run out, and the run ends on
|
|
87
|
-
* a stack trace that names neither the session nor the cause. A
|
|
88
|
-
* terminal outcome ends it at the first attempt instead, with the exit code
|
|
89
|
-
* the runtime uses for a killed process and an explanation on `stderr`,
|
|
90
|
-
* which is exactly the channel a session that died without a result line
|
|
91
|
-
* already reports through. The wording is {@link containerLost}'s.
|
|
92
|
-
*/
|
|
93
|
-
resume(runtime: SessionRuntime, cursor: DrainCursor, sinks?: DrainOptions): Promise<DrainOutcome>;
|
|
94
|
-
/** Stop a session — `SIGTERM`, so its own process tree goes with it. */
|
|
95
|
-
stop(runtime: SessionRuntime, runId: string): Promise<void>;
|
|
96
|
-
/**
|
|
97
|
-
* Is any credential usable right now, and if not, when?
|
|
98
|
-
*
|
|
99
|
-
* The same question {@link egress} answers per request, asked ahead of time
|
|
100
|
-
* so a host can decline to start a session it cannot pay for. That is not a
|
|
101
|
-
* micro-optimisation: an invocation carries an 18.7-27k-token cached prefix
|
|
102
|
-
* before it does anything, so starting one and letting the gateway refuse
|
|
103
|
-
* its first model call costs a container start and that prefix to learn what
|
|
104
|
-
* this returns for free — and reports it as a failed run rather than as a
|
|
105
|
-
* rate limit with a time on it.
|
|
106
|
-
*
|
|
107
|
-
* Reads only. Nothing here marks anything spent.
|
|
108
|
-
*/
|
|
109
|
-
credentials: (store: CredentialStore) => Promise<Lead>;
|
|
110
|
-
/**
|
|
111
|
-
* The `Fetcher` the workspace object installs as its egress policy.
|
|
112
|
-
*
|
|
113
|
-
* `store` is an **argument rather than a config field**, and that is the
|
|
114
|
-
* point: the credential pool's state belongs to whichever object has
|
|
115
|
-
* storage, and this same config object is also held by the agents that run
|
|
116
|
-
* sessions, which have none of their own for it. Making it a field would
|
|
117
|
-
* force them to invent one.
|
|
118
|
-
*/
|
|
119
|
-
egress: (store: CredentialStore) => {
|
|
120
|
-
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
121
|
-
connect(address: SocketAddress | string, options?: SocketOptions): Socket;
|
|
122
|
-
};
|
|
123
|
-
};
|
|
124
|
-
export type ClaudeCodeSession = ReturnType<typeof claudeCodeSession>;
|
|
125
|
-
/**
|
|
126
|
-
* Refuse a deployment with no credential when the model is built, naming this
|
|
127
|
-
* plugin, rather than at the first model call inside a run somebody is waiting
|
|
128
|
-
* on. The thunk is still what the gateway calls per request, so a rotation is
|
|
129
|
-
* picked up.
|
|
130
|
-
*/
|
|
131
|
-
export declare function requireCredentials(config: ClaudeCodeConfig): void;
|
|
@@ -1,285 +0,0 @@
|
|
|
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 { claudeCodeEgress } from "./egress.js";
|
|
54
|
-
import { credentialPool } from "./credentials.js";
|
|
55
|
-
import { attachRun, containerLost, drainRun, execIdFor, followUpExecIdFor, freshCursor, isExecLost, killRun, startRun } from "./run.js";
|
|
56
|
-
import { DEFAULT_TIMEOUT_MS } from "./config.js";
|
|
57
|
-
/**
|
|
58
|
-
* Bind a config to a workspace runtime: start, follow up, resume, stop.
|
|
59
|
-
*
|
|
60
|
-
* What `claudeCodeModel` drives a run with, and what a host's `settle` stops
|
|
61
|
-
* one with. State lives in the {@link DrainCursor} the caller stores, so this
|
|
62
|
-
* holds none and a fresh isolate picks up exactly where the last one stopped.
|
|
63
|
-
*
|
|
64
|
-
* ## Two senses of "resume", and they are not the same mechanism
|
|
65
|
-
*
|
|
66
|
-
* {@link ClaudeCodeSession.resume} re-attaches to a running **exec** — the
|
|
67
|
-
* process is alive in the container and a drain that was cut reads on from the
|
|
68
|
-
* cursor's sequence. Nothing about the conversation changes; this is plumbing.
|
|
69
|
-
*
|
|
70
|
-
* {@link StartSession.resume} continues a Claude Code **conversation** that has
|
|
71
|
-
* already ended, in a new process with a new exec: the session's transcript is
|
|
72
|
-
* read back into context and the prompt is the next user turn. Where that
|
|
73
|
-
* transcript lives — and so how long this is possible at all — is
|
|
74
|
-
* {@link file://./run.ts SESSION_CONFIG_DIR}.
|
|
75
|
-
*/
|
|
76
|
-
export function claudeCodeSession(config) {
|
|
77
|
-
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
78
|
-
const launch = (prompt, dir, permissionMode = config.permissionMode) => ({
|
|
79
|
-
prompt,
|
|
80
|
-
dir,
|
|
81
|
-
...(config.model ? { model: config.model } : {}),
|
|
82
|
-
...(config.effort ? { effort: config.effort } : {}),
|
|
83
|
-
...(config.maxSubagentDepth === undefined
|
|
84
|
-
? {}
|
|
85
|
-
: { maxSubagentDepth: config.maxSubagentDepth }),
|
|
86
|
-
...(config.maxConcurrentSubagents === undefined
|
|
87
|
-
? {}
|
|
88
|
-
: { maxConcurrentSubagents: config.maxConcurrentSubagents }),
|
|
89
|
-
// Forwarded only when set, so `buildLaunch` owns the default in one place
|
|
90
|
-
// rather than this line resolving it and the flag being written twice.
|
|
91
|
-
...(permissionMode ? { permissionMode } : {}),
|
|
92
|
-
...(config.env ? { env: config.env } : {}),
|
|
93
|
-
...(config.author ? { author: config.author } : {}),
|
|
94
|
-
...(config.githubToken ? { github: true } : {})
|
|
95
|
-
});
|
|
96
|
-
return {
|
|
97
|
-
/**
|
|
98
|
-
* Spawn a session for one run and drain it.
|
|
99
|
-
*
|
|
100
|
-
* `runId` namespaces the exec id. Runs are concurrent, so two sessions in
|
|
101
|
-
* one workspace under one id would spawn over each other — see
|
|
102
|
-
* {@link execIdFor}.
|
|
103
|
-
*
|
|
104
|
-
* `resume` continues a conversation on this session's **own** exec rather
|
|
105
|
-
* than on a second one: a run given a conversation to continue has no first
|
|
106
|
-
* session of its own, so there is nothing for a follow-up exec to follow.
|
|
107
|
-
*/
|
|
108
|
-
async start(runtime, runId, options, sinks = {}) {
|
|
109
|
-
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
110
|
-
try {
|
|
111
|
-
const execId = execIdFor(runId);
|
|
112
|
-
// `using`, so the attachment is released even when the drain throws.
|
|
113
|
-
const handle = __addDisposableResource(env_1, await startRun(runtime, {
|
|
114
|
-
...launch(options.prompt, options.dir, options.permissionMode),
|
|
115
|
-
...(options.jsonSchema ? { jsonSchema: options.jsonSchema } : {}),
|
|
116
|
-
...resumption(options.resume),
|
|
117
|
-
execId,
|
|
118
|
-
timeoutMs,
|
|
119
|
-
signal: sinks.signal
|
|
120
|
-
}), false);
|
|
121
|
-
return await drainRun(handle, freshCursor(execId), sinks);
|
|
122
|
-
}
|
|
123
|
-
catch (e_1) {
|
|
124
|
-
env_1.error = e_1;
|
|
125
|
-
env_1.hasError = true;
|
|
126
|
-
}
|
|
127
|
-
finally {
|
|
128
|
-
__disposeResources(env_1);
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
/**
|
|
132
|
-
* Give a finished writing session one more turn, and drain it.
|
|
133
|
-
*
|
|
134
|
-
* `sessionId` is the one the session reported — on its `result` line, or on
|
|
135
|
-
* its cursor when it ended without one. This runs in the workspace the
|
|
136
|
-
* session did, because that workspace's {@link file://./run.ts SESSION_CONFIG_DIR}
|
|
137
|
-
* is where the transcript it is continuing can be found. A drain cut short goes
|
|
138
|
-
* on through {@link resume} with the cursor it stored, like any other
|
|
139
|
-
* session's.
|
|
140
|
-
*
|
|
141
|
-
* Never forked: a follow-up is one more turn of the same conversation, which
|
|
142
|
-
* is exactly what a fork is for *not* doing. For the same reason it runs
|
|
143
|
-
* under the session's own `permissionMode`.
|
|
144
|
-
*/
|
|
145
|
-
async followUp(runtime, runId, options, sinks = {}) {
|
|
146
|
-
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
147
|
-
try {
|
|
148
|
-
// Without one, `--resume` would be dropped and a new session started
|
|
149
|
-
// under the follow-up's id — unrelated work, reported as the follow-up.
|
|
150
|
-
if (!options.sessionId) {
|
|
151
|
-
throw new Error("claude-code: a follow-up needs the session id its result reported");
|
|
152
|
-
}
|
|
153
|
-
const execId = followUpExecIdFor(runId);
|
|
154
|
-
const handle = __addDisposableResource(env_2, await startRun(runtime, {
|
|
155
|
-
...launch(options.prompt, options.dir, options.permissionMode),
|
|
156
|
-
resume: options.sessionId,
|
|
157
|
-
execId,
|
|
158
|
-
timeoutMs,
|
|
159
|
-
signal: sinks.signal
|
|
160
|
-
}), false);
|
|
161
|
-
return await drainRun(handle, freshCursor(execId), sinks);
|
|
162
|
-
}
|
|
163
|
-
catch (e_2) {
|
|
164
|
-
env_2.error = e_2;
|
|
165
|
-
env_2.hasError = true;
|
|
166
|
-
}
|
|
167
|
-
finally {
|
|
168
|
-
__disposeResources(env_2);
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
/**
|
|
172
|
-
* Re-attach to a running session and drain it to its end.
|
|
173
|
-
*
|
|
174
|
-
* **A session whose container was replaced is reported, not thrown.** The
|
|
175
|
-
* attachment is the first thing to notice a replacement, and the caller is a
|
|
176
|
-
* recovered turn with a cursor it will happily keep presenting: a throw here
|
|
177
|
-
* retries the same dead id until the recoveries run out, and the run ends on
|
|
178
|
-
* a stack trace that names neither the session nor the cause. A
|
|
179
|
-
* terminal outcome ends it at the first attempt instead, with the exit code
|
|
180
|
-
* the runtime uses for a killed process and an explanation on `stderr`,
|
|
181
|
-
* which is exactly the channel a session that died without a result line
|
|
182
|
-
* already reports through. The wording is {@link containerLost}'s.
|
|
183
|
-
*/
|
|
184
|
-
async resume(runtime, cursor, sinks = {}) {
|
|
185
|
-
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
186
|
-
try {
|
|
187
|
-
let handle;
|
|
188
|
-
try {
|
|
189
|
-
handle = await attachRun(runtime, cursor, { signal: sinks.signal });
|
|
190
|
-
}
|
|
191
|
-
catch (err) {
|
|
192
|
-
if (!isExecLost(err))
|
|
193
|
-
throw err;
|
|
194
|
-
console.warn("[claude-code] the session's container was replaced", {
|
|
195
|
-
execId: cursor.execId,
|
|
196
|
-
err: String(err)
|
|
197
|
-
});
|
|
198
|
-
return {
|
|
199
|
-
done: true,
|
|
200
|
-
cursor,
|
|
201
|
-
progress: [],
|
|
202
|
-
exitCode: -1,
|
|
203
|
-
stderr: containerLost()
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
const session = __addDisposableResource(env_3, handle, false);
|
|
207
|
-
return await drainRun(session, cursor, sinks);
|
|
208
|
-
}
|
|
209
|
-
catch (e_3) {
|
|
210
|
-
env_3.error = e_3;
|
|
211
|
-
env_3.hasError = true;
|
|
212
|
-
}
|
|
213
|
-
finally {
|
|
214
|
-
__disposeResources(env_3);
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
/** Stop a session — `SIGTERM`, so its own process tree goes with it. */
|
|
218
|
-
async stop(runtime, runId) {
|
|
219
|
-
// First, and allowed to fail: most sessions never had a follow-up, and
|
|
220
|
-
// one that did has usually finished its first exec already.
|
|
221
|
-
await killRun(runtime, followUpExecIdFor(runId)).catch(() => { });
|
|
222
|
-
await killRun(runtime, execIdFor(runId));
|
|
223
|
-
},
|
|
224
|
-
/**
|
|
225
|
-
* Is any credential usable right now, and if not, when?
|
|
226
|
-
*
|
|
227
|
-
* The same question {@link egress} answers per request, asked ahead of time
|
|
228
|
-
* so a host can decline to start a session it cannot pay for. That is not a
|
|
229
|
-
* micro-optimisation: an invocation carries an 18.7-27k-token cached prefix
|
|
230
|
-
* before it does anything, so starting one and letting the gateway refuse
|
|
231
|
-
* its first model call costs a container start and that prefix to learn what
|
|
232
|
-
* this returns for free — and reports it as a failed run rather than as a
|
|
233
|
-
* rate limit with a time on it.
|
|
234
|
-
*
|
|
235
|
-
* Reads only. Nothing here marks anything spent.
|
|
236
|
-
*/
|
|
237
|
-
credentials: (store) => credentialPool({ credentials: config.credentials, store }).lead(),
|
|
238
|
-
/**
|
|
239
|
-
* The `Fetcher` the workspace object installs as its egress policy.
|
|
240
|
-
*
|
|
241
|
-
* `store` is an **argument rather than a config field**, and that is the
|
|
242
|
-
* point: the credential pool's state belongs to whichever object has
|
|
243
|
-
* storage, and this same config object is also held by the agents that run
|
|
244
|
-
* sessions, which have none of their own for it. Making it a field would
|
|
245
|
-
* force them to invent one.
|
|
246
|
-
*/
|
|
247
|
-
egress: (store) => claudeCodeEgress({
|
|
248
|
-
credentials: config.credentials,
|
|
249
|
-
store,
|
|
250
|
-
// Forwarded only when set. Defaulting it to `[]` here would turn "the
|
|
251
|
-
// host said nothing" into "Anthropic only", which is the one reading
|
|
252
|
-
// the three-way semantics exist to keep distinct.
|
|
253
|
-
...(config.restrictToHosts === undefined
|
|
254
|
-
? {}
|
|
255
|
-
: { restrictToHosts: config.restrictToHosts }),
|
|
256
|
-
...(config.githubToken ? { githubToken: config.githubToken } : {}),
|
|
257
|
-
label: "claude-code"
|
|
258
|
-
})
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* A conversation to continue, as launch flags.
|
|
263
|
-
*
|
|
264
|
-
* One place rather than a spread at each call site, so `fork` can never travel
|
|
265
|
-
* without the id it forks — which {@link file://./run.ts buildLaunch} refuses,
|
|
266
|
-
* but refuses at launch rather than here.
|
|
267
|
-
*/
|
|
268
|
-
function resumption(resume) {
|
|
269
|
-
if (!resume)
|
|
270
|
-
return undefined;
|
|
271
|
-
return { resume: resume.sessionId, ...(resume.fork ? { fork: true } : {}) };
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Refuse a deployment with no credential when the model is built, naming this
|
|
275
|
-
* plugin, rather than at the first model call inside a run somebody is waiting
|
|
276
|
-
* on. The thunk is still what the gateway calls per request, so a rotation is
|
|
277
|
-
* picked up.
|
|
278
|
-
*/
|
|
279
|
-
export function requireCredentials(config) {
|
|
280
|
-
if (config.credentials().filter(Boolean).length === 0) {
|
|
281
|
-
throw new Error("claude-code: no credentials. Set at least one `claude setup-token` " +
|
|
282
|
-
"credential and pass it as " +
|
|
283
|
-
"`credentials: () => [env.CLAUDE_CODE_OAUTH_TOKEN_1]`.");
|
|
284
|
-
}
|
|
285
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type { Workspace } from "@cloudflare/computer";
|
|
2
|
-
/**
|
|
3
|
-
* Making a container able to speak TLS, once there is a CA to trust.
|
|
4
|
-
*
|
|
5
|
-
* Only `egress: { mode: "http-gateway" }` needs this, but it lives on every
|
|
6
|
-
* workspace because the cost of getting it wrong is asymmetric: the trust
|
|
7
|
-
* install against a container with no CA prints one line and exits 0, while a
|
|
8
|
-
* container that missed it fails every later HTTPS connection with an error
|
|
9
|
-
* that names no cause.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Install the egress interception CA, and say what was there to install.
|
|
13
|
-
*
|
|
14
|
-
* One shell string rather than a script in the image, because **the image cannot
|
|
15
|
-
* run this at all**, and the reason is ordering rather than preference.
|
|
16
|
-
* Cloudflare's own recipe assumes interception is declared as container
|
|
17
|
-
* configuration, so the runtime mounts the CA before the container starts.
|
|
18
|
-
* `@cloudflare/computer` uses the raw container API, where the only interception
|
|
19
|
-
* hooks are methods called *after* `start()` — so an entrypoint runs strictly
|
|
20
|
-
* before the CA can exist, finds nothing, and reports the container
|
|
21
|
-
* un-intercepted while every later TLS connection fails.
|
|
22
|
-
*
|
|
23
|
-
* The listing comes first and runs unconditionally: when the CA is missing,
|
|
24
|
-
* *what else is in that directory* is the only evidence distinguishing "mounted
|
|
25
|
-
* somewhere else" from "never provisioned", and it costs one line.
|
|
26
|
-
*/
|
|
27
|
-
export declare const TRUST_CA_COMMAND: string;
|
|
28
|
-
export interface ContainerTrustDeps {
|
|
29
|
-
workspace: () => Workspace;
|
|
30
|
-
/** The runtime's own container handle, for the exit this has to hear about. */
|
|
31
|
-
container: () => Container | undefined;
|
|
32
|
-
/** Log prefix and object id, for the one line an operator can see. */
|
|
33
|
-
tag: () => string;
|
|
34
|
-
id: () => string;
|
|
35
|
-
/** Told when the watched container exits, for what else it described. */
|
|
36
|
-
onExit?: () => void;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Whether the container this object is talking to has had the CA installed.
|
|
40
|
-
*
|
|
41
|
-
* ## Why the answer is in memory
|
|
42
|
-
*
|
|
43
|
-
* What it describes is a *container*, which does not outlive the isolate in any
|
|
44
|
-
* way worth persisting. A stored `true` would be the exact bug this exists to
|
|
45
|
-
* prevent — a flag surviving the container it describes, and vouching for its
|
|
46
|
-
* replacement.
|
|
47
|
-
*
|
|
48
|
-
* It is wrong only in the safe direction. An isolate that lost it re-runs an
|
|
49
|
-
* idempotent `install -m 644`.
|
|
50
|
-
*
|
|
51
|
-
* ## What clears it
|
|
52
|
-
*
|
|
53
|
-
* **The container's own exit**, watched through `monitor()`. This is the signal
|
|
54
|
-
* that does not depend on anyone noticing: a container replaced underneath a
|
|
55
|
-
* running command — by a reconnect, a relaunch, a crash — exits, and the watch
|
|
56
|
-
* fires whoever caused it. Nothing else here is in a position to know, because
|
|
57
|
-
* most commands run through the stub this object hands out and report their
|
|
58
|
-
* failures to their own caller, not to it.
|
|
59
|
-
*
|
|
60
|
-
* The watch lives in memory beside the flag it clears, which is the right
|
|
61
|
-
* lifetime: an isolate that loses one loses the other, and the replacement
|
|
62
|
-
* starts out untrusted. It is deliberately not held open with `waitUntil` —
|
|
63
|
-
* that would keep an invocation alive for the life of the container.
|
|
64
|
-
*
|
|
65
|
-
* A container seen not running, and a command reporting `EEXEC_LOST`, both call
|
|
66
|
-
* {@link forget} as well. They are cheap, they are strictly earlier in some
|
|
67
|
-
* orderings, and neither is load-bearing on its own.
|
|
68
|
-
*/
|
|
69
|
-
export declare class ContainerTrust {
|
|
70
|
-
#private;
|
|
71
|
-
private readonly deps;
|
|
72
|
-
constructor(deps: ContainerTrustDeps);
|
|
73
|
-
/**
|
|
74
|
-
* Forget that any container was trusted.
|
|
75
|
-
*
|
|
76
|
-
* Drops the standing watch too, because this is also reached for a container
|
|
77
|
-
* that keeps running — a `running` read, a lost exec. The watch it leaves
|
|
78
|
-
* behind ignores that container's real exit, so without a fresh one nothing
|
|
79
|
-
* would clear the flag again and the replacement would be vouched for.
|
|
80
|
-
*/
|
|
81
|
-
forget(): void;
|
|
82
|
-
/**
|
|
83
|
-
* Trust the CA if this container has not been trusted yet.
|
|
84
|
-
*
|
|
85
|
-
* Called from the workspace's `ready()` path, which is the earliest point that
|
|
86
|
-
* is not too early: the backend's `connect()` has completed, so start and
|
|
87
|
-
* interception have both happened.
|
|
88
|
-
*
|
|
89
|
-
* **Never throws.** A workspace that cannot trust the CA still has a checkout,
|
|
90
|
-
* a shell and a git history, and whatever runs next will say plainly what went
|
|
91
|
-
* wrong — refusing to proceed here would replace a legible TLS error with an
|
|
92
|
-
* opaque one.
|
|
93
|
-
*/
|
|
94
|
-
ensure(): Promise<void>;
|
|
95
|
-
}
|