@famonfa/mono 0.0.0-stage → 0.1.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 (61) hide show
  1. package/bin/mono.mjs +210 -0
  2. package/node_modules/@anthropic-ai/claude-agent-sdk/LICENSE.md +1 -0
  3. package/node_modules/@anthropic-ai/claude-agent-sdk/README.md +69 -0
  4. package/node_modules/@anthropic-ai/claude-agent-sdk/agentSdkTypes.d.ts +1 -0
  5. package/node_modules/@anthropic-ai/claude-agent-sdk/bridge.d.ts +396 -0
  6. package/node_modules/@anthropic-ai/claude-agent-sdk/bridge.mjs +142 -0
  7. package/node_modules/@anthropic-ai/claude-agent-sdk/browser-sdk.d.ts +208 -0
  8. package/node_modules/@anthropic-ai/claude-agent-sdk/browser-sdk.js +145 -0
  9. package/node_modules/@anthropic-ai/claude-agent-sdk/core-36zyfan5.mjs +52 -0
  10. package/node_modules/@anthropic-ai/claude-agent-sdk/core-5682eevd.mjs +27 -0
  11. package/node_modules/@anthropic-ai/claude-agent-sdk/core-nne0e2ds.mjs +40 -0
  12. package/node_modules/@anthropic-ai/claude-agent-sdk/core-xpxe8nzb.mjs +26 -0
  13. package/node_modules/@anthropic-ai/claude-agent-sdk/core.d.ts +22 -0
  14. package/node_modules/@anthropic-ai/claude-agent-sdk/core.mjs +34 -0
  15. package/node_modules/@anthropic-ai/claude-agent-sdk/extractFromBunfs.d.ts +1 -0
  16. package/node_modules/@anthropic-ai/claude-agent-sdk/extractFromBunfs.js +156 -0
  17. package/node_modules/@anthropic-ai/claude-agent-sdk/manifest.json +82 -0
  18. package/node_modules/@anthropic-ai/claude-agent-sdk/manifest.zst.json +90 -0
  19. package/node_modules/@anthropic-ai/claude-agent-sdk/package.json +94 -0
  20. package/node_modules/@anthropic-ai/claude-agent-sdk/sdk-tools.d.ts +4222 -0
  21. package/node_modules/@anthropic-ai/claude-agent-sdk/sdk.d.ts +10277 -0
  22. package/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs +169 -0
  23. package/node_modules/ws/LICENSE +20 -0
  24. package/node_modules/ws/README.md +548 -0
  25. package/node_modules/ws/browser.js +8 -0
  26. package/node_modules/ws/index.js +22 -0
  27. package/node_modules/ws/lib/buffer-util.js +131 -0
  28. package/node_modules/ws/lib/constants.js +19 -0
  29. package/node_modules/ws/lib/event-target.js +292 -0
  30. package/node_modules/ws/lib/extension.js +203 -0
  31. package/node_modules/ws/lib/limiter.js +55 -0
  32. package/node_modules/ws/lib/permessage-deflate.js +530 -0
  33. package/node_modules/ws/lib/receiver.js +743 -0
  34. package/node_modules/ws/lib/sender.js +607 -0
  35. package/node_modules/ws/lib/stream.js +161 -0
  36. package/node_modules/ws/lib/subprotocol.js +62 -0
  37. package/node_modules/ws/lib/validation.js +152 -0
  38. package/node_modules/ws/lib/websocket-server.js +562 -0
  39. package/node_modules/ws/lib/websocket.js +1421 -0
  40. package/node_modules/ws/package.json +74 -0
  41. package/node_modules/ws/wrapper.mjs +21 -0
  42. package/package.json +126 -3
  43. package/skills/workspace/SKILL.md +108 -0
  44. package/src/api.mjs +279 -0
  45. package/src/chats.mjs +419 -0
  46. package/src/commands.mjs +100 -0
  47. package/src/groups.mjs +84 -0
  48. package/src/launcher.mjs +212 -0
  49. package/src/main.mjs +42 -0
  50. package/src/paths.mjs +44 -0
  51. package/src/projects.mjs +199 -0
  52. package/src/refresh.mjs +124 -0
  53. package/src/remote.mjs +129 -0
  54. package/src/sessions.mjs +422 -0
  55. package/src/store.mjs +253 -0
  56. package/web/assets/index-BMbPwlF6.js +55 -0
  57. package/web/assets/index-Ke-WlOuz.css +1 -0
  58. package/web/icon.svg +1 -0
  59. package/web/index.html +17 -0
  60. package/web/manifest.webmanifest +9 -0
  61. package/README.md +0 -3
package/bin/mono.mjs ADDED
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { execFileSync } from "node:child_process";
5
+ import * as store from "../src/store.mjs";
6
+ import * as sessions from "../src/sessions.mjs";
7
+ import * as groups from "../src/groups.mjs";
8
+ import * as launcher from "../src/launcher.mjs";
9
+
10
+ launcher.runFromRuntime();
11
+
12
+ const USAGE = `mono (alias: ws) — CLI de Mono (http://localhost:4600)
13
+
14
+ mono Arranca el server si hace falta y abre la app (escritorio o navegador)
15
+ mono serve Corre el server en primer plano
16
+ mono status Estado del server, del servicio y de la conexión remota
17
+ mono connect <relay-url> Conecta esta máquina al relay (Google) para usarla desde el celu/web
18
+ mono disconnect Corta la conexión remota
19
+ mono service install|uninstall Arranca Mono solo al iniciar sesión (launchd) y pone mono/ws en el PATH
20
+
21
+ ws list Lista las tareas
22
+ ws show <task> Muestra task.json + boards/docs/assets
23
+ ws get <task> <board> Imprime un board (nodos y conexiones) para editarlo
24
+ ws task <task> <file.json|-> Crea/actualiza metadatos (merge superficial)
25
+ ws board <task> <board> <file.json|-> [--relayout | --patch]
26
+ Crea/actualiza un board conservando lo que movió el usuario.
27
+ --patch solo agrega/actualiza nodos, nunca borra.
28
+ ws undo <task> <board> Vuelve el board a la versión anterior a la última escritura
29
+ ws doc <task> <name.md> <file.md|-> Escribe un documento
30
+ ws asset <task> <image...> Copia imágenes a assets/
31
+ ws sessions [task] [--since ISO] Actividad reciente de los agentes (de una tarea o todos)
32
+ ws groups Lista los grupos de sesiones (canvas de chats)
33
+ ws group <grupo> <session-id...> Manda sesiones al canvas de un grupo (lo crea si no existe)
34
+ ws open [task] Abre la app en el navegador
35
+ ws path [task] Imprime la carpeta de datos`;
36
+
37
+ const [, , command, ...args] = process.argv;
38
+
39
+ function readInput(source) {
40
+ return source === "-" ? fs.readFileSync(0, "utf8") : fs.readFileSync(source, "utf8");
41
+ }
42
+
43
+ function fail(message) {
44
+ console.error(message);
45
+ process.exit(1);
46
+ }
47
+
48
+ function requireArgs(count) {
49
+ if (args.filter((a) => !a.startsWith("--")).length < count) fail(USAGE);
50
+ }
51
+
52
+ // `ws` with no args keeps printing usage (the /workspace skill relies on it); `mono` opens the app.
53
+ const invokedAs = path.basename(process.argv[1] ?? "");
54
+
55
+ switch (command ?? (invokedAs === "ws" ? "help" : "launch")) {
56
+ case "launch":
57
+ await launcher.launch();
58
+ break;
59
+ case "serve":
60
+ await import("../src/main.mjs");
61
+ break;
62
+ case "status":
63
+ await launcher.status();
64
+ break;
65
+ case "connect":
66
+ await launcher.connect(args[0], args[1]);
67
+ break;
68
+ case "disconnect":
69
+ launcher.disconnect();
70
+ break;
71
+ case "service":
72
+ if (args[0] === "install") launcher.installService({ ifMissing: args.includes("--if-missing") });
73
+ else if (args[0] === "uninstall") launcher.uninstallService();
74
+ else fail(USAGE);
75
+ break;
76
+ case "list": {
77
+ for (const t of store.listTasks()) {
78
+ console.log(`${t.id.padEnd(14)} ${String(t.status).padEnd(10)} ${t.title} [${t.boards.map((b) => b.id).join(", ")}]`);
79
+ }
80
+ break;
81
+ }
82
+ case "show": {
83
+ requireArgs(1);
84
+ const task = store.getTask(args[0]);
85
+ if (!task) fail(`No existe la tarea ${args[0]}`);
86
+ console.log(JSON.stringify(task, null, 2));
87
+ break;
88
+ }
89
+ case "get": {
90
+ requireArgs(2);
91
+ const board = store.getBoard(args[0], args[1]);
92
+ if (!board) fail(`No existe el board ${args[0]}/${args[1]}`);
93
+ const compact = {
94
+ ...board,
95
+ // Lanes, parents and positions are the app's layout; agents place nodes with the \`lane\` name.
96
+ nodes: board.nodes.filter((n) => n.type !== "lane").map(({ id, type, data }) => ({ id, type, ...data })),
97
+ };
98
+ console.log(JSON.stringify(compact, null, 2));
99
+ break;
100
+ }
101
+ case "task": {
102
+ requireArgs(2);
103
+ const [id, source] = args;
104
+ store.assertSafe(id);
105
+ const task = store.saveTask(id, JSON.parse(readInput(source)));
106
+ console.log(`✓ tarea ${task.id} actualizada`);
107
+ break;
108
+ }
109
+ case "board": {
110
+ requireArgs(3);
111
+ const [id, boardId, source] = args.filter((a) => !a.startsWith("--"));
112
+ const incoming = JSON.parse(readInput(source));
113
+ const existing = store.getBoard(id, boardId);
114
+ const merged = store.mergeBoard(existing, incoming, { relayout: args.includes("--relayout"), patch: args.includes("--patch") });
115
+ store.snapshotBoard(id, boardId);
116
+ store.saveBoard(id, boardId, merged);
117
+ const kept = existing ? merged.nodes.filter((n) => n.position).length : 0;
118
+ console.log(`✓ board ${id}/${boardId}: ${merged.nodes.length} nodos, ${merged.edges.length} conexiones${kept ? ` (${kept} conservaron su posición)` : ""}`);
119
+ break;
120
+ }
121
+ case "undo": {
122
+ requireArgs(2);
123
+ const restored = store.restoreBoard(args[0], args[1]);
124
+ console.log(`✓ board ${args[0]}/${args[1]} restaurado a ${restored.replace(".json", "")}`);
125
+ break;
126
+ }
127
+ case "doc": {
128
+ requireArgs(3);
129
+ const [id, name, source] = args;
130
+ store.saveDoc(id, name, readInput(source));
131
+ console.log(`✓ doc ${id}/docs/${name}`);
132
+ break;
133
+ }
134
+ case "asset": {
135
+ requireArgs(2);
136
+ const [id, ...files] = args;
137
+ store.assertSafe(id);
138
+ const dir = path.join(store.TASKS_DIR, id, "assets");
139
+ fs.mkdirSync(dir, { recursive: true });
140
+ for (const file of files) {
141
+ const name = path.basename(file).replace(/[^A-Za-z0-9._-]/g, "-");
142
+ fs.copyFileSync(file, path.join(dir, name));
143
+ console.log(`✓ assets/${name}`);
144
+ }
145
+ break;
146
+ }
147
+ case "sessions": {
148
+ const [id] = args.filter((a) => !a.startsWith("--"));
149
+ const sinceArg = args.indexOf("--since");
150
+ const since = sinceArg >= 0 ? args[sinceArg + 1] : undefined;
151
+ const all = sessions.listSessions({ days: 7 });
152
+ const task = id ? store.getTask(id) : null;
153
+ if (id && !task) fail(`No existe la tarea ${id}`);
154
+ const list = task ? sessions.sessionsForTask(task, all) : all.filter((x) => x.status !== "inactive");
155
+ if (!list.length) console.log("Sin sesiones vinculadas.");
156
+ for (const session of list) printSessionDigest(session, since);
157
+ break;
158
+ }
159
+ case "groups": {
160
+ for (const g of groups.listGroups()) console.log(`${g.id}\t${g.name}\t${g.panes.length} sesiones\thttp://localhost:4600/#/g/${g.id}`);
161
+ break;
162
+ }
163
+ case "group": {
164
+ requireArgs(2);
165
+ const [ref, ...ids] = args;
166
+ const titles = new Map(sessions.listSessions({ days: 30 }).map((s) => [s.id, s.title]));
167
+ let group = groups.findGroup(ref) ?? groups.createGroup({ name: ref });
168
+ for (const id of ids) group = groups.addSession(group.id, id, titles.get(id));
169
+ console.log(`${group.name}: ${group.panes.length} sesiones · http://localhost:4600/#/g/${group.id}`);
170
+ break;
171
+ }
172
+ case "open": {
173
+ await launcher.ensureServer();
174
+ const url = `${launcher.APP_URL}/${args[0] ? `#/t/${args[0]}` : ""}`;
175
+ execFileSync("open", [url]);
176
+ console.log(url);
177
+ break;
178
+ }
179
+ case "path": {
180
+ console.log(args[0] ? path.join(store.TASKS_DIR, args[0]) : store.TASKS_DIR);
181
+ break;
182
+ }
183
+ default:
184
+ console.log(USAGE);
185
+ }
186
+
187
+ function printSessionDigest(session, since) {
188
+ const short = (text, max) => (text && text.length > max ? `${text.slice(0, max)}…` : text ?? "");
189
+ console.log(`\n## ${session.title} [${session.status}] ${session.id}`);
190
+ console.log(`${session.project} · ${session.gitBranch ?? "-"} · última actividad ${session.lastTs}${session.prLinks.length ? ` · PRs ${session.prLinks.map((u) => "#" + u.split("/").pop()).join(" ")}` : ""}`);
191
+ const detail = sessions.readSessionEvents(session.id);
192
+ const events = detail.events.filter((e) => !since || e.ts > since);
193
+ const results = new Map(events.filter((e) => e.kind === "result").map((e) => [e.toolUseId, e]));
194
+ console.log("\n### Línea de tiempo (más reciente al final)");
195
+ for (const e of events.slice(-70)) {
196
+ if (e.kind === "prompt") console.log(`\n👤 ${short(e.text, 500)}`);
197
+ if (e.kind === "text") console.log(`\n🤖 ${short(e.text, 700)}`);
198
+ if (e.kind === "notice") console.log(`ℹ️ ${short(e.text, 200)}`);
199
+ if (e.kind === "tool") {
200
+ const r = results.get(e.id);
201
+ console.log(`→ ${e.name}: ${short(e.title, 140)}${r?.isError ? ` ✗ ${short(r.text, 300)}` : ""}`);
202
+ }
203
+ }
204
+ for (const agent of session.subagents.filter((a) => !since || (a.lastTs ?? "") > since)) {
205
+ const agentDetail = sessions.readSessionEvents(session.id, { agent: agent.id });
206
+ const finalTexts = agentDetail?.events.filter((e) => e.kind === "text").slice(-2).map((e) => e.text) ?? [];
207
+ console.log(`\n### Subagente: ${agent.description} [${agent.status}]`);
208
+ console.log(short(finalTexts.join("\n\n"), 2500) || "(sin texto todavía)");
209
+ }
210
+ }
@@ -0,0 +1 @@
1
+ © Anthropic PBC. All rights reserved. Use is subject to the Legal Agreements outlined here: https://code.claude.com/docs/en/legal-and-compliance.
@@ -0,0 +1,69 @@
1
+ # Claude Agent SDK
2
+
3
+ ![](https://img.shields.io/badge/Node.js-18%2B-brightgreen?style=flat-square) [![npm]](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk)
4
+
5
+ [npm]: https://img.shields.io/npm/v/@anthropic-ai/claude-agent-sdk.svg?style=flat-square
6
+
7
+ The Claude Agent SDK enables you to programmatically build AI agents with Claude Code's capabilities. Create autonomous agents that can understand codebases, edit files, run commands, and execute complex workflows.
8
+
9
+ **Learn more in the [official documentation](https://platform.claude.com/docs/en/agent-sdk/overview)**.
10
+
11
+ ## Get started
12
+
13
+ Install the Claude Agent SDK:
14
+
15
+ ```sh
16
+ npm install @anthropic-ai/claude-agent-sdk
17
+ ```
18
+
19
+ ## The `/core` entry (for apps that bundle the SDK)
20
+
21
+ `@anthropic-ai/claude-agent-sdk/core` exports the same `query()`, `startup()`, `tool()`, `createSdkMcpServer()`, `renameSession()`/`tagSession()`/`deleteSession()`, `resolveSettings()`/`filterEscalatingDefaultMode()` and runtime constants as the root entry, and nothing else — no session listing/reading/import helpers — so its eagerly loaded code is about a quarter of the root's; the settings resolver behind `resolveSettings()` and the code behind the three session mutations load on first call. Unlike the root entry it does **not** inline the SDK's peer dependencies: `zod` (^4, as declared in this package's `peerDependencies`) and `@modelcontextprotocol/sdk` (^1.29) are imported from your install — specifically the `zod/v4` subpath, plus `zod/v3` when the settings resolver loads — which is what you want when your bundler already carries them. (zod 3.25+, which carries the v4 engine under `zod/v4`, also works in practice, but ^4 is the supported range.) Import from **either** the root **or** `/core` in a given process, not both — they are separate bundles, and mixing them loads two copies of the SDK's classes and state. Its types require TypeScript 5.0+.
22
+
23
+ ## Compiled binaries (`bun build --compile`)
24
+
25
+ When bundling your application into a single executable with `bun build --compile`, the SDK cannot resolve the native CLI binary at runtime — `require.resolve` doesn't work from inside the compiled `$bunfs` (or `B:\~BUN\...` on Windows) virtual filesystem.
26
+
27
+ Embed the platform-specific binary as a file asset, extract it to a real path, and pass it explicitly:
28
+
29
+ ```js
30
+ import binPath from '@anthropic-ai/claude-agent-sdk-darwin-arm64/claude' with { type: 'file' }
31
+ import { extractFromBunfs } from '@anthropic-ai/claude-agent-sdk/extract'
32
+ import { query } from '@anthropic-ai/claude-agent-sdk'
33
+
34
+ const cliPath = extractFromBunfs(binPath)
35
+
36
+ for await (const message of query({
37
+ prompt: '…',
38
+ options: { pathToClaudeCodeExecutable: cliPath },
39
+ })) { /* … */ }
40
+ ```
41
+
42
+ Each compiled executable embeds one platform's binary, matching your `--target`. Cross-compiling requires installing the non-matching platform package (e.g. `npm install @anthropic-ai/claude-agent-sdk-linux-x64 --force`). On Windows the binary subpath is `/claude.exe` (e.g. `@anthropic-ai/claude-agent-sdk-win32-x64/claude.exe`).
43
+
44
+ ## Migrating from the Claude Code SDK
45
+
46
+ The Claude Code SDK is now the Claude Agent SDK. Please check out the [migration guide](https://platform.claude.com/docs/en/agent-sdk/migration-guide) for details on breaking changes.
47
+
48
+ ## Reporting Bugs
49
+
50
+ We welcome your feedback. File a [GitHub issue](https://github.com/anthropics/claude-agent-sdk-typescript/issues) to report bugs or request features.
51
+
52
+ ## Connect on Discord
53
+
54
+ Join the [Claude Developers Discord](https://anthropic.com/discord) to connect with other developers building with the Claude Agent SDK. Get help, share feedback, and discuss your projects with the community.
55
+
56
+ ## Data collection, usage, and retention
57
+
58
+ When you use the Claude Agent SDK, we collect feedback, which includes usage data (such as code acceptance or rejections), associated conversation data, and user feedback submitted via the /bug command.
59
+
60
+ ### How we use your data
61
+
62
+ See our [data usage policies](https://code.claude.com/docs/en/data-usage).
63
+
64
+ ### Privacy safeguards
65
+
66
+ We have implemented several safeguards to protect your data, including limited retention periods for sensitive information and restricted access to user session data.
67
+
68
+ For full details, please review our [Commercial Terms of Service](https://www.anthropic.com/legal/commercial-terms) and [Privacy Policy](https://www.anthropic.com/legal/privacy).
69
+
@@ -0,0 +1 @@
1
+ export * from './sdk.js'
@@ -0,0 +1,396 @@
1
+ /**
2
+ * API surface definition for @anthropic-ai/claude-agent-sdk/bridge.
3
+ *
4
+ * This file is the source of truth for the /bridge export's public types.
5
+ * It imports ONLY from agentSdkTypes.ts so the compiled .d.ts has exactly
6
+ * one import to rewrite (./agentSdkTypes → ./sdk) for the flat package layout.
7
+ *
8
+ * Compiled by scripts/build-ant-sdk-typings.sh; see build-agent-sdk.sh for the
9
+ * copy into the package. Runtime code is in agentSdkBridge.ts (separate file,
10
+ * bun-built to bridge.mjs).
11
+ *
12
+ * The two type definitions below are copied from src/bridge/sessionHandle.ts.
13
+ * Keep in sync — sessionHandle.ts is the implementation source of truth;
14
+ * this file exists to produce a clean .d.ts without walking the implementation
15
+ * import graph.
16
+ */
17
+ import type { PermissionMode, SDKControlRequest, SDKControlResponse, SDKMessage } from './agentSdkTypes.js';
18
+ /**
19
+ * Session state reported to the CCR /worker endpoint.
20
+ * @alpha
21
+ */
22
+ export type SessionState = 'idle' | 'running' | 'requires_action';
23
+ /**
24
+ * Per-session bridge transport handle.
25
+ *
26
+ * Auth is instance-scoped — the JWT lives in this handle's closure, not a
27
+ * process-wide env var, so multiple handles can coexist without stomping
28
+ * each other.
29
+ * @alpha
30
+ */
31
+ export type BridgeSessionHandle = {
32
+ readonly sessionId: string;
33
+ /**
34
+ * Live SSE event-stream high-water mark. Updates as the underlying
35
+ * transport receives frames. Persist this and pass back as
36
+ * `initialSequenceNum` on re-attach so the server resumes instead of
37
+ * replaying full history.
38
+ */
39
+ getSequenceNum(): number;
40
+ /**
41
+ * Worker epoch the current transport is writing as. Callers that
42
+ * reconnect for a token refresh (not a cold re-attach) pass this back
43
+ * via `reconnectTransport({epoch})` so the handle reuses the epoch
44
+ * instead of calling registerWorker again.
45
+ */
46
+ getEpoch(): number | undefined;
47
+ /** True once the write path (CCRClient initialize) is ready. */
48
+ isConnected(): boolean;
49
+ /** Write a single SDKMessage. `session_id` is injected automatically. */
50
+ write(msg: SDKMessage): void;
51
+ /** Signal turn boundary — claude.ai stops the "working" spinner. */
52
+ sendResult(): void;
53
+ /** Forward a permission request (`can_use_tool`) to claude.ai. */
54
+ sendControlRequest(req: SDKControlRequest): void;
55
+ /** Forward a permission response back through the bridge. */
56
+ sendControlResponse(res: SDKControlResponse): void;
57
+ /**
58
+ * Tell claude.ai to dismiss a pending permission prompt (e.g. caller
59
+ * aborted the turn locally before the user answered).
60
+ */
61
+ sendControlCancelRequest(requestId: string): void;
62
+ /**
63
+ * Swap the underlying transport in place with a fresh JWT (and epoch).
64
+ * Carries the SSE sequence number so the server resumes the stream.
65
+ * Call this when the poll loop re-dispatches work for the same session
66
+ * with a fresh secret (JWT is 4h; backend mints a new one every dispatch).
67
+ *
68
+ * Throws if `createV2ReplTransport` fails (registerWorker error, etc).
69
+ * Caller should treat that as a close and drop this handle.
70
+ */
71
+ reconnectTransport(opts: {
72
+ ingressToken: string;
73
+ apiBaseUrl: string;
74
+ /** Omit to reuse the current transport's epoch (token-refresh reconnect); provide to override. */
75
+ epoch?: number;
76
+ }): Promise<void>;
77
+ /**
78
+ * PUT /worker state. Multi-session workers: `running` on turn start,
79
+ * `requires_action` on permission prompt, `idle` on turn end. Daemon
80
+ * callers don't need this — user watches the REPL locally.
81
+ */
82
+ reportState(state: SessionState): void;
83
+ /** PUT /worker external_metadata (branch, dir shown on claude.ai). */
84
+ reportMetadata(metadata: Record<string, unknown>): void;
85
+ /**
86
+ * POST /worker/events/{id}/delivery. Populates CCR's processing_at /
87
+ * processed_at columns. `received` is auto-fired internally; this
88
+ * surfaces `processing` (turn start) and `processed` (turn end).
89
+ */
90
+ reportDelivery(eventId: string, status: 'processing' | 'processed'): void;
91
+ /** Drain the write queue. Call before close() when delivery matters. */
92
+ flush(): Promise<void>;
93
+ close(): void;
94
+ };
95
+ /** @alpha */
96
+ export type AttachBridgeSessionOptions = {
97
+ /**
98
+ * Session ID (`cse_*` form). Comes from `WorkResponse.data.id` in the
99
+ * poll-loop path, or from whatever created the session.
100
+ */
101
+ sessionId: string;
102
+ /** Worker JWT. Comes from `decodeWorkSecret(work.secret).session_ingress_token`. */
103
+ ingressToken: string;
104
+ /** `WorkSecret.api_base_url` or wherever the session ingress lives. */
105
+ apiBaseUrl: string;
106
+ /**
107
+ * Worker epoch if already known (e.g. from a `/bridge` call that bumps
108
+ * epoch server-side). Omit to have `createV2ReplTransport` call
109
+ * `registerWorker` itself — correct for poll-loop callers where the
110
+ * work secret doesn't carry epoch.
111
+ */
112
+ epoch?: number;
113
+ /**
114
+ * SSE sequence-number high-water mark from a prior handle or persisted
115
+ * state. Seeds the first SSE connect's `from_sequence_num` so the server
116
+ * resumes instead of replaying full history. Omit (→ 0) for genuinely
117
+ * fresh attach.
118
+ */
119
+ initialSequenceNum?: number;
120
+ /**
121
+ * CCRClient heartbeat interval seed. Defaults to 20s. The server-advised
122
+ * interval (ccr_heartbeat_policy) overrides this after the first heartbeat.
123
+ */
124
+ heartbeatIntervalMs?: number;
125
+ /**
126
+ * When true, the bridge only forwards events outbound (local → CCR). The
127
+ * SSE read stream is not opened — no inbound events are received. Control
128
+ * requests that arrive via the write-path ACK channel reply with an error
129
+ * instead of false-success. onInboundMessage is never called. Use for
130
+ * mirror-mode attachments where the remote UI should see the session but
131
+ * not be able to drive it.
132
+ */
133
+ outboundOnly?: boolean;
134
+ /**
135
+ * Version of the Claude Code CLI this host runs the session's turns with.
136
+ * Reported to attaching clients as `claude_code_version` on the initialize
137
+ * reply so they can gate features before the first turn's `system`/`init`
138
+ * arrives; omit when unknown and clients wait for that message instead.
139
+ */
140
+ claudeCodeVersion?: string;
141
+ /**
142
+ * User message typed on claude.ai. Echoes of outbound writes and
143
+ * re-deliveries of prompts already forwarded are filtered before this
144
+ * fires. May be async (e.g. attachment resolution).
145
+ */
146
+ onInboundMessage?: (msg: SDKMessage) => void | Promise<void>;
147
+ /**
148
+ * `control_response` from claude.ai — the user answered a `can_use_tool`
149
+ * prompt sent via `sendControlRequest`. Caller correlates by `request_id`.
150
+ * Return `false` when the response is rejected (malformed/forged) so the
151
+ * prompt stays eligible for initialize re-delivery; void = accepted.
152
+ */
153
+ onPermissionResponse?: (res: SDKControlResponse) => boolean | void;
154
+ /** `interrupt` control_request from claude.ai. Already auto-replied-to. */
155
+ onInterrupt?: () => void;
156
+ /**
157
+ * `stop_task` control_request from claude.ai — per-task Stop from the
158
+ * client's tasks panel. Resolve = stopped (hosts should treat a task the
159
+ * process no longer tracks or that already finished as stopped and
160
+ * resolve, so the client prunes the stale row — but NOT a live paused or
161
+ * pending task, nor an ambiguous name matching several live tasks: those
162
+ * should reject so the user sees an accurate
163
+ * refusal); reject = error control_response with the
164
+ * rejection's message. Omit if the host has no task registry — the CLI
165
+ * then answers with a "not supported in this context" error.
166
+ */
167
+ onStopTask?: (taskId: string) => Promise<void>;
168
+ /**
169
+ * `background_tasks` from claude.ai — the client's Ctrl+B. With a
170
+ * toolUseId, background the single foreground task that tool_use block
171
+ * started and return whether one was found; without, background every
172
+ * foreground task and return true. May answer asynchronously (e.g. by
173
+ * delegating to `Query.backgroundTasks()`); a rejection is sent as an
174
+ * error reply. Omit if the host has no task registry — the CLI then
175
+ * answers with a "not supported in this context" error.
176
+ */
177
+ onBackgroundTasks?: (toolUseId: string | undefined) => boolean | Promise<boolean>;
178
+ onSetModel?: (model: string | undefined) => {
179
+ ok: true;
180
+ notices?: string[];
181
+ } | {
182
+ ok: false;
183
+ error: string;
184
+ } | void | Promise<{
185
+ ok: true;
186
+ notices?: string[];
187
+ } | {
188
+ ok: false;
189
+ error: string;
190
+ }>;
191
+ onSetMaxThinkingTokens?: (tokens: number | null | undefined, thinkingDisplay?: 'summarized' | 'omitted' | 'highlights' | null) => {
192
+ ok: true;
193
+ } | {
194
+ ok: false;
195
+ error: string;
196
+ } | void | Promise<{
197
+ ok: true;
198
+ } | {
199
+ ok: false;
200
+ error: string;
201
+ } | void>;
202
+ /**
203
+ * `set_permission_mode` from claude.ai. Return an error verdict to send
204
+ * an error control_response (vs silently false-succeeding). Omit if
205
+ * the caller doesn't support permission modes — the shared handler
206
+ * returns a "not supported in this context" error.
207
+ */
208
+ onSetPermissionMode?: (mode: PermissionMode) => {
209
+ ok: true;
210
+ } | {
211
+ ok: false;
212
+ error: string;
213
+ };
214
+ /** `rename_session` from claude.ai. Return an error verdict to reject. */
215
+ onRenameSession?: (title: string) => {
216
+ ok: true;
217
+ } | {
218
+ ok: false;
219
+ error: string;
220
+ };
221
+ /**
222
+ * Transport died permanently. 401 = JWT expired (re-attach with fresh
223
+ * secret), 4090 = epoch superseded (no longer the active worker),
224
+ * 4091 = CCRClient init failed, 4092 = codeless close (defensive
225
+ * fallback — cause unknown), 4093 = presence heartbeats kept failing
226
+ * while the SSE stream stayed healthy (transport self-heal candidate),
227
+ * 4094 = worker credential expired or rejected on the request path
228
+ * (heartbeat/write auth exhaustion — re-attach with a fresh secret,
229
+ * like 401), 403/404 = permanent SSE HTTP rejection. Transient
230
+ * disconnects (503, network blips) retry indefinitely inside
231
+ * SSETransport and do NOT fire this.
232
+ */
233
+ onClose?: (code?: number) => void;
234
+ };
235
+ /**
236
+ * Attach to an existing bridge session. Creates the v2 transport
237
+ * (SSETransport + CCRClient), wires ingress routing and control dispatch,
238
+ * returns a handle scoped to this one session.
239
+ *
240
+ * Throws if `createV2ReplTransport` fails (registerWorker error, etc).
241
+ *
242
+ * ALPHA STABILITY. This is a separate versioning universe from the main
243
+ * `query()` surface: breaking changes here do NOT bump the package major.
244
+ * @alpha
245
+ */
246
+ export declare function attachBridgeSession(opts: AttachBridgeSessionOptions): Promise<BridgeSessionHandle>;
247
+ /**
248
+ * Worker credentials from `POST /v1/code/sessions/{id}/bridge`.
249
+ * Each call bumps `worker_epoch` server-side — the call IS the worker register.
250
+ * @alpha
251
+ */
252
+ export type RemoteCredentials = {
253
+ worker_jwt: string;
254
+ api_base_url: string;
255
+ expires_in: number;
256
+ worker_epoch: number;
257
+ };
258
+ /**
259
+ * Terminal failure from `fetchRemoteCredentials` — retrying with the same
260
+ * inputs is guaranteed to fail. Server-minted reasons arrive as 403 with
261
+ * `error.resource` set to `"untrusted_device"` (token missing/revoked —
262
+ * enroll) or `"session_stale_relogin"` (OAuth session older than the
263
+ * freshness window — re-authenticate). `"invalid_session_id"` is
264
+ * client-minted: the session id failed validation (`/^[a-zA-Z0-9_-]+$/`)
265
+ * before any request was sent. `"request_rejected"` is any other
266
+ * authoritative non-retryable 4xx (the server answered; neither time nor a
267
+ * new credential changes the request). `"malformed_response"` is a 2xx this
268
+ * client could not parse — the mint SUCCEEDED server-side (each call bumps
269
+ * `worker_epoch`), so retrying epoch-bumps per attempt; not transient, not
270
+ * an authoritative denial.
271
+ * @alpha
272
+ */
273
+ export type CredentialsFailure = {
274
+ terminal: true;
275
+ reason: 'untrusted_device' | 'session_stale_relogin' | 'invalid_session_id';
276
+ } | {
277
+ terminal: true;
278
+ reason: 'request_rejected';
279
+ /** HTTP status, for the debug trail and user-facing hints. */
280
+ status: number;
281
+ /**
282
+ * 403 only: who wrote the rejection, from response headers — the
283
+ * origin (`request-id: req_…`), a Cloudflare edge before it, or a hop
284
+ * that never reached Anthropic. Attribution for telemetry/copy; not a
285
+ * verdict on ownership.
286
+ */
287
+ source?: 'origin' | 'nonorigin_cf' | 'nonorigin_other';
288
+ } | {
289
+ terminal: true;
290
+ reason: 'malformed_response';
291
+ /** HTTP status, for the debug trail and user-facing hints. */
292
+ status: number;
293
+ };
294
+ /**
295
+ * Non-terminal classified rejection: the OAuth bearer itself was rejected
296
+ * (401). Retrying with the SAME credential is pointless, but a DIFFERENT
297
+ * credential can succeed (post-re-authentication) — distinct from
298
+ * `CredentialsFailure` (`terminal: true`) and from null, which is reserved
299
+ * for transient transport-shaped failures (network error / timeout / 5xx).
300
+ * @alpha
301
+ */
302
+ export type CredentialsRejection = {
303
+ terminal: false;
304
+ reason: 'oauth_rejected';
305
+ };
306
+ /**
307
+ * Type guard for `fetchRemoteCredentials` results.
308
+ * @alpha
309
+ */
310
+ export declare function isCredentialsFailure(r: RemoteCredentials | CredentialsFailure | CredentialsRejection | null): r is CredentialsFailure;
311
+ /**
312
+ * Type guard for the non-terminal classified 401 rejection. Accepts
313
+ * `unknown`: callers hand it unions whose success arm is a plain string
314
+ * (session ids), and it narrows structurally.
315
+ * @alpha
316
+ */
317
+ export declare function isCredentialsRejection(r: unknown): r is CredentialsRejection;
318
+ /**
319
+ * Git source/outcome context attached to a v2 code session on create.
320
+ * @alpha
321
+ */
322
+ export type CodeSessionGitContext = {
323
+ gitRepoUrl: string;
324
+ branch: string;
325
+ /**
326
+ * The repo's default branch, when authoritatively known. LOAD-BEARING
327
+ * for branch continuity: when absent, `branch` is omitted from
328
+ * `outcomes.branches` entirely (the classification never acts on a
329
+ * guess), so the remote session works on a runner-generated branch
330
+ * instead of `branch`, with only a debug-level signal. Callers that
331
+ * want the session to check out AND push to `branch` must supply
332
+ * this — read `git symbolic-ref refs/remotes/origin/HEAD`, or run
333
+ * `git remote set-head origin -a` to repair a missing symref.
334
+ */
335
+ defaultBranch?: string;
336
+ };
337
+ /**
338
+ * Caller-owned dedupe state for createCodeSession's branch-drop debug
339
+ * signal: create one object per logical create (outside your retry
340
+ * loop) and pass it to every attempt so the drop logs once per
341
+ * decision. Omit it to log on every attempt.
342
+ * @alpha
343
+ */
344
+ export declare type BranchDropLogDedup = {
345
+ lastKey?: string | null;
346
+ };
347
+ /**
348
+ * Terminal failure from `POST /v1/code/sessions` — retrying with the same
349
+ * inputs fails identically. `reason` distinguishes the recognized
350
+ * `session_grouping_id` rejection family (`"grouping_rejected"` — the
351
+ * caller may retry without the grouping) from any other authoritative
352
+ * non-retryable 4xx (`"request_rejected"`) and from a 2xx this client
353
+ * could not parse (`"malformed_response"` — the create SUCCEEDED
354
+ * server-side, so a retry would orphan one session per attempt).
355
+ * @alpha
356
+ */
357
+ export type CreateSessionFailure = {
358
+ terminal: true;
359
+ reason: 'grouping_rejected' | 'request_rejected' | 'malformed_response';
360
+ status: number;
361
+ /** The service's own message, unchanged and still untrusted, or undefined. It is passed on only if it is one line of at most 1,024 UTF-16 units, with no control or invisible characters and no whitespace other than single ASCII spaces. */
362
+ detail: string | undefined;
363
+ };
364
+ /**
365
+ * Type guard for `createCodeSession` results. Matches only `terminal: true`
366
+ * failures — a `CredentialsRejection` (`terminal: false`) does not match.
367
+ * @alpha
368
+ */
369
+ export declare function isCreateSessionFailure(r: string | CreateSessionFailure | CredentialsRejection | null): r is CreateSessionFailure;
370
+ /**
371
+ * `POST /v1/code/sessions` — create a fresh CCR session. Returns the `cse_*`
372
+ * session id on success, a classified `CreateSessionFailure` (terminal —
373
+ * don't retry; see its `reason`), a `CredentialsRejection` when the OAuth
374
+ * bearer was rejected (retry only with a NEW credential), or null on
375
+ * transient transport-shaped failures (network error / timeout / 5xx).
376
+ *
377
+ * Callers supply their own OAuth token — this is a thin HTTP wrapper with no
378
+ * implicit auth, so it works from any process (not just the CLI).
379
+ * @alpha
380
+ */
381
+ export declare function createCodeSession(baseUrl: string, accessToken: string, title: string, timeoutMs: number, tags?: string[], gitContext?: CodeSessionGitContext, cwd?: string, model?: string, sessionGroupingId?: string, dropLogDedup?: BranchDropLogDedup): Promise<string | CreateSessionFailure | CredentialsRejection | null>;
382
+ /**
383
+ * `POST /v1/code/sessions/{id}/bridge` — mint a worker JWT for the session.
384
+ * Returns credentials, a `CredentialsFailure` for terminal failures (don't
385
+ * retry — see `CredentialsFailure.reason` for remediation), a
386
+ * `CredentialsRejection` when the OAuth bearer was rejected (retry only
387
+ * with a NEW credential), or null on transient transport-shaped failure. The call IS the worker register (bumps epoch
388
+ * server-side), so pass `epoch: creds.worker_epoch` to `attachBridgeSession`
389
+ * to skip a redundant register.
390
+ *
391
+ * `trustedDeviceToken` sets the `X-Trusted-Device-Token` header. Required
392
+ * when the server's `sessions_elevated_auth_enforcement` flag is on
393
+ * (bridge sessions are SecurityTier=ELEVATED). See anthropics/anthropic#274559.
394
+ * @alpha
395
+ */
396
+ export declare function fetchRemoteCredentials(sessionId: string, baseUrl: string, accessToken: string, timeoutMs: number, trustedDeviceToken?: string): Promise<RemoteCredentials | CredentialsFailure | CredentialsRejection | null>;