@claudexor/daemon 1.0.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/dist/server.js ADDED
@@ -0,0 +1,544 @@
1
+ import { connect, createServer } from "node:net";
2
+ import { timingSafeEqual } from "node:crypto";
3
+ import { chmodSync, copyFileSync, mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
+ import { dirname } from "node:path";
5
+ import { createInterface } from "node:readline";
6
+ import { join } from "node:path";
7
+ import { appendRunEvent } from "@claudexor/event-log";
8
+ import { assertNoInlineSecretValues, errorCode, newId, nowIso, pathExists, readJsonSafe, redactSecrets } from "@claudexor/util";
9
+ export const JOB_STATES = [
10
+ "queued",
11
+ "running",
12
+ "blocked",
13
+ "succeeded",
14
+ "no_op",
15
+ "ungated",
16
+ "review_not_run",
17
+ "failed",
18
+ "cancelled",
19
+ "interrupted",
20
+ "exhausted",
21
+ "not_converged",
22
+ "stuck_no_progress",
23
+ ];
24
+ /**
25
+ * Per-record validation for the persisted registry: one hand-edited or
26
+ * version-skewed record must not wipe the whole run history, and a record
27
+ * with a state outside the enum must never reach the strict control-api
28
+ * DTOs (where it would 500 the entire GET /runs list).
29
+ */
30
+ function salvageJobRecord(raw) {
31
+ if (!raw || typeof raw !== "object")
32
+ return null;
33
+ const rec = raw;
34
+ if (typeof rec["id"] !== "string" || rec["id"].length === 0)
35
+ return null;
36
+ if (typeof rec["state"] !== "string" || !JOB_STATES.includes(rec["state"]))
37
+ return null;
38
+ if (typeof rec["createdAt"] !== "string")
39
+ return null;
40
+ const optionalString = (key) => typeof rec[key] === "string" ? rec[key] : undefined;
41
+ return {
42
+ id: rec["id"],
43
+ state: rec["state"],
44
+ params: rec["params"],
45
+ error: optionalString("error"),
46
+ errorCode: optionalString("errorCode"),
47
+ createdAt: rec["createdAt"],
48
+ runId: optionalString("runId"),
49
+ taskId: optionalString("taskId"),
50
+ runDir: optionalString("runDir"),
51
+ startedAt: optionalString("startedAt"),
52
+ finishedAt: optionalString("finishedAt"),
53
+ };
54
+ }
55
+ /**
56
+ * Local daemon: Unix-socket JSON-RPC with token auth + a bounded-concurrency
57
+ * worker pool (up to maxConcurrent jobs in parallel) backed by an optional
58
+ * durable, atomically-written job registry. It does NOT contain a second
59
+ * scheduler — it calls the injected runner (the same Orchestrator the CLI uses).
60
+ */
61
+ export class DaemonServer {
62
+ opts;
63
+ server;
64
+ queue = [];
65
+ records = new Map();
66
+ cancelled = new Set();
67
+ controllers = new Map();
68
+ active = 0;
69
+ startedAt = Date.now();
70
+ onClosed;
71
+ constructor(opts) {
72
+ this.opts = opts;
73
+ }
74
+ async start() {
75
+ // Refuse to clobber a LIVE daemon: deleting its socket would orphan it and
76
+ // turn jobs.json into a last-writer-wins race between two processes.
77
+ if (pathExists(this.opts.socketPath) && (await socketAlive(this.opts.socketPath))) {
78
+ throw new Error(`a claudexor daemon is already listening on ${this.opts.socketPath}; stop it first`);
79
+ }
80
+ this.load();
81
+ try {
82
+ rmSync(this.opts.socketPath, { force: true });
83
+ }
84
+ catch {
85
+ /* nothing to clean */
86
+ }
87
+ await new Promise((resolve, reject) => {
88
+ this.server = createServer((sock) => this.onConnection(sock));
89
+ this.server.once("error", reject);
90
+ this.server.listen(this.opts.socketPath, () => {
91
+ // Owner-only socket: the bearer token is the auth layer, but a
92
+ // world-connectable socket needlessly exposes the RPC surface to every
93
+ // local user; chmod narrows it to the owning account.
94
+ try {
95
+ chmodSync(this.opts.socketPath, 0o600);
96
+ }
97
+ catch {
98
+ /* best-effort on exotic filesystems */
99
+ }
100
+ resolve();
101
+ });
102
+ });
103
+ // Resume any queued jobs re-enqueued from a previous session (see load()).
104
+ void this.drain();
105
+ }
106
+ async stop() {
107
+ // Graceful shutdown: abort in-flight runs so the runner cancels their harness
108
+ // children and settles each job (no orphaned processes / "running" zombies in
109
+ // jobs.json), then WAIT (bounded) for the cancellations to settle. Without
110
+ // the wait, the process could exit before the SIGKILL escalation timers
111
+ // fire, leaving a SIGTERM-ignoring harness child alive in its group.
112
+ for (const controller of this.controllers.values()) {
113
+ try {
114
+ controller.abort();
115
+ }
116
+ catch {
117
+ /* already gone */
118
+ }
119
+ }
120
+ const deadline = Date.now() + 5_000;
121
+ while (this.active > 0 && Date.now() < deadline) {
122
+ await new Promise((resolve) => setTimeout(resolve, 50));
123
+ }
124
+ this.persist();
125
+ await new Promise((resolve) => {
126
+ if (!this.server)
127
+ return resolve();
128
+ this.server.close(() => resolve());
129
+ });
130
+ this.onClosed?.();
131
+ }
132
+ /** Resolves when the daemon is shut down via RPC. */
133
+ waitForShutdown() {
134
+ return new Promise((resolve) => {
135
+ this.onClosed = resolve;
136
+ });
137
+ }
138
+ onConnection(sock) {
139
+ const rl = createInterface({ input: sock });
140
+ rl.on("line", (line) => {
141
+ void this.handle(line, sock);
142
+ });
143
+ sock.on("error", () => rl.close());
144
+ }
145
+ send(sock, obj) {
146
+ try {
147
+ sock.write(JSON.stringify(obj) + "\n");
148
+ }
149
+ catch {
150
+ /* socket closed */
151
+ }
152
+ }
153
+ async handle(line, sock) {
154
+ const trimmed = line.trim();
155
+ if (!trimmed)
156
+ return;
157
+ let msg;
158
+ try {
159
+ msg = JSON.parse(trimmed);
160
+ }
161
+ catch {
162
+ return;
163
+ }
164
+ const { id, method, params, token } = msg;
165
+ if (!tokenMatches(typeof token === "string" ? token : "", this.opts.token)) {
166
+ this.send(sock, { id, error: { message: "unauthorized" } });
167
+ return;
168
+ }
169
+ try {
170
+ this.send(sock, { id, result: await this.dispatch(method, params) });
171
+ }
172
+ catch (err) {
173
+ // Carry the machine-readable error code (e.g. inline_secret_rejected)
174
+ // alongside the redacted message so socket clients get the typed class.
175
+ const code = errorCode(err);
176
+ this.send(sock, { id, error: { message: redactSecrets(err instanceof Error ? err.message : String(err)), ...(code ? { code } : {}) } });
177
+ }
178
+ }
179
+ async dispatch(method, params) {
180
+ switch (method) {
181
+ case "claudexor.health":
182
+ return {
183
+ ok: true,
184
+ uptime_ms: Date.now() - this.startedAt,
185
+ queue: this.queue.length,
186
+ running: this.active > 0,
187
+ active: this.active,
188
+ jobs: this.records.size,
189
+ };
190
+ case "claudexor.enqueue": {
191
+ assertNoInlineSecretValues(params, "$", "daemon job params");
192
+ const id = newId("job");
193
+ this.records.set(id, { id, state: "queued", params, createdAt: nowIso() });
194
+ this.queue.push(id);
195
+ this.persist();
196
+ void this.drain();
197
+ return { id, state: "queued" };
198
+ }
199
+ case "claudexor.status": {
200
+ const rec = this.records.get(String(params?.id));
201
+ if (!rec)
202
+ throw new Error(`no such job: ${params?.id}`);
203
+ return publicJobRecord(rec);
204
+ }
205
+ case "claudexor.list":
206
+ return [...this.records.values()].map(publicJobRecord);
207
+ case "claudexor.cancel": {
208
+ const jid = String(params?.id);
209
+ // Honesty: cancelling an unknown id must fail loudly (like status),
210
+ // never claim `{cancelled:true}` for a job that does not exist.
211
+ const rec = this.records.get(jid);
212
+ if (!rec)
213
+ throw new Error(`no such job: ${jid}`);
214
+ this.cancelled.add(jid);
215
+ if (rec.state === "queued")
216
+ rec.state = "cancelled";
217
+ // Abort the in-flight run; the runner (Orchestrator) honors the signal,
218
+ // cancels the harness, then settles this job as cancelled.
219
+ this.controllers.get(jid)?.abort();
220
+ this.persist();
221
+ return { id: jid, cancelled: true };
222
+ }
223
+ case "claudexor.shutdown":
224
+ setTimeout(() => void this.stop(), 10);
225
+ return { ok: true };
226
+ default:
227
+ throw new Error(`unknown method: ${method}`);
228
+ }
229
+ }
230
+ get maxConcurrent() {
231
+ return this.opts.maxConcurrent ?? 4;
232
+ }
233
+ /**
234
+ * Best-effort durable persistence of the job registry. Writes atomically
235
+ * (temp file + rename) so a crash mid-write cannot corrupt/drop the registry.
236
+ * The raw run `result` is intentionally NOT persisted: canonical output lives
237
+ * in .claudexor/runs (redacted), and result.summary can contain raw model text —
238
+ * keeping it out of jobs.json upholds the redaction-at-persistence invariant.
239
+ */
240
+ persist() {
241
+ const path = this.opts.persistPath;
242
+ if (!path)
243
+ return;
244
+ try {
245
+ const view = [...this.records.values()].map(persistedJobRecord);
246
+ mkdirSync(dirname(path), { recursive: true });
247
+ const tmp = `${path}.tmp`;
248
+ writeFileSync(tmp, JSON.stringify(view, null, 2) + "\n", { mode: 0o600 });
249
+ chmodSync(tmp, 0o600);
250
+ renameSync(tmp, path);
251
+ chmodSync(path, 0o600);
252
+ }
253
+ catch {
254
+ /* best-effort; never break a run on a persistence failure */
255
+ }
256
+ }
257
+ /** Bound memory/disk: prune the oldest terminal jobs beyond maxHistory.
258
+ * `blocked` runs are NEVER pruned — they are the needs-human inbox awaiting an
259
+ * operator decision; dropping one would silently lose a pending action. */
260
+ pruneHistory() {
261
+ const cap = this.opts.maxHistory ?? 500;
262
+ const terminal = [...this.records.values()].filter((r) => r.state !== "running" && r.state !== "queued" && r.state !== "blocked");
263
+ if (terminal.length <= cap)
264
+ return;
265
+ terminal.sort((a, b) => (a.createdAt < b.createdAt ? -1 : 1));
266
+ for (const r of terminal.slice(0, terminal.length - cap)) {
267
+ this.records.delete(r.id);
268
+ this.cancelled.delete(r.id);
269
+ }
270
+ }
271
+ /** Reload the registry on startup; a fresh process cannot resume in-memory runs. */
272
+ load() {
273
+ const path = this.opts.persistPath;
274
+ if (!path || !pathExists(path))
275
+ return;
276
+ const saved = readJsonSafe(path);
277
+ if (saved === null || !Array.isArray(saved)) {
278
+ // A corrupt registry must not be silently wiped: the run history includes
279
+ // the blocked needs-human inbox. Back the raw bytes up, start empty, and
280
+ // say so loudly (ThreadStore discipline).
281
+ this.backupCorruptRegistry(path, "registry file is not a JSON array");
282
+ return;
283
+ }
284
+ let dropped = 0;
285
+ for (const raw of saved) {
286
+ const rec = salvageJobRecord(raw);
287
+ if (!rec) {
288
+ dropped += 1;
289
+ continue;
290
+ }
291
+ // A fresh process cannot resume an in-memory RUN, so a `running` job becomes
292
+ // interrupted (honest). `blocked` is a TERMINAL outcome (NEEDS_HUMAN / web
293
+ // policy) the review queue must keep across restarts.
294
+ if (rec.state === "running") {
295
+ rec.state = "interrupted";
296
+ // Stamp the orphaned event log with a TERMINAL event: the
297
+ // canonical events.jsonl must agree with jobs.json, or SSE tailers and
298
+ // `follow` wait forever on a log that will never terminate.
299
+ if (rec.runDir && rec.runId) {
300
+ try {
301
+ appendRunEvent(join(rec.runDir, "events.jsonl"), rec.runId, rec.taskId ?? "", "run.failed", {
302
+ status: "interrupted",
303
+ error: "daemon restarted while the run was in flight",
304
+ });
305
+ }
306
+ catch {
307
+ /* best-effort: a missing/corrupt log must not block startup */
308
+ }
309
+ }
310
+ }
311
+ this.records.set(rec.id, rec);
312
+ // A `queued` job never started; its params are persisted, so RE-ENQUEUE it
313
+ // on restart (drain() runs after start()) instead of silently dropping
314
+ // pending work to interrupted.
315
+ if (rec.state === "queued")
316
+ this.queue.push(rec.id);
317
+ }
318
+ if (dropped > 0) {
319
+ this.backupCorruptRegistry(path, `${dropped} unparseable job record(s) dropped`);
320
+ }
321
+ }
322
+ /** Preserve the raw bytes of a damaged registry and report the loss loudly. */
323
+ backupCorruptRegistry(path, reason) {
324
+ try {
325
+ copyFileSync(path, `${path}.bak`);
326
+ console.error(`[claudexor] jobs store: ${reason}; original backed up to ${path}.bak`);
327
+ }
328
+ catch {
329
+ console.error(`[claudexor] jobs store: ${reason}; backup to ${path}.bak FAILED`);
330
+ }
331
+ }
332
+ threadIdOf(rec) {
333
+ const p = rec.params;
334
+ return p && typeof p.threadId === "string" ? p.threadId : undefined;
335
+ }
336
+ /**
337
+ * Schedule queued jobs up to the concurrency limit (non-blocking).
338
+ *
339
+ * One active run per thread: a thread is a linear conversation and an in-place
340
+ * turn mutates the live tree, so two concurrent turns on the same thread would
341
+ * race the same files. We pick the first queued job whose thread is idle rather
342
+ * than always taking the head; thread-less jobs (CLI/MCP) keep running in
343
+ * parallel as before. drain() re-runs on every completion, so a thread's next
344
+ * turn starts as soon as its previous one settles.
345
+ */
346
+ drain() {
347
+ while (this.active < this.maxConcurrent && this.queue.length > 0) {
348
+ const busyThreads = new Set([...this.records.values()]
349
+ .filter((r) => r.state === "running")
350
+ .map((r) => this.threadIdOf(r))
351
+ .filter((t) => !!t));
352
+ let pickIdx = -1;
353
+ for (let i = 0; i < this.queue.length; i++) {
354
+ const rec = this.records.get(this.queue[i]);
355
+ const tid = rec ? this.threadIdOf(rec) : undefined;
356
+ if (!rec || !tid || !busyThreads.has(tid)) {
357
+ pickIdx = i;
358
+ break;
359
+ }
360
+ }
361
+ if (pickIdx === -1)
362
+ break; // every queued job waits on a busy thread
363
+ const id = this.queue.splice(pickIdx, 1)[0];
364
+ const rec = this.records.get(id);
365
+ if (!rec)
366
+ continue;
367
+ if (this.cancelled.has(id)) {
368
+ rec.state = "cancelled";
369
+ continue;
370
+ }
371
+ this.active += 1;
372
+ void this.runJob(id, rec);
373
+ }
374
+ }
375
+ async runJob(id, rec) {
376
+ const controller = new AbortController();
377
+ this.controllers.set(id, controller);
378
+ rec.state = "running";
379
+ rec.startedAt = nowIso();
380
+ this.persist();
381
+ try {
382
+ rec.result = await this.opts.runner(rec.params, {
383
+ signal: controller.signal,
384
+ onRunStart: (info) => {
385
+ rec.runId = info.runId;
386
+ rec.taskId = info.taskId;
387
+ rec.runDir = info.runDir;
388
+ // Persist the pointer immediately so a mid-run crash still reloads with
389
+ // runId/runDir to locate .claudexor/runs/<runId> (the recovery path).
390
+ this.persist();
391
+ },
392
+ });
393
+ rec.state = jobStateFromResult(rec.result, controller.signal.aborted);
394
+ // Only failure-shaped terminals carry an error string. no_op / ungated /
395
+ // review_not_run / blocked are HONEST terminals: fabricating an error here
396
+ // would make the control facade render a failure that never happened.
397
+ if (rec.state === "failed" || rec.state === "exhausted" || rec.state === "not_converged" || rec.state === "stuck_no_progress") {
398
+ rec.error = resultSummary(rec.result) ?? `run ended with status ${rec.state}`;
399
+ }
400
+ }
401
+ catch (err) {
402
+ rec.state = controller.signal.aborted ? "cancelled" : "failed";
403
+ rec.error = redactSecrets(err instanceof Error ? err.message : String(err));
404
+ // Preserve a typed throw's machine code (e.g. the trust gate) so
405
+ // consumers can key remedies on it instead of parsing the message.
406
+ const code = err && typeof err === "object" && "code" in err ? err.code : undefined;
407
+ if (typeof code === "string" && code)
408
+ rec.errorCode = code;
409
+ }
410
+ finally {
411
+ rec.finishedAt = nowIso();
412
+ this.controllers.delete(id);
413
+ this.active -= 1;
414
+ if (rec.runId) {
415
+ try {
416
+ this.opts.onRunTerminal?.(rec.runId);
417
+ }
418
+ catch {
419
+ /* observer failure must not corrupt terminal bookkeeping */
420
+ }
421
+ }
422
+ else if (rec.error) {
423
+ // Failure-shaped terminal with NO run ever bound: the refusal happened
424
+ // before the run materialized. If this job carried a pre-created thread
425
+ // turn, persist the reason on it (honest inline refusal, INV-093).
426
+ const turnId = rec.params?.turnId;
427
+ if (typeof turnId === "string" && turnId) {
428
+ try {
429
+ this.opts.onTurnEnqueueFailed?.(turnId, rec.error, rec.errorCode ?? null);
430
+ }
431
+ catch {
432
+ /* observer failure must not corrupt terminal bookkeeping */
433
+ }
434
+ }
435
+ }
436
+ this.pruneHistory();
437
+ this.persist();
438
+ this.drain();
439
+ }
440
+ }
441
+ }
442
+ function jobStateFromResult(result, aborted) {
443
+ if (aborted)
444
+ return "cancelled";
445
+ const status = resultStatus(result);
446
+ switch (status) {
447
+ case "success":
448
+ return "succeeded";
449
+ case "no_op":
450
+ return "no_op";
451
+ case "ungated":
452
+ return "ungated";
453
+ case "review_not_run":
454
+ return "review_not_run";
455
+ case "blocked":
456
+ return "blocked";
457
+ case "cancelled":
458
+ return "cancelled";
459
+ case "exhausted":
460
+ return "exhausted";
461
+ case "not_converged":
462
+ return "not_converged";
463
+ case "stuck_no_progress":
464
+ return "stuck_no_progress";
465
+ case "failed":
466
+ return "failed";
467
+ default:
468
+ // Fail loudly: a runner result without a recognizable status is NOT a
469
+ // success — success-by-default would mask malformed results forever.
470
+ return "failed";
471
+ }
472
+ }
473
+ /** Constant-time token comparison (parity with the HTTP control facade). */
474
+ function tokenMatches(candidate, expected) {
475
+ const a = Buffer.from(candidate);
476
+ const b = Buffer.from(expected);
477
+ if (a.length !== b.length)
478
+ return false;
479
+ return timingSafeEqual(a, b);
480
+ }
481
+ /** True when something is actively accepting connections on the socket path. */
482
+ /** Is a daemon already listening on this socket? Exported so the claudexord
483
+ * entrypoint can refuse BEFORE running crash GC — a second daemon must never
484
+ * reap the live daemon's children or sweep envelopes its jobs still own. */
485
+ export function socketAlive(socketPath) {
486
+ return new Promise((resolve) => {
487
+ const sock = connect(socketPath);
488
+ const done = (alive) => {
489
+ sock.destroy();
490
+ resolve(alive);
491
+ };
492
+ sock.once("connect", () => done(true));
493
+ sock.once("error", () => done(false));
494
+ setTimeout(() => done(false), 500).unref();
495
+ });
496
+ }
497
+ function resultStatus(result) {
498
+ if (!result || typeof result !== "object" || Array.isArray(result))
499
+ return null;
500
+ const status = result["status"];
501
+ return typeof status === "string" ? status : null;
502
+ }
503
+ function resultSummary(result) {
504
+ if (!result || typeof result !== "object" || Array.isArray(result))
505
+ return null;
506
+ const summary = result["summary"];
507
+ return typeof summary === "string" ? redactSecrets(summary) : null;
508
+ }
509
+ function publicJobRecord(rec) {
510
+ return {
511
+ ...rec,
512
+ error: rec.error ? redactSecrets(rec.error) : undefined,
513
+ params: redactParams(rec.params),
514
+ };
515
+ }
516
+ function persistedJobRecord(rec) {
517
+ return {
518
+ id: rec.id,
519
+ state: rec.state,
520
+ params: redactParams(rec.params),
521
+ error: rec.error ? redactSecrets(rec.error) : undefined,
522
+ errorCode: rec.errorCode,
523
+ createdAt: rec.createdAt,
524
+ runId: rec.runId,
525
+ taskId: rec.taskId,
526
+ runDir: rec.runDir,
527
+ startedAt: rec.startedAt,
528
+ finishedAt: rec.finishedAt,
529
+ };
530
+ }
531
+ function redactParams(value) {
532
+ if (typeof value === "string")
533
+ return redactSecrets(value);
534
+ if (Array.isArray(value))
535
+ return value.map(redactParams);
536
+ if (!value || typeof value !== "object")
537
+ return value;
538
+ const out = {};
539
+ for (const [key, child] of Object.entries(value)) {
540
+ out[key] = key === "prompt" && typeof child === "string" ? redactSecrets(child) : redactParams(child);
541
+ }
542
+ return out;
543
+ }
544
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import type { Attachment, Session, Thread, ThreadTurn, WorkspaceMode } from "@claudexor/schema";
2
+ export interface CreateThreadInput {
3
+ title?: string;
4
+ repoRoot?: string | null;
5
+ mode?: Thread["mode"];
6
+ /** in_place (default) mutates the live tree; isolated keeps a thread worktree. */
7
+ workspace?: WorkspaceMode;
8
+ authPreference?: Thread["auth_preference"];
9
+ primaryHarness?: string | null;
10
+ /** Sticky eligible harness pool for the thread (turns inherit when unset). */
11
+ eligibleHarnesses?: string[];
12
+ }
13
+ export interface CreateTurnInput {
14
+ kind?: ThreadTurn["kind"];
15
+ parentRunId?: string | null;
16
+ /** Set when this turn implements an approved plan from an earlier run. */
17
+ planRunId?: string | null;
18
+ /** Files/images attached to this turn, already resolved to scoped on-disk paths. */
19
+ attachments?: Attachment[];
20
+ }
21
+ export interface UpdateThreadInput {
22
+ title?: string;
23
+ state?: Thread["state"];
24
+ /** Switch the sticky primary harness (null => clear back to auto). */
25
+ primaryHarness?: string | null;
26
+ /** Replace the sticky eligible harness pool. */
27
+ eligibleHarnesses?: string[];
28
+ }
29
+ /**
30
+ * Durable thread/session registry (chat/session-first SSOT). The Thread is
31
+ * the Claudexor-owned conversation; Sessions are re-hostable pointers to each
32
+ * harness's native CLI session. Persisted as one JSON file with atomic writes
33
+ * (temp + rename), mirroring the daemon job registry's durability contract.
34
+ */
35
+ export declare class ThreadStore {
36
+ private readonly path;
37
+ private state;
38
+ constructor(path: string);
39
+ private load;
40
+ private persist;
41
+ createThread(input: CreateThreadInput): Thread;
42
+ /** Rename and/or open/close (archive) a thread. */
43
+ updateThread(id: string, patch: UpdateThreadInput): Thread;
44
+ /** Persist the resolved isolated worktree path + base sha for a thread. */
45
+ setThreadWorktree(id: string, worktreePath: string, baseSha: string): void;
46
+ listThreads(): Thread[];
47
+ getThread(id: string): Thread | undefined;
48
+ turnsFor(threadId: string): ThreadTurn[];
49
+ getTurn(turnId: string): ThreadTurn | undefined;
50
+ /**
51
+ * Fail-loud prologue for the daemon runner: control-api validates thread/turn
52
+ * ids at the HTTP boundary, but a direct socket caller can pass bogus ids —
53
+ * a silent unbind would orphan the run from its conversation. A typed throw
54
+ * settles the job `failed` instead. Returns the normalized ids.
55
+ */
56
+ assertKnownIds(rawThreadId: unknown, rawTurnId: unknown): {
57
+ threadId?: string;
58
+ turnId?: string;
59
+ };
60
+ sessionsForThread(threadId: string): Session[];
61
+ /** Native resume map for a thread: harnessId -> native session id (live sessions only). */
62
+ resumeMap(threadId: string): Record<string, string>;
63
+ /**
64
+ * Create a turn BEFORE its run is enqueued (run_id is bound later via
65
+ * `bindTurnRun`). This is the single-writer entry point: the control API and
66
+ * the daemon runner both create here, so a run is recorded on its thread
67
+ * exactly once — there is no second "POST /runs with threadId silently skips
68
+ * the turn" path. `parentRunId` is captured here (head at creation time), so
69
+ * concurrent turns cannot both claim the same stale head.
70
+ */
71
+ createTurn(threadId: string, prompt: string, input?: CreateTurnInput): ThreadTurn;
72
+ /** Bind a started run to its turn and advance the thread head (runner-owned). */
73
+ bindTurnRun(turnId: string, runId: string): void;
74
+ /**
75
+ * Persist the reason a turn's run could NOT be enqueued/started (trust
76
+ * refusal, preflight validation, enqueue throw). Only meaningful for a
77
+ * RUNLESS turn: once a run is bound the turn's honesty lives on the run's
78
+ * own terminal artifacts, so a late failure report is ignored. `code` is
79
+ * the typed throw's machine code (e.g. trust_full_access_required) that
80
+ * surfaces key remedies on; `retryable=false` marks refusals with NO
81
+ * recorded job to replay (the enqueue itself threw) so surfaces offer
82
+ * "send a new message" instead of a doomed Retry.
83
+ */
84
+ setTurnEnqueueError(turnId: string, message: string, code?: string | null, retryable?: boolean): void;
85
+ /** Record/refresh the native CLI session a harness emitted for this thread. */
86
+ recordSession(threadId: string, harnessId: string, nativeSessionId: string, observedModel?: string | null): void;
87
+ }
88
+ //# sourceMappingURL=threads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../src/threads.ts"],"names":[],"mappings":"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"}