wicked-crew 0.1.0 → 0.1.1
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/api/gate-cache.d.ts +38 -0
- package/dist/api/gate-cache.d.ts.map +1 -0
- package/dist/api/gate-cache.js +58 -0
- package/dist/api/gate-cache.js.map +1 -0
- package/dist/api/routes.d.ts +9 -0
- package/dist/api/routes.d.ts.map +1 -0
- package/dist/api/routes.js +250 -0
- package/dist/api/routes.js.map +1 -0
- package/dist/api/server.d.ts +10 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +66 -0
- package/dist/api/server.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +134 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/adapter.d.ts +66 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +145 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/types.d.ts +129 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +15 -0
- package/dist/core/types.js.map +1 -0
- package/dist/events/bus.d.ts +10 -0
- package/dist/events/bus.d.ts.map +1 -0
- package/dist/events/bus.js +48 -0
- package/dist/events/bus.js.map +1 -0
- package/dist/events/terminals.d.ts +42 -0
- package/dist/events/terminals.d.ts.map +1 -0
- package/dist/events/terminals.js +106 -0
- package/dist/events/terminals.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CoreEvent, SessionView } from '../core/types.js';
|
|
2
|
+
/** A cached open human gate for a run. */
|
|
3
|
+
export interface GateCacheEntry {
|
|
4
|
+
/** The unit `ord` the run paused before. */
|
|
5
|
+
ord: number;
|
|
6
|
+
/** The gate prompt (lives only on the transient event — core does not persist it). */
|
|
7
|
+
prompt: string;
|
|
8
|
+
/** Lifecycle state. Only `open` in this foundation increment (see the class note). */
|
|
9
|
+
lifecycle: 'open';
|
|
10
|
+
/** When the daemon observed the gate. */
|
|
11
|
+
receivedAt: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Self-healing gate-prompt cache (DES-STUDIO-001 §3.3).
|
|
15
|
+
*
|
|
16
|
+
* Core does NOT persist the gate prompt — it exists only on the transient
|
|
17
|
+
* `awaitingHuman` CoreEvent (`AgentSession` has no prompt field). So the daemon
|
|
18
|
+
* event-sources it here, keyed by runId (a paused run has exactly one open gate,
|
|
19
|
+
* before `unit_ix`). Entries are pruned on any resumed/terminal event for the
|
|
20
|
+
* run, and re-checked against `sessionsDetail()` on every list reconcile so the
|
|
21
|
+
* cache can neither leak nor go stale ("re-merged on reconcile, pruned to
|
|
22
|
+
* still-paused — can't leak or blank").
|
|
23
|
+
*
|
|
24
|
+
* NOTE: the full HITL lifecycle from §3.3 (advisory / hard-expiry timers,
|
|
25
|
+
* append-only message log, auto-cancel-on-expiry, synthesized `gateLifecycle`
|
|
26
|
+
* frames) is a deliberate follow-on. This increment caches only the prompt so a
|
|
27
|
+
* late-joining browser can render the gate; `lifecycle` is always `open`.
|
|
28
|
+
*/
|
|
29
|
+
export declare class GateCache {
|
|
30
|
+
private readonly entries;
|
|
31
|
+
/** Fold one CoreEvent into the cache. */
|
|
32
|
+
ingest(event: CoreEvent): void;
|
|
33
|
+
/** The cached open gate for a run, if any. */
|
|
34
|
+
get(runId: string): GateCacheEntry | undefined;
|
|
35
|
+
/** Drop cache entries whose run is no longer `awaiting_human` (self-healing on reconcile). */
|
|
36
|
+
reconcile(views: SessionView[]): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=gate-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-cache.d.ts","sourceRoot":"","sources":["../../src/api/gate-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/D,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAE7D,yCAAyC;IACzC,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAyB9B,8CAA8C;IAC9C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI9C,8FAA8F;IAC9F,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI;CAQtC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-healing gate-prompt cache (DES-STUDIO-001 §3.3).
|
|
3
|
+
*
|
|
4
|
+
* Core does NOT persist the gate prompt — it exists only on the transient
|
|
5
|
+
* `awaitingHuman` CoreEvent (`AgentSession` has no prompt field). So the daemon
|
|
6
|
+
* event-sources it here, keyed by runId (a paused run has exactly one open gate,
|
|
7
|
+
* before `unit_ix`). Entries are pruned on any resumed/terminal event for the
|
|
8
|
+
* run, and re-checked against `sessionsDetail()` on every list reconcile so the
|
|
9
|
+
* cache can neither leak nor go stale ("re-merged on reconcile, pruned to
|
|
10
|
+
* still-paused — can't leak or blank").
|
|
11
|
+
*
|
|
12
|
+
* NOTE: the full HITL lifecycle from §3.3 (advisory / hard-expiry timers,
|
|
13
|
+
* append-only message log, auto-cancel-on-expiry, synthesized `gateLifecycle`
|
|
14
|
+
* frames) is a deliberate follow-on. This increment caches only the prompt so a
|
|
15
|
+
* late-joining browser can render the gate; `lifecycle` is always `open`.
|
|
16
|
+
*/
|
|
17
|
+
export class GateCache {
|
|
18
|
+
entries = new Map();
|
|
19
|
+
/** Fold one CoreEvent into the cache. */
|
|
20
|
+
ingest(event) {
|
|
21
|
+
const session = typeof event.session === 'string' ? event.session : undefined;
|
|
22
|
+
if (session === undefined)
|
|
23
|
+
return;
|
|
24
|
+
switch (event.type) {
|
|
25
|
+
case 'awaitingHuman':
|
|
26
|
+
if (typeof event.ord === 'number' && typeof event.prompt === 'string') {
|
|
27
|
+
this.entries.set(session, {
|
|
28
|
+
ord: event.ord,
|
|
29
|
+
prompt: event.prompt,
|
|
30
|
+
lifecycle: 'open',
|
|
31
|
+
receivedAt: new Date().toISOString(),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case 'resumed':
|
|
36
|
+
case 'sessionCompleted':
|
|
37
|
+
case 'runCancelled':
|
|
38
|
+
case 'sessionFailed':
|
|
39
|
+
this.entries.delete(session);
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** The cached open gate for a run, if any. */
|
|
46
|
+
get(runId) {
|
|
47
|
+
return this.entries.get(runId);
|
|
48
|
+
}
|
|
49
|
+
/** Drop cache entries whose run is no longer `awaiting_human` (self-healing on reconcile). */
|
|
50
|
+
reconcile(views) {
|
|
51
|
+
const awaiting = new Set(views.filter((v) => v.session.status === 'awaiting_human').map((v) => v.session.id));
|
|
52
|
+
for (const id of [...this.entries.keys()]) {
|
|
53
|
+
if (!awaiting.has(id))
|
|
54
|
+
this.entries.delete(id);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=gate-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-cache.js","sourceRoot":"","sources":["../../src/api/gate-cache.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,SAAS;IACH,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE7D,yCAAyC;IACzC,MAAM,CAAC,KAAgB;QACrB,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9E,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO;QAClC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,eAAe;gBAClB,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;oBACtE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE;wBACxB,GAAG,EAAE,KAAK,CAAC,GAAG;wBACd,MAAM,EAAE,KAAK,CAAC,MAAM;wBACpB,SAAS,EAAE,MAAM;wBACjB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;qBACrC,CAAC,CAAC;gBACL,CAAC;gBACD,MAAM;YACR,KAAK,SAAS,CAAC;YACf,KAAK,kBAAkB,CAAC;YACxB,KAAK,cAAc,CAAC;YACpB,KAAK,eAAe;gBAClB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC7B,MAAM;YACR;gBACE,MAAM;QACV,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,8FAA8F;IAC9F,SAAS,CAAC,KAAoB;QAC5B,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CACpF,CAAC;QACF,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import { CoreAdapter } from '../core/adapter.js';
|
|
3
|
+
import type { GateCache } from './gate-cache.js';
|
|
4
|
+
/**
|
|
5
|
+
* The daemon REST surface. Every endpoint is a thin wrapper over one adapter /
|
|
6
|
+
* core-ts call (DES-STUDIO-001 §2). `session`/`phase` nouns are now `run`/`unit`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerRoutes(app: FastifyInstance, adapter: CoreAdapter, gateCache: GateCache): void;
|
|
9
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AA6DjD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAkMrG"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { CoreAdapter } from '../core/adapter.js';
|
|
4
|
+
const V = '/api/v1';
|
|
5
|
+
// Actionable-first ordering for the run list (DES-STUDIO-001 §11.6): a run
|
|
6
|
+
// awaiting a human sorts to the top; terminal runs sink.
|
|
7
|
+
const STATUS_ORDER = {
|
|
8
|
+
awaiting_human: 0,
|
|
9
|
+
executing: 1,
|
|
10
|
+
distributing: 2,
|
|
11
|
+
planning: 3,
|
|
12
|
+
failed: 4,
|
|
13
|
+
completed: 5,
|
|
14
|
+
cancelled: 6,
|
|
15
|
+
};
|
|
16
|
+
function sortActionableFirst(views) {
|
|
17
|
+
return [...views].sort((a, b) => (STATUS_ORDER[a.session.status] ?? 9) - (STATUS_ORDER[b.session.status] ?? 9));
|
|
18
|
+
}
|
|
19
|
+
function message(err) {
|
|
20
|
+
return err instanceof Error ? err.message : String(err);
|
|
21
|
+
}
|
|
22
|
+
const RegisterRepoSchema = z.object({
|
|
23
|
+
name: z.string().min(1),
|
|
24
|
+
rootPath: z.string().min(1),
|
|
25
|
+
});
|
|
26
|
+
const LaunchSchema = z.object({
|
|
27
|
+
problem: z.string().min(1),
|
|
28
|
+
sessionId: z.string().min(1).optional(),
|
|
29
|
+
clisJson: z.string().min(1).optional(),
|
|
30
|
+
entityMode: z.enum(['shared', 'isolated']).optional(),
|
|
31
|
+
humanConfirm: z.string().min(1).optional(),
|
|
32
|
+
repoRef: z.string().min(1).optional(),
|
|
33
|
+
});
|
|
34
|
+
const GateSchema = z.object({
|
|
35
|
+
approve: z.boolean(),
|
|
36
|
+
amend: z.string().optional(),
|
|
37
|
+
});
|
|
38
|
+
const OpenTerminalSchema = z.object({
|
|
39
|
+
cwd: z.string().min(1),
|
|
40
|
+
cmd: z.array(z.string().min(1)).min(1).optional(),
|
|
41
|
+
cols: z.number().int().positive(),
|
|
42
|
+
rows: z.number().int().positive(),
|
|
43
|
+
// Optional so omission is the SAFE governed default (§7 — `false` is never a
|
|
44
|
+
// default; the ungoverned operator shell must opt in explicitly).
|
|
45
|
+
governed: z.boolean().optional(),
|
|
46
|
+
});
|
|
47
|
+
const ResizeTerminalSchema = z.object({
|
|
48
|
+
cols: z.number().int().positive(),
|
|
49
|
+
rows: z.number().int().positive(),
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* The daemon REST surface. Every endpoint is a thin wrapper over one adapter /
|
|
53
|
+
* core-ts call (DES-STUDIO-001 §2). `session`/`phase` nouns are now `run`/`unit`.
|
|
54
|
+
*/
|
|
55
|
+
export function registerRoutes(app, adapter, gateCache) {
|
|
56
|
+
// Liveness — also proves the actor + event pump are up.
|
|
57
|
+
app.get(`${V}/health`, async () => {
|
|
58
|
+
const ping = await adapter.ping();
|
|
59
|
+
return { status: 'ok', version: '0.1.0', ping };
|
|
60
|
+
});
|
|
61
|
+
// Report the actually-bound port/host (honours --port / CREW_PORT / port 0).
|
|
62
|
+
app.get(`${V}/config`, async () => {
|
|
63
|
+
const addr = app.server.address();
|
|
64
|
+
const port = typeof addr === 'object' && addr ? addr.port : 7701;
|
|
65
|
+
const host = typeof addr === 'object' && addr ? addr.address : '127.0.0.1';
|
|
66
|
+
return { port, host };
|
|
67
|
+
});
|
|
68
|
+
// The council seats for the launch form (static production roster).
|
|
69
|
+
app.get(`${V}/roster`, async () => ({ roster: CoreAdapter.roster() }));
|
|
70
|
+
// Registered repos → target-repo picker.
|
|
71
|
+
app.get(`${V}/repos`, async () => ({ repos: await adapter.listRepos() }));
|
|
72
|
+
app.post(`${V}/repos`, async (req, reply) => {
|
|
73
|
+
const parsed = RegisterRepoSchema.safeParse(req.body);
|
|
74
|
+
if (!parsed.success) {
|
|
75
|
+
return reply.code(400).send({ error: 'Invalid request body', details: parsed.error.issues });
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const repo = await adapter.registerRepo(parsed.data.name, parsed.data.rootPath);
|
|
79
|
+
return reply.code(201).send({ repo });
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
// Core rejects a non-git / zero-commit path — a client error, not a 500.
|
|
83
|
+
return reply.code(400).send({ error: message(err) });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
// Launch a run (replaces POST /sessions). `clisJson` defaults to the roster;
|
|
87
|
+
// `sessionId` is minted if the client omits it.
|
|
88
|
+
app.post(`${V}/runs`, async (req, reply) => {
|
|
89
|
+
const parsed = LaunchSchema.safeParse(req.body);
|
|
90
|
+
if (!parsed.success) {
|
|
91
|
+
return reply.code(400).send({ error: 'Invalid request body', details: parsed.error.issues });
|
|
92
|
+
}
|
|
93
|
+
const b = parsed.data;
|
|
94
|
+
const input = {
|
|
95
|
+
problem: b.problem,
|
|
96
|
+
sessionId: b.sessionId ?? randomUUID(),
|
|
97
|
+
clisJson: b.clisJson ?? JSON.stringify(CoreAdapter.roster()),
|
|
98
|
+
};
|
|
99
|
+
if (b.entityMode !== undefined)
|
|
100
|
+
input.entityMode = b.entityMode;
|
|
101
|
+
if (b.humanConfirm !== undefined)
|
|
102
|
+
input.humanConfirm = b.humanConfirm;
|
|
103
|
+
if (b.repoRef !== undefined)
|
|
104
|
+
input.repoRef = b.repoRef;
|
|
105
|
+
try {
|
|
106
|
+
const runId = await adapter.launchRun(input);
|
|
107
|
+
return reply.code(201).send({ runId });
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
const msg = message(err);
|
|
111
|
+
const busy = /busy|in flight|already/i.test(msg);
|
|
112
|
+
return reply.code(busy ? 409 : 400).send({ error: msg });
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
// Run list (replaces GET /sessions). Actionable-first; reconciles the gate cache.
|
|
116
|
+
app.get(`${V}/runs`, async () => {
|
|
117
|
+
const views = await adapter.sessionsDetail();
|
|
118
|
+
gateCache.reconcile(views);
|
|
119
|
+
return { runs: sortActionableFirst(views) };
|
|
120
|
+
});
|
|
121
|
+
// One run's detail.
|
|
122
|
+
app.get(`${V}/runs/:id`, async (req, reply) => {
|
|
123
|
+
const { id } = req.params;
|
|
124
|
+
const views = await adapter.sessionsDetail();
|
|
125
|
+
const run = views.find((v) => v.session.id === id);
|
|
126
|
+
if (!run)
|
|
127
|
+
return reply.code(404).send({ error: 'Run not found' });
|
|
128
|
+
return { run };
|
|
129
|
+
});
|
|
130
|
+
// A unit's captured transcript. Unit id convention: `<run>:u<ord>`.
|
|
131
|
+
app.get(`${V}/runs/:id/units/:ord/output`, async (req, reply) => {
|
|
132
|
+
const { id, ord } = req.params;
|
|
133
|
+
const output = await adapter.workOutput(`${id}:u${ord}`);
|
|
134
|
+
return reply.send({ output });
|
|
135
|
+
});
|
|
136
|
+
// The steering gate (§11.1). approve+amend = approve-with-steer; approve:false = reject (cancels).
|
|
137
|
+
app.post(`${V}/runs/:id/gate`, async (req, reply) => {
|
|
138
|
+
const { id } = req.params;
|
|
139
|
+
const parsed = GateSchema.safeParse(req.body);
|
|
140
|
+
if (!parsed.success) {
|
|
141
|
+
return reply.code(400).send({ error: 'Invalid request body', details: parsed.error.issues });
|
|
142
|
+
}
|
|
143
|
+
const views = await adapter.sessionsDetail();
|
|
144
|
+
const run = views.find((v) => v.session.id === id);
|
|
145
|
+
if (!run)
|
|
146
|
+
return reply.code(404).send({ error: 'Run not found' });
|
|
147
|
+
if (run.session.status !== 'awaiting_human') {
|
|
148
|
+
return reply
|
|
149
|
+
.code(409)
|
|
150
|
+
.send({ error: `Run is not awaiting a human gate (status: ${run.session.status})` });
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const status = await adapter.confirmGate(id, parsed.data.approve, parsed.data.amend);
|
|
154
|
+
return reply.send({ status });
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
return reply.code(409).send({ error: message(err) });
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
// Cancel a running or paused run (distinct third action, §11.1).
|
|
161
|
+
app.post(`${V}/runs/:id/cancel`, async (req, reply) => {
|
|
162
|
+
const { id } = req.params;
|
|
163
|
+
const views = await adapter.sessionsDetail();
|
|
164
|
+
const run = views.find((v) => v.session.id === id);
|
|
165
|
+
if (!run)
|
|
166
|
+
return reply.code(404).send({ error: 'Run not found' });
|
|
167
|
+
try {
|
|
168
|
+
const status = await adapter.cancelRun(id);
|
|
169
|
+
return reply.send({ status });
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
return reply.code(409).send({ error: message(err) });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// Advance semantics (§11.8): a gated run advances via confirmGate; otherwise
|
|
176
|
+
// resumeRun re-enters the cursor. Never resumeRun a gated run (it would re-pause).
|
|
177
|
+
app.post(`${V}/runs/:id/resume`, async (req, reply) => {
|
|
178
|
+
const { id } = req.params;
|
|
179
|
+
const views = await adapter.sessionsDetail();
|
|
180
|
+
const run = views.find((v) => v.session.id === id);
|
|
181
|
+
if (!run)
|
|
182
|
+
return reply.code(404).send({ error: 'Run not found' });
|
|
183
|
+
try {
|
|
184
|
+
const status = run.session.status === 'awaiting_human'
|
|
185
|
+
? await adapter.confirmGate(id, true)
|
|
186
|
+
: await adapter.resumeRun(id);
|
|
187
|
+
return reply.send({ status });
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
return reply.code(409).send({ error: message(err) });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
// The daemon-cached gate prompt for a paused run (not a core call) so a fresh
|
|
194
|
+
// browser can render the gate after a late join.
|
|
195
|
+
app.get(`${V}/runs/:id/gate`, async (req, reply) => {
|
|
196
|
+
const { id } = req.params;
|
|
197
|
+
const entry = gateCache.get(id);
|
|
198
|
+
if (!entry)
|
|
199
|
+
return reply.code(404).send({ error: 'No open gate for this run' });
|
|
200
|
+
return { runId: id, ...entry };
|
|
201
|
+
});
|
|
202
|
+
// ── PTY terminal sessions (DES-TERMINAL-001 §6) ────────────────────────────
|
|
203
|
+
// Open a PTY → its id. Drive it over the per-terminal WS `/ws/terminals/:id`;
|
|
204
|
+
// raw output arrives there. `governed` defaults to `true` (the gate-hook-routed
|
|
205
|
+
// default, §7) — an ungoverned operator shell must pass `governed:false` EXPLICITLY.
|
|
206
|
+
app.post(`${V}/terminals`, async (req, reply) => {
|
|
207
|
+
const parsed = OpenTerminalSchema.safeParse(req.body);
|
|
208
|
+
if (!parsed.success) {
|
|
209
|
+
return reply.code(400).send({ error: 'Invalid request body', details: parsed.error.issues });
|
|
210
|
+
}
|
|
211
|
+
const b = parsed.data;
|
|
212
|
+
try {
|
|
213
|
+
const id = await adapter.openTerminal(b.cwd, b.cmd, b.cols, b.rows, b.governed ?? true);
|
|
214
|
+
return reply.code(201).send({ id });
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
// Core rejects a bad cwd / spawn failure — a client error, not a 500.
|
|
218
|
+
return reply.code(400).send({ error: message(err) });
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// Resize a live terminal's PTY.
|
|
222
|
+
app.post(`${V}/terminals/:id/resize`, async (req, reply) => {
|
|
223
|
+
const { id } = req.params;
|
|
224
|
+
const parsed = ResizeTerminalSchema.safeParse(req.body);
|
|
225
|
+
if (!parsed.success) {
|
|
226
|
+
return reply.code(400).send({ error: 'Invalid request body', details: parsed.error.issues });
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const status = await adapter.resizeTerminal(id, parsed.data.cols, parsed.data.rows);
|
|
230
|
+
return reply.send({ status });
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
// Unknown / already-closed terminal id → 404, not 500.
|
|
234
|
+
return reply.code(404).send({ error: message(err) });
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
// Close a live terminal (kill child, join reader). A second close of an
|
|
238
|
+
// already-gone terminal 404s rather than 500s.
|
|
239
|
+
app.post(`${V}/terminals/:id/close`, async (req, reply) => {
|
|
240
|
+
const { id } = req.params;
|
|
241
|
+
try {
|
|
242
|
+
const status = await adapter.closeTerminal(id);
|
|
243
|
+
return reply.send({ status });
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
return reply.code(404).send({ error: message(err) });
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD,MAAM,CAAC,GAAG,SAAS,CAAC;AAEpB,2EAA2E;AAC3E,yDAAyD;AACzD,MAAM,YAAY,GAAkC;IAClD,cAAc,EAAE,CAAC;IACjB,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;IACf,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,CAAC;IACT,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;CACb,CAAC;AAEF,SAAS,mBAAmB,CAAC,KAAoB;IAC/C,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CACpB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CACxF,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,GAAY;IAC3B,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC5B,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE;IACrD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACjD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,6EAA6E;IAC7E,kEAAkE;IAClE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAoB,EAAE,OAAoB,EAAE,SAAoB;IAC7F,wDAAwD;IACxD,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;QAC3E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,oEAAoE;IACpE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IAEvE,yCAAyC;IACzC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IAE1E,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAC1C,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yEAAyE;YACzE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,gDAAgD;IAChD,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACzC,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;QACtB,MAAM,KAAK,GAAmB;YAC5B,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,UAAU,EAAE;YACtC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;SAC7D,CAAC;QACF,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS;YAAE,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;QAChE,IAAI,CAAC,CAAC,YAAY,KAAK,SAAS;YAAE,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC;QACtE,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS;YAAE,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YACzB,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,kFAAkF;IAClF,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7C,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,oBAAoB;IACpB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAC5C,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;QAClE,OAAO,EAAE,GAAG,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,oEAAoE;IACpE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,6BAA6B,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAC9D,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,MAAqC,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;QACzD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,mGAAmG;IACnG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAClD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;QAClE,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;YAC5C,OAAO,KAAK;iBACT,IAAI,CAAC,GAAG,CAAC;iBACT,IAAI,CAAC,EAAE,KAAK,EAAE,6CAA6C,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrF,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,iEAAiE;IACjE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACpD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,mFAAmF;IACnF,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACpD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC;YACH,MAAM,MAAM,GACV,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,gBAAgB;gBACrC,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC;gBACrC,CAAC,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAClC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,iDAAiD;IACjD,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACjD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;QAChF,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,8EAA8E;IAC9E,gFAAgF;IAChF,qFAAqF;IACrF,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;YACxF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,sEAAsE;YACtE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,gCAAgC;IAChC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,uBAAuB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACzD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpF,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,uDAAuD;YACvD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,+CAA+C;IAC/C,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACxD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import type { CoreAdapter } from '../core/adapter.js';
|
|
3
|
+
export declare function createServer(adapter: CoreAdapter): Promise<ReturnType<typeof Fastify>>;
|
|
4
|
+
export interface StartedServer {
|
|
5
|
+
app: ReturnType<typeof Fastify>;
|
|
6
|
+
port: number;
|
|
7
|
+
host: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function startServer(adapter: CoreAdapter, port?: number, host?: string): Promise<StartedServer>;
|
|
10
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAO9B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOtD,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAmD5F;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,IAAI,SAAO,EACX,IAAI,SAAc,GACjB,OAAO,CAAC,aAAa,CAAC,CAQxB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import fastifyWebsocket from '@fastify/websocket';
|
|
3
|
+
import { registerRoutes } from './routes.js';
|
|
4
|
+
import { GateCache } from './gate-cache.js';
|
|
5
|
+
import { registerClient, broadcast } from '../events/bus.js';
|
|
6
|
+
import { TerminalHub, registerTerminalWs } from '../events/terminals.js';
|
|
7
|
+
// Allow the studio (a separate localhost origin, e.g. :4200) to call the
|
|
8
|
+
// daemon's REST API. Restricted to loopback origins — the daemon only binds
|
|
9
|
+
// 127.0.0.1, so this never widens exposure beyond the local machine.
|
|
10
|
+
const LOOPBACK_ORIGIN = /^http:\/\/(127\.0\.0\.1|localhost):\d+$/;
|
|
11
|
+
export async function createServer(adapter) {
|
|
12
|
+
const app = Fastify({ logger: { level: process.env['LOG_LEVEL'] ?? 'info' } });
|
|
13
|
+
const gateCache = new GateCache();
|
|
14
|
+
const terminals = new TerminalHub();
|
|
15
|
+
// The daemon's single CoreEvent subscription fans out here: cache gate prompts
|
|
16
|
+
// (§3.3), route terminal frames to their owning per-terminal socket (by id,
|
|
17
|
+
// DES-TERMINAL-001 §6), then forward every frame verbatim to all `/ws` clients (§2.1).
|
|
18
|
+
adapter.onEvent((event) => {
|
|
19
|
+
gateCache.ingest(event);
|
|
20
|
+
terminals.route(event);
|
|
21
|
+
broadcast(event);
|
|
22
|
+
});
|
|
23
|
+
app.addHook('onRequest', async (req, reply) => {
|
|
24
|
+
const origin = req.headers.origin;
|
|
25
|
+
if (origin && LOOPBACK_ORIGIN.test(origin)) {
|
|
26
|
+
reply.header('Access-Control-Allow-Origin', origin);
|
|
27
|
+
reply.header('Vary', 'Origin');
|
|
28
|
+
reply.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
|
|
29
|
+
reply.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
30
|
+
}
|
|
31
|
+
if (req.method === 'OPTIONS') {
|
|
32
|
+
await reply.code(204).send();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
// Tolerate an empty body on application/json POSTs (some actions take no body).
|
|
36
|
+
// Default Fastify v5 rejects "" with FST_ERR_CTP_EMPTY_JSON_BODY.
|
|
37
|
+
app.addContentTypeParser('application/json', { parseAs: 'string' }, (_req, body, done) => {
|
|
38
|
+
if (body === '' || body === undefined || body === null)
|
|
39
|
+
return done(null, undefined);
|
|
40
|
+
try {
|
|
41
|
+
done(null, JSON.parse(body));
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
done(err);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
await app.register(fastifyWebsocket);
|
|
48
|
+
app.get('/ws', { websocket: true }, (socket) => {
|
|
49
|
+
// Late-join gets no replay; the studio reconciles with a one-shot GET /runs.
|
|
50
|
+
registerClient(socket);
|
|
51
|
+
});
|
|
52
|
+
// One dedicated WS channel per PTY: /ws/terminals/:id (DES-TERMINAL-001 §6).
|
|
53
|
+
registerTerminalWs(app, adapter, terminals);
|
|
54
|
+
registerRoutes(app, adapter, gateCache);
|
|
55
|
+
return app;
|
|
56
|
+
}
|
|
57
|
+
export async function startServer(adapter, port = 7701, host = '127.0.0.1') {
|
|
58
|
+
const app = await createServer(adapter);
|
|
59
|
+
await app.listen({ port, host });
|
|
60
|
+
const addr = app.server.address();
|
|
61
|
+
const boundPort = typeof addr === 'object' && addr ? addr.port : port;
|
|
62
|
+
const boundHost = typeof addr === 'object' && addr ? addr.address : host;
|
|
63
|
+
app.log.info(`wicked-crew daemon listening on ${boundHost}:${boundPort}`);
|
|
64
|
+
return { app, port: boundPort, host: boundHost };
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { performance } from 'node:perf_hooks';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { CoreAdapter } from '../core/adapter.js';
|
|
7
|
+
import { startServer } from '../api/server.js';
|
|
8
|
+
const [, , command, ...argv] = process.argv;
|
|
9
|
+
function flag(args, name) {
|
|
10
|
+
const i = args.indexOf(name);
|
|
11
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
12
|
+
}
|
|
13
|
+
function hasFlag(args, name) {
|
|
14
|
+
return args.includes(name);
|
|
15
|
+
}
|
|
16
|
+
function parseBootstrap(args) {
|
|
17
|
+
const dbPath = flag(args, '--db') ?? join(tmpdir(), 'wicked-crew-core.db');
|
|
18
|
+
const portStr = flag(args, '--port') ?? process.env['CREW_PORT'];
|
|
19
|
+
const port = portStr !== undefined ? Number(portStr) : 7701;
|
|
20
|
+
const stub = hasFlag(args, '--stub') || process.env['WICKED_CORE_STUB'] === '1';
|
|
21
|
+
return { dbPath, port, stub };
|
|
22
|
+
}
|
|
23
|
+
let adapterRef;
|
|
24
|
+
async function bootstrap(opts) {
|
|
25
|
+
const adapter = new CoreAdapter({ dbPath: opts.dbPath, stub: opts.stub });
|
|
26
|
+
adapterRef = adapter;
|
|
27
|
+
const { port } = await startServer(adapter, opts.port);
|
|
28
|
+
installShutdownHandlers();
|
|
29
|
+
return { adapter, port };
|
|
30
|
+
}
|
|
31
|
+
function installShutdownHandlers() {
|
|
32
|
+
let shuttingDown = false;
|
|
33
|
+
const shutdown = () => {
|
|
34
|
+
if (shuttingDown)
|
|
35
|
+
return;
|
|
36
|
+
shuttingDown = true;
|
|
37
|
+
// Close the single subscription so the pump thread + tsfn release and the
|
|
38
|
+
// process can exit on its own.
|
|
39
|
+
try {
|
|
40
|
+
adapterRef?.close();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* already closed */
|
|
44
|
+
}
|
|
45
|
+
process.exit(0);
|
|
46
|
+
};
|
|
47
|
+
process.on('SIGTERM', shutdown);
|
|
48
|
+
process.on('SIGINT', shutdown);
|
|
49
|
+
}
|
|
50
|
+
function printReady(fields) {
|
|
51
|
+
// Machine-readable readiness marker for evidence harnesses.
|
|
52
|
+
process.stdout.write(`WICKED_CREW_READY ${JSON.stringify(fields)}\n`);
|
|
53
|
+
}
|
|
54
|
+
async function main() {
|
|
55
|
+
const t0 = performance.now();
|
|
56
|
+
if (command === 'serve') {
|
|
57
|
+
const opts = parseBootstrap(argv);
|
|
58
|
+
const { port } = await bootstrap(opts);
|
|
59
|
+
printReady({ mode: 'serve', port, db: opts.dbPath, stub: opts.stub, startupMs: Math.round(performance.now() - t0) });
|
|
60
|
+
}
|
|
61
|
+
else if (command === 'start') {
|
|
62
|
+
const opts = parseBootstrap(argv);
|
|
63
|
+
const problem = flag(argv, '--problem') ?? 'No problem specified';
|
|
64
|
+
const humanConfirm = flag(argv, '--human-confirm'); // none | all | before:<ord>
|
|
65
|
+
const { adapter, port } = await bootstrap(opts);
|
|
66
|
+
const input = {
|
|
67
|
+
problem,
|
|
68
|
+
sessionId: flag(argv, '--session') ?? randomUUID(),
|
|
69
|
+
clisJson: JSON.stringify(CoreAdapter.roster()),
|
|
70
|
+
};
|
|
71
|
+
if (humanConfirm !== undefined)
|
|
72
|
+
input.humanConfirm = humanConfirm;
|
|
73
|
+
const runId = await adapter.launchRun(input);
|
|
74
|
+
printReady({ mode: 'start', port, db: opts.dbPath, run: runId, startupMs: Math.round(performance.now() - t0) });
|
|
75
|
+
}
|
|
76
|
+
else if (command === 'resume') {
|
|
77
|
+
const sessionId = flag(argv, '--session');
|
|
78
|
+
if (!sessionId) {
|
|
79
|
+
console.error('Usage: wicked-crew resume --session <id> [--db <path>] [--port <n>] [--stub]');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
const opts = parseBootstrap(argv);
|
|
83
|
+
const { adapter, port } = await bootstrap(opts);
|
|
84
|
+
const status = await adapter.resumeRun(sessionId);
|
|
85
|
+
printReady({ mode: 'resume', port, db: opts.dbPath, run: sessionId, status, startupMs: Math.round(performance.now() - t0) });
|
|
86
|
+
}
|
|
87
|
+
else if (command === 'gate') {
|
|
88
|
+
await runGate(argv);
|
|
89
|
+
}
|
|
90
|
+
else if (command === 'status') {
|
|
91
|
+
await runStatus(argv);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.error(`Unknown command: ${command ?? '(none)'}`);
|
|
95
|
+
console.error('Usage: wicked-crew serve|start|resume|gate|status');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function runGate(args) {
|
|
100
|
+
const runId = flag(args, '--run') ?? flag(args, '--session');
|
|
101
|
+
const approve = !hasFlag(args, '--reject');
|
|
102
|
+
const amend = flag(args, '--amend');
|
|
103
|
+
const port = flag(args, '--port') !== undefined ? Number(flag(args, '--port')) : 7701;
|
|
104
|
+
if (!runId) {
|
|
105
|
+
console.error('Usage: wicked-crew gate --run <id> [--reject] [--amend <text>] [--port <n>]');
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
const body = { approve };
|
|
109
|
+
if (amend !== undefined)
|
|
110
|
+
body['amend'] = amend;
|
|
111
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/v1/runs/${runId}/gate`, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: { 'Content-Type': 'application/json' },
|
|
114
|
+
body: JSON.stringify(body),
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
console.error(`Gate action failed: ${res.status} ${await res.text()}`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
console.log(`Gate ${approve ? 'approve' : 'reject'} applied to run ${runId}`);
|
|
121
|
+
}
|
|
122
|
+
async function runStatus(args) {
|
|
123
|
+
const runId = flag(args, '--run') ?? flag(args, '--session');
|
|
124
|
+
const port = flag(args, '--port') !== undefined ? Number(flag(args, '--port')) : 7701;
|
|
125
|
+
const base = `http://127.0.0.1:${port}/api/v1`;
|
|
126
|
+
const url = runId ? `${base}/runs/${runId}` : `${base}/runs`;
|
|
127
|
+
const res = await fetch(url);
|
|
128
|
+
console.log(JSON.stringify(await res.json(), null, 2));
|
|
129
|
+
}
|
|
130
|
+
main().catch((err) => {
|
|
131
|
+
console.error(err);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|