@dynamicagents/plugins 0.14.0 → 0.16.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.
Files changed (141) hide show
  1. package/README.md +14 -14
  2. package/dist/claude-code/cards.d.ts +2 -0
  3. package/dist/claude-code/cards.js +11 -0
  4. package/dist/claude-code/config.d.ts +10 -83
  5. package/dist/claude-code/config.js +0 -2
  6. package/dist/claude-code/credentials.d.ts +32 -50
  7. package/dist/claude-code/credentials.js +115 -74
  8. package/dist/claude-code/daemon/index.d.ts +24 -0
  9. package/dist/claude-code/daemon/index.js +203 -0
  10. package/dist/claude-code/egress.d.ts +35 -117
  11. package/dist/claude-code/egress.js +80 -325
  12. package/dist/claude-code/events.d.ts +14 -17
  13. package/dist/claude-code/events.js +19 -15
  14. package/dist/claude-code/harness-wire.d.ts +45 -0
  15. package/dist/claude-code/harness-wire.js +47 -0
  16. package/dist/claude-code/index.d.ts +19 -29
  17. package/dist/claude-code/index.js +17 -25
  18. package/dist/claude-code/language-model.d.ts +19 -0
  19. package/dist/claude-code/language-model.js +71 -0
  20. package/dist/claude-code/model.d.ts +77 -70
  21. package/dist/claude-code/model.js +327 -327
  22. package/dist/claude-code/placeholder.d.ts +12 -0
  23. package/dist/claude-code/placeholder.js +12 -0
  24. package/dist/claude-code/spec.d.ts +4 -4
  25. package/dist/claude-code/spec.js +4 -4
  26. package/dist/computer/client.d.ts +88 -0
  27. package/dist/computer/client.js +6 -0
  28. package/dist/computer/context.d.ts +7 -7
  29. package/dist/computer/context.js +14 -18
  30. package/dist/computer/gate.d.ts +4 -23
  31. package/dist/computer/gate.js +1 -37
  32. package/dist/computer/index.d.ts +44 -43
  33. package/dist/computer/index.js +29 -50
  34. package/dist/computer/paths.d.ts +5 -27
  35. package/dist/computer/paths.js +7 -30
  36. package/dist/computer/proxy.d.ts +17 -31
  37. package/dist/computer/proxy.js +9 -44
  38. package/dist/computer/render.d.ts +3 -40
  39. package/dist/computer/render.js +3 -36
  40. package/dist/computer/sandbox.d.ts +55 -0
  41. package/dist/computer/sandbox.js +236 -0
  42. package/dist/computer/shell.d.ts +36 -0
  43. package/dist/computer/shell.js +41 -0
  44. package/dist/computer/tools-exec.js +3 -9
  45. package/dist/computer/tools-file.d.ts +1 -1
  46. package/dist/computer/tools-file.js +1 -1
  47. package/dist/{repo → repo-github}/checkout.d.ts +3 -4
  48. package/dist/{repo → repo-github}/checkout.js +3 -4
  49. package/dist/{repo → repo-github}/context.d.ts +14 -32
  50. package/dist/{repo → repo-github}/context.js +46 -81
  51. package/dist/{repo → repo-github}/index.d.ts +30 -13
  52. package/dist/{repo → repo-github}/index.js +25 -6
  53. package/dist/repo-github/mcp.d.ts +95 -0
  54. package/dist/repo-github/mcp.js +107 -0
  55. package/dist/repo-github/sandbox-egress.d.ts +68 -0
  56. package/dist/repo-github/sandbox-egress.js +272 -0
  57. package/dist/repo-github/sandbox-git.d.ts +30 -0
  58. package/dist/repo-github/sandbox-git.js +113 -0
  59. package/dist/{repo → repo-github}/tools-checks.js +43 -4
  60. package/dist/{repo → repo-github}/tools-clone.js +2 -21
  61. package/dist/{repo → repo-github}/tools-pr.d.ts +0 -1
  62. package/dist/{repo → repo-github}/tools-pr.js +85 -20
  63. package/dist/{repo → repo-github}/tools-review.d.ts +6 -0
  64. package/dist/{repo → repo-github}/tools-review.js +62 -176
  65. package/dist/{repo → repo-github}/url.d.ts +11 -0
  66. package/dist/{repo → repo-github}/url.js +12 -1
  67. package/dist/{workspace → sandbox}/advisory.d.ts +16 -35
  68. package/dist/{workspace → sandbox}/advisory.js +2 -29
  69. package/dist/sandbox/agent-exec.d.ts +31 -0
  70. package/dist/sandbox/agent-exec.js +62 -0
  71. package/dist/sandbox/ca-trust.d.ts +9 -0
  72. package/dist/sandbox/ca-trust.js +21 -0
  73. package/dist/sandbox/constants.d.ts +22 -0
  74. package/dist/sandbox/constants.js +22 -0
  75. package/dist/sandbox/daemon/composite.d.ts +9 -0
  76. package/dist/sandbox/daemon/composite.js +35 -0
  77. package/dist/sandbox/daemon/index.d.ts +47 -0
  78. package/dist/sandbox/daemon/index.js +116 -0
  79. package/dist/sandbox/egress.d.ts +81 -0
  80. package/dist/sandbox/egress.js +109 -0
  81. package/dist/sandbox/exec.d.ts +57 -0
  82. package/dist/sandbox/exec.js +52 -0
  83. package/dist/sandbox/format.d.ts +2 -0
  84. package/dist/sandbox/format.js +7 -0
  85. package/dist/sandbox/header.d.ts +50 -0
  86. package/dist/sandbox/header.js +94 -0
  87. package/dist/sandbox/index.d.ts +17 -0
  88. package/dist/sandbox/index.js +17 -0
  89. package/dist/{workspace/install.d.ts → sandbox/install-plan.d.ts} +2 -2
  90. package/dist/{workspace/install.js → sandbox/install-plan.js} +2 -2
  91. package/dist/sandbox/name.d.ts +27 -0
  92. package/dist/sandbox/name.js +32 -0
  93. package/dist/sandbox/object.d.ts +244 -0
  94. package/dist/sandbox/object.js +1139 -0
  95. package/dist/scratch/index.d.ts +1 -9
  96. package/dist/scratch/index.js +2 -18
  97. package/package.json +24 -20
  98. package/dist/claude-code/github.d.ts +0 -39
  99. package/dist/claude-code/github.js +0 -82
  100. package/dist/claude-code/run.d.ts +0 -491
  101. package/dist/claude-code/run.js +0 -913
  102. package/dist/claude-code/session.d.ts +0 -131
  103. package/dist/claude-code/session.js +0 -288
  104. package/dist/workspace/ca-trust.d.ts +0 -95
  105. package/dist/workspace/ca-trust.js +0 -312
  106. package/dist/workspace/container-deps.d.ts +0 -58
  107. package/dist/workspace/container-deps.js +0 -249
  108. package/dist/workspace/container-fault.d.ts +0 -38
  109. package/dist/workspace/container-fault.js +0 -73
  110. package/dist/workspace/deps-snapshot.d.ts +0 -110
  111. package/dist/workspace/deps-snapshot.js +0 -424
  112. package/dist/workspace/exec.d.ts +0 -94
  113. package/dist/workspace/exec.js +0 -153
  114. package/dist/workspace/format.d.ts +0 -36
  115. package/dist/workspace/format.js +0 -57
  116. package/dist/workspace/git-host.d.ts +0 -79
  117. package/dist/workspace/git-host.js +0 -226
  118. package/dist/workspace/git-identity.d.ts +0 -57
  119. package/dist/workspace/git-identity.js +0 -147
  120. package/dist/workspace/index.d.ts +0 -50
  121. package/dist/workspace/index.js +0 -58
  122. package/dist/workspace/install-job.d.ts +0 -170
  123. package/dist/workspace/install-job.js +0 -934
  124. package/dist/workspace/object.d.ts +0 -522
  125. package/dist/workspace/object.js +0 -1541
  126. package/dist/workspace/open.d.ts +0 -95
  127. package/dist/workspace/open.js +0 -63
  128. package/dist/workspace/read.d.ts +0 -16
  129. package/dist/workspace/read.js +0 -22
  130. package/dist/workspace/shell.d.ts +0 -45
  131. package/dist/workspace/shell.js +0 -80
  132. package/dist/workspace/sync.d.ts +0 -111
  133. package/dist/workspace/sync.js +0 -124
  134. package/dist/workspace/wake.d.ts +0 -21
  135. package/dist/workspace/wake.js +0 -10
  136. /package/dist/{repo → repo-github}/tools-checks.d.ts +0 -0
  137. /package/dist/{repo → repo-github}/tools-clone.d.ts +0 -0
  138. /package/dist/{repo → repo-github}/tools-worktree.d.ts +0 -0
  139. /package/dist/{repo → repo-github}/tools-worktree.js +0 -0
  140. /package/dist/{repo → repo-github}/tools-worktrees.d.ts +0 -0
  141. /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,288 +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, {
190
- signal: sinks.signal,
191
- maxWaitMs: timeoutMs
192
- });
193
- }
194
- catch (err) {
195
- if (!isExecLost(err))
196
- throw err;
197
- console.warn("[claude-code] the session's container was replaced", {
198
- execId: cursor.execId,
199
- err: String(err)
200
- });
201
- return {
202
- done: true,
203
- cursor,
204
- progress: [],
205
- exitCode: -1,
206
- stderr: containerLost()
207
- };
208
- }
209
- const session = __addDisposableResource(env_3, handle, false);
210
- return await drainRun(session, cursor, sinks);
211
- }
212
- catch (e_3) {
213
- env_3.error = e_3;
214
- env_3.hasError = true;
215
- }
216
- finally {
217
- __disposeResources(env_3);
218
- }
219
- },
220
- /** Stop a session — `SIGTERM`, so its own process tree goes with it. */
221
- async stop(runtime, runId) {
222
- // First, and allowed to fail: most sessions never had a follow-up, and
223
- // one that did has usually finished its first exec already.
224
- await killRun(runtime, followUpExecIdFor(runId)).catch(() => { });
225
- await killRun(runtime, execIdFor(runId));
226
- },
227
- /**
228
- * Is any credential usable right now, and if not, when?
229
- *
230
- * The same question {@link egress} answers per request, asked ahead of time
231
- * so a host can decline to start a session it cannot pay for. That is not a
232
- * micro-optimisation: an invocation carries an 18.7-27k-token cached prefix
233
- * before it does anything, so starting one and letting the gateway refuse
234
- * its first model call costs a container start and that prefix to learn what
235
- * this returns for free — and reports it as a failed run rather than as a
236
- * rate limit with a time on it.
237
- *
238
- * Reads only. Nothing here marks anything spent.
239
- */
240
- credentials: (store) => credentialPool({ credentials: config.credentials, store }).lead(),
241
- /**
242
- * The `Fetcher` the workspace object installs as its egress policy.
243
- *
244
- * `store` is an **argument rather than a config field**, and that is the
245
- * point: the credential pool's state belongs to whichever object has
246
- * storage, and this same config object is also held by the agents that run
247
- * sessions, which have none of their own for it. Making it a field would
248
- * force them to invent one.
249
- */
250
- egress: (store) => claudeCodeEgress({
251
- credentials: config.credentials,
252
- store,
253
- // Forwarded only when set. Defaulting it to `[]` here would turn "the
254
- // host said nothing" into "Anthropic only", which is the one reading
255
- // the three-way semantics exist to keep distinct.
256
- ...(config.restrictToHosts === undefined
257
- ? {}
258
- : { restrictToHosts: config.restrictToHosts }),
259
- ...(config.githubToken ? { githubToken: config.githubToken } : {}),
260
- label: "claude-code"
261
- })
262
- };
263
- }
264
- /**
265
- * A conversation to continue, as launch flags.
266
- *
267
- * One place rather than a spread at each call site, so `fork` can never travel
268
- * without the id it forks — which {@link file://./run.ts buildLaunch} refuses,
269
- * but refuses at launch rather than here.
270
- */
271
- function resumption(resume) {
272
- if (!resume)
273
- return undefined;
274
- return { resume: resume.sessionId, ...(resume.fork ? { fork: true } : {}) };
275
- }
276
- /**
277
- * Refuse a deployment with no credential when the model is built, naming this
278
- * plugin, rather than at the first model call inside a run somebody is waiting
279
- * on. The thunk is still what the gateway calls per request, so a rotation is
280
- * picked up.
281
- */
282
- export function requireCredentials(config) {
283
- if (config.credentials().filter(Boolean).length === 0) {
284
- throw new Error("claude-code: no credentials. Set at least one `claude setup-token` " +
285
- "credential and pass it as " +
286
- "`credentials: () => [env.CLAUDE_CODE_OAUTH_TOKEN_1]`.");
287
- }
288
- }
@@ -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
- }