wicked-crew 0.8.1 → 0.8.2

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 (91) hide show
  1. package/dist/api/ask-paths.d.ts +90 -0
  2. package/dist/api/ask-paths.d.ts.map +1 -0
  3. package/dist/api/ask-paths.js +145 -0
  4. package/dist/api/ask-paths.js.map +1 -0
  5. package/dist/api/ask-relay.d.ts +150 -0
  6. package/dist/api/ask-relay.d.ts.map +1 -0
  7. package/dist/api/ask-relay.js +601 -0
  8. package/dist/api/ask-relay.js.map +1 -0
  9. package/dist/api/chat-scope.d.ts +25 -2
  10. package/dist/api/chat-scope.d.ts.map +1 -1
  11. package/dist/api/chat-scope.js +47 -4
  12. package/dist/api/chat-scope.js.map +1 -1
  13. package/dist/api/diagnostics.d.ts +5 -2
  14. package/dist/api/diagnostics.d.ts.map +1 -1
  15. package/dist/api/diagnostics.js +7 -3
  16. package/dist/api/diagnostics.js.map +1 -1
  17. package/dist/api/eval-sample.d.ts +12 -12
  18. package/dist/api/mcp.d.ts +10 -10
  19. package/dist/api/plan-schema.d.ts +14 -0
  20. package/dist/api/plan-schema.d.ts.map +1 -1
  21. package/dist/api/plan-schema.js +4 -0
  22. package/dist/api/plan-schema.js.map +1 -1
  23. package/dist/api/recording.d.ts +30 -1
  24. package/dist/api/recording.d.ts.map +1 -1
  25. package/dist/api/recording.js +54 -6
  26. package/dist/api/recording.js.map +1 -1
  27. package/dist/api/roster-standing.d.ts.map +1 -1
  28. package/dist/api/roster-standing.js +6 -2
  29. package/dist/api/roster-standing.js.map +1 -1
  30. package/dist/api/routes.d.ts +144 -14
  31. package/dist/api/routes.d.ts.map +1 -1
  32. package/dist/api/routes.js +341 -202
  33. package/dist/api/routes.js.map +1 -1
  34. package/dist/api/seat-standing.d.ts +9 -1
  35. package/dist/api/seat-standing.d.ts.map +1 -1
  36. package/dist/api/seat-standing.js +27 -1
  37. package/dist/api/seat-standing.js.map +1 -1
  38. package/dist/api/server.d.ts +5 -0
  39. package/dist/api/server.d.ts.map +1 -1
  40. package/dist/api/server.js +76 -5
  41. package/dist/api/server.js.map +1 -1
  42. package/dist/api/testing.d.ts +4 -4
  43. package/dist/campaigns/routes.d.ts +2 -2
  44. package/dist/cli/index.d.ts.map +1 -1
  45. package/dist/cli/index.js +9 -3
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/core/adapter.d.ts +1 -0
  48. package/dist/core/adapter.d.ts.map +1 -1
  49. package/dist/core/adapter.js +8 -0
  50. package/dist/core/adapter.js.map +1 -1
  51. package/dist/core/bridge-reaper.d.ts +50 -7
  52. package/dist/core/bridge-reaper.d.ts.map +1 -1
  53. package/dist/core/bridge-reaper.js +242 -42
  54. package/dist/core/bridge-reaper.js.map +1 -1
  55. package/dist/core/types.d.ts +2 -0
  56. package/dist/core/types.d.ts.map +1 -1
  57. package/dist/core/types.js.map +1 -1
  58. package/dist/decisions/chat-recorder.d.ts +18 -0
  59. package/dist/decisions/chat-recorder.d.ts.map +1 -1
  60. package/dist/decisions/chat-recorder.js +107 -14
  61. package/dist/decisions/chat-recorder.js.map +1 -1
  62. package/dist/decisions/consider.d.ts +13 -0
  63. package/dist/decisions/consider.d.ts.map +1 -1
  64. package/dist/decisions/consider.js +20 -4
  65. package/dist/decisions/consider.js.map +1 -1
  66. package/dist/interactive/bridge-pool.d.ts.map +1 -1
  67. package/dist/interactive/bridge-pool.js +3 -2
  68. package/dist/interactive/bridge-pool.js.map +1 -1
  69. package/dist/interactive/draft-events.d.ts +28 -1
  70. package/dist/interactive/draft-events.d.ts.map +1 -1
  71. package/dist/interactive/draft-events.js +79 -17
  72. package/dist/interactive/draft-events.js.map +1 -1
  73. package/dist/interactive/draft-skill.d.ts.map +1 -1
  74. package/dist/interactive/draft-skill.js +24 -6
  75. package/dist/interactive/draft-skill.js.map +1 -1
  76. package/dist/interactive/review-events.d.ts +1 -1
  77. package/dist/interactive/review-events.d.ts.map +1 -1
  78. package/dist/interactive/review-events.js +4 -2
  79. package/dist/interactive/review-events.js.map +1 -1
  80. package/dist/studio/assets/index-CGjbTpLl.css +32 -0
  81. package/dist/studio/assets/index-DRybGZtf.js +580 -0
  82. package/dist/studio/editors/wicked-page/editor.json +1 -1
  83. package/dist/studio/editors/wicked-page/index.html +1 -1
  84. package/dist/studio/index.html +2 -2
  85. package/dist/studio/testid-inventory.json +112 -4
  86. package/dist/team/routes.d.ts +38 -0
  87. package/dist/team/routes.d.ts.map +1 -1
  88. package/endpoint-manifest.json +1 -1
  89. package/package.json +3 -3
  90. package/dist/studio/assets/index-D9cD_lY1.js +0 -580
  91. package/dist/studio/assets/index-DEBAWrq3.css +0 -32
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The daemon's record of each chat's ASK PATH (DES-ASK-TEAM-CHAT-001 §5.1): who was eligible when
3
+ * the chat opened, the seat the operator chose (if any), and — once the first message launched it —
4
+ * the run the conversation IS and the answer steps it has added. In memory, like the chat scope
5
+ * index it sits beside: a chat is a session of this daemon; the run and its transcript are durable.
6
+ *
7
+ * Crew owns ELIGIBILITY and the launch COMMAND; the engine owns the PICK (`path.started.cli`,
8
+ * `selection`) and every fact after it. `pa` here is what this daemon has seen of the engine's
9
+ * pick (the relay fills it from `path.started`; a chosen seat is known at once).
10
+ */
11
+ export interface AskPath {
12
+ chatId: string;
13
+ /** Seats admitted to the chat at open (signed in, not benched, allowed for the scope). */
14
+ eligible: string[];
15
+ /** The operator's choice, one of `eligible`; `undefined` ⇒ the engine picks at random. */
16
+ primary?: string;
17
+ /** The run the conversation is, once the first message launched it. */
18
+ runId?: string;
19
+ /** A message of this chat is in flight on this daemon — launching the run or continuing it
20
+ * (status read → proposal → approval) — so a second one meanwhile is `turn_in_flight`. */
21
+ busy?: boolean;
22
+ /** Bumped on open; a launch that resolves after the chat was closed and reopened must not
23
+ * attach its run to the newcomer. */
24
+ generation: number;
25
+ /** The answer steps added so far (`answer-1`, `answer-2`, …). */
26
+ steps: string[];
27
+ /** The engine's pick as this daemon has seen it. */
28
+ pa: string | null;
29
+ selection: 'chosen' | 'random';
30
+ reviewer: string | null;
31
+ helpers: string[];
32
+ }
33
+ export declare class AskPathIndex {
34
+ private readonly paths;
35
+ /** Per chat id, across closes — a close-and-reopen must read as a NEW generation. */
36
+ private readonly generations;
37
+ /** Record an opened chat's eligibility and the operator's choice. */
38
+ open(chatId: string, eligible: readonly string[], primary?: string): AskPath;
39
+ get(chatId: string): AskPath | undefined;
40
+ /** The chat a run was launched from, if it is an ask path of this daemon. */
41
+ chatOf(runId: string): string | undefined;
42
+ private nextGeneration;
43
+ /** Reserve the chat for one message (a launch or a continuation): the lease (the chat's
44
+ * generation) to hand back to {@link release}; `null` when a message is in flight. */
45
+ reserve(chatId: string): number | null;
46
+ /** Give a lease back — only the generation that holds it (codex on #808 r2, 1: a request of a
47
+ * closed-and-reopened chat must not free the newcomer's reservation). */
48
+ release(chatId: string, lease: number): void;
49
+ /** The first message launched the run; `stepId` is its answer step. False when the chat was
50
+ * closed (or closed and reopened) while the launch was in flight: the caller cancels the run. */
51
+ started(chatId: string, generation: number, runId: string, stepId: string): boolean;
52
+ /** A later message added an answer step. Returns the new step id. */
53
+ /** A message of this chat is in flight right now (launching or continuing). */
54
+ busy(chatId: string): boolean;
55
+ /** The continuation the engine accepted landed on the chat: records the step — only on the
56
+ * generation that holds the lease (codex on #808 r3, 2: a continuation of a closed-and-reopened
57
+ * chat must not write into the newcomer's record). */
58
+ continued(chatId: string, lease: number, stepId: string): boolean;
59
+ /** The id the NEXT answer step takes (`answer-N`); nothing is recorded until {@link continued}. */
60
+ nextStep(chatId: string): string;
61
+ /** A re-seat: the named seats are eligible (a sign-in fixed). */
62
+ admit(chatId: string, seats: readonly string[]): string[];
63
+ /** What the relay learned from the run's `path.started` / `member.joined` / `help.answered`. */
64
+ observe(runId: string, fact: {
65
+ pa?: string;
66
+ selection?: 'chosen' | 'random';
67
+ reviewer?: string | null;
68
+ helper?: string;
69
+ }): void;
70
+ /** Every chat this daemon holds a path record for (`GET /chats`). */
71
+ list(): AskPath[];
72
+ close(chatId: string): AskPath | undefined;
73
+ /** The wire view (`ChatDetailResponse.path`). */
74
+ view(chatId: string): {
75
+ runId: string;
76
+ pa: string | null;
77
+ selection: 'chosen' | 'random';
78
+ reviewer: string | null;
79
+ helpers: string[];
80
+ stepId: string;
81
+ } | undefined;
82
+ }
83
+ /** The one answer step shape an ask adds per message (DES-ASK-TEAM-CHAT-001 §3, §4.4). */
84
+ export declare const ASK_TURN_BUDGET_SECS = 600;
85
+ export declare function answerStep(stepId: string, text: string): {
86
+ catalog: string;
87
+ id: string;
88
+ [k: string]: unknown;
89
+ };
90
+ //# sourceMappingURL=ask-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-paths.d.ts","sourceRoot":"","sources":["../../src/api/ask-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;+FAC2F;IAC3F,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;0CACsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8B;IACpD,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,qEAAqE;IACrE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAkB5E,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIxC,6EAA6E;IAC7E,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKzC,OAAO,CAAC,cAAc;IAMtB;2FACuF;IACvF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOtC;8EAC0E;IAC1E,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5C;sGACkG;IAClG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IASnF,qEAAqE;IACrE,+EAA+E;IAC/E,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI7B;;2DAEuD;IACvD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAOjE,mGAAmG;IACnG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAMhC,iEAAiE;IACjE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE;IAOzD,gGAAgG;IAChG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAU/H,qEAAqE;IACrE,IAAI,IAAI,OAAO,EAAE;IAIjB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAM1C,iDAAiD;IACjD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;CAYnK;AAED,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAQ9G"}
@@ -0,0 +1,145 @@
1
+ export class AskPathIndex {
2
+ paths = new Map();
3
+ /** Per chat id, across closes — a close-and-reopen must read as a NEW generation. */
4
+ generations = new Map();
5
+ /** Record an opened chat's eligibility and the operator's choice. */
6
+ open(chatId, eligible, primary) {
7
+ const path = {
8
+ chatId,
9
+ eligible: [...eligible],
10
+ ...(primary !== undefined ? { primary } : {}),
11
+ steps: [],
12
+ generation: this.nextGeneration(chatId),
13
+ // One eligible seat is a certain voice (the engine's random pick over a roster of one):
14
+ // the turn index and the transcript can name it before `path.started` lands.
15
+ pa: primary ?? (eligible.length === 1 ? eligible[0] : null),
16
+ selection: primary !== undefined ? 'chosen' : 'random',
17
+ reviewer: null,
18
+ helpers: [],
19
+ };
20
+ this.paths.set(chatId, path);
21
+ return path;
22
+ }
23
+ get(chatId) {
24
+ return this.paths.get(chatId);
25
+ }
26
+ /** The chat a run was launched from, if it is an ask path of this daemon. */
27
+ chatOf(runId) {
28
+ for (const p of this.paths.values())
29
+ if (p.runId === runId)
30
+ return p.chatId;
31
+ return undefined;
32
+ }
33
+ nextGeneration(chatId) {
34
+ const g = (this.generations.get(chatId) ?? 0) + 1;
35
+ this.generations.set(chatId, g);
36
+ return g;
37
+ }
38
+ /** Reserve the chat for one message (a launch or a continuation): the lease (the chat's
39
+ * generation) to hand back to {@link release}; `null` when a message is in flight. */
40
+ reserve(chatId) {
41
+ const p = this.paths.get(chatId);
42
+ if (p === undefined || p.busy === true)
43
+ return null;
44
+ p.busy = true;
45
+ return p.generation;
46
+ }
47
+ /** Give a lease back — only the generation that holds it (codex on #808 r2, 1: a request of a
48
+ * closed-and-reopened chat must not free the newcomer's reservation). */
49
+ release(chatId, lease) {
50
+ const p = this.paths.get(chatId);
51
+ if (p !== undefined && p.generation === lease)
52
+ p.busy = false;
53
+ }
54
+ /** The first message launched the run; `stepId` is its answer step. False when the chat was
55
+ * closed (or closed and reopened) while the launch was in flight: the caller cancels the run. */
56
+ started(chatId, generation, runId, stepId) {
57
+ const p = this.paths.get(chatId);
58
+ if (p === undefined || p.generation !== generation)
59
+ return false;
60
+ p.busy = false;
61
+ p.runId = runId;
62
+ p.steps.push(stepId);
63
+ return true;
64
+ }
65
+ /** A later message added an answer step. Returns the new step id. */
66
+ /** A message of this chat is in flight right now (launching or continuing). */
67
+ busy(chatId) {
68
+ return this.paths.get(chatId)?.busy === true;
69
+ }
70
+ /** The continuation the engine accepted landed on the chat: records the step — only on the
71
+ * generation that holds the lease (codex on #808 r3, 2: a continuation of a closed-and-reopened
72
+ * chat must not write into the newcomer's record). */
73
+ continued(chatId, lease, stepId) {
74
+ const p = this.paths.get(chatId);
75
+ if (p === undefined || p.generation !== lease)
76
+ return false;
77
+ p.steps.push(stepId);
78
+ return true;
79
+ }
80
+ /** The id the NEXT answer step takes (`answer-N`); nothing is recorded until {@link continued}. */
81
+ nextStep(chatId) {
82
+ const p = this.paths.get(chatId);
83
+ return `answer-${(p?.steps.length ?? 0) + 1}`;
84
+ }
85
+ /** A re-seat: the named seats are eligible (a sign-in fixed). */
86
+ admit(chatId, seats) {
87
+ const p = this.paths.get(chatId);
88
+ if (p === undefined)
89
+ return [];
90
+ for (const s of seats)
91
+ if (!p.eligible.includes(s))
92
+ p.eligible.push(s);
93
+ return [...p.eligible];
94
+ }
95
+ /** What the relay learned from the run's `path.started` / `member.joined` / `help.answered`. */
96
+ observe(runId, fact) {
97
+ const chatId = this.chatOf(runId);
98
+ const p = chatId !== undefined ? this.paths.get(chatId) : undefined;
99
+ if (p === undefined)
100
+ return;
101
+ if (fact.pa !== undefined)
102
+ p.pa = fact.pa;
103
+ if (fact.selection !== undefined)
104
+ p.selection = fact.selection;
105
+ if (fact.reviewer !== undefined)
106
+ p.reviewer = fact.reviewer;
107
+ if (fact.helper !== undefined && !p.helpers.includes(fact.helper))
108
+ p.helpers.push(fact.helper);
109
+ }
110
+ /** Every chat this daemon holds a path record for (`GET /chats`). */
111
+ list() {
112
+ return [...this.paths.values()];
113
+ }
114
+ close(chatId) {
115
+ const p = this.paths.get(chatId);
116
+ this.paths.delete(chatId);
117
+ return p;
118
+ }
119
+ /** The wire view (`ChatDetailResponse.path`). */
120
+ view(chatId) {
121
+ const p = this.paths.get(chatId);
122
+ if (p?.runId === undefined)
123
+ return undefined;
124
+ return {
125
+ runId: p.runId,
126
+ pa: p.pa,
127
+ selection: p.selection,
128
+ reviewer: p.reviewer,
129
+ helpers: [...p.helpers],
130
+ stepId: p.steps[p.steps.length - 1] ?? 'answer-1',
131
+ };
132
+ }
133
+ }
134
+ /** The one answer step shape an ask adds per message (DES-ASK-TEAM-CHAT-001 §3, §4.4). */
135
+ export const ASK_TURN_BUDGET_SECS = 600;
136
+ export function answerStep(stepId, text) {
137
+ return {
138
+ catalog: 'understand',
139
+ id: stepId,
140
+ gate: { human_confirm: { unconditional: true } },
141
+ budget_secs: ASK_TURN_BUDGET_SECS,
142
+ instructions: text,
143
+ };
144
+ }
145
+ //# sourceMappingURL=ask-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-paths.js","sourceRoot":"","sources":["../../src/api/ask-paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * DES-ASK-TEAM-CHAT-001 §5.2 (ASK-C2) — the ask relay, crew's READ side of an ask path.
3
+ *
4
+ * After ASK-C1 an ask is a team run: the PA answers in an `understand` step `answer-N`, and the
5
+ * engine publishes the run's unit frames (`unitDispatched`, `unitOutputDelta`, `unitOutputCaptured`,
6
+ * `unitDone`, …) and team rows (`wicked.team.*`) — none of them a chat frame. This relay is the ONE
7
+ * producer of chat frames for a path: it folds the answer unit's `unitOutputDelta` into
8
+ * `chatDelta{chat, cliKey:<PA>}` (live typing only) and folds one `chatReply{chat, cliKey:<PA>, text,
9
+ * ok, run_id, ord}` per answer unit whose text is the output the team row
10
+ * `step.completed{step_id:"answer-N"}.output_ref` names — read through the engine's `work_output` at
11
+ * the FOLD (`unitDone{ord}`), not at the row (the row is published by the worker before the actor
12
+ * folds; the record exists once the fold ran — §5.2 "when the text is readable, verified").
13
+ *
14
+ * The join is by ATTEMPT (codex on #810 r1, 2): `output_ref` is `unit:<run>:<ord>:<attempt>`, and the
15
+ * attempt the fold settles is the latest the engine dispatched for that ord (`unitDispatched`,
16
+ * `unitOutputDelta`, `unitOutputCaptured` all carry it) — a failed attempt's row never decides a
17
+ * successful retry. A fold whose row has not arrived (the bus poll is 2 s) waits for it; past
18
+ * `rowGraceMs` the reply is read from the record anyway, with `ok` from the engine's own
19
+ * `unitOutputCaptured.stepStatus` — the un-teamed run of §8 F7 publishes no team row at all, and its
20
+ * answer still arrives (r1, 5). A RUN-terminal frame with no fold (`sessionFailed{ord}`,
21
+ * `runCancelled`) ends the turn with `ok:false` (r1, 6); `stepFailed` / `unitDenied` are NOT
22
+ * terminal — the engine fails over (a re-pick re-dispatches the ord, §8 F2) or opens an escalation
23
+ * gate whose Approve re-dispatches it, and a failed run says so with `sessionFailed` (r2, 1).
24
+ *
25
+ * The PA: the team rows (`path.started`, `path.repicked`) are authoritative; the unit's assigned seat
26
+ * is the fallback while none has arrived, and the unit record is re-read on every new attempt (a
27
+ * re-pick re-dispatches the same ord on another seat — r1, 1). Control lines (`HELP:`, `PLAN+`,
28
+ * `PLAN <id>:`, `ADVICE <id>:`, `STEP <id>:`, `SCOPE`, `RISK`) are stripped from the displayed text
29
+ * (§4.7); a delta stream that disagrees with the record is overwritten by it (the transcript's
30
+ * `seat` record is written from the reply).
31
+ *
32
+ * Every frame goes through the server's event fold (`fold`), so the turn index stamps `turn_id`, the
33
+ * transcript persists the reply, the decision recorder and the citation verifier see what they saw
34
+ * for a pool chat, and /ws fans it out — unchanged consumers (§5.2, codex #4). Every await is
35
+ * followed by a re-check that the run still belongs to the chat (End forgets it — r1, 4). Crew
36
+ * publishes no bus row (T2 §7 assertion 4). The relay is in-memory: a daemon restart forgets which
37
+ * run is which chat (the ask-path index is in-memory too), so a path that outlives the daemon is
38
+ * read from the run view, not relayed.
39
+ */
40
+ import type { AskPathIndex } from './ask-paths.js';
41
+ import type { ChatTurnIndex } from './chat-turns.js';
42
+ import type { BusEvent } from '../core/bus.js';
43
+ import type { CoreEvent } from '../core/types.js';
44
+ /** A unit as the relay needs it (the run view's `WorkUnit`, narrowed). */
45
+ export interface RelayUnit {
46
+ id: string;
47
+ ord: number;
48
+ status: string;
49
+ assigned_cli: string | null;
50
+ /** The engine's persisted attempt counter for the unit (0-based), when the run view carries it:
51
+ * the durable half of the attempt boundary (codex on #810 r4, 2). */
52
+ last_attempt?: number;
53
+ }
54
+ export interface AskRelayDeps {
55
+ paths: AskPathIndex;
56
+ turns: ChatTurnIndex;
57
+ /** `Core::work_output(unit_id)` — the stored output of an approved unit, `null` when none. */
58
+ workOutput: (unitId: string) => Promise<string | null>;
59
+ /** The run's units (the run view) — resolved per (run, ord, attempt) and cached. */
60
+ units: (runId: string) => Promise<RelayUnit[]>;
61
+ /** Where frames go: the server's event fold (stamp → transcript → recorder → /ws). Not a bus
62
+ * publish — crew puts no row on the bus (tests/team-no-publish.test.ts). */
63
+ fold: (frame: CoreEvent) => void;
64
+ /** The voice of a turn was learned (a random pick, a re-pick): the decision recorder's audience
65
+ * follows the turn index's (r1, 7). */
66
+ recorderReconcile?: (chat: string, turnId: string, seats: readonly string[]) => void;
67
+ /** How long a fold waits for its `step.completed` row before the reply is read from the record
68
+ * anyway (the un-teamed run publishes none). Default 5 s. */
69
+ rowGraceMs?: number;
70
+ log?: (msg: string) => void;
71
+ }
72
+ /** The displayed text: every control line removed, surrounding blank lines trimmed. */
73
+ export declare function stripControlLines(text: string): string;
74
+ /** `unit:<run>:<ord>:<attempt>` → `{ord, attempt}`, or `null` for any other shape. */
75
+ export declare function refOf(ref: string): {
76
+ ord: number;
77
+ attempt: number;
78
+ } | null;
79
+ /** `unit:<run>:<ord>:<attempt>` → the ord, or `null` for any other shape. */
80
+ export declare function ordOfOutputRef(ref: string): number | null;
81
+ /** The step id an answer unit's id carries (`<run>:answer-N` → `answer-N`), or `null`. */
82
+ export declare function answerStepOf(runId: string, unitId: string): string | null;
83
+ export declare class AskRelay {
84
+ private readonly deps;
85
+ /** run → ord → attempt → the `step.completed` row. */
86
+ private readonly rows;
87
+ /** run → ord → the latest attempt the engine dispatched / streamed / captured. */
88
+ private readonly attempts;
89
+ /** run → ord → the engine's own status of the latest captured attempt (`unitOutputCaptured`). */
90
+ private readonly captured;
91
+ /** run → ord → the unit (id + seat), resolved lazily from the run view; re-read per attempt. */
92
+ private readonly units;
93
+ /** `${run}:${ord}` → a fold waiting for its row (bounded by `rowGraceMs`). */
94
+ private readonly waiting;
95
+ /** `${run}:${ord}` whose reply went out (or is going out) — exactly one per answer unit. */
96
+ private readonly replied;
97
+ /** `${run}:${ord}` → the partial last line of the delta stream (a control line may split). */
98
+ private readonly tails;
99
+ /** Runs a terminal frame has ended: no later fold, row, grace or read continuation may speak
100
+ * for them (codex on #810 r10, 2). */
101
+ private readonly ended;
102
+ /** `${run}:${ord}` whose reply was actually FOLDED (a reservation in `replied` may still be in
103
+ * flight — a terminal must speak for it, r11, 1). */
104
+ private readonly spoken;
105
+ private readonly rowGraceMs;
106
+ constructor(deps: AskRelayDeps);
107
+ private log;
108
+ /** A `teamEvent` frame's bus row (the team /ws relay hands every row here). */
109
+ onTeamRow(row: BusEvent | undefined): void;
110
+ /** A CoreEvent of the engine's stream — only the unit / terminal frames are read. */
111
+ onCoreEvent(event: CoreEvent): Promise<void>;
112
+ /** A fold with no row of its attempt yet: wait for the row (the bus poll is 2 s) — bounded by
113
+ * `rowGraceMs`, after which the reply is read from the record anyway. */
114
+ private awaitRow;
115
+ /** Forget a run (its chat closed). */
116
+ forget(runId: string): void;
117
+ private nested;
118
+ private nestedOne;
119
+ private noteAttempt;
120
+ /** The attempt the fold settles for (run, ord): the latest the engine's frames, the team rows or
121
+ * the unit's persisted counter named — one monotonic boundary (r3, 1); attempts are 0-based
122
+ * (r4, 1), so `undefined` = nothing has named one yet. */
123
+ private attemptOf;
124
+ /** Whether a frame labelled `attempt` belongs to an attempt the boundary has moved past. */
125
+ private superseded;
126
+ private rowFor;
127
+ private stopWaiting;
128
+ private learnPa;
129
+ /** The PA: the unit's seat for the CURRENT attempt (the cache is dropped per attempt, so a read
130
+ * unit is this attempt's — a re-pick shows here before its bus row does; r4, 3); the team rows
131
+ * (`path.started` / `path.repicked`) when the unit names no seat yet. */
132
+ private paOf;
133
+ /** `undefined`: a FRESH read failed — the durable record could not be certified (the caller
134
+ * must not answer from the cache; r6, 1). `null`: no such unit. */
135
+ private unit;
136
+ /** The complete lines of the stream so far, control lines removed; the partial tail is held. */
137
+ private deltaText;
138
+ /** ONE reply per answer unit: the key is reserved before the first await (r1, 8). */
139
+ private reply;
140
+ /** The seats a failure must be said for: the PA when the path knows it, else every seat the
141
+ * chat's live turns still wait on (the reserved audience of a random pick), else `pa`. */
142
+ private voicesFor;
143
+ /** The run view, retried a few times — a terminal fact must not be lost to one failed read. */
144
+ private unitsRetrying;
145
+ /** A terminal frame with no fold: the answer unit(s) still pending end the turn with `ok:false`.
146
+ * The run view is read with a bounded retry; if it still cannot be read, the turn is ended
147
+ * without the unit's facts rather than left pending (r8, 2). */
148
+ private terminal;
149
+ }
150
+ //# sourceMappingURL=ask-relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-relay.d.ts","sourceRoot":"","sources":["../../src/api/ask-relay.ts"],"names":[],"mappings":"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"}