wicked-crew 0.4.0 → 0.6.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 (132) hide show
  1. package/dist/api/api-prefix.d.ts +13 -0
  2. package/dist/api/api-prefix.d.ts.map +1 -0
  3. package/dist/api/api-prefix.js +13 -0
  4. package/dist/api/api-prefix.js.map +1 -0
  5. package/dist/api/audit.d.ts +57 -0
  6. package/dist/api/audit.d.ts.map +1 -0
  7. package/dist/api/audit.js +115 -0
  8. package/dist/api/audit.js.map +1 -0
  9. package/dist/api/auth.d.ts +192 -0
  10. package/dist/api/auth.d.ts.map +1 -0
  11. package/dist/api/auth.js +515 -0
  12. package/dist/api/auth.js.map +1 -0
  13. package/dist/api/evidence.d.ts +11 -0
  14. package/dist/api/evidence.d.ts.map +1 -1
  15. package/dist/api/evidence.js +8 -3
  16. package/dist/api/evidence.js.map +1 -1
  17. package/dist/api/gate-cache.d.ts +8 -0
  18. package/dist/api/gate-cache.d.ts.map +1 -1
  19. package/dist/api/gate-cache.js +10 -0
  20. package/dist/api/gate-cache.js.map +1 -1
  21. package/dist/api/open-path.d.ts +18 -0
  22. package/dist/api/open-path.d.ts.map +1 -0
  23. package/dist/api/open-path.js +79 -0
  24. package/dist/api/open-path.js.map +1 -0
  25. package/dist/api/routes.d.ts +113 -1
  26. package/dist/api/routes.d.ts.map +1 -1
  27. package/dist/api/routes.js +516 -27
  28. package/dist/api/routes.js.map +1 -1
  29. package/dist/api/seat-health.d.ts +55 -0
  30. package/dist/api/seat-health.d.ts.map +1 -0
  31. package/dist/api/seat-health.js +273 -0
  32. package/dist/api/seat-health.js.map +1 -0
  33. package/dist/api/seat-signin.d.ts +27 -0
  34. package/dist/api/seat-signin.d.ts.map +1 -0
  35. package/dist/api/seat-signin.js +143 -0
  36. package/dist/api/seat-signin.js.map +1 -0
  37. package/dist/api/server.d.ts +111 -3
  38. package/dist/api/server.d.ts.map +1 -1
  39. package/dist/api/server.js +236 -11
  40. package/dist/api/server.js.map +1 -1
  41. package/dist/api/unit-output.d.ts +62 -0
  42. package/dist/api/unit-output.d.ts.map +1 -0
  43. package/dist/api/unit-output.js +108 -0
  44. package/dist/api/unit-output.js.map +1 -0
  45. package/dist/cli/index.js +97 -3
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/cli/mcp.d.ts +14 -0
  48. package/dist/cli/mcp.d.ts.map +1 -0
  49. package/dist/cli/mcp.js +119 -0
  50. package/dist/cli/mcp.js.map +1 -0
  51. package/dist/core/adapter.d.ts +106 -1
  52. package/dist/core/adapter.d.ts.map +1 -1
  53. package/dist/core/adapter.js +293 -12
  54. package/dist/core/adapter.js.map +1 -1
  55. package/dist/core/bridge-path.d.ts +17 -6
  56. package/dist/core/bridge-path.d.ts.map +1 -1
  57. package/dist/core/bridge-path.js +17 -6
  58. package/dist/core/bridge-path.js.map +1 -1
  59. package/dist/core/types.d.ts +23 -352
  60. package/dist/core/types.d.ts.map +1 -1
  61. package/dist/core/types.js +11 -4
  62. package/dist/core/types.js.map +1 -1
  63. package/dist/interactive/bridge-pool.d.ts +71 -0
  64. package/dist/interactive/bridge-pool.d.ts.map +1 -0
  65. package/dist/interactive/bridge-pool.js +187 -0
  66. package/dist/interactive/bridge-pool.js.map +1 -0
  67. package/dist/interactive/bridge-root.d.ts +36 -0
  68. package/dist/interactive/bridge-root.d.ts.map +1 -0
  69. package/dist/interactive/bridge-root.js +48 -0
  70. package/dist/interactive/bridge-root.js.map +1 -0
  71. package/dist/interactive/draft-events.d.ts +144 -0
  72. package/dist/interactive/draft-events.d.ts.map +1 -0
  73. package/dist/interactive/draft-events.js +490 -0
  74. package/dist/interactive/draft-events.js.map +1 -0
  75. package/dist/interactive/edit-events.d.ts +172 -0
  76. package/dist/interactive/edit-events.d.ts.map +1 -0
  77. package/dist/interactive/edit-events.js +530 -0
  78. package/dist/interactive/edit-events.js.map +1 -0
  79. package/dist/interactive/ledger.d.ts +39 -0
  80. package/dist/interactive/ledger.d.ts.map +1 -0
  81. package/dist/interactive/ledger.js +93 -0
  82. package/dist/interactive/ledger.js.map +1 -0
  83. package/dist/interactive/proxy-routes.d.ts +39 -0
  84. package/dist/interactive/proxy-routes.d.ts.map +1 -0
  85. package/dist/interactive/proxy-routes.js +189 -0
  86. package/dist/interactive/proxy-routes.js.map +1 -0
  87. package/dist/interactive/ws-relay.d.ts +85 -0
  88. package/dist/interactive/ws-relay.d.ts.map +1 -0
  89. package/dist/interactive/ws-relay.js +191 -0
  90. package/dist/interactive/ws-relay.js.map +1 -0
  91. package/dist/projects/activity.d.ts +29 -0
  92. package/dist/projects/activity.d.ts.map +1 -0
  93. package/dist/projects/activity.js +172 -0
  94. package/dist/projects/activity.js.map +1 -0
  95. package/dist/projects/charter.d.ts +28 -0
  96. package/dist/projects/charter.d.ts.map +1 -0
  97. package/dist/projects/charter.js +53 -0
  98. package/dist/projects/charter.js.map +1 -0
  99. package/dist/projects/events.d.ts +55 -0
  100. package/dist/projects/events.d.ts.map +1 -0
  101. package/dist/projects/events.js +141 -0
  102. package/dist/projects/events.js.map +1 -0
  103. package/dist/projects/membership-index.d.ts +25 -0
  104. package/dist/projects/membership-index.d.ts.map +1 -0
  105. package/dist/projects/membership-index.js +46 -0
  106. package/dist/projects/membership-index.js.map +1 -0
  107. package/dist/projects/routes.d.ts +90 -0
  108. package/dist/projects/routes.d.ts.map +1 -0
  109. package/dist/projects/routes.js +388 -0
  110. package/dist/projects/routes.js.map +1 -0
  111. package/dist/projects/settings.d.ts +32 -0
  112. package/dist/projects/settings.d.ts.map +1 -0
  113. package/dist/projects/settings.js +64 -0
  114. package/dist/projects/settings.js.map +1 -0
  115. package/dist/qe/acceptance.d.ts +137 -0
  116. package/dist/qe/acceptance.d.ts.map +1 -0
  117. package/dist/qe/acceptance.js +249 -0
  118. package/dist/qe/acceptance.js.map +1 -0
  119. package/dist/qe/gate-events.d.ts +111 -0
  120. package/dist/qe/gate-events.d.ts.map +1 -0
  121. package/dist/qe/gate-events.js +168 -0
  122. package/dist/qe/gate-events.js.map +1 -0
  123. package/dist/qe/ledger.d.ts +100 -0
  124. package/dist/qe/ledger.d.ts.map +1 -0
  125. package/dist/qe/ledger.js +154 -0
  126. package/dist/qe/ledger.js.map +1 -0
  127. package/dist/studio/assets/index-CCwXa1cn.js +428 -0
  128. package/dist/studio/assets/index-HWxo0h41.css +32 -0
  129. package/dist/studio/index.html +2 -2
  130. package/package.json +10 -4
  131. package/dist/studio/assets/index-Ci_R6ARr.js +0 -423
  132. package/dist/studio/assets/index-Dio_c1Q3.css +0 -32
@@ -0,0 +1,530 @@
1
+ /**
2
+ * Opt-in governed answering of wicked-interactive's STRUCTURAL edits (task #86, Phase 7c
3
+ * final leg — the draft leg's sibling, see draft-events.ts).
4
+ *
5
+ * wicked-interactive's service is model-free: a feedback batch's deterministic items
6
+ * (content/style/remove) are applied instantly by the service and NEVER reach this seam —
7
+ * only `structural-change` items climb. The service lands the deterministic partial as
8
+ * `_v{N}.html`, then emits `wicked.interactive.feedback.processed` with `awaiting_structural > 0`
9
+ * and the structural items INLINE (selector + instruction + the element's CURRENT fragment),
10
+ * expecting *something with intelligence* to answer with `wicked.interactive.edit.completed`
11
+ * carrying the edited fragments. Today that answerer is an ad-hoc `assist` agent session
12
+ * (assist skill Step 3); this module makes a crew-governed run the answerer instead.
13
+ *
14
+ * Same shape as the draft leg, with the structural deltas:
15
+ *
16
+ * - VERSIONED TARGETING: the dedupe unit is the HANDOFF — `<doc>:v<version>` — not the doc
17
+ * (one doc produces many structural handoffs over its life). The durable ledger keys on the
18
+ * handoff, and the closing emit's idempotency key carries doc+version.
19
+ * - INV-2 AT SCALE: unlike a first draft (no pre-existing anchors), an edited fragment MUST
20
+ * retain every pre-existing `data-wid` BYTE-EXACT — the service silently rejects violations
21
+ * (regenerate.js Inv2Error → the user's edit dies with no version landed). So this seam runs
22
+ * a deterministic PRE-EMIT SELF-CHECK mirroring the assist skill's Step 2/Step 3c discipline:
23
+ * parse the handed-off fragment's data-wids, verify the worker's fragment retains all of
24
+ * them, and fail HONEST (error status, no emit) on any violation — a loud crew-side rejection
25
+ * instead of a silent service-side one.
26
+ * - HANDOFF BY FILE: fragments can be arbitrarily large and the PTY seat runner's prompt is
27
+ * single-line, so the seam writes the items to a handoff JSON on disk and names its path in
28
+ * the problem; the worker writes each edited fragment to a per-item output file (never JSON
29
+ * with hand-escaped HTML — the exact failure the assist skill's Step 3c warns about).
30
+ * - PROJECT ATTRIBUTION (the 7b surface): a project-bound doc's events carry `project_id`
31
+ * (interactive's DES-PROJECT-001 enrichment); the governed run is launched with
32
+ * `LaunchOptions.projectId` so the edit shows up in the project's activity feed.
33
+ */
34
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
35
+ import { join } from 'node:path';
36
+ import { homedir } from 'node:os';
37
+ import { randomUUID } from 'node:crypto';
38
+ import { DOC_NAME, INTERACTIVE_DOMAIN, INTERACTIVE_PRODUCER, STATUS_POSTED, oneLine, } from './draft-events.js';
39
+ import { InteractiveHandoffLedger } from './ledger.js';
40
+ // ── Vocabulary constants (interactive's, verbatim — src/service/events.js is the truth) ──────
41
+ export const FEEDBACK_PROCESSED = 'wicked.interactive.feedback.processed';
42
+ export const EDIT_COMPLETED = 'wicked.interactive.edit.completed';
43
+ /** Exact-type filter with a domain guard — no wildcard, one event type is the whole trigger. */
44
+ export const INTERACTIVE_EDIT_BUS_FILTER = `${FEEDBACK_PROCESSED}@${INTERACTIVE_DOMAIN}`;
45
+ /** Dedicated durable-cursor identity — NOT the draft seam's, so the two interactive seams
46
+ * advance independent cursors and stopping one never strands the other. */
47
+ export const INTERACTIVE_EDIT_BUS_PLUGIN = 'wicked-crew-interactive-edit';
48
+ // ── The workflow (workflows-as-data) ─────────────────────────────────────────────────────────
49
+ export const INTERACTIVE_EDIT_WORKFLOW = 'interactive-edit';
50
+ /**
51
+ * The governed workflow that fulfils a structural handoff. ONE agent phase — `edit` (build,
52
+ * creator role): the target fragments are already extracted and the instructions already
53
+ * written, so unlike the draft leg there is nothing left to plan; a recon phase would only
54
+ * burn a council turn re-reading a handoff the edit phase reads anyway.
55
+ *
56
+ * The phase `instructions` adapt the fragment-edit contract from interactive's assist skill
57
+ * (Step 2 + Step 3): rewrite each handed-off fragment per its instruction, preserve every
58
+ * pre-existing `data-wid` byte-for-byte, never mint new anchors, keep the markup well-formed,
59
+ * and never fabricate facts. SINGLE-LINE by contract (PTY seat runner, wicked-core FINDING-011).
60
+ *
61
+ * The gate is `auto` with `validator_pin: null` — no human gate, no deterministic floor —
62
+ * because this seam runs its own deterministic pre-emit self-check (INV-2) and interactive's
63
+ * apply path re-checks the same invariant; a wrong-but-anchor-safe edit is the user's to judge
64
+ * on the canvas, exactly as with the assist session it replaces.
65
+ */
66
+ export const INTERACTIVE_EDIT_WORKFLOW_DEF = {
67
+ id: INTERACTIVE_EDIT_WORKFLOW,
68
+ is_system: true,
69
+ phases: [
70
+ {
71
+ id: 'edit',
72
+ kind: 'build',
73
+ instructions: 'Read the handoff JSON file named in the task; for EACH entry of its items array: rewrite that item\'s "fragment" (the current outerHTML of one document element) to fulfil the item\'s "instruction", and SAVE the complete edited fragment — the element\'s full outerHTML only, no document wrapper, no markdown fences — to the item\'s exact absolute "output_path" (create parent directories if needed, overwrite if present). NON-NEGOTIABLE (INV-2): every data-wid attribute in the input fragment MUST survive in your edited fragment byte-for-byte — never remove, rename, or re-value a data-wid, and keep the root element\'s own data-wid on the root; elements you ADD must carry no data-wid at all (the wicked-interactive service instruments its own anchors). Keep the markup well-formed (balanced tags), change only what the instruction asks, and never fabricate facts or figures. Write every output file before you finish and end your reply with the absolute paths you wrote.',
74
+ gate_type: 'execution',
75
+ gate: 'auto',
76
+ executes_code: false,
77
+ verified_evidence: false,
78
+ required_deliverables: [],
79
+ depends_on: [],
80
+ role: 'creator',
81
+ skill_ref: null,
82
+ allowed_skills: [],
83
+ validator_pin: null,
84
+ },
85
+ ],
86
+ };
87
+ /**
88
+ * Parse a bus frame into a {@link StructuralHandoff}, or `null` when it is not an actionable
89
+ * structural handoff: wrong type, malformed payload, slug-invalid document_id, non-integer
90
+ * version, or NO usable structural items. Deterministic-only batches (`awaiting_structural: 0`)
91
+ * return `null` by construction — those edits already landed inside the service (edit-routing
92
+ * rung 1) and must never climb to a crew. Items whose `fragment` is missing/null (the service
93
+ * could not extract the element) are dropped: there is no current markup to edit.
94
+ */
95
+ export function parseStructuralFeedback(eventType, payload) {
96
+ if (eventType !== FEEDBACK_PROCESSED)
97
+ return null;
98
+ if (typeof payload !== 'object' || payload === null)
99
+ return null;
100
+ const p = payload;
101
+ // The declared handoff size is the explicit gate: a frame carrying structural_items while
102
+ // announcing `awaiting_structural: 0` (or omitting it) is producer drift, not a handoff —
103
+ // never launch a governed run off an inconsistent frame.
104
+ const awaiting = p['awaiting_structural'];
105
+ if (typeof awaiting !== 'number' || !Number.isInteger(awaiting) || awaiting <= 0)
106
+ return null;
107
+ const documentId = typeof p['document_id'] === 'string' ? p['document_id'] : '';
108
+ if (!DOC_NAME.test(documentId))
109
+ return null;
110
+ const version = p['version'];
111
+ if (typeof version !== 'number' || !Number.isInteger(version) || version < 0)
112
+ return null;
113
+ const rawItems = Array.isArray(p['structural_items']) ? p['structural_items'] : [];
114
+ const items = [];
115
+ for (const raw of rawItems) {
116
+ if (typeof raw !== 'object' || raw === null)
117
+ continue;
118
+ const r = raw;
119
+ const selector = typeof r['selector'] === 'string' ? r['selector'] : '';
120
+ const fragment = typeof r['fragment'] === 'string' ? r['fragment'] : '';
121
+ if (selector.length === 0 || fragment.length === 0)
122
+ continue;
123
+ items.push({
124
+ selector,
125
+ instruction: typeof r['instruction'] === 'string' ? r['instruction'] : '',
126
+ fragment,
127
+ });
128
+ }
129
+ if (items.length === 0)
130
+ return null;
131
+ const projectId = typeof p['project_id'] === 'string' && p['project_id'].length > 0 ? p['project_id'] : undefined;
132
+ return { documentId, version, items, ...(projectId !== undefined ? { projectId } : {}) };
133
+ }
134
+ /** The one dedupe unit of this seam: a handoff is doc+version, NOT doc-lifetime. */
135
+ export function handoffKey(documentId, version) {
136
+ return `${documentId}:v${version}`;
137
+ }
138
+ /** Deterministic bus idempotency key for the one edit this seam may land per handoff. */
139
+ export function editIdempotencyKey(documentId, version) {
140
+ return `crew:interactive.edit:${documentId}:v${version}`;
141
+ }
142
+ /** Per-item output paths are INDEX-named (`fragment-1.html`, …), never selector-named — a
143
+ * selector is bus-supplied data and must not name a filesystem path. */
144
+ export function handoffFileItems(handoff, outDir) {
145
+ return handoff.items.map((item, i) => ({
146
+ ...item,
147
+ output_path: join(outDir, `fragment-${i + 1}.html`),
148
+ }));
149
+ }
150
+ /**
151
+ * The run's problem statement. Single-line (PTY contract); the bulky fragments ride in the
152
+ * handoff FILE, so only identity, the capped instruction gist, and the file path ride here.
153
+ */
154
+ export function editProblem(handoff, handoffPath) {
155
+ const gist = oneLine(handoff.items.map((i) => i.instruction).filter((s) => s.length > 0).join('; '), 600);
156
+ return (`Fulfil ${handoff.items.length} structural edit(s) on the wicked-interactive document ` +
157
+ `"${handoff.documentId}" (editing version ${handoff.version}). Read the handoff file at ` +
158
+ `${handoffPath} — a JSON file whose items array carries, per edit: the user's instruction, ` +
159
+ `the element's current HTML fragment, and the exact absolute output_path where the edited ` +
160
+ `fragment must be saved. The user asked: ${gist.length > 0 ? gist : '(no instruction text)'}`);
161
+ }
162
+ // ── The pre-emit INV-2 self-check (deterministic; mirrors assist skill Step 3c) ──────────────
163
+ /** Every `data-wid` value in a fragment, in document order (duplicates preserved). */
164
+ export function fragmentWids(fragment) {
165
+ return [...fragment.matchAll(/data-wid="([^"]*)"/g)].map((m) => m[1]);
166
+ }
167
+ /** The data-wids of `before` missing from `after`, byte-exact. Non-empty = INV-2 violation.
168
+ * Deliberately conservative: a wid that survives with different quoting/escaping counts as
169
+ * dropped — the service compares exact attribute values, and fail-closed here beats a silent
170
+ * Inv2Error rejection there. */
171
+ export function droppedWids(before, after) {
172
+ const kept = new Set(fragmentWids(after));
173
+ return [...new Set(fragmentWids(before))].filter((w) => !kept.has(w));
174
+ }
175
+ /**
176
+ * Read the worker's per-item output files and verify each against the handed-off fragment:
177
+ * the file must exist non-empty, and every pre-existing `data-wid` must survive byte-exact.
178
+ * ANY violation fails the whole handoff (all-or-nothing): a partial apply would land a version
179
+ * the user believes complete, and the violating item would die silently service-side.
180
+ */
181
+ export function collectEditResults(items) {
182
+ const results = [];
183
+ const violations = [];
184
+ for (const item of items) {
185
+ let fragment = '';
186
+ try {
187
+ fragment = readFileSync(item.output_path, 'utf8').trim();
188
+ }
189
+ catch {
190
+ /* missing file → the empty-fragment violation below */
191
+ }
192
+ if (fragment.length === 0) {
193
+ violations.push({ selector: item.selector, reason: `no edited fragment at ${item.output_path}` });
194
+ continue;
195
+ }
196
+ const dropped = droppedWids(item.fragment, fragment);
197
+ if (dropped.length > 0) {
198
+ violations.push({
199
+ selector: item.selector,
200
+ reason: `INV-2 violation — data-wid(s) dropped: ${dropped.join(', ')}`,
201
+ });
202
+ continue;
203
+ }
204
+ results.push({ selector: item.selector, fragment });
205
+ }
206
+ return { results, violations };
207
+ }
208
+ function defaultStateDir() {
209
+ return join(homedir(), '.wicked-crew');
210
+ }
211
+ /** The production council roster, resolved lazily through the adapter's own class so this module
212
+ * never imports the native addon at runtime (unit tests pass `clisJson` and a fake adapter). */
213
+ function rosterOf(adapter) {
214
+ return adapter.constructor.roster();
215
+ }
216
+ /**
217
+ * Arm the seam: register the `interactive-edit` workflow, open a durable
218
+ * `wicked.interactive.feedback.processed` subscription, and answer each handoff carrying
219
+ * structural items with a governed run that ends in `wicked.interactive.edit.completed`.
220
+ *
221
+ * Graceful degradation mirrors the draft seam: a missing wicked-bus package or an unopenable
222
+ * db LOGS and returns `null` — the daemon must still boot on a machine whose bus is broken;
223
+ * interactive's assist loop remains the (always-available) fallback answerer.
224
+ */
225
+ export async function startInteractiveEditSubscriber(adapter, opts = {}) {
226
+ const log = opts.log ?? ((m) => console.error(m));
227
+ let bus;
228
+ try {
229
+ bus = await import('wicked-bus');
230
+ }
231
+ catch (err) {
232
+ log(`[interactive-edit] wicked-bus is not importable — governed structural edits disabled: ${err instanceof Error ? err.message : String(err)}`);
233
+ return null;
234
+ }
235
+ let db;
236
+ let config;
237
+ try {
238
+ config = bus.loadConfig(opts.dbPath !== undefined ? { db_path: opts.dbPath } : {});
239
+ db = bus.openDb(opts.dbPath !== undefined ? { db_path: opts.dbPath } : {});
240
+ }
241
+ catch (err) {
242
+ log(`[interactive-edit] could not open the bus db${opts.dbPath !== undefined ? ` at ${opts.dbPath}` : ''} — governed structural edits disabled: ${err instanceof Error ? err.message : String(err)}`);
243
+ return null;
244
+ }
245
+ // The workflow rides the normal registration path — core validates the def BEFORE it is
246
+ // persisted/hot-registered (FINDING-002 ordering), so a drifted def fails the arm loudly
247
+ // instead of failing the first launch obscurely.
248
+ try {
249
+ await adapter.registerWorkflow(INTERACTIVE_EDIT_WORKFLOW_DEF);
250
+ }
251
+ catch (err) {
252
+ log(`[interactive-edit] could not register the '${INTERACTIVE_EDIT_WORKFLOW}' workflow — ` +
253
+ `governed structural edits disabled: ${err instanceof Error ? err.message : String(err)}`);
254
+ return null;
255
+ }
256
+ const ledger = new InteractiveHandoffLedger(opts.ledgerPath ?? join(defaultStateDir(), 'interactive-edit-ledger.json'));
257
+ const editDir = opts.editDir ?? join(defaultStateDir(), 'interactive-edits');
258
+ const heartbeatMs = opts.heartbeatMs ?? 15_000;
259
+ const inFlight = new Map(); // runId → live state
260
+ /** Emit onto interactive's vocabulary as the `wi-crew` producer. Never throws into the
261
+ * caller: narration/announce failures are logged — a lost status line must not kill the
262
+ * subscription, and a duplicate edit emit (WB-002) is the idempotency key WORKING. */
263
+ function emitInteractive(type, payload, idempotencyKey) {
264
+ try {
265
+ bus.emit(db, config, {
266
+ event_type: type,
267
+ domain: INTERACTIVE_DOMAIN,
268
+ subdomain: type === EDIT_COMPLETED ? 'feedback' : 'status',
269
+ payload: { ts: new Date().toISOString(), ...payload },
270
+ producer_id: INTERACTIVE_PRODUCER,
271
+ ...(idempotencyKey !== undefined ? { idempotency_key: idempotencyKey } : {}),
272
+ });
273
+ return true;
274
+ }
275
+ catch (err) {
276
+ const code = err.error;
277
+ if (code === 'WB-002') {
278
+ // Duplicate idempotency key — the emit already happened (redelivery race). Success.
279
+ return true;
280
+ }
281
+ log(`[interactive-edit] emit ${type} failed: ${err instanceof Error ? err.message : String(err)}`);
282
+ return false;
283
+ }
284
+ }
285
+ function narrate(flight, message) {
286
+ flight.narration = message;
287
+ emitInteractive(STATUS_POSTED, {
288
+ document_id: flight.documentId,
289
+ version: flight.version,
290
+ state: 'working',
291
+ message,
292
+ });
293
+ }
294
+ function endFlight(runId) {
295
+ const flight = inFlight.get(runId);
296
+ if (flight) {
297
+ clearInterval(flight.heartbeat);
298
+ inFlight.delete(runId);
299
+ }
300
+ return flight;
301
+ }
302
+ /** Terminal-event fold: turn the governed run's own events into interactive narration, and
303
+ * close the loop with `edit.completed` when the run lands AND the self-check passes. */
304
+ const offCoreEvents = adapter.onEvent((event) => {
305
+ const runId = typeof event.session === 'string' ? event.session : undefined;
306
+ if (runId === undefined)
307
+ return;
308
+ const flight = inFlight.get(runId);
309
+ if (flight === undefined)
310
+ return;
311
+ // Narration ladder — same rationale as the draft fold: the heartbeat repeats the LATEST
312
+ // line and the transcript dedups repeats, so advancing the line = visible progress.
313
+ const blocks = flight.items.length === 1 ? 'the targeted block' : `${flight.items.length} targeted blocks`;
314
+ if (event.type === 'councilConvened') {
315
+ const seats = Array.isArray(event.clis) ? event.clis.length : 0;
316
+ // "0-seat council" reads like a bug — generic phrasing whenever clis is missing or empty
317
+ // (Copilot, #269).
318
+ const council = seats > 0 ? `a ${seats}-seat council` : 'a council';
319
+ narrate(flight, `Convening ${council} to pick who reworks ${blocks}…`);
320
+ return;
321
+ }
322
+ if (event.type === 'unitDistributed') {
323
+ const who = typeof event.cli === 'string' ? event.cli : 'a worker';
324
+ const pct = typeof event.agreement_pct === 'number' ? ` (${event.agreement_pct}% agreement)` : '';
325
+ narrate(flight, `Council picked ${who} to rework ${blocks}${pct}…`);
326
+ return;
327
+ }
328
+ if (event.type === 'unitDispatched') {
329
+ narrate(flight, `Crew is reworking ${blocks}…`);
330
+ return;
331
+ }
332
+ if (event.type === 'toolInvoked') {
333
+ const tools = Array.isArray(event.tools) ? [...new Set(event.tools)].join(', ') : '';
334
+ if (tools)
335
+ narrate(flight, `Worker is using ${tools} on ${blocks}…`);
336
+ return;
337
+ }
338
+ if (event.type === 'unitOutputCaptured') {
339
+ narrate(flight, `Rework finished — the governance gate is reviewing it…`);
340
+ return;
341
+ }
342
+ if (event.type === 'gateDecided' && event.allow === true) {
343
+ narrate(flight, 'Gate approved the edit — landing the new version now…');
344
+ return;
345
+ }
346
+ if (event.type === 'acpFallback') {
347
+ const who = typeof event.cliKey === 'string' ? event.cliKey : 'the worker';
348
+ narrate(flight, `${who}'s live session dropped — continuing in single-shot mode…`);
349
+ return;
350
+ }
351
+ if (event.type === 'sessionCompleted') {
352
+ endFlight(runId);
353
+ finalize(flight, runId);
354
+ return;
355
+ }
356
+ if (event.type === 'sessionFailed' || event.type === 'runCancelled') {
357
+ endFlight(runId);
358
+ ledger.recordFailure(flight.key);
359
+ emitInteractive(STATUS_POSTED, {
360
+ document_id: flight.documentId,
361
+ version: flight.version,
362
+ state: 'error',
363
+ message: `The crew run answering this edit ${event.type === 'runCancelled' ? 'was cancelled' : 'failed'} ` +
364
+ `(run ${runId}). Inspect it via the crew API (GET /api/v1/runs/${runId}); the assist loop can still take over.`,
365
+ });
366
+ log(`[interactive-edit] run ${runId} for handoff ${flight.key} ended: ${event.type}`);
367
+ }
368
+ });
369
+ function finalize(flight, runId) {
370
+ const { documentId, version, key, items } = flight;
371
+ // The deterministic pre-emit self-check (INV-2 at scale): a violating fragment would be
372
+ // rejected SILENTLY by the service (regenerate.js Inv2Error) — the user's edit would just
373
+ // die. Fail honest here instead: error status, failure row, no emit.
374
+ const { results, violations } = collectEditResults(items);
375
+ if (violations.length > 0) {
376
+ ledger.recordFailure(key);
377
+ const detail = violations.map((v) => `${v.selector}: ${v.reason}`).join('; ');
378
+ emitInteractive(STATUS_POSTED, {
379
+ document_id: documentId,
380
+ version,
381
+ state: 'error',
382
+ message: `The crew's edit failed its pre-emit self-check and was NOT applied — ${detail} ` +
383
+ `(run ${runId}). The document is unchanged; resubmit the edit or let the assist loop take over.`,
384
+ });
385
+ log(`[interactive-edit] run ${runId} rejected by self-check for ${key}: ${detail}`);
386
+ return;
387
+ }
388
+ // Announce with the handoff's version (the parent the service forks from) and the
389
+ // deterministic doc+version key — a re-announce is a WB-002 no-op.
390
+ const emitted = emitInteractive(EDIT_COMPLETED, { document_id: documentId, version, results }, editIdempotencyKey(documentId, version));
391
+ if (!emitted) {
392
+ // The bus refused the announce (non-WB-002): the edit exists on disk but never reached
393
+ // the service. Fail HONEST — leaving the ledger row launched-but-never-closed would
394
+ // silently eat every replay of this handoff (the launch gate is `ledger.has`).
395
+ ledger.recordFailure(key);
396
+ emitInteractive(STATUS_POSTED, {
397
+ document_id: documentId,
398
+ version,
399
+ state: 'error',
400
+ message: `Crew finished the edit but could not announce it on the bus (run ${runId}); ` +
401
+ `the document is unchanged. Inspect the crew daemon log, then resubmit the edit.`,
402
+ });
403
+ log(`[interactive-edit] edit.completed emit FAILED for ${key} (run ${runId}) — recorded as failure`);
404
+ return;
405
+ }
406
+ ledger.recordEmitted(key);
407
+ emitInteractive(STATUS_POSTED, {
408
+ document_id: documentId,
409
+ version,
410
+ state: 'complete',
411
+ message: 'Edit is in — landing the new version on the canvas now.',
412
+ });
413
+ log(`[interactive-edit] edit.completed emitted for ${key} (run ${runId}, ${results.length} fragment(s))`);
414
+ }
415
+ async function handleFeedbackProcessed(event) {
416
+ const handoff = parseStructuralFeedback(event.event_type, event.payload);
417
+ if (handoff === null)
418
+ return;
419
+ const key = handoffKey(handoff.documentId, handoff.version);
420
+ // Replay-dedup: the ledger is the durable gate (redelivery after crash/restart), the
421
+ // in-flight scan the live one (redelivery inside a single process lifetime). Keyed by
422
+ // HANDOFF — a later feedback batch on the same doc is a new key and launches normally.
423
+ if (ledger.has(key)) {
424
+ log(`[interactive-edit] handoff ${key} already answered (run ${ledger.get(key)?.runId}) — replay ignored`);
425
+ return;
426
+ }
427
+ for (const f of inFlight.values()) {
428
+ if (f.key === key)
429
+ return;
430
+ }
431
+ const outDir = join(editDir, key.replace(':', '-'));
432
+ mkdirSync(outDir, { recursive: true });
433
+ const items = handoffFileItems(handoff, outDir);
434
+ const handoffPath = join(editDir, `${key.replace(':', '-')}-handoff.json`);
435
+ writeFileSync(handoffPath, JSON.stringify({ document_id: handoff.documentId, version: handoff.version, items }, null, 2), 'utf8');
436
+ const runId = randomUUID();
437
+ emitInteractive(STATUS_POSTED, {
438
+ document_id: handoff.documentId,
439
+ version: handoff.version,
440
+ state: 'processing',
441
+ message: `A governed crew picked up your edit — reworking ${items.length === 1 ? 'the block' : `${items.length} blocks`}…`,
442
+ });
443
+ try {
444
+ const input = {
445
+ problem: editProblem(handoff, handoffPath),
446
+ sessionId: runId,
447
+ clisJson: opts.clisJson ?? JSON.stringify(rosterOf(adapter)),
448
+ workflow: INTERACTIVE_EDIT_WORKFLOW,
449
+ // The 7b surface: a project-bound doc's governed edits are FILED — the run lands in
450
+ // the project's activity feed instead of floating unattributed.
451
+ ...(handoff.projectId !== undefined ? { projectId: handoff.projectId } : {}),
452
+ // The task names the handoff JSON + per-block output files under `editDir`, which sits
453
+ // OUTSIDE the unit's sandbox — the wrapped-CLI boundary would deny both the reads and
454
+ // the deliverable writes (crew#263, same shape as the draft path). One declared root
455
+ // covers both: write roots are readable (wicked-core#259).
456
+ extraWriteRoots: [editDir],
457
+ };
458
+ await adapter.launchRun(input);
459
+ }
460
+ catch (err) {
461
+ // The 'processing' status is already on the thread — close it out honestly so the
462
+ // canvas never sits in an in-between state on a launch that went nowhere.
463
+ const reason = err instanceof Error ? err.message : String(err);
464
+ emitInteractive(STATUS_POSTED, {
465
+ document_id: handoff.documentId,
466
+ version: handoff.version,
467
+ state: 'error',
468
+ message: `Crew could not start a run for this edit: ${reason}. The assist loop can still take over.`,
469
+ });
470
+ // DELIBERATELY no ledger write: only an answered handoff earns a row, so an operator can
471
+ // replay the dead-lettered feedback.processed after fixing the daemon and get a real
472
+ // retry. Re-throw so the bus (maxRetries 0) dead-letters the frame — visible, replayable,
473
+ // and incapable of hot-looping.
474
+ throw err;
475
+ }
476
+ // Record AFTER the launch resolved: a failed launch leaves no ledger row, so a replayed
477
+ // delivery retries. The crash window between launch and this write is the reason the
478
+ // edit emit ALSO carries a deterministic idempotency key.
479
+ ledger.recordLaunch(key, runId);
480
+ if (handoff.projectId !== undefined)
481
+ opts.onRunFiled?.(runId, handoff.projectId);
482
+ const flight = {
483
+ key,
484
+ documentId: handoff.documentId,
485
+ version: handoff.version,
486
+ items,
487
+ narration: 'Crew run launched — working on your edit…',
488
+ heartbeat: setInterval(() => {
489
+ // Repeat the last real narration so the ~20s status.requested window is always fed,
490
+ // even mid-phase when the engine is quiet.
491
+ emitInteractive(STATUS_POSTED, {
492
+ document_id: flight.documentId,
493
+ version: flight.version,
494
+ state: 'working',
495
+ message: flight.narration,
496
+ });
497
+ }, heartbeatMs),
498
+ // Do not keep the daemon alive for narration alone.
499
+ };
500
+ flight.heartbeat.unref?.();
501
+ inFlight.set(runId, flight);
502
+ log(`[interactive-edit] handoff ${key} → governed run ${runId} (${items.length} item(s), handoff ${handoffPath})`);
503
+ }
504
+ const sub = bus.subscribe({
505
+ db,
506
+ plugin: INTERACTIVE_EDIT_BUS_PLUGIN,
507
+ filter: INTERACTIVE_EDIT_BUS_FILTER,
508
+ // Live triggers only: replaying a bus backlog would answer handoffs whose edits the assist
509
+ // loop long since produced. History reconciliation belongs to the state plane, not here.
510
+ cursor_init: 'latest',
511
+ pollIntervalMs: opts.pollIntervalMs ?? 2000,
512
+ // Our own ledger + idempotency key are the dedupe; a bus-level retry of a failed launch
513
+ // would double-launch precisely because the ledger row is only written on success.
514
+ maxRetries: 0,
515
+ handler: (event) => handleFeedbackProcessed(event),
516
+ onError: (err, event) => {
517
+ log(`[interactive-edit] handler error on event ${String(event?.event_id ?? '?')}: ${err.message}`);
518
+ },
519
+ });
520
+ return {
521
+ ledger,
522
+ stop: async () => {
523
+ offCoreEvents();
524
+ for (const runId of [...inFlight.keys()])
525
+ endFlight(runId);
526
+ await sub.stop();
527
+ },
528
+ };
529
+ }
530
+ //# sourceMappingURL=edit-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-events.js","sourceRoot":"","sources":["../../src/interactive/edit-events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Durable handoff ledger shared by crew's wicked-interactive seams (task #86, Phase 7c).
3
+ *
4
+ * Extracted from the draft leg (draft-events.ts, PR #241) when the structural-edit leg arrived,
5
+ * because both seams need the same replay-dedup discipline with DIFFERENT key grammars:
6
+ *
7
+ * - the DRAFT leg keys by document id — one first draft per document lifetime;
8
+ * - the EDIT leg keys by `<doc>:v<version>` — one governed edit per HANDOFF, because the same
9
+ * document legitimately produces many structural handoffs over its life (versioned targeting).
10
+ *
11
+ * The ledger itself is key-agnostic: a durable map `key → HandoffLedgerEntry`, JSON on disk,
12
+ * written atomically (tmp + rename). The bus cursor alone cannot carry this: at-least-once
13
+ * delivery means the same trigger can arrive again after a crash between handling and cursor
14
+ * advance, and in-memory state dies with the process. The ledger is the system of record for
15
+ * "this handoff was answered"; each seam's in-flight map is just the live half.
16
+ */
17
+ /** One ledger row — the lifecycle of a handoff a seam answered. */
18
+ export interface HandoffLedgerEntry {
19
+ runId: string;
20
+ launchedAt: string;
21
+ /** Set once the closing event (draft.completed / edit.completed) was emitted. */
22
+ emittedAt?: string;
23
+ /** Set when the governed run ended without a usable result; kept so a redelivered trigger
24
+ * does not silently relaunch a run an operator should look at first. */
25
+ failedAt?: string;
26
+ }
27
+ export declare class InteractiveHandoffLedger {
28
+ private readonly path;
29
+ private entries;
30
+ constructor(path: string);
31
+ has(key: string): boolean;
32
+ get(key: string): HandoffLedgerEntry | undefined;
33
+ recordLaunch(key: string, runId: string): void;
34
+ recordEmitted(key: string): void;
35
+ recordFailure(key: string): void;
36
+ size(): number;
37
+ private persist;
38
+ }
39
+ //# sourceMappingURL=ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/interactive/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;6EACyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,OAAO,CAAqC;gBAExC,IAAI,EAAE,MAAM;IAuCxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIhD,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK9C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQhC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQhC,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,OAAO;CAMhB"}