agent-yes 1.267.2 → 1.269.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +73 -0
  2. package/dist/{SUPPORTED_CLIS-CpWKDCtL.js → SUPPORTED_CLIS-Bne04-66.js} +2 -2
  3. package/dist/SUPPORTED_CLIS-CdyjhpZP.js +12 -0
  4. package/dist/{agent-yes.config-DzNini0E.js → agent-yes.config-2xKNJM5Y.js} +2 -2
  5. package/dist/{agentShare-D0reU6LW.js → agentShare-BI126Ej9.js} +8 -8
  6. package/dist/askCli-Bbxt9Umz.js +272 -0
  7. package/dist/{browser-DSduVZeZ.js → browser-CorYp8Yu.js} +1 -1
  8. package/dist/{browser-B7eYrBy7.js → browser-_2ndf80G.js} +5 -5
  9. package/dist/callback-BnUbjH7p.js +13 -0
  10. package/dist/{callback-Dlqwh9n7.js → callback-DI2r3NrV.js} +5 -5
  11. package/dist/{callbackCore-K99x3C75.js → callbackCore-Bbe7rpN2.js} +1 -1
  12. package/dist/{callbackCore-DcptaZwH.js → callbackCore-C0Cg9RbS.js} +1 -1
  13. package/dist/{channels-DQaZbare.js → channels-3gz9gHP7.js} +6 -6
  14. package/dist/{channels-yE1YUHCl.js → channels-CkaCyvEp.js} +2 -2
  15. package/dist/channels.js +5 -5
  16. package/dist/cli.js +11 -11
  17. package/dist/{cmdPs-D8gsRFVV.js → cmdPs-CVnlflxP.js} +7 -7
  18. package/dist/{configShared-DtHMBCl7.js → configShared-DYxlvrH0.js} +1 -1
  19. package/dist/{cwdConflictWarn-BpweoAiy.js → cwdConflictWarn-Buy3r_qc.js} +1 -1
  20. package/dist/{cwdPassthroughHint-BlRuOGo_.js → cwdPassthroughHint-BlWO-h5w.js} +1 -1
  21. package/dist/{e2e-CUMZC53I.js → e2e-OLfcNxiv.js} +1 -1
  22. package/dist/{expose-DyiZ5AU0.js → expose-Bfo-dZdy.js} +1 -1
  23. package/dist/{forkNested-B_4c-TQk.js → forkNested-jc2ER9xn.js} +1 -1
  24. package/dist/{hist-BoZPJ2ah.js → hist-DiOYRXuD.js} +1 -1
  25. package/dist/{html2canvas-pro.esm-cq4l_ZIw.js → html2canvas-pro.esm-D19oTQeV.js} +1 -1
  26. package/dist/identity-BmDYOuZE.js +3 -0
  27. package/dist/identity-CLaJ9-uE.js +109 -0
  28. package/dist/index.js +4 -3
  29. package/dist/{initMsg-D8cmdY76.js → initMsg-Bat5PUDf.js} +1 -1
  30. package/dist/{initMsg-BKqWDYFk.js → initMsg-CTAIqBWF.js} +8 -4
  31. package/dist/{needsInput-103zhZ90.js → needsInput-DhfIwxse.js} +1 -1
  32. package/dist/{nodeRuntime-QihGFQbI.js → nodeRuntime-CKc1BN5J.js} +1 -1
  33. package/dist/{notifyDaemon-TKtSYtEO.js → notifyDaemon-Cf4KHDOr.js} +7 -7
  34. package/dist/{notifyStore-CEDiVyis.js → notifyStore-0hlFPa6z.js} +1 -1
  35. package/dist/{notifyStore-Cbw2ZJ0X.js → notifyStore-Dus2D1XA.js} +1 -1
  36. package/dist/{openBrowser-Cs46NiH6.js → openBrowser-Dmg2Oi4q.js} +1 -1
  37. package/dist/{parentLink-CTgZZCgw.js → parentLink-BwX4jaGD.js} +1 -1
  38. package/dist/{parentLink-CQrn998L.js → parentLink-DS-XflaJ.js} +1 -1
  39. package/dist/{parentPingLoop-BEvJ2ElR.js → parentPingLoop-Bxd3dXWO.js} +6 -6
  40. package/dist/{peer-DIl5xtx8.js → peer-Dr4zvtcd.js} +3 -3
  41. package/dist/peer-u1AUAZeA.js +4 -0
  42. package/dist/{remotes-M8FbM92D.js → remotes-BiftUp09.js} +3 -3
  43. package/dist/{remotes-DdAfueOu.js → remotes-IzQHupeo.js} +3 -3
  44. package/dist/{rustBinary-B9FEbqTu.js → rustBinary-B2lNFJSe.js} +2 -2
  45. package/dist/{schedule-Bmh5uaDr.js → schedule-D1CNvuKT.js} +8 -7
  46. package/dist/{serve-BqRNIxeq.js → serve-BaHCO0bU.js} +49 -42
  47. package/dist/{setup-GYkQYxlf.js → setup-B8EL0SWL.js} +4 -4
  48. package/dist/{share-Db_zb6gH.js → share-DTPZgbfH.js} +2 -2
  49. package/dist/{share-NUhi-Wdd.js → share-RgJUhzqG.js} +2 -2
  50. package/dist/{spawnGate-CZlMs6uV.js → spawnGate-C6YKlnmb.js} +1 -1
  51. package/dist/{spawnGate-DN4wNXHq.js → spawnGate-CS3oFdJ9.js} +2 -2
  52. package/dist/{store-BW5NBouz.js → store-C7I2CAu9.js} +1 -1
  53. package/dist/{subcommands-DJpVXIb6.js → subcommands-03ghe-aZ.js} +192 -157
  54. package/dist/{subcommands-DLrJfG4D.js → subcommands-BS4lnTrb.js} +6 -6
  55. package/dist/{systemPathLink-BHv1I6wh.js → systemPathLink-DGVcx0fg.js} +1 -1
  56. package/dist/{terminal-CRLPUaKF.js → terminal-DrCP-200.js} +2 -2
  57. package/dist/terminal.js +1 -1
  58. package/dist/todoAutomation-BETGOik9.js +302 -0
  59. package/dist/{todoCli-BYGZ7_C5.js → todoCli-DUoxA1dh.js} +164 -37
  60. package/dist/todoIdentity-BffBxRHA.js +138 -0
  61. package/dist/{todoAutomation-BQRW614S.js → todoStore-Wk8U4zJ8.js} +63 -280
  62. package/dist/{tray-CzGs9-ch.js → tray-Bxq_sfvU.js} +1 -1
  63. package/dist/trayApp-BDMzlxRo.js +5 -0
  64. package/dist/{trayApp-DLMUu2sB.js → trayApp-DC4qjut7.js} +2 -2
  65. package/dist/{ts-ClwhahH9.js → ts-D0Pk-WJg.js} +14 -8
  66. package/dist/{versionChecker-ZQYirfMp.js → versionChecker-V6ceVsu9.js} +2 -2
  67. package/dist/{webrtcLink-DyCj380i.js → webrtcLink-B72AQ2eb.js} +2 -2
  68. package/dist/{webrtcRemote-Bl8eowma.js → webrtcRemote-D68dkqFp.js} +3 -3
  69. package/dist/{widget-DtZ1WXkf.js → widget-BM03OkC1.js} +3 -3
  70. package/dist/widget.js +1 -1
  71. package/dist/widgets.js +5 -5
  72. package/dist/{workspaceConfig-CBKlgA_q.js → workspaceConfig-EK7XNsgR.js} +1 -1
  73. package/dist/{ws-CiR2nOD3.js → ws-6l7Wb_0r.js} +7 -7
  74. package/dist/{ws-Ba372Tym.js → ws-pRFrqms9.js} +3 -3
  75. package/lab/ui/console-logic.js +64 -0
  76. package/lab/ui/index.html +58 -4
  77. package/package.json +1 -1
  78. package/ts/askCli.spec.ts +304 -0
  79. package/ts/askCli.ts +378 -0
  80. package/ts/identity.spec.ts +80 -1
  81. package/ts/identity.ts +16 -9
  82. package/ts/index.ts +6 -1
  83. package/ts/initMsg.spec.ts +22 -14
  84. package/ts/initMsg.ts +7 -2
  85. package/ts/ipcLock.spec.ts +107 -0
  86. package/ts/ipcLock.ts +130 -0
  87. package/ts/serve.ts +68 -17
  88. package/ts/subcommandMirror.spec.ts +76 -0
  89. package/ts/subcommands.spec.ts +115 -10
  90. package/ts/subcommands.ts +108 -36
  91. package/ts/todoAutomation.spec.ts +64 -0
  92. package/ts/todoAutomation.ts +25 -2
  93. package/ts/todoBlock.spec.ts +31 -1
  94. package/ts/todoBlock.ts +33 -1
  95. package/ts/todoCli.spec.ts +199 -4
  96. package/ts/todoCli.ts +266 -42
  97. package/ts/todoIdentity.spec.ts +85 -0
  98. package/ts/todoIdentity.ts +76 -0
  99. package/ts/todoLifecycle.spec.ts +13 -1
  100. package/ts/todoLifecycle.ts +35 -1
  101. package/ts/todoRoot.spec.ts +117 -0
  102. package/ts/todoRoot.ts +90 -0
  103. package/ts/todoStore.spec.ts +25 -0
  104. package/ts/todoStore.ts +36 -2
  105. package/dist/SUPPORTED_CLIS-DDs0xUvV.js +0 -11
  106. package/dist/callback-Bgehh-IW.js +0 -13
  107. package/dist/peer-Cvntlw1i.js +0 -4
  108. package/dist/trayApp-CoD89Y1_.js +0 -5
@@ -2,18 +2,6 @@ import { t as JsonlStore } from "./JsonlStore-CPGIR0Wy.js";
2
2
  import path from "path";
3
3
  import { lock } from "proper-lockfile";
4
4
 
5
- //#region ts/removeControlCharacters.ts
6
- const ESC = String.fromCharCode(27);
7
- const C1 = String.fromCharCode(155);
8
- const BACKSLASH = String.fromCharCode(92);
9
- const ST_PATTERN_SOURCE = ESC + BACKSLASH + BACKSLASH;
10
- const OSC_PATTERN = new RegExp(ESC + "][^\x07\x1B]*(?:\x07|" + ST_PATTERN_SOURCE + ")", "g");
11
- const CSI_PATTERN = new RegExp("[" + ESC + C1 + "][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]", "g");
12
- function removeControlCharacters(str) {
13
- return str.replace(OSC_PATTERN, "").replace(CSI_PATTERN, "");
14
- }
15
-
16
- //#endregion
17
5
  //#region ts/todoLifecycle.ts
18
6
  /**
19
7
  * States considered "finished" across every kind. A finished task is never
@@ -130,6 +118,21 @@ const LIFECYCLES = {
130
118
  from: "decided",
131
119
  to: "done"
132
120
  }]
121
+ },
122
+ question: {
123
+ states: [
124
+ "pending",
125
+ "answered",
126
+ "done"
127
+ ],
128
+ transitions: [{
129
+ from: "pending",
130
+ to: "answered",
131
+ gate: "answer-received"
132
+ }, {
133
+ from: "answered",
134
+ to: "done"
135
+ }]
133
136
  }
134
137
  };
135
138
  /** The state a newly-created task of `kind` starts in (its graph's first state). */
@@ -138,6 +141,23 @@ function initialState(kind) {
138
141
  if (!first) throw new Error(`lifecycle kind "${kind}" has no states`);
139
142
  return first;
140
143
  }
144
+ /**
145
+ * Every transition of `kind`, or `[]` when this binary has never heard of that
146
+ * kind.
147
+ *
148
+ * Use this — never a bare `LIFECYCLES[rec.kind]` — whenever the kind comes off
149
+ * a STORED RECORD rather than from validated CLI input. The store is shared by
150
+ * every agent on a machine, and those agents routinely run different builds
151
+ * (one lane on a fresh `bun link`, another on the published npm package), so an
152
+ * older binary WILL read records whose kind was added later. Indexing directly
153
+ * throws `Cannot read properties of undefined`, taking down `ls`/`reconcile`
154
+ * for every task rather than just the one it cannot interpret. Degrading to "no
155
+ * transitions" instead means the unknown task is simply not actionable by the
156
+ * old binary — it still lists, and its data is untouched.
157
+ */
158
+ function transitionsOf(kind) {
159
+ return LIFECYCLES[kind]?.transitions ?? [];
160
+ }
141
161
  /** States reachable in one transition from `currentState`, regardless of gates. */
142
162
  function nextStates(kind, currentState) {
143
163
  return LIFECYCLES[kind].transitions.filter((t) => t.from === currentState).map((t) => t.to);
@@ -388,7 +408,7 @@ var TodoStore = class TodoStore {
388
408
  return this.withStoreLock(async () => {
389
409
  await this.jsonl.load();
390
410
  const rec = this.mustGet(id);
391
- if (!LIFECYCLES[rec.kind].transitions.some((t) => t.from === rec.state && t.gate === gateName)) throw new Error(`task ${id}: "${gateName}" is not a gate on any transition from its current state "${rec.state}"`);
411
+ if (!transitionsOf(rec.kind).some((t) => t.from === rec.state && t.gate === gateName)) throw new Error(`task ${id}: "${gateName}" is not a gate on any transition from its current state "${rec.state}"`);
392
412
  if (rec.owner && rec.owner.trim().toLowerCase() === validator.toLowerCase()) throw new Error(`task ${id}: independent verification required — validator "${validator}" is the same identity as owner "${rec.owner}"; the worker cannot certify their own work`);
393
413
  const satisfied = new Set(rec.satisfiedGates);
394
414
  satisfied.add(gateName);
@@ -433,7 +453,7 @@ var TodoStore = class TodoStore {
433
453
  */
434
454
  async verify(id, gateName) {
435
455
  const rec = this.mustGet(id);
436
- const edges = LIFECYCLES[rec.kind].transitions.filter((t) => t.from === rec.state && t.gate);
456
+ const edges = transitionsOf(rec.kind).filter((t) => t.from === rec.state && t.gate);
437
457
  if (edges.length === 0) throw new Error(`task ${id}: no gated transition from state "${rec.state}"`);
438
458
  const targetEdge = gateName ? edges.find((e) => e.gate === gateName) : edges.find((e) => this.gates.has(e.gate));
439
459
  if (!targetEdge || !targetEdge.gate) throw new Error(`task ${id}: no registered gate found for a transition from "${rec.state}"${gateName ? ` matching "${gateName}"` : ""}`);
@@ -510,6 +530,33 @@ var TodoStore = class TodoStore {
510
530
  if (!trimmed) throw new Error(`task ${id}: acceptance criteria text must not be empty`);
511
531
  return this.rawUpdate(id, () => ({ acceptanceCriteria: trimmed }));
512
532
  }
533
+ /**
534
+ * Reassign a task (`ay todo claim`). Ownership is the one field in this
535
+ * store that TWO agents actively compete for, so this takes the owner the
536
+ * caller believed was current and re-checks it against the FRESH record
537
+ * inside the write lock.
538
+ *
539
+ * Without that check, the CLI's shape — read the task, decide whether its
540
+ * owner is a live agent, then write — is a textbook lost update: two agents
541
+ * that both read "unowned" a millisecond apart would both pass their own
542
+ * liveness check and both write, and the loser would never learn it lost.
543
+ * The same revalidate-against-fresh discipline `clearWaitingOnAgentBlock`
544
+ * and `markOrphaned` already use, for the same reason.
545
+ *
546
+ * `expectedOwner` is `undefined` to skip the check, `null` to require the
547
+ * task still be unowned, or a string to require that exact current owner.
548
+ */
549
+ async setOwner(id, owner, expectedOwner) {
550
+ const trimmed = owner.trim();
551
+ if (!trimmed) throw new Error(`task ${id}: owner must not be empty`);
552
+ return this.rawUpdate(id, (fresh) => {
553
+ if (expectedOwner !== void 0) {
554
+ const current = fresh.owner ?? null;
555
+ if (current !== expectedOwner) throw new Error(`task ${id}: owner changed to ${current ?? "(none)"} while claiming (expected ${expectedOwner ?? "(none)"}) — re-read it and try again`);
556
+ }
557
+ return { owner: trimmed };
558
+ });
559
+ }
513
560
  setBlock(id, block) {
514
561
  return this.rawUpdate(id, (fresh) => ({
515
562
  block,
@@ -693,269 +740,5 @@ async function openStore(projectRoot) {
693
740
  }
694
741
 
695
742
  //#endregion
696
- //#region ts/todoBlock.ts
697
- /**
698
- * How a block of this type should be watched. Kept as one pure function so
699
- * every caller (CLI rendering, automation, `/ask` aggregation) agrees on the
700
- * same classification instead of re-deriving it ad hoc.
701
- */
702
- function monitorHint(block) {
703
- switch (block.type) {
704
- case "blocked-by-task":
705
- case "blocked-by-human": return "none";
706
- case "waiting-on-agent": return "notify-agent";
707
- case "blocked-by-external": return "poll-external";
708
- }
709
- }
710
- /** One-line human-readable summary, used by CLI/digest rendering. */
711
- function describeBlock(block) {
712
- switch (block.type) {
713
- case "blocked-by-task": return `blocked by task ${block.taskId}`;
714
- case "blocked-by-human": return `waiting on ${block.who}${block.question ? `: ${block.question}` : ""}${block.actionLink ? ` (action: ${block.actionLink})` : ""}`;
715
- case "blocked-by-external": return `waiting on external signal: ${block.signal}`;
716
- case "waiting-on-agent": return `waiting on agent ${block.agentId}`;
717
- }
718
- }
719
-
720
- //#endregion
721
- //#region ts/todoDigest.ts
722
- /**
723
- * Read-side views over the `ay todo` store: dependency-tree rendering and a
724
- * per-tag digest board. Pure functions over an already-loaded task list — no
725
- * I/O — so they are trivially unit-testable and reusable by both the CLI
726
- * (`todoCli.ts`) and any future web view.
727
- *
728
- * `unblockedTasks` is ported near-verbatim from the equivalent, already
729
- * mutation-tested algorithm in a private sibling CLI's `deps.ts` (a closed-source
730
- * downstream consumer of an earlier, less general version of this idea) —
731
- * generalized here to the new `TodoRecord` shape and the `done` state name
732
- * from `todoLifecycle.ts` instead of a hardcoded status string.
733
- */
734
- /**
735
- * The full set of task ids `t` is waiting on: the structural `blockedBy`
736
- * array PLUS, if `t.block` is a `blocked-by-task` shape, that block's own
737
- * `taskId`. Without folding the latter in, a task blocked via
738
- * `ay todo block --type blocked-by-task --task X` would never be detected
739
- * as resolved once X reaches `done` — contradicting `todoBlock.ts`'s own
740
- * documented promise that this block type "clears itself... pure data, no
741
- * monitor needed" (codex-review Important: the two mechanisms didn't
742
- * actually talk to each other, making `blocked-by-task` blocks inert).
743
- */
744
- function declaredTaskDeps(t) {
745
- return t.block?.type === "blocked-by-task" ? [...t.blockedBy, t.block.taskId] : t.blockedBy;
746
- }
747
- /**
748
- * A task is "unblocked" when it is not itself finished, it declares task
749
- * dependencies (via `blockedBy` and/or a `blocked-by-task` block), and
750
- * every one of them has reached `done`.
751
- * Surfaced for a caller to act on — never auto-applied here (deciding to
752
- * resume a task is left to automation, a later milestone, or a human).
753
- */
754
- function unblockedTasks(tasks) {
755
- const byId = new Map(tasks.map((t) => [t._id, t]));
756
- return tasks.filter((t) => {
757
- if (t.state === DONE_STATE) return false;
758
- const deps = declaredTaskDeps(t);
759
- if (deps.length === 0) return false;
760
- return deps.every((d) => byId.get(d)?.state === DONE_STATE);
761
- });
762
- }
763
- /** Blockers of `t` that have not reached `done` yet (a missing id is reported as-is, still "open"). */
764
- function openBlockers(t, byId) {
765
- return declaredTaskDeps(t).filter((d) => byId.get(d)?.state !== DONE_STATE);
766
- }
767
- function nodeLine(t) {
768
- return [`${t._id} [${t.state}] ${t.summary}`, ...t.owner ? [`owner:${t.owner}`] : []].join(" ");
769
- }
770
- /**
771
- * Dependency tree, rendered from roots (tasks nothing depends on, that
772
- * themselves declare at least one dependency) down their `blockedBy` edges:
773
- * a parent's children are what it is waiting for.
774
- */
775
- function renderTree(tasks, rootId) {
776
- const byId = new Map(tasks.map((t) => [t._id, t]));
777
- const dependedOn = new Set(tasks.flatMap((t) => t.blockedBy));
778
- const roots = rootId ? [byId.get(rootId) ?? null].filter((t) => t !== null) : tasks.filter((t) => !dependedOn.has(t._id) && t.blockedBy.length > 0);
779
- if (rootId && roots.length === 0) throw new Error(`no such task: ${rootId}`);
780
- if (roots.length === 0) return "(no dependency links)";
781
- const lines = [];
782
- const walk = (t, prefix, isLast, depth, seen) => {
783
- lines.push(depth === 0 ? nodeLine(t) : `${prefix}${isLast ? "└─" : "├─"} ${nodeLine(t)}`);
784
- if (seen.has(t._id)) return;
785
- seen.add(t._id);
786
- const deps = t.blockedBy.map((d) => byId.get(d)).filter((x) => x !== void 0);
787
- deps.forEach((d, i) => {
788
- walk(d, depth === 0 ? "" : `${prefix}${isLast ? " " : "│ "}`, i === deps.length - 1, depth + 1, seen);
789
- });
790
- };
791
- roots.forEach((r) => walk(r, "", true, 0, /* @__PURE__ */ new Set()));
792
- return lines.join("\n");
793
- }
794
- /**
795
- * JSON-shaped equivalent of `renderTree` — same roots-and-edges logic, built
796
- * as data instead of formatted lines, so a machine caller (`--format json`)
797
- * gets the actual tree structure rather than a string it would have to
798
- * re-parse (codex-review Important: the CLI previously ignored --format for
799
- * this command entirely, always writing the human text with exit code 0).
800
- */
801
- function buildTreeJSON(tasks, rootId) {
802
- const byId = new Map(tasks.map((t) => [t._id, t]));
803
- const dependedOn = new Set(tasks.flatMap((t) => t.blockedBy));
804
- const roots = rootId ? [byId.get(rootId) ?? null].filter((t) => t !== null) : tasks.filter((t) => !dependedOn.has(t._id) && t.blockedBy.length > 0);
805
- if (rootId && roots.length === 0) throw new Error(`no such task: ${rootId}`);
806
- const build = (t, ancestors) => {
807
- const node = {
808
- id: t._id,
809
- state: t.state,
810
- summary: t.summary,
811
- ...t.owner ? { owner: t.owner } : {},
812
- children: []
813
- };
814
- if (ancestors.has(t._id)) return node;
815
- const nextAncestors = new Set(ancestors).add(t._id);
816
- node.children = t.blockedBy.map((d) => byId.get(d)).filter((x) => x !== void 0).map((d) => build(d, nextAncestors));
817
- return node;
818
- };
819
- return roots.map((r) => build(r, /* @__PURE__ */ new Set()));
820
- }
821
- /** Per-tag board: state counts per tag, plus an unblocked-tasks callout. */
822
- function renderDigest(tasks) {
823
- if (tasks.length === 0) return "(no tasks)";
824
- const byId = new Map(tasks.map((t) => [t._id, t]));
825
- const unblocked = new Set(unblockedTasks(tasks).map((t) => t._id));
826
- const streams = /* @__PURE__ */ new Map();
827
- for (const t of tasks) for (const tag of t.tags.length ? t.tags : ["(untagged)"]) {
828
- if (!streams.has(tag)) streams.set(tag, []);
829
- streams.get(tag).push(t);
830
- }
831
- const lines = [];
832
- for (const [stream, items] of [...streams.entries()].sort(([a], [b]) => a.localeCompare(b))) {
833
- const allStates = [...new Set(items.map((t) => t.state))].sort();
834
- const counts = allStates.map((s) => `${s}:${items.filter((t) => t.state === s).length}`).join(" ");
835
- lines.push(`## ${stream} (${counts})`);
836
- for (const s of allStates) for (const t of items.filter((x) => x.state === s)) {
837
- const open = openBlockers(t, byId);
838
- const extra = [
839
- ...t.owner ? [`owner:${t.owner}`] : [],
840
- ...t.block ? [`block:${t.block.type}`] : [],
841
- ...open.length ? [`blockedBy:${open.join(",")}`] : [],
842
- ...unblocked.has(t._id) ? ["UNBLOCKED"] : []
843
- ];
844
- lines.push(` [${t.state}] ${t._id} ${t.summary}${extra.length ? ` [${extra.join(" ")}]` : ""}`);
845
- }
846
- lines.push("");
847
- }
848
- const ub = unblockedTasks(tasks);
849
- if (ub.length) {
850
- lines.push("## unblocked (all blockers reached done — resume these)");
851
- for (const t of ub) lines.push(` ${t._id} ${t.summary}${t.owner ? ` (owner:${t.owner})` : ""}`);
852
- lines.push("");
853
- }
854
- return lines.join("\n").trimEnd();
855
- }
856
-
857
- //#endregion
858
- //#region ts/todoAutomation.ts
859
- /**
860
- * Reactive layer for the `ay todo` engine (Milestone 2): makes the engine
861
- * self-driving for agent-facing signals `agent-yes` already tracks, instead
862
- * of requiring every state change to be typed by hand.
863
- *
864
- * `reconcileTodos` is pure — decision logic only, no I/O — exactly the same
865
- * "decide" / "do" split a private sibling CLI's existing `watchdog.ts`
866
- * (`decideActions`) already uses successfully: the hard-to-get-right parts
867
- * (edge cases) live in a function that takes plain data in and returns plain
868
- * data out, so they are trivially unit-testable without a real store, real
869
- * processes, or real time. Applying the returned actions to a real
870
- * `TodoStore` (I/O) is a separate, thin step (see `todoCli.ts`'s `reconcile`
871
- * verb) deliberately kept out of this file — including revalidating each
872
- * action against a FRESH record immediately before writing, since the
873
- * snapshot this function decided from can be stale by the time the caller
874
- * applies it (codex-review Important, see the action shapes below).
875
- */
876
- /**
877
- * `TodoRecord.owner` is opaque — a human name/handle OR a tracked agent's
878
- * stable id, this module cannot tell which just by looking at the string.
879
- * The only safe signal is whether the identifier appears in the live-agent
880
- * registry AT ALL: a KNOWN agent id whose latest record says `exited` is
881
- * confirmed dead and orphan-eligible; an identifier with NO record at all is
882
- * assumed to be a human owner (who was never going to appear there) and is
883
- * never orphaned on that basis alone. Getting this backwards would orphan
884
- * every human-owned task on every tick, since a human obviously never shows
885
- * up in the agent process table.
886
- */
887
- function deadOwnerAgent(ownerId, agents) {
888
- const rec = agents.find((a) => a.agent_id === ownerId);
889
- return rec !== void 0 && rec.status === "exited";
890
- }
891
- /** Up to `limit` OTHER agent ids currently idle — candidates to hand an orphaned task to. */
892
- function idleCandidates(excludeAgentId, agents, limit = 3) {
893
- return agents.filter((a) => !!a.agent_id).filter((a) => a.agent_id !== excludeAgentId && a.status === "idle").map((a) => a.agent_id).slice(0, limit);
894
- }
895
- /**
896
- * Decide what should happen given the current tasks and the current live-agent
897
- * snapshot. Four rules, each traceable to a specific requirement (see
898
- * `docs/2026-07-23-todo-lifecycle-execplan.md`'s Milestone 2 section):
899
- *
900
- * - owner's agent process is gone and the task isn't finished → `orphan`.
901
- * - a `waiting-on-agent` block whose agent went idle or exited successfully
902
- * (exit code 0) → `clear-waiting-on-agent`.
903
- * - a task currently in `unblockedTasks()` with an owner → `notify-unblocked`,
904
- * reported on EVERY call (no dedup/state file): there is no real delivery
905
- * channel wired yet (see `todoCli.ts`'s `reconcile` verb doc comment), so
906
- * persisting "already notified" would silently retire the one signal an
907
- * owner would ever get with nobody having actually received it
908
- * (codex-review Important) — the same no-dedup convention `renderDigest`'s
909
- * own "unblocked" section already uses.
910
- * - a task in a state whose outgoing edge's gate is registered → `auto-verify`
911
- * (the actual gate CALL is real I/O and happens in the caller via `store.verify()`;
912
- * this only decides which tasks are eligible to try).
913
- *
914
- * An orphaned task is skipped for the OTHER rules this same tick (its owner is
915
- * gone, so it cannot also be "waiting on" that same dead agent in a meaningful
916
- * way, and it is no longer eligible for auto-verify either).
917
- */
918
- function reconcileTodos(tasks, agents, registeredGates) {
919
- const actions = [];
920
- const orphanedThisTick = /* @__PURE__ */ new Set();
921
- for (const t of tasks) {
922
- if (t.state === DONE_STATE || t.state === ORPHANED_STATE) continue;
923
- if (t.owner && deadOwnerAgent(t.owner, agents)) {
924
- actions.push({
925
- type: "orphan",
926
- taskId: t._id,
927
- from: t.state,
928
- expectedOwner: t.owner,
929
- candidates: idleCandidates(t.owner, agents)
930
- });
931
- orphanedThisTick.add(t._id);
932
- continue;
933
- }
934
- if (t.block?.type === "waiting-on-agent") {
935
- const agentId = t.block.agentId;
936
- const agent = agents.find((a) => a.agent_id === agentId);
937
- if (agent && (agent.status === "idle" || agent.status === "exited" && agent.exit_code === 0)) actions.push({
938
- type: "clear-waiting-on-agent",
939
- taskId: t._id,
940
- expectedAgentId: agentId
941
- });
942
- }
943
- if (LIFECYCLES[t.kind].transitions.some((edge) => edge.from === t.state && edge.gate && registeredGates.has(edge.gate))) actions.push({
944
- type: "auto-verify",
945
- taskId: t._id
946
- });
947
- }
948
- for (const t of unblockedTasks(tasks)) {
949
- if (orphanedThisTick.has(t._id) || !t.owner) continue;
950
- actions.push({
951
- type: "notify-unblocked",
952
- taskId: t._id,
953
- owner: t.owner
954
- });
955
- }
956
- return actions;
957
- }
958
-
959
- //#endregion
960
- export { isKnownKind as _, renderTree as a, statesOf as b, monitorHint as c, openStore as d, DONE_STATE as f, initialState as g, canTransition as h, renderDigest as i, CycleError as l, ORPHANED_STATE as m, buildTreeJSON as n, unblockedTasks as o, LIFECYCLES as p, openBlockers as r, describeBlock as s, reconcileTodos as t, TodoStore as u, nextStates as v, removeControlCharacters as x, requiredGate as y };
961
- //# sourceMappingURL=todoAutomation-BQRW614S.js.map
743
+ export { LIFECYCLES as a, initialState as c, requiredGate as d, statesOf as f, DONE_STATE as i, isKnownKind as l, TodoStore as n, ORPHANED_STATE as o, transitionsOf as p, openStore as r, canTransition as s, CycleError as t, nextStates as u };
744
+ //# sourceMappingURL=todoStore-Wk8U4zJ8.js.map
@@ -187,4 +187,4 @@ async function startTray() {
187
187
 
188
188
  //#endregion
189
189
  export { ensureTray, startTray };
190
- //# sourceMappingURL=tray-CzGs9-ch.js.map
190
+ //# sourceMappingURL=tray-Bxq_sfvU.js.map
@@ -0,0 +1,5 @@
1
+ import "./versionChecker-V6ceVsu9.js";
2
+ import "./rustBinary-B2lNFJSe.js";
3
+ import { a as trayHiddenMarker, i as launchTray, n as hasDesktop, r as isTrayHidden, t as cmdTray } from "./trayApp-DC4qjut7.js";
4
+
5
+ export { cmdTray };
@@ -1,4 +1,4 @@
1
- import { n as findTrayLauncher } from "./rustBinary-B9FEbqTu.js";
1
+ import { n as findTrayLauncher } from "./rustBinary-B2lNFJSe.js";
2
2
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
@@ -97,4 +97,4 @@ async function cmdTray(args) {
97
97
 
98
98
  //#endregion
99
99
  export { trayHiddenMarker as a, launchTray as i, hasDesktop as n, isTrayHidden as r, cmdTray as t };
100
- //# sourceMappingURL=trayApp-DLMUu2sB.js.map
100
+ //# sourceMappingURL=trayApp-DC4qjut7.js.map
@@ -1,13 +1,14 @@
1
1
  import { n as __esmMin, r as __exportAll } from "./chunk-cZBX9HZv.js";
2
2
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-ZQYirfMp.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-V6ceVsu9.js";
4
4
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
5
- import { d as openStore, p as LIFECYCLES, x as removeControlCharacters } from "./todoAutomation-BQRW614S.js";
5
+ import { u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
6
6
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
7
7
  import { i as readGlobalPids } from "./globalPidIndex-Dq4KY2IV.js";
8
8
  import { t as PidStore } from "./pidStore-DJqSZPJi.js";
9
9
  import { r as recordInbox } from "./messageLog-BYFwioFY.js";
10
10
  import { n as register, r as sweep } from "./reaper-C4BvNylH.js";
11
+ import { a as LIFECYCLES, r as openStore } from "./todoStore-Wk8U4zJ8.js";
11
12
  import { arch, platform } from "process";
12
13
  import { execSync } from "child_process";
13
14
  import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
@@ -1525,7 +1526,7 @@ async function compactRawLogTail(logPath, keepBytes = RAW_LOG_KEEP_BYTES) {
1525
1526
  await fh.close();
1526
1527
  }
1527
1528
  }
1528
- const config = await import("./agent-yes.config-DzNini0E.js").then((mod) => mod.default || mod);
1529
+ const config = await import("./agent-yes.config-2xKNJM5Y.js").then((mod) => mod.default || mod);
1529
1530
  const CLIS_CONFIG = config.clis;
1530
1531
  /**
1531
1532
  * Main function to run agent-cli with automatic yes/no responses
@@ -1598,11 +1599,16 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1598
1599
  })();
1599
1600
  const originalPrompt = prompt;
1600
1601
  if (prompt && inheritedParentPid) try {
1601
- const { resolveSpawner } = await import("./parentLink-CQrn998L.js");
1602
+ const { resolveSpawner } = await import("./parentLink-DS-XflaJ.js");
1602
1603
  const spawner = await resolveSpawner(inheritedParentPid);
1603
1604
  if (spawner) {
1604
- const { buildInitMsg } = await import("./initMsg-D8cmdY76.js");
1605
- prompt = buildInitMsg(prompt, spawner, randomBytes(4).toString("hex"));
1605
+ const { buildInitMsg } = await import("./initMsg-Bat5PUDf.js");
1606
+ const { formatIdentity } = await import("./identity-BmDYOuZE.js");
1607
+ const identity = formatIdentity({
1608
+ cwd: spawner.cwd,
1609
+ pid: spawner.pid
1610
+ });
1611
+ prompt = buildInitMsg(prompt, spawner, randomBytes(4).toString("hex"), identity);
1606
1612
  }
1607
1613
  } catch (error) {
1608
1614
  if (verbose) logger.warn("[init-msg] failed to wrap initial prompt:", { error });
@@ -2068,7 +2074,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
2068
2074
  }, 100);
2069
2075
  const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
2070
2076
  shell.onExit(cleanupHeartbeat);
2071
- const { startParentPingLoop } = await import("./parentPingLoop-BEvJ2ElR.js");
2077
+ const { startParentPingLoop } = await import("./parentPingLoop-Bxd3dXWO.js");
2072
2078
  const parentPingLoop = startParentPingLoop({
2073
2079
  parentPid,
2074
2080
  selfWrapperPid: process.pid,
@@ -2332,4 +2338,4 @@ function sleep(ms) {
2332
2338
 
2333
2339
  //#endregion
2334
2340
  export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
2335
- //# sourceMappingURL=ts-ClwhahH9.js.map
2341
+ //# sourceMappingURL=ts-D0Pk-WJg.js.map
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
7
7
 
8
8
  //#region package.json
9
9
  var name = "agent-yes";
10
- var version = "1.267.2";
10
+ var version = "1.269.1";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -215,4 +215,4 @@ async function displayVersion() {
215
215
 
216
216
  //#endregion
217
217
  export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
218
- //# sourceMappingURL=versionChecker-ZQYirfMp.js.map
218
+ //# sourceMappingURL=versionChecker-V6ceVsu9.js.map
@@ -1,4 +1,4 @@
1
- import { u as parseSecret } from "./e2e-CUMZC53I.js";
1
+ import { u as parseSecret } from "./e2e-OLfcNxiv.js";
2
2
 
3
3
  //#region ts/webrtcLink.ts
4
4
  const SIGNAL_SUBPROTOCOL = "ay-signal-1";
@@ -42,4 +42,4 @@ function isWebrtcSpec(spec) {
42
42
 
43
43
  //#endregion
44
44
  export { isWebrtcSpec as n, parseWebrtcLink as r, SIGNAL_SUBPROTOCOL as t };
45
- //# sourceMappingURL=webrtcLink-DyCj380i.js.map
45
+ //# sourceMappingURL=webrtcLink-B72AQ2eb.js.map
@@ -1,5 +1,5 @@
1
- import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys } from "./e2e-CUMZC53I.js";
2
- import { n as isWebrtcSpec, r as parseWebrtcLink, t as SIGNAL_SUBPROTOCOL } from "./webrtcLink-DyCj380i.js";
1
+ import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys } from "./e2e-OLfcNxiv.js";
2
+ import { n as isWebrtcSpec, r as parseWebrtcLink, t as SIGNAL_SUBPROTOCOL } from "./webrtcLink-B72AQ2eb.js";
3
3
  import { RTCPeerConnection } from "node-datachannel/polyfill";
4
4
 
5
5
  //#region ts/webrtcRemote.ts
@@ -256,4 +256,4 @@ async function startWebrtcBridge(link) {
256
256
 
257
257
  //#endregion
258
258
  export { startWebrtcBridge };
259
- //# sourceMappingURL=webrtcRemote-Bl8eowma.js.map
259
+ //# sourceMappingURL=webrtcRemote-D68dkqFp.js.map
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
28
28
  }
29
29
  /** Resolve the local daemon base URL + token (flags override discovery). */
30
30
  async function daemonTarget(flags) {
31
- const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-BqRNIxeq.js");
31
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-BaHCO0bU.js");
32
32
  const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
33
33
  if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
34
34
  const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
@@ -186,7 +186,7 @@ async function cmdMint(args) {
186
186
  const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
187
187
  if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
188
188
  const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
189
- const { mintScopedTermToken } = await import("./serve-BqRNIxeq.js");
189
+ const { mintScopedTermToken } = await import("./serve-BaHCO0bU.js");
190
190
  const r = await mintScopedTermToken(target, {
191
191
  ttlSec,
192
192
  caps
@@ -202,4 +202,4 @@ async function cmdMint(args) {
202
202
 
203
203
  //#endregion
204
204
  export { cmdMint, cmdWidget };
205
- //# sourceMappingURL=widget-DtZ1WXkf.js.map
205
+ //# sourceMappingURL=widget-BM03OkC1.js.map
package/dist/widget.js CHANGED
@@ -142,7 +142,7 @@ var AyWidget = class {
142
142
  }
143
143
  async h2c(el, viewport, rect, unclipSelector) {
144
144
  const g = globalThis;
145
- const mod = await import("./html2canvas-pro.esm-cq4l_ZIw.js");
145
+ const mod = await import("./html2canvas-pro.esm-D19oTQeV.js");
146
146
  const html2canvas = mod.default ?? mod;
147
147
  const opts = {
148
148
  backgroundColor: viewport ? "#ffffff" : null,
package/dist/widgets.js CHANGED
@@ -1,8 +1,8 @@
1
- import "./e2e-CUMZC53I.js";
2
- import "./channels-yE1YUHCl.js";
3
- import "./peer-DIl5xtx8.js";
4
- import { t as AyChannel } from "./browser-B7eYrBy7.js";
5
- import { t as AyTerminal } from "./browser-DSduVZeZ.js";
1
+ import "./e2e-OLfcNxiv.js";
2
+ import "./channels-CkaCyvEp.js";
3
+ import "./peer-Dr4zvtcd.js";
4
+ import { t as AyChannel } from "./browser-_2ndf80G.js";
5
+ import { t as AyTerminal } from "./browser-CorYp8Yu.js";
6
6
  import { AyWidget } from "./widget.js";
7
7
 
8
8
  export { AyChannel, AyTerminal, AyWidget };
@@ -215,4 +215,4 @@ function allowsSkipPermissions() {
215
215
 
216
216
  //#endregion
217
217
  export { getProvisionRoot as a, getWorkspaceRoot as c, isProvisionAllowed as d, resolveSpawnCwd as f, getProvisionHook as i, hasProvisionHook as l, getMaxAgents as n, getSpawnHook as o, setWorkspaceRoot as p, getMinFreeMb as r, getSpawnWaitMs as s, allowsSkipPermissions as t, hasSpawnHook as u };
218
- //# sourceMappingURL=workspaceConfig-CBKlgA_q.js.map
218
+ //# sourceMappingURL=workspaceConfig-EK7XNsgR.js.map
@@ -1,12 +1,12 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-Dq4KY2IV.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
- import "./e2e-CUMZC53I.js";
5
- import "./configShared-DtHMBCl7.js";
6
- import "./subcommands-DJpVXIb6.js";
7
- import "./notifyStore-Cbw2ZJ0X.js";
8
- import "./webrtcLink-DyCj380i.js";
9
- import "./remotes-DdAfueOu.js";
10
- import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-Ba372Tym.js";
4
+ import "./e2e-OLfcNxiv.js";
5
+ import "./configShared-DYxlvrH0.js";
6
+ import "./subcommands-03ghe-aZ.js";
7
+ import "./notifyStore-Dus2D1XA.js";
8
+ import "./webrtcLink-B72AQ2eb.js";
9
+ import "./remotes-IzQHupeo.js";
10
+ import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-pRFrqms9.js";
11
11
 
12
12
  export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, walkWorkspaces, workspaceStatus };
@@ -1,5 +1,5 @@
1
- import { O as listRecords } from "./subcommands-DJpVXIb6.js";
2
- import { a as getProvisionRoot } from "./workspaceConfig-CBKlgA_q.js";
1
+ import { O as listRecords } from "./subcommands-03ghe-aZ.js";
2
+ import { a as getProvisionRoot } from "./workspaceConfig-EK7XNsgR.js";
3
3
  import { existsSync } from "fs";
4
4
  import { lstat, opendir } from "fs/promises";
5
5
  import path from "path";
@@ -424,4 +424,4 @@ async function cmdWs(args) {
424
424
 
425
425
  //#endregion
426
426
  export { isPathInside as a, walkWorkspaces as c, importProvisionModule as i, workspaceStatus as l, cmdWs as n, loadProvision as o, collectWorkspaces as r, resolveOperand as s, WS_JSON_SCHEMA as t };
427
- //# sourceMappingURL=ws-Ba372Tym.js.map
427
+ //# sourceMappingURL=ws-pRFrqms9.js.map