agent-coord-mcp 0.26.19 → 0.26.21

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 (56) hide show
  1. package/README.md +82 -0
  2. package/dist/capabilities.js +57 -1
  3. package/dist/capabilities.js.map +1 -1
  4. package/dist/gated-head.js +130 -0
  5. package/dist/gated-head.js.map +1 -0
  6. package/dist/server.js +23 -0
  7. package/dist/server.js.map +1 -1
  8. package/dist/tools/queue-write.js +431 -0
  9. package/dist/tools/queue-write.js.map +1 -0
  10. package/dist/tools/records.js +406 -70
  11. package/dist/tools/records.js.map +1 -1
  12. package/dist/tools/registry.js +34 -5
  13. package/dist/tools/registry.js.map +1 -1
  14. package/dist/tools/shared.js.map +1 -1
  15. package/dist/tools/stall.js +2 -1
  16. package/dist/tools/stall.js.map +1 -1
  17. package/dist/tools/transport.js +82 -42
  18. package/dist/tools/transport.js.map +1 -1
  19. package/dist/tools/tree-provenance.js +107 -0
  20. package/dist/tools/tree-provenance.js.map +1 -0
  21. package/dist/tools/work.js +95 -3
  22. package/dist/tools/work.js.map +1 -1
  23. package/dist/transports/config.js +82 -0
  24. package/dist/transports/config.js.map +1 -0
  25. package/dist/transports/index.js +113 -0
  26. package/dist/transports/index.js.map +1 -0
  27. package/dist/transports/tmux.js +140 -0
  28. package/dist/transports/tmux.js.map +1 -0
  29. package/dist/transports/types.js +86 -0
  30. package/dist/transports/types.js.map +1 -0
  31. package/hooks/peek-coord.mjs +0 -0
  32. package/hooks/tmux-pusher.mjs +33 -3
  33. package/package.json +14 -11
  34. package/scripts/coord-attention-clock.mjs +0 -0
  35. package/scripts/coord-node.sh +0 -0
  36. package/scripts/coord-stall-clock.mjs +0 -0
  37. package/scripts/coord-token.mjs +0 -0
  38. package/scripts/probe-tmux-liveness.sh +0 -0
  39. package/scripts/spawn-agent.sh +0 -0
  40. package/scripts/stop-agent.sh +0 -0
  41. package/scripts/typed-record-stats.mjs +0 -0
  42. package/src/capabilities.ts +104 -1
  43. package/src/gated-head.ts +134 -0
  44. package/src/server.ts +29 -0
  45. package/src/tools/queue-write.ts +485 -0
  46. package/src/tools/records.ts +409 -40
  47. package/src/tools/registry.ts +36 -5
  48. package/src/tools/shared.ts +12 -36
  49. package/src/tools/stall.ts +2 -1
  50. package/src/tools/transport.ts +96 -43
  51. package/src/tools/tree-provenance.ts +136 -0
  52. package/src/tools/work.ts +95 -3
  53. package/src/transports/config.ts +110 -0
  54. package/src/transports/index.ts +126 -0
  55. package/src/transports/tmux.ts +177 -0
  56. package/src/transports/types.ts +201 -0
@@ -0,0 +1,431 @@
1
+ /*
2
+ * `queue_write` — FILE, AMEND and REPRIORITISE a queue item through a verb.
3
+ *
4
+ * ⭐ DAVID SET THE LEVEL OF THIS API, NOT JUST ITS EXISTENCE (2026-09-09):
5
+ * "where possible we should hide the plumbing from the agents. with a tool he
6
+ * can just say task x is ready and then the tool moves it to done."
7
+ * "as long as we offer enough tooling to support future reads and writes
8
+ * through tools we should as much as possible discourage direct file editing.
9
+ * we also should avoid token costs an agent patching lines would cost tokens."
10
+ *
11
+ * ⛔ SO THE SURFACE IS INTENT PLUS EVIDENCE, NEVER FIELDS PLUS FORMAT. The caller
12
+ * says WHAT the item is and HOW URGENT; this module owns the grammar, the id, the
13
+ * glyphs and the file. **No caller-supplied string reaches a document verbatim**
14
+ * — `text` is carried inside a modelled `QueueItem` and rendered by the seam's
15
+ * `renderQueueLine`, which is the same function the parser round-trips against.
16
+ * A verb that accepted a pre-formatted row would be hand-editing with an API on
17
+ * top, which is the defect this row names.
18
+ *
19
+ * WHY THE AGENT MUST NOT KNOW THE GRAMMAR — an inventory, not a preference. Every
20
+ * one of these cost this fleet something in one week, and not one is a rule an
21
+ * agent should ever have had to know:
22
+ * · the closing citation must sit on the item's OWN FIRST LINE (⟨q-6d21ff84⟩,
23
+ * paid for twice, and a continuation line does not satisfy it)
24
+ * · every item must carry a RECORDED id and the writer must stamp it
25
+ * (⟨q-c50e9b83⟩, which reddened `main` twice in six minutes)
26
+ * · `queue.v1` is ONE LINE PER ITEM — a wrapped continuation is dropped by
27
+ * every parser (⟨q-8c1f04b7⟩: 83% of one item's content lost)
28
+ * · conflict markers committed into QUEUE.md with every gate green
29
+ * Each disappears behind a verb that renders the line itself.
30
+ *
31
+ * CONCURRENCY is not handled here and that is deliberate: every write goes
32
+ * through `writeDoc`, which re-reads and REFUSES a moved base (⟨q-0c5e73a1⟩).
33
+ * This module would be unsafe without it, which is why that landed first.
34
+ */
35
+ import { z } from "zod";
36
+ import path from "node:path";
37
+ import { existsSync, readFileSync } from "node:fs";
38
+ import { parseWorkDoc, queueItemsOf, withRecordedId, renderQueueLine, leadingTagsOf, } from "@davidbalzan/groundwork-seam";
39
+ import { writeDoc, StaleWriteError } from "./records.js";
40
+ const QUEUE_DOC = "docs/QUEUE.md";
41
+ const PRIORITIES = ["P1", "P2", "P3"];
42
+ /**
43
+ * ⛔ THE GUARD MUST ASK ABOUT THE ROW AS IT WILL BE *READ*, NOT AS IT WAS BUILT.
44
+ *
45
+ * QA FAIL on #263 @ 05bf3ee: `" **[AWAITS:david]** x"` — leading whitespace, a
46
+ * TAB too — passed the gate and landed LIVE. Measured, both halves:
47
+ *
48
+ * pre-id item text `" **[AWAITS..."` leadingTagsOf -> []
49
+ * as written text `"**[AWAITS..."` leadingTagsOf -> [{awaits:david}]
50
+ *
51
+ * `LEADING_TAG` is anchored `^\*\*\[`, so the spaces hid the tag from it. Then
52
+ * `renderQueueLine` stamps the id, and the parser's id-strip consumes exactly
53
+ * that whitespace — so the text the gate cleared is not the text a consumer
54
+ * reads. The sigil is the discriminator, not the render/parse round-trip: the
55
+ * same line without an id still parses to `[]`.
56
+ *
57
+ * ⭐ So the row goes through the PARSER before it is judged — the oracle this
58
+ * module already uses for the empty-queue append. Trimming `text` would also
59
+ * close this one input; re-parsing closes the CLASS, because anything else the
60
+ * id-strip swallows arrives here already swallowed.
61
+ */
62
+ function asWritten(item) {
63
+ const parsed = queueItemsOf(parseWorkDoc(`## Queue\n${renderQueueLine(item)}\n`))[0];
64
+ if (!parsed) {
65
+ throw new QueueWriteError(`the composed row does not parse as queue.v1 — refusing to write it: ${renderQueueLine(item)}`);
66
+ }
67
+ return parsed;
68
+ }
69
+ /**
70
+ * ⛔ THE TEXT FIELD LANDS IN ROW-PREFIX POSITION, WHICH IS STRUCTURAL, NOT BODY.
71
+ *
72
+ * `renderQueueLine` puts `text` immediately after the id — and the first thing
73
+ * after the id is MACHINE-READABLE. `leadingTagsOf` reads `**[key:value]**`
74
+ * there, `awaitingOf` reads `awaits`, and `next_unblocked` routes on it. So a
75
+ * caller passing `**[AWAITS:david]**` as prose changed ROUTING: measured end to
76
+ * end on the first version of this verb, `leadingTagsOf` returned
77
+ * `[{key:"awaits",value:"david"}]` and the item appeared on `awaitingDecision`.
78
+ *
79
+ * ⭐ THE GATE IS THE REAL PREDICATE, NOT A PATTERN. The first version of this
80
+ * module had no gate and its test used a regex proxy
81
+ * (`^- \[|⟨q-|\(P[123]\)`) which the tag grammar matches none of — so the
82
+ * suite was green while the premise was false. Asking `leadingTagsOf` the
83
+ * question it exists to answer means the gate cannot drift from the grammar: if
84
+ * the tag vocabulary widens, this widens with it, for free.
85
+ *
86
+ * Tags are not refused because they are dangerous to write — they are refused
87
+ * because they are not this verb's arguments. Adding them as TYPED arguments the
88
+ * verb renders itself is a separate, coherent change; letting them in through
89
+ * prose is the hand-editing this verb exists to replace.
90
+ */
91
+ function assertNoLeadingTag(item) {
92
+ const tags = leadingTagsOf(asWritten(item));
93
+ if (tags.length) {
94
+ const shown = tags.map((t) => `**[${t.key}:${t.value}]**`).join(" ");
95
+ throw new QueueWriteError(`text must not begin with a row-prefix tag (${shown}): the position right after the id is ` +
96
+ `MACHINE-READABLE, so this would change routing rather than describe the item — ` +
97
+ `\`leadingTagsOf\` reads it and \`next_unblocked\` acts on it. ` +
98
+ `Markers are set by the seats that own them, not through an item's prose.`);
99
+ }
100
+ }
101
+ /*
102
+ * ⛔⛆⛆ THE TAG THAT DECIDES ROUTING HAD NO FIELD, SO THE STATE "BUILT, GREEN,
103
+ * STOPPED AT A HUMAN" WAS UNREACHABLE THROUGH THIS VERB — `⟨q-d920a123⟩`.
104
+ *
105
+ * `**[AWAITS:<who>]**` is READ by `next_unblocked` and reported on its own
106
+ * `awaitingDecision` axis, and the seam calls it "a FIELD set by whoever files the
107
+ * item". But this verb's schema was `op · id · text · priority` and nothing else, so
108
+ * the only route through it was to smuggle the tag inside `text` — which
109
+ * `assertNoLeadingTag` correctly refuses. ⭐ THE MARKER WAS NEVER WRITTEN AT THE
110
+ * TRANSITION NOT THROUGH FORGETFULNESS BUT BECAUSE THERE WAS NO MECHANISM: the aide
111
+ * hand-edited `⟨q-217cc151⟩`'s marker at 17:05 because the verb could not.
112
+ *
113
+ * The live instance is the cost: `next_unblocked` offered `⟨q-217cc151⟩` as `next`
114
+ * while that row was built, CI-green, gated FAIL and blocked on a publish only a
115
+ * human can perform.
116
+ *
117
+ * ⛔ AND THE REFUSAL STAYS EXACTLY AS STRONG. Tags arrive as TYPED FIELDS the verb
118
+ * renders itself; a tag inside `text` is still refused. The file already said this
119
+ * was the coherent change — "Adding them as TYPED arguments the verb renders itself
120
+ * is a separate, coherent change; letting them in through prose is the hand-editing
121
+ * this verb exists to replace." A field satisfiable by prose would BE the defect.
122
+ */
123
+ /*
124
+ * ⭐ THE KEYS THIS VERB WILL SET, AND WHY THE LIST IS SHORT RATHER THAN OPEN.
125
+ *
126
+ * `awaits` and `sweep` are both READ by shipped code (`awaitingOf`, `sweepTagOf`),
127
+ * so setting them completes a loop that already exists. `undelivered` uses the same
128
+ * grammar and is deliberately NOT settable here: it is a fact about what is on the
129
+ * REGISTRY, derived by `check-undelivered-markers` from the publish record, and an
130
+ * agent asserting it by hand is how that marker would start lying. A caller that
131
+ * wants it is asking the wrong question of the wrong verb.
132
+ */
133
+ const TAG_KEYS = ["awaits", "sweep"];
134
+ /**
135
+ * Split `item.text` into its carried tag run and the body after it.
136
+ *
137
+ * ⛔ THE SEAM IS THE ONLY LEXER, AND THAT IS THE POINT — NOT AN ECONOMY.
138
+ * `⟨q-1c4f8ae3⟩` is exactly this shape: one grammar, two parsers, different
139
+ * domains, both "working" (the check accepted `@scope/name@1.0.0`; the seam dropped
140
+ * it). So this does NOT re-implement `LEADING_TAG`. It asks `leadingTagsOf` where
141
+ * the run ends, by finding the SMALLEST boundary `i` such that
142
+ *
143
+ * · the suffix from `i` carries NO tags, and
144
+ * · the prefix up to `i`, with a tag-free sentinel appended so its run
145
+ * terminates, carries ALL of them.
146
+ *
147
+ * Both conditions are needed. The first alone is satisfied by `i = 1` — cutting one
148
+ * `*` off `**[AWAITS:x]**` leaves a suffix that parses to `[]`, which would report
149
+ * the whole tag as body. The second alone is satisfied by `i = text.length` on a row
150
+ * whose BODY quotes a tag, which would report the whole body as tag run.
151
+ *
152
+ * ⭐ SMALLEST rather than largest, and the difference is a swallowed body: for
153
+ * `**[A:b]** body **[C:d]** x` the largest valid boundary is the end of the line —
154
+ * the prefix still carries exactly the one real tag and the empty suffix carries
155
+ * none — so a descending scan returns an EMPTY body. Measured before it was written.
156
+ */
157
+ function splitLeadingTags(item) {
158
+ const text = String(item.text);
159
+ const tagsOf = (t) => leadingTagsOf({ ...item, text: t });
160
+ const tags = tagsOf(text);
161
+ if (tags.length === 0)
162
+ return { tags, body: text };
163
+ // Tag-free by construction: the grammar's key class is [a-z]+ and its value class
164
+ // admits no NUL, so this can never extend a run it is appended to.
165
+ const SENTINEL = "\u0000";
166
+ for (let i = 1; i <= text.length; i++) {
167
+ if (tagsOf(text.slice(i)).length !== 0)
168
+ continue;
169
+ if (tagsOf(text.slice(0, i) + SENTINEL).length !== tags.length)
170
+ continue;
171
+ // The grammar consumes the whitespace after `]**`; a second space would
172
+ // otherwise survive into the rendered line as a double space.
173
+ return { tags, body: text.slice(i).replace(/^\s+/, "") };
174
+ }
175
+ throw new QueueWriteError(`could not locate the end of the tag run in ${JSON.stringify(text)} — refusing to guess a boundary, ` +
176
+ `because a wrong one would move part of the item's prose into machine-readable position`);
177
+ }
178
+ /**
179
+ * `item.text` with `changes` applied to its leading tags. `null` CLEARS a key.
180
+ *
181
+ * Existing tags are preserved and their order is kept, so setting `awaits` on a row
182
+ * that already carries `**[SWEEP:console]**` does not silently drop the sweep tag —
183
+ * the failure that would make this verb worse than the hand-edit it replaces.
184
+ */
185
+ function retagged(item, changes) {
186
+ const { tags, body } = splitLeadingTags(item);
187
+ const map = new Map(tags.map((t) => [t.key, t.value]));
188
+ for (const [k, v] of Object.entries(changes)) {
189
+ if (v === null)
190
+ map.delete(k);
191
+ else if (v !== undefined)
192
+ map.set(k, String(v));
193
+ }
194
+ const rendered = [...map].map(([k, v]) => `**[${k.toUpperCase()}:${v}]**`).join(" ");
195
+ return { text: rendered ? `${rendered} ${body}` : body, want: map };
196
+ }
197
+ /**
198
+ * ⛔ WHAT WAS INTENDED IS WHAT THE ROW WILL BE READ AS — asked of the parser, not assumed.
199
+ *
200
+ * `renderQueueLine` then the parser then `leadingTagsOf`, exactly the path a consumer
201
+ * takes. A value the grammar cannot express (a space, a `%`) composes into a token that
202
+ * does not match, and the oracle reports the tag as MISSING rather than this module
203
+ * deciding what the value class is — the charset stays the seam's, which is the lesson
204
+ * of `⟨q-1c4f8ae3⟩` where a reused grammar silently inherited a domain.
205
+ */
206
+ function assertTagsAsRead(item, want) {
207
+ const got = new Map(leadingTagsOf(asWritten(item)).map((t) => [t.key, t.value]));
208
+ const same = got.size === want.size && [...want].every(([k, v]) => got.get(k) === String(v).toLowerCase());
209
+ if (!same) {
210
+ const show = (m) => m.size ? [...m].map(([k, v]) => `**[${k.toUpperCase()}:${v}]**`).join(" ") : "(none)";
211
+ throw new QueueWriteError(`the tags this would WRITE are not the tags a consumer would READ — wanted ${show(want)}, ` +
212
+ `the row parses as ${show(got)}. Most likely a value the tag grammar cannot express; ` +
213
+ `the value class is the seam's and this verb will not widen it by guessing.`);
214
+ }
215
+ }
216
+ /**
217
+ * ⛔ THE ONE-LINE INVARIANT, ENFORCED AT THE BOUNDARY RATHER THAN DOCUMENTED.
218
+ *
219
+ * `queue.v1` is one line per item and a continuation is silently dropped by every
220
+ * consumer — measured at 83% of one item's content. An agent cannot be expected
221
+ * to know that, so a multi-line `text` is REFUSED here with the reason, instead
222
+ * of being written and quietly truncated later.
223
+ */
224
+ function assertSingleLine(text) {
225
+ if (/[\r\n]/.test(text)) {
226
+ throw new QueueWriteError("text must be a single line: queue.v1 is one line per item, and every parser drops a " +
227
+ "continuation line silently (measured: 83% of one item's content lost). " +
228
+ "Put detail in a file the row points at, or fold it into this line.");
229
+ }
230
+ }
231
+ /** The tags the row will be READ as, for the result. Read back, never echoed. */
232
+ function tagsAsRead(item) {
233
+ return Object.fromEntries(leadingTagsOf(asWritten(item)).map((t) => [t.key, t.value]));
234
+ }
235
+ /** A refusal the caller can act on, distinct from a stale-base refusal. */
236
+ export class QueueWriteError extends Error {
237
+ constructor(message) {
238
+ super(message);
239
+ this.name = "QueueWriteError";
240
+ }
241
+ }
242
+ const readQueue = (repo) => {
243
+ const p = path.join(repo, QUEUE_DOC);
244
+ if (!existsSync(p))
245
+ throw new QueueWriteError(`${QUEUE_DOC} does not exist under ${repo}`);
246
+ const text = readFileSync(p, "utf8");
247
+ return { text, doc: parseWorkDoc(text) };
248
+ };
249
+ export const queueWriteSchema = {
250
+ project: z.string().min(1),
251
+ repo: z.string().optional(),
252
+ op: z.enum(["file", "amend", "reprioritise", "retag"]),
253
+ /** Required for amend and reprioritise; never supplied for file (the verb mints it). */
254
+ id: z.string().optional(),
255
+ /** What the item is about. Prose, not markdown — a single line. */
256
+ text: z.string().min(1).optional(),
257
+ priority: z.enum(PRIORITIES).optional(),
258
+ /**
259
+ * Leading tags as FIELDS. `null` clears a key; an omitted key is left alone, so
260
+ * setting `awaits` never drops a `sweep` tag the row already carries.
261
+ */
262
+ tags: z
263
+ .object({
264
+ awaits: z.string().min(1).nullable().optional(),
265
+ sweep: z.string().min(1).nullable().optional(),
266
+ })
267
+ .optional(),
268
+ };
269
+ export async function queueWriteTool(args) {
270
+ const repo = args.repo ?? process.cwd();
271
+ try {
272
+ // Refused at the boundary rather than rendered: an unknown key would compose a
273
+ // token the grammar accepts and no reader asks for — a tag nothing routes on,
274
+ // which is worse than an error because it LOOKS set.
275
+ for (const k of Object.keys(args.tags ?? {})) {
276
+ if (!TAG_KEYS.includes(k)) {
277
+ throw new QueueWriteError(`unknown tag field '${k}' — this verb sets ${TAG_KEYS.join(", ")}. ` +
278
+ `\`undelivered\` is deliberately not settable here: it is derived from the publish ` +
279
+ `record by check-undelivered-markers, and asserting it by hand is how that marker starts lying.`);
280
+ }
281
+ }
282
+ const { text: original, doc } = readQueue(repo);
283
+ const items = queueItemsOf(doc);
284
+ // Locate the block the items live in, so a filed row joins the record model
285
+ // rather than being appended as text the parser has to re-discover.
286
+ const block = doc.blocks.find((b) => b.kind === "queue");
287
+ let target;
288
+ if (args.op === "file") {
289
+ if (args.id)
290
+ throw new QueueWriteError("do not supply an id when filing: the verb mints and stamps it");
291
+ if (!args.text)
292
+ throw new QueueWriteError("filing needs `text` — what the item is about");
293
+ if (!args.priority)
294
+ throw new QueueWriteError(`filing needs \`priority\` — one of ${PRIORITIES.join(", ")}`);
295
+ assertSingleLine(args.text);
296
+ // Identity is the seam's to mint: derived from the text, then RECORDED, so
297
+ // the id stops depending on prose the moment it exists.
298
+ const seeded = parseWorkDoc(`## Queue\n- [ ] (${args.priority}) ${args.text}\n`);
299
+ const minted = queueItemsOf(seeded)[0];
300
+ if (!minted)
301
+ throw new QueueWriteError("the composed row does not parse as queue.v1 — refusing to write it");
302
+ target = withRecordedId(minted);
303
+ // AFTER the id is stamped, never before: `assertNoLeadingTag` re-parses the
304
+ // rendered row, and the id-strip is the step that exposes a hidden tag.
305
+ assertNoLeadingTag(target);
306
+ // Tags AFTER the prose gate, never instead of it: `text` is still judged on its
307
+ // own, so the field form cannot be used to smuggle what the gate refuses.
308
+ if (args.tags && Object.keys(args.tags).length) {
309
+ const { text: next, want } = retagged(target, args.tags);
310
+ assertTagsAsRead({ ...target, text: next }, want);
311
+ assertSingleLine(next);
312
+ target.text = next;
313
+ }
314
+ if (block) {
315
+ block.items.push(target);
316
+ }
317
+ else {
318
+ // AN EMPTY QUEUE SECTION HAS NO BLOCK, because blocks appear when items
319
+ // parse — and a fresh `groundwork init` queue is exactly that, so the
320
+ // FIRST filed row would otherwise be the one that cannot be filed.
321
+ //
322
+ // The seam's heading classifier is private and this module will not widen
323
+ // a shipped package's surface for its own convenience, so THE PARSER IS
324
+ // THE ORACLE instead of a guess: append the rendered line, re-parse, and
325
+ // accept only if the document now yields exactly this item as a queue
326
+ // item. If the append landed outside the queue section — a document whose
327
+ // queue is not last — the re-parse does not see it and this REFUSES
328
+ // rather than corrupting the file.
329
+ const candidate = `${original.replace(/\n*$/, "\n")}${renderQueueLine(target)}\n`;
330
+ const reparsed = parseWorkDoc(candidate);
331
+ const got = queueItemsOf(reparsed);
332
+ if (got.length !== items.length + 1 || !got.some((i) => i.id === target.id)) {
333
+ throw new QueueWriteError(`${QUEUE_DOC} has no parsed queue block and appending did not produce one — the queue section is ` +
334
+ `probably not the last section in the file. Refusing to guess where the row goes; file the first ` +
335
+ `item by hand once, or move the queue section last.`);
336
+ }
337
+ const w0 = writeDoc(repo, QUEUE_DOC, reparsed, original);
338
+ return {
339
+ ok: true,
340
+ op: args.op,
341
+ id: target.id,
342
+ priority: args.priority,
343
+ text: target.text,
344
+ wrote: w0.written ? [QUEUE_DOC] : [],
345
+ stampedNotSupplied: w0.stamped.filter((id) => id !== target.id),
346
+ tags: tagsAsRead(target),
347
+ };
348
+ }
349
+ }
350
+ else if (args.op === "retag") {
351
+ /*
352
+ * ⛔ THE WHOLE POINT: TAGS CHANGE WITHOUT THE TEXT BEING REWRITTEN.
353
+ *
354
+ * `amend` would have worked by making the caller resend the row's prose, and
355
+ * that is the defect in miniature — a verb that makes you restate 400 characters
356
+ * to set one field is a verb nobody uses at the transition, which is how the
357
+ * marker went unwritten in the first place. So `retag` REFUSES `text`: if it
358
+ * accepted it, the easy path would silently be "rewrite the row" again.
359
+ */
360
+ if (!args.id)
361
+ throw new QueueWriteError("retag needs `id` — which item to tag");
362
+ if (args.text !== undefined) {
363
+ throw new QueueWriteError("retag does not take `text`: it exists so a tag can be set WITHOUT rewriting the item's prose. " +
364
+ "Use `amend` to change what the item says.");
365
+ }
366
+ if (args.priority !== undefined) {
367
+ throw new QueueWriteError("retag does not take `priority` — use `reprioritise`");
368
+ }
369
+ const changes = args.tags ?? {};
370
+ if (!Object.keys(changes).length) {
371
+ throw new QueueWriteError(`retag needs \`tags\` — at least one of ${TAG_KEYS.join(", ")} (a value to set, or null to clear)`);
372
+ }
373
+ const found = items.find((i) => i.id === args.id);
374
+ if (!found)
375
+ throw new QueueWriteError(`no queue item with id '${args.id}' in ${QUEUE_DOC}`);
376
+ target = found;
377
+ const { text: next, want } = retagged(target, changes);
378
+ // Composed on a COPY and judged BEFORE the item is mutated, so a refusal cannot
379
+ // leave a half-tagged row in the document about to be written.
380
+ assertTagsAsRead({ ...target, text: next }, want);
381
+ assertSingleLine(next);
382
+ target.text = next;
383
+ }
384
+ else {
385
+ if (!args.id)
386
+ throw new QueueWriteError(`${args.op} needs \`id\` — which item to change`);
387
+ const found = items.find((i) => i.id === args.id);
388
+ if (!found)
389
+ throw new QueueWriteError(`no queue item with id '${args.id}' in ${QUEUE_DOC}`);
390
+ target = found;
391
+ if (args.op === "amend") {
392
+ if (!args.text)
393
+ throw new QueueWriteError("amend needs `text`");
394
+ assertSingleLine(args.text);
395
+ // Amend has the same hole as file — the rewritten text occupies the same
396
+ // structural slot — so it gets the same gate. Applied to a COPY first, so
397
+ // a refusal cannot leave the in-memory item half-changed.
398
+ assertNoLeadingTag({ ...target, text: args.text });
399
+ target.text = args.text;
400
+ }
401
+ else {
402
+ if (!args.priority)
403
+ throw new QueueWriteError(`reprioritise needs \`priority\` — one of ${PRIORITIES.join(", ")}`);
404
+ target.priority = args.priority;
405
+ // A raw tag that disagreed with the parsed priority would re-render the
406
+ // old value; clearing it keeps the two from drifting apart.
407
+ delete target.priorityRaw;
408
+ }
409
+ }
410
+ const w = writeDoc(repo, QUEUE_DOC, doc, original);
411
+ return {
412
+ ok: true,
413
+ op: args.op,
414
+ id: target.id,
415
+ priority: (target.priority ?? args.priority),
416
+ text: target.text,
417
+ wrote: w.written ? [QUEUE_DOC] : [],
418
+ stampedNotSupplied: w.stamped.filter((id) => id !== target.id),
419
+ tags: tagsAsRead(target),
420
+ };
421
+ }
422
+ catch (e) {
423
+ if (e instanceof StaleWriteError) {
424
+ return { ok: false, error: e.message, staleWrite: { doc: e.rel, drift: e.detail, alreadyWritten: e.alreadyWritten } };
425
+ }
426
+ if (e instanceof QueueWriteError)
427
+ return { ok: false, error: e.message };
428
+ throw e;
429
+ }
430
+ }
431
+ //# sourceMappingURL=queue-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-write.js","sourceRoot":"","sources":["../../src/tools/queue-write.ts"],"names":[],"mappings":"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"}