@xenosystem/agent-interface-core 0.1.3

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 (122) hide show
  1. package/LICENSE +67 -0
  2. package/dist/agentDiscovery.d.ts +97 -0
  3. package/dist/agentDiscovery.d.ts.map +1 -0
  4. package/dist/agentDiscovery.js +93 -0
  5. package/dist/agentDiscovery.js.map +1 -0
  6. package/dist/capabilityRouting.d.ts +72 -0
  7. package/dist/capabilityRouting.d.ts.map +1 -0
  8. package/dist/capabilityRouting.js +124 -0
  9. package/dist/capabilityRouting.js.map +1 -0
  10. package/dist/capabilityTier.d.ts +105 -0
  11. package/dist/capabilityTier.d.ts.map +1 -0
  12. package/dist/capabilityTier.js +120 -0
  13. package/dist/capabilityTier.js.map +1 -0
  14. package/dist/combinationVerification.d.ts +101 -0
  15. package/dist/combinationVerification.d.ts.map +1 -0
  16. package/dist/combinationVerification.js +115 -0
  17. package/dist/combinationVerification.js.map +1 -0
  18. package/dist/context/agentAttachedContextPrompt.d.ts +13 -0
  19. package/dist/context/agentAttachedContextPrompt.d.ts.map +1 -0
  20. package/dist/context/agentAttachedContextPrompt.js +50 -0
  21. package/dist/context/agentAttachedContextPrompt.js.map +1 -0
  22. package/dist/context/agentModelContext.d.ts +77 -0
  23. package/dist/context/agentModelContext.d.ts.map +1 -0
  24. package/dist/context/agentModelContext.js +297 -0
  25. package/dist/context/agentModelContext.js.map +1 -0
  26. package/dist/fanOutPlanner.d.ts +65 -0
  27. package/dist/fanOutPlanner.d.ts.map +1 -0
  28. package/dist/fanOutPlanner.js +78 -0
  29. package/dist/fanOutPlanner.js.map +1 -0
  30. package/dist/fleetBoardProjection.d.ts +143 -0
  31. package/dist/fleetBoardProjection.d.ts.map +1 -0
  32. package/dist/fleetBoardProjection.js +156 -0
  33. package/dist/fleetBoardProjection.js.map +1 -0
  34. package/dist/fleetProjection.d.ts +63 -0
  35. package/dist/fleetProjection.d.ts.map +1 -0
  36. package/dist/fleetProjection.js +86 -0
  37. package/dist/fleetProjection.js.map +1 -0
  38. package/dist/hostBackedCapabilities.d.ts +50 -0
  39. package/dist/hostBackedCapabilities.d.ts.map +1 -0
  40. package/dist/hostBackedCapabilities.js +66 -0
  41. package/dist/hostBackedCapabilities.js.map +1 -0
  42. package/dist/index.d.ts +54 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +134 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/intakeBoardProjection.d.ts +75 -0
  47. package/dist/intakeBoardProjection.d.ts.map +1 -0
  48. package/dist/intakeBoardProjection.js +90 -0
  49. package/dist/intakeBoardProjection.js.map +1 -0
  50. package/dist/intakeClaim.d.ts +156 -0
  51. package/dist/intakeClaim.d.ts.map +1 -0
  52. package/dist/intakeClaim.js +190 -0
  53. package/dist/intakeClaim.js.map +1 -0
  54. package/dist/knowledgeBoardProjection.d.ts +57 -0
  55. package/dist/knowledgeBoardProjection.d.ts.map +1 -0
  56. package/dist/knowledgeBoardProjection.js +74 -0
  57. package/dist/knowledgeBoardProjection.js.map +1 -0
  58. package/dist/landingOverlap.d.ts +127 -0
  59. package/dist/landingOverlap.d.ts.map +1 -0
  60. package/dist/landingOverlap.js +107 -0
  61. package/dist/landingOverlap.js.map +1 -0
  62. package/dist/landingQueue.d.ts +152 -0
  63. package/dist/landingQueue.d.ts.map +1 -0
  64. package/dist/landingQueue.js +258 -0
  65. package/dist/landingQueue.js.map +1 -0
  66. package/dist/markdown/markdownWindowsPaths.d.ts +20 -0
  67. package/dist/markdown/markdownWindowsPaths.d.ts.map +1 -0
  68. package/dist/markdown/markdownWindowsPaths.js +208 -0
  69. package/dist/markdown/markdownWindowsPaths.js.map +1 -0
  70. package/dist/reviewProjection.d.ts +118 -0
  71. package/dist/reviewProjection.d.ts.map +1 -0
  72. package/dist/reviewProjection.js +133 -0
  73. package/dist/reviewProjection.js.map +1 -0
  74. package/dist/runDiff.d.ts +86 -0
  75. package/dist/runDiff.d.ts.map +1 -0
  76. package/dist/runDiff.js +103 -0
  77. package/dist/runDiff.js.map +1 -0
  78. package/dist/runtime/agentReasoningEffort.d.ts +22 -0
  79. package/dist/runtime/agentReasoningEffort.d.ts.map +1 -0
  80. package/dist/runtime/agentReasoningEffort.js +76 -0
  81. package/dist/runtime/agentReasoningEffort.js.map +1 -0
  82. package/dist/runtime/agentRuntimeProvider.d.ts +12 -0
  83. package/dist/runtime/agentRuntimeProvider.d.ts.map +1 -0
  84. package/dist/runtime/agentRuntimeProvider.js +294 -0
  85. package/dist/runtime/agentRuntimeProvider.js.map +1 -0
  86. package/dist/runtime/agentRuntimeProviderTypes.d.ts +100 -0
  87. package/dist/runtime/agentRuntimeProviderTypes.d.ts.map +1 -0
  88. package/dist/runtime/agentRuntimeProviderTypes.js +2 -0
  89. package/dist/runtime/agentRuntimeProviderTypes.js.map +1 -0
  90. package/dist/runtime/conversationRuntime.d.ts +53 -0
  91. package/dist/runtime/conversationRuntime.d.ts.map +1 -0
  92. package/dist/runtime/conversationRuntime.js +207 -0
  93. package/dist/runtime/conversationRuntime.js.map +1 -0
  94. package/dist/runtime/legacyAgentRuntimeEvents.d.ts +65 -0
  95. package/dist/runtime/legacyAgentRuntimeEvents.d.ts.map +1 -0
  96. package/dist/runtime/legacyAgentRuntimeEvents.js +104 -0
  97. package/dist/runtime/legacyAgentRuntimeEvents.js.map +1 -0
  98. package/dist/runtimeProjection.d.ts +19 -0
  99. package/dist/runtimeProjection.d.ts.map +1 -0
  100. package/dist/runtimeProjection.js +133 -0
  101. package/dist/runtimeProjection.js.map +1 -0
  102. package/dist/sessionBoardProjection.d.ts +84 -0
  103. package/dist/sessionBoardProjection.d.ts.map +1 -0
  104. package/dist/sessionBoardProjection.js +103 -0
  105. package/dist/sessionBoardProjection.js.map +1 -0
  106. package/dist/sessionMode.d.ts +115 -0
  107. package/dist/sessionMode.d.ts.map +1 -0
  108. package/dist/sessionMode.js +98 -0
  109. package/dist/sessionMode.js.map +1 -0
  110. package/dist/workspace/workspaceSelectionContinuation.d.ts +8 -0
  111. package/dist/workspace/workspaceSelectionContinuation.d.ts.map +1 -0
  112. package/dist/workspace/workspaceSelectionContinuation.js +18 -0
  113. package/dist/workspace/workspaceSelectionContinuation.js.map +1 -0
  114. package/dist/workspaceKnowledge.d.ts +90 -0
  115. package/dist/workspaceKnowledge.d.ts.map +1 -0
  116. package/dist/workspaceKnowledge.js +103 -0
  117. package/dist/workspaceKnowledge.js.map +1 -0
  118. package/dist/writeLease.d.ts +92 -0
  119. package/dist/writeLease.d.ts.map +1 -0
  120. package/dist/writeLease.js +108 -0
  121. package/dist/writeLease.js.map +1 -0
  122. package/package.json +29 -0
@@ -0,0 +1,258 @@
1
+ /**
2
+ * The serialised path to trunk — §5.7's landing queue.
3
+ *
4
+ * Overlap detection says two runs collided. Combination verification says
5
+ * whether the union was checked. Neither of them *sequences* anything, and
6
+ * sequencing is the part that makes the other two mean something: if two runs
7
+ * can land concurrently, the combination each of them verified was not the
8
+ * combination that landed, and the gate is decorative.
9
+ *
10
+ * Pure, and deliberately so. Everything here is a decision about what may land
11
+ * next; running the checks and moving the git refs are side effects that belong
12
+ * to the host. A rule that migrates into the executor stops being testable —
13
+ * that is the split `updaterPolicy.ts` already uses in this repo, for the same
14
+ * reason.
15
+ *
16
+ * ## 🔴 One lands at a time, and that is the whole design
17
+ *
18
+ * The queue admits **one** run to `landing` at a time. Not for throughput and
19
+ * not for tidiness: a verification result is bound to a fingerprint of the
20
+ * accepted set, and a second run landing in parallel changes that set. Both
21
+ * runs would then be landing against a combination neither verified — which is
22
+ * exactly the merge-debt failure this pillar exists to answer, arrived at
23
+ * through the mechanism built to prevent it.
24
+ *
25
+ * ## Accepting a change invalidates every earlier result
26
+ *
27
+ * Uncomfortable and correct. The fingerprint covers content, so a run that kept
28
+ * working after being verified is a different input wearing the same name.
29
+ * `verdictForCombination` reports that as `stale` rather than `failed`, because
30
+ * a human's next action differs: re-run the checks, not debug a failure.
31
+ */
32
+ import { fingerprintCombination, verdictForCombination, } from './combinationVerification.js';
33
+ import { mayLandCombination } from './landingOverlap.js';
34
+ export class LandingQueue {
35
+ #entries = new Map();
36
+ /** Insertion order. A Map preserves it, but relying on that implicitly in a
37
+ * queue is the kind of assumption that survives a refactor and then does not. */
38
+ #order = [];
39
+ #landing;
40
+ #now;
41
+ constructor(options = {}) {
42
+ this.#now = options.now ?? (() => Date.now());
43
+ }
44
+ /**
45
+ * Puts a run in line, or updates the revision of one already waiting.
46
+ *
47
+ * Re-enqueuing a run that moved on is not an error and does not lose its
48
+ * place: an agent that keeps working while queued is the normal case, and
49
+ * sending it to the back would punish the run that is still being improved.
50
+ * The revision changes, so the fingerprint changes, so every verification of
51
+ * the old set correctly goes stale — the ordering does not need to carry that.
52
+ */
53
+ enqueue(runId, revision) {
54
+ const existing = this.#entries.get(runId);
55
+ if (existing) {
56
+ // A run that is already landing must not have its revision swapped under
57
+ // it: the checks that admitted it ran against the old content, and the
58
+ // whole point of the fingerprint is that new content is a new input.
59
+ if (existing.state === 'landing')
60
+ return existing;
61
+ existing.revision = revision;
62
+ existing.state = 'queued';
63
+ delete existing.reason;
64
+ existing.updatedAt = this.#now();
65
+ this.#reposition();
66
+ return existing;
67
+ }
68
+ const entry = {
69
+ runId,
70
+ revision,
71
+ state: 'queued',
72
+ enqueuedAt: this.#now(),
73
+ updatedAt: this.#now(),
74
+ };
75
+ this.#entries.set(runId, entry);
76
+ this.#order.push(runId);
77
+ this.#reposition();
78
+ return entry;
79
+ }
80
+ /** Removes a run from the queue entirely — it is no longer trying to land. */
81
+ remove(runId) {
82
+ if (this.#landing === runId)
83
+ this.#landing = undefined;
84
+ const index = this.#order.indexOf(runId);
85
+ if (index >= 0)
86
+ this.#order.splice(index, 1);
87
+ const removed = this.#entries.delete(runId);
88
+ this.#reposition();
89
+ return removed;
90
+ }
91
+ /**
92
+ * The set that would land if the head proceeded.
93
+ *
94
+ * The head plus everything already landed is NOT what this returns — landed
95
+ * work is in trunk and is the baseline, not part of the combination. What is
96
+ * combined is the head with every other run still in flight, because those are
97
+ * the changes a check would have to run against for its result to describe
98
+ * what trunk becomes.
99
+ */
100
+ acceptedFor(runId) {
101
+ return this.#order
102
+ .map((id) => this.#entries.get(id))
103
+ .filter((entry) => Boolean(entry))
104
+ .filter((entry) => entry.state === 'queued' || entry.state === 'landing' || entry.runId === runId)
105
+ .map((entry) => ({ runId: entry.runId, revision: entry.revision }));
106
+ }
107
+ /**
108
+ * Whether the head may land, and against what.
109
+ *
110
+ * 🔴 Computes the verdict itself rather than accepting one. `mayLandCombination`
111
+ * was written the same way after the first version took a pre-computed
112
+ * `{ok: true}` and could therefore be satisfied by a caller asserting success
113
+ * — the gate has to be the thing that decides, or it is a formality.
114
+ */
115
+ next(context) {
116
+ if (this.#landing) {
117
+ const accepted = this.acceptedFor(this.#landing);
118
+ return {
119
+ runId: this.#landing,
120
+ ok: false,
121
+ reason: `${this.#landing} is already landing; one run lands at a time so the verified combination is the one that lands`,
122
+ accepted,
123
+ fingerprint: fingerprintCombination(accepted),
124
+ };
125
+ }
126
+ const head = this.#order
127
+ .map((id) => this.#entries.get(id))
128
+ .find((entry) => entry?.state === 'queued');
129
+ if (!head) {
130
+ return { ok: false, reason: 'nothing is waiting to land', accepted: [], fingerprint: 'empty' };
131
+ }
132
+ const accepted = this.acceptedFor(head.runId);
133
+ const fingerprint = fingerprintCombination(accepted);
134
+ const verdict = mayLandCombination(context.overlaps, accepted, context.verifications);
135
+ return { runId: head.runId, ok: verdict.ok, reason: verdict.reason, accepted, fingerprint };
136
+ }
137
+ /**
138
+ * Admits the head to `landing`, or records why it was refused.
139
+ *
140
+ * Returns the entry so a caller sees the outcome of its own call rather than
141
+ * having to read the queue back — the same reason `RunObservationService.poll`
142
+ * returns its snapshot.
143
+ */
144
+ admit(context) {
145
+ const decision = this.next(context);
146
+ if (!decision.runId)
147
+ return undefined;
148
+ const entry = this.#entries.get(decision.runId);
149
+ if (!entry)
150
+ return undefined;
151
+ if (!decision.ok) {
152
+ // 🔴 A refusal must not silently leave the run `queued`. It would be
153
+ // retried on every tick, refused every time, and look from the outside
154
+ // exactly like a queue that is merely slow.
155
+ if (entry.state === 'queued') {
156
+ entry.state = 'refused';
157
+ entry.reason = decision.reason;
158
+ entry.updatedAt = this.#now();
159
+ this.#reposition();
160
+ }
161
+ return entry;
162
+ }
163
+ entry.state = 'landing';
164
+ delete entry.reason;
165
+ entry.updatedAt = this.#now();
166
+ this.#landing = entry.runId;
167
+ this.#reposition();
168
+ return entry;
169
+ }
170
+ /**
171
+ * Records how a landing ended.
172
+ *
173
+ * `landed` is terminal and leaves the queue; the run is in trunk. `failed`
174
+ * keeps the entry so a human can see what happened — a landing that vanished
175
+ * on failure is indistinguishable from one that never started.
176
+ */
177
+ settle(runId, outcome) {
178
+ const entry = this.#entries.get(runId);
179
+ if (!entry)
180
+ return undefined;
181
+ if (this.#landing === runId)
182
+ this.#landing = undefined;
183
+ entry.state = outcome.landed ? 'landed' : 'failed';
184
+ if (outcome.reason)
185
+ entry.reason = outcome.reason;
186
+ else
187
+ delete entry.reason;
188
+ entry.updatedAt = this.#now();
189
+ if (outcome.landed) {
190
+ const index = this.#order.indexOf(runId);
191
+ if (index >= 0)
192
+ this.#order.splice(index, 1);
193
+ this.#entries.delete(runId);
194
+ }
195
+ this.#reposition();
196
+ return entry;
197
+ }
198
+ /**
199
+ * Puts a refused or failed run back in line.
200
+ *
201
+ * Explicit rather than automatic: a refusal means something has to change —
202
+ * the overlap resolved, the checks re-run — and retrying on a timer would
203
+ * spin against an unchanged verdict while looking like progress.
204
+ */
205
+ requeue(runId, revision) {
206
+ const entry = this.#entries.get(runId);
207
+ if (!entry || entry.state === 'landing')
208
+ return entry;
209
+ entry.revision = revision;
210
+ entry.state = 'queued';
211
+ delete entry.reason;
212
+ entry.updatedAt = this.#now();
213
+ this.#reposition();
214
+ return entry;
215
+ }
216
+ snapshot() {
217
+ const entries = this.#order
218
+ .map((id) => this.#entries.get(id))
219
+ .filter((entry) => Boolean(entry))
220
+ .map((entry) => ({ ...entry }));
221
+ const head = entries.find((entry) => entry.state === 'queued');
222
+ const accepted = head ? this.acceptedFor(head.runId) : [];
223
+ return {
224
+ entries,
225
+ ...(this.#landing ? { landing: this.#landing } : {}),
226
+ fingerprint: fingerprintCombination(accepted),
227
+ };
228
+ }
229
+ /** Positions describe the WAITING line only. A landing or refused run has no
230
+ * position, because "3rd in line" said of a run that is not in line is worse
231
+ * than saying nothing. */
232
+ #reposition() {
233
+ let position = 0;
234
+ for (const runId of this.#order) {
235
+ const entry = this.#entries.get(runId);
236
+ if (!entry)
237
+ continue;
238
+ if (entry.state === 'queued') {
239
+ position += 1;
240
+ entry.position = position;
241
+ }
242
+ else {
243
+ delete entry.position;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ /**
249
+ * Whether a verification result still describes what would land.
250
+ *
251
+ * Exported because the executor needs the same answer as the queue and must not
252
+ * arrive at it independently: two implementations of "is this result current"
253
+ * is precisely how a stale green gets trusted.
254
+ */
255
+ export function verificationIsCurrent(accepted, verifications) {
256
+ return verdictForCombination(accepted, verifications).ok;
257
+ }
258
+ //# sourceMappingURL=landingQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landingQueue.js","sourceRoot":"","sources":["../src/landingQueue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAGtB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAA6B,MAAM,qBAAqB,CAAA;AAyDnF,MAAM,OAAO,YAAY;IACd,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAA;IACnD;sFACkF;IACzE,MAAM,GAAa,EAAE,CAAA;IAC9B,QAAQ,CAAoB;IACnB,IAAI,CAAc;IAE3B,YAAY,UAAkC,EAAE;QAC9C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC/C,CAAC;IAED;;;;;;;;OAQG;IACH,OAAO,CAAC,KAAa,EAAE,QAAgB;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACzC,IAAI,QAAQ,EAAE,CAAC;YACb,yEAAyE;YACzE,uEAAuE;YACvE,qEAAqE;YACrE,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;YACjD,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAA;YAC5B,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAA;YACzB,OAAO,QAAQ,CAAC,MAAM,CAAA;YACtB,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;YAChC,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,MAAM,KAAK,GAAiB;YAC1B,KAAK;YACL,QAAQ;YACR,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE;YACvB,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE;SACvB,CAAA;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvB,IAAI,CAAC,WAAW,EAAE,CAAA;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,8EAA8E;IAC9E,MAAM,CAAC,KAAa;QAClB,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK;YAAE,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QACxC,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC3C,IAAI,CAAC,WAAW,EAAE,CAAA;QAClB,OAAO,OAAO,CAAA;IAChB,CAAC;IAED;;;;;;;;OAQG;IACH,WAAW,CAAC,KAAa;QACvB,OAAO,IAAI,CAAC,MAAM;aACf,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aAClC,MAAM,CAAC,CAAC,KAAK,EAAyB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aACxD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;aACjG,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IACvE,CAAC;IAED;;;;;;;OAOG;IACH,IAAI,CAAC,OAAuB;QAC1B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAChD,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,QAAQ;gBACpB,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,gGAAgG;gBACxH,QAAQ;gBACR,WAAW,EAAE,sBAAsB,CAAC,QAAQ,CAAC;aAC9C,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;aACrB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aAClC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAA;QAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,CAAA;QAChG,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC7C,MAAM,WAAW,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAA;QACpD,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;QACrF,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAA;IAC7F,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,OAAuB;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACnC,IAAI,CAAC,QAAQ,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC/C,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QAE5B,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,qEAAqE;YACrE,uEAAuE;YACvE,4CAA4C;YAC5C,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC7B,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;gBACvB,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAA;gBAC9B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;gBAC7B,IAAI,CAAC,WAAW,EAAE,CAAA;YACpB,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QAED,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;QACvB,OAAO,KAAK,CAAC,MAAM,CAAA;QACnB,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAA;QAC3B,IAAI,CAAC,WAAW,EAAE,CAAA;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,KAAa,EAAE,OAA6C;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACtC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QAC5B,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK;YAAE,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAA;QACtD,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;QAClD,IAAI,OAAO,CAAC,MAAM;YAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;;YAC5C,OAAO,KAAK,CAAC,MAAM,CAAA;QACxB,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YACxC,IAAI,KAAK,IAAI,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;YAC5C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC7B,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAA;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,KAAa,EAAE,QAAgB;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;QACrD,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACzB,KAAK,CAAC,KAAK,GAAG,QAAQ,CAAA;QACtB,OAAO,KAAK,CAAC,MAAM,CAAA;QACnB,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7B,IAAI,CAAC,WAAW,EAAE,CAAA;QAClB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,QAAQ;QACN,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM;aACxB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aAClC,MAAM,CAAC,CAAC,KAAK,EAAyB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aACxD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;QACjC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAA;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACzD,OAAO;YACL,OAAO;YACP,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,WAAW,EAAE,sBAAsB,CAAC,QAAQ,CAAC;SAC9C,CAAA;IACH,CAAC;IAED;;+BAE2B;IAC3B,WAAW;QACT,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACtC,IAAI,CAAC,KAAK;gBAAE,SAAQ;YACpB,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC7B,QAAQ,IAAI,CAAC,CAAA;gBACb,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAA;YAC3B,CAAC;iBAAM,CAAC;gBACN,OAAO,KAAK,CAAC,QAAQ,CAAA;YACvB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAA0B,EAC1B,aAAwC;IAExC,OAAO,qBAAqB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,EAAE,CAAA;AAC1D,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface MarkdownFileReference {
2
+ path: string;
3
+ label: string;
4
+ }
5
+ export declare function resolveMarkdownLocalFilePath(href?: string): string | null;
6
+ export declare function extractWindowsFilePathsFromToolResult(value: string): string[];
7
+ /**
8
+ * CommonMark treats a backslash before punctuation as an escape, so a bare path such as
9
+ * `C:\Users\name\.xeno` loses the separator before `.xeno`. Escape only bare drive paths,
10
+ * while leaving inline and fenced code untouched because code already preserves backslashes.
11
+ */
12
+ export declare function protectWindowsPathsForMarkdown(markdown: string): string;
13
+ /**
14
+ * Turns file references in ordinary prose into inline file chips without rewriting
15
+ * existing inline/fenced code. Exact token boundaries prevent a directory-shaped
16
+ * reference such as `C:\Users\name\.xeno` from replacing the prefix of a longer path.
17
+ */
18
+ export declare function injectMessageFileLinks(markdown: string, refs: MarkdownFileReference[]): string;
19
+ export declare function prepareAgentMarkdown(markdown: string, refs?: MarkdownFileReference[]): string;
20
+ //# sourceMappingURL=markdownWindowsPaths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownWindowsPaths.d.ts","sourceRoot":"","sources":["../../src/markdown/markdownWindowsPaths.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,4BAA4B,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBzE;AAkGD,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAG7E;AAqCD;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAyBvE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,qBAAqB,EAAE,GAC5B,MAAM,CAsCR;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,qBAAqB,EAAO,GACjC,MAAM,CAER"}
@@ -0,0 +1,208 @@
1
+ const WINDOWS_DRIVE_PATH_PATTERN = /\b[A-Za-z]:\\[^\s<>"`]+/g;
2
+ const WINDOWS_FILE_RESULT_PATTERN = /[A-Za-z]:\\[^\n\r<>:"|?*]*?\.[A-Za-z0-9]{1,16}(?=$|[\s"'`)\],;:]|\.(?=$|\s))/gm;
3
+ const MARKDOWN_PATH_PREFIX_BOUNDARY = 'A-Za-z0-9_./\\\\-';
4
+ const MARKDOWN_PATH_SUFFIX_GUARD = '(?![A-Za-z0-9_/\\\\-]|\\.[A-Za-z0-9_])';
5
+ export function resolveMarkdownLocalFilePath(href) {
6
+ if (!href?.trim())
7
+ return null;
8
+ let candidate = href.trim();
9
+ try {
10
+ candidate = decodeURIComponent(candidate);
11
+ }
12
+ catch {
13
+ // Keep the original value when a malformed percent escape is present.
14
+ }
15
+ candidate = candidate
16
+ .replace(/^xeno-file:\/\/+/i, '')
17
+ .replace(/^file:\/\/+/i, '')
18
+ .replace(/^\/(?=[A-Za-z]:[\\/])/, '');
19
+ if (!/^[A-Za-z]:[\\/]/.test(candidate))
20
+ return null;
21
+ return candidate.replace(/\//g, '\\');
22
+ }
23
+ function escapeRegExp(value) {
24
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
25
+ }
26
+ function isEscapedBacktick(markdown, index) {
27
+ let slashCount = 0;
28
+ for (let cursor = index - 1; cursor >= 0 && markdown[cursor] === '\\'; cursor -= 1) {
29
+ slashCount += 1;
30
+ }
31
+ return slashCount % 2 === 1;
32
+ }
33
+ function mapMarkdownOutsideCode(markdown, transform) {
34
+ let output = '';
35
+ let plainText = '';
36
+ let cursor = 0;
37
+ let inlineDelimiterLength = 0;
38
+ let fence = null;
39
+ const flushPlainText = () => {
40
+ if (!plainText)
41
+ return;
42
+ output += transform(plainText);
43
+ plainText = '';
44
+ };
45
+ while (cursor < markdown.length) {
46
+ const atLineStart = cursor === 0 || markdown[cursor - 1] === '\n';
47
+ if (atLineStart && inlineDelimiterLength === 0) {
48
+ const nextNewline = markdown.indexOf('\n', cursor);
49
+ const lineEnd = nextNewline === -1 ? markdown.length : nextNewline + 1;
50
+ const line = markdown.slice(cursor, lineEnd);
51
+ const fenceMarker = line.match(/^ {0,3}(`{3,}|~{3,})/);
52
+ if (fence) {
53
+ flushPlainText();
54
+ output += line;
55
+ if (fenceMarker
56
+ && fenceMarker[1][0] === fence.character
57
+ && fenceMarker[1].length >= fence.length) {
58
+ fence = null;
59
+ }
60
+ cursor = lineEnd;
61
+ continue;
62
+ }
63
+ if (fenceMarker) {
64
+ flushPlainText();
65
+ const marker = fenceMarker[1];
66
+ fence = {
67
+ character: marker[0],
68
+ length: marker.length,
69
+ };
70
+ output += line;
71
+ cursor = lineEnd;
72
+ continue;
73
+ }
74
+ }
75
+ if (markdown[cursor] === '`' && !isEscapedBacktick(markdown, cursor)) {
76
+ let runEnd = cursor + 1;
77
+ while (markdown[runEnd] === '`')
78
+ runEnd += 1;
79
+ const delimiterLength = runEnd - cursor;
80
+ if (inlineDelimiterLength === 0) {
81
+ flushPlainText();
82
+ inlineDelimiterLength = delimiterLength;
83
+ }
84
+ else if (delimiterLength === inlineDelimiterLength) {
85
+ inlineDelimiterLength = 0;
86
+ }
87
+ output += markdown.slice(cursor, runEnd);
88
+ cursor = runEnd;
89
+ continue;
90
+ }
91
+ if (inlineDelimiterLength > 0) {
92
+ output += markdown[cursor];
93
+ }
94
+ else {
95
+ plainText += markdown[cursor];
96
+ }
97
+ cursor += 1;
98
+ }
99
+ flushPlainText();
100
+ return output;
101
+ }
102
+ function escapeBareWindowsPaths(value) {
103
+ return value.replace(WINDOWS_DRIVE_PATH_PATTERN, (path) => (path.replace(/(?<!\\)\\(?!\\)/g, '\\\\')));
104
+ }
105
+ export function extractWindowsFilePathsFromToolResult(value) {
106
+ if (!value)
107
+ return [];
108
+ return value.match(WINDOWS_FILE_RESULT_PATTERN) || [];
109
+ }
110
+ function protectInlineCode(line) {
111
+ let output = '';
112
+ let cursor = 0;
113
+ let codeDelimiterLength = 0;
114
+ for (let index = 0; index < line.length;) {
115
+ if (line[index] !== '`') {
116
+ index += 1;
117
+ continue;
118
+ }
119
+ let end = index + 1;
120
+ while (line[end] === '`')
121
+ end += 1;
122
+ const delimiterLength = end - index;
123
+ if (codeDelimiterLength === 0) {
124
+ output += escapeBareWindowsPaths(line.slice(cursor, index));
125
+ output += line.slice(index, end);
126
+ codeDelimiterLength = delimiterLength;
127
+ cursor = end;
128
+ }
129
+ else if (delimiterLength === codeDelimiterLength) {
130
+ output += line.slice(cursor, end);
131
+ codeDelimiterLength = 0;
132
+ cursor = end;
133
+ }
134
+ index = end;
135
+ }
136
+ output += codeDelimiterLength === 0
137
+ ? escapeBareWindowsPaths(line.slice(cursor))
138
+ : line.slice(cursor);
139
+ return output;
140
+ }
141
+ /**
142
+ * CommonMark treats a backslash before punctuation as an escape, so a bare path such as
143
+ * `C:\Users\name\.xeno` loses the separator before `.xeno`. Escape only bare drive paths,
144
+ * while leaving inline and fenced code untouched because code already preserves backslashes.
145
+ */
146
+ export function protectWindowsPathsForMarkdown(markdown) {
147
+ if (!markdown || !/[A-Za-z]:\\/.test(markdown))
148
+ return markdown;
149
+ let fenceCharacter = null;
150
+ let fenceLength = 0;
151
+ return markdown.split(/(\r?\n)/).map((part) => {
152
+ if (part === '\n' || part === '\r\n')
153
+ return part;
154
+ const fence = part.match(/^\s*(`{3,}|~{3,})/);
155
+ if (fence) {
156
+ const marker = fence[1];
157
+ const markerCharacter = marker[0];
158
+ if (fenceCharacter === null) {
159
+ fenceCharacter = markerCharacter;
160
+ fenceLength = marker.length;
161
+ }
162
+ else if (markerCharacter === fenceCharacter && marker.length >= fenceLength) {
163
+ fenceCharacter = null;
164
+ fenceLength = 0;
165
+ }
166
+ return part;
167
+ }
168
+ return fenceCharacter === null ? protectInlineCode(part) : part;
169
+ }).join('');
170
+ }
171
+ /**
172
+ * Turns file references in ordinary prose into inline file chips without rewriting
173
+ * existing inline/fenced code. Exact token boundaries prevent a directory-shaped
174
+ * reference such as `C:\Users\name\.xeno` from replacing the prefix of a longer path.
175
+ */
176
+ export function injectMessageFileLinks(markdown, refs) {
177
+ if (!markdown || refs.length === 0)
178
+ return markdown;
179
+ let output = markdown;
180
+ for (const ref of refs) {
181
+ const label = ref.label.trim();
182
+ const path = ref.path.trim();
183
+ if (!label || !path)
184
+ continue;
185
+ const chip = `\`${label}\``;
186
+ const escapedChip = escapeRegExp(chip);
187
+ const escapedPath = escapeRegExp(path);
188
+ let replacedExactPath = false;
189
+ output = mapMarkdownOutsideCode(output, (plainText) => plainText.replace(new RegExp(`(^|[^${MARKDOWN_PATH_PREFIX_BOUNDARY}])(${escapedPath})${MARKDOWN_PATH_SUFFIX_GUARD}`, 'gi'), (_match, prefix) => {
190
+ replacedExactPath = true;
191
+ return `${prefix}${chip}`;
192
+ }));
193
+ if (!replacedExactPath && !output.includes(chip)) {
194
+ const escapedLabel = escapeRegExp(label);
195
+ output = mapMarkdownOutsideCode(output, (plainText) => plainText.replace(new RegExp(`(^|[^${MARKDOWN_PATH_PREFIX_BOUNDARY}])(${escapedLabel})${MARKDOWN_PATH_SUFFIX_GUARD}`, 'gi'), (_match, prefix) => `${prefix}${chip}`));
196
+ }
197
+ // Agents sometimes emit the created/opened filename on its own line, e.g.
198
+ // "Done. Created:\n`file.txt`\nwith:". Keep that chip with the sentence.
199
+ output = output.replace(new RegExp(`:\\s*\\n+\\s*${escapedChip}`, 'gi'), `: ${chip}`);
200
+ output = output.replace(new RegExp(`${escapedChip}\\s*\\n+\\s*(?=[A-Za-z0-9(])`, 'gi'), `${chip} `);
201
+ output = output.replace(new RegExp(`(?<=[A-Za-z0-9])\\s*\\n+\\s*${escapedChip}`, 'gi'), ` ${chip}`);
202
+ }
203
+ return output;
204
+ }
205
+ export function prepareAgentMarkdown(markdown, refs = []) {
206
+ return protectWindowsPathsForMarkdown(injectMessageFileLinks(markdown, refs));
207
+ }
208
+ //# sourceMappingURL=markdownWindowsPaths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownWindowsPaths.js","sourceRoot":"","sources":["../../src/markdown/markdownWindowsPaths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * What a review surface is allowed to SHOW — §2.9 and §5.7, as a projection.
3
+ *
4
+ * Pure, and in `core` rather than in a component, because every rule here is a
5
+ * statement about honesty rather than about layout, and the honesty is the part
6
+ * that must not depend on someone remembering it while writing JSX.
7
+ * `packages/ui` holds `toolCardProjection` for the same reason — a projection
8
+ * kept out of the component that renders it.
9
+ *
10
+ * ⚠️ This sentence used to say `core` holds it. It does not; it is in
11
+ * `packages/ui`. Corrected rather than left, because a wrong pointer in a
12
+ * doc comment sends the next reader to the wrong package.
13
+ *
14
+ * ## 🔴 The rule the whole module exists for
15
+ *
16
+ * **An incomplete diff must never be presented as a review.** §2.9's claim is
17
+ * that tier 1 yields a real diff; a diff that quietly omits changes is worse
18
+ * than no diff, because a reviewer reads "3 files changed" and approves. So an
19
+ * incomplete snapshot projects to a state a surface cannot render as an ordinary
20
+ * file list — not to a list with a warning beside it, which is a thing people
21
+ * learn to skip past.
22
+ *
23
+ * ## Unobserved is not empty
24
+ *
25
+ * "This run changed nothing" and "nobody was watching" produce the same zero
26
+ * changes and mean opposite things. They are separate states here, and the
27
+ * second is not a variant of the first.
28
+ */
29
+ import type { LandingEntry, LandingState } from './landingQueue.js';
30
+ export interface ReviewChange {
31
+ path: string;
32
+ kind: 'added' | 'modified' | 'deleted';
33
+ /** True when another live run also changed this path — §5.7, surfaced while
34
+ * both runs can still act on it. */
35
+ contested?: boolean;
36
+ }
37
+ /** The snapshot a surface receives, mirroring `run.observation.snapshot`. */
38
+ export interface ReviewSnapshotInput {
39
+ available: boolean;
40
+ runId: string;
41
+ changes: Array<{
42
+ path: string;
43
+ kind: 'added' | 'modified' | 'deleted';
44
+ }>;
45
+ complete: boolean;
46
+ droppedEvents: number;
47
+ problems: string[];
48
+ reason?: string;
49
+ }
50
+ export interface ReviewOverlapsInput {
51
+ available: boolean;
52
+ overlaps: Array<{
53
+ path: string;
54
+ runIds: string[];
55
+ kind: string;
56
+ unclaimed?: boolean;
57
+ }>;
58
+ incompleteRuns: string[];
59
+ complete: boolean;
60
+ }
61
+ export type ReviewStatus =
62
+ /** No observation for this run. NOT a review of an empty diff. */
63
+ 'unobserved'
64
+ /** Observed, complete, and nothing changed. */
65
+ | 'clean'
66
+ /** Observed and complete. The only state that may render as a plain diff. */
67
+ | 'reviewable'
68
+ /** Observed with a known hole. Renders as a warning FIRST, never as a list. */
69
+ | 'incomplete';
70
+ export interface ReviewProjection {
71
+ runId: string;
72
+ status: ReviewStatus;
73
+ changes: ReviewChange[];
74
+ counts: {
75
+ added: number;
76
+ modified: number;
77
+ deleted: number;
78
+ contested: number;
79
+ };
80
+ /**
81
+ * One sentence a human can act on. Present for every status except
82
+ * `reviewable`, because that is the only one needing no explanation.
83
+ */
84
+ notice?: string;
85
+ /** True only when the diff may be treated as the whole story. */
86
+ trustworthy: boolean;
87
+ }
88
+ export declare function projectReview(snapshot: ReviewSnapshotInput, overlaps?: ReviewOverlapsInput): ReviewProjection;
89
+ export interface LandingRowProjection {
90
+ runId: string;
91
+ state: LandingState;
92
+ /** "3rd in line", or absent for a run that is not waiting. */
93
+ positionLabel?: string;
94
+ /** The queue's own reason, never a re-worded one. */
95
+ reason?: string;
96
+ /** True when a human action could move this run forward. */
97
+ actionable: boolean;
98
+ }
99
+ export interface LandingProjection {
100
+ rows: LandingRowProjection[];
101
+ landing?: string;
102
+ /**
103
+ * Whether a `land` call could plausibly succeed right now.
104
+ *
105
+ * Advisory ONLY. The gate is the host's, and a surface that treated this as
106
+ * the decision would be a second implementation of it — which is how the two
107
+ * come to disagree, always in the direction of the optimistic one.
108
+ */
109
+ couldLand: boolean;
110
+ notice?: string;
111
+ }
112
+ export declare function projectLanding(input: {
113
+ available: boolean;
114
+ entries: LandingEntry[];
115
+ landing?: string;
116
+ reason?: string;
117
+ }): LandingProjection;
118
+ //# sourceMappingURL=reviewProjection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewProjection.d.ts","sourceRoot":"","sources":["../src/reviewProjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEnE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;IACtC;yCACqC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;KAAE,CAAC,CAAA;IACxE,QAAQ,EAAE,OAAO,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACtF,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,MAAM,YAAY;AACtB,kEAAkE;AAChE,YAAY;AACd,+CAA+C;GAC7C,OAAO;AACT,6EAA6E;GAC3E,YAAY;AACd,+EAA+E;GAC7E,YAAY,CAAA;AAEhB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,YAAY,CAAA;IACpB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iEAAiE;IACjE,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,mBAAmB,EAC7B,QAAQ,CAAC,EAAE,mBAAmB,GAC7B,gBAAgB,CA2DlB;AAkBD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,YAAY,CAAA;IACnB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,oBAAoB,EAAE,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,GAAG,iBAAiB,CA+BpB"}