agent-yes 1.224.0 → 1.224.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 (28) hide show
  1. package/dist/SUPPORTED_CLIS-CRNfIM9q.js +11 -0
  2. package/dist/{SUPPORTED_CLIS-5asavJDC.js → SUPPORTED_CLIS-DThRslpE.js} +2 -2
  3. package/dist/{agentShare-CE3boH9f.js → agentShare-CX0Yx0xV.js} +2 -2
  4. package/dist/{callback-C77nNtIx.js → callback-BS1sVPyI.js} +2 -2
  5. package/dist/{callback-BtoB1O6q.js → callback-CvMtnvHj.js} +3 -3
  6. package/dist/cli.js +4 -4
  7. package/dist/index.js +4 -4
  8. package/dist/{notifyDaemon-BGN6c7NX.js → notifyDaemon-Bn0fdB-q.js} +2 -2
  9. package/dist/{rustBinary-Dy4Ihc_-.js → rustBinary-Dt7076RL.js} +2 -2
  10. package/dist/{schedule-1h-bLkTA.js → schedule-CibcxLts.js} +5 -5
  11. package/dist/{serve-Ds16KtBb.js → serve-BeChfwBV.js} +14 -14
  12. package/dist/{setup-DexcDADP.js → setup-MPt6wg7U.js} +2 -2
  13. package/dist/{subcommands-DNEyI_ft.js → subcommands-DHC1a4y2.js} +9 -9
  14. package/dist/{subcommands-DTfe_MGc.js → subcommands-DXRmodQq.js} +1 -1
  15. package/dist/{todoBlock-N6Kr9HnP.js → todoBlock-C5wUhsSH.js} +6 -5
  16. package/dist/{todoCli-DXY3TEnZ.js → todoCli-BdJaiX1x.js} +5 -5
  17. package/dist/todoDigest-CAi1HHla.js +3 -0
  18. package/dist/{todoDigest-DvG0AVQ7.js → todoDigest-DaEklQg1.js} +21 -6
  19. package/dist/{ts-xL_389P-.js → ts-QB4DPAk_.js} +2 -2
  20. package/dist/{versionChecker-B3YbJSF2.js → versionChecker-C_CrMn4v.js} +2 -2
  21. package/dist/{ws-VOsw_etQ.js → ws-BYkQq5aZ.js} +2 -2
  22. package/package.json +1 -1
  23. package/ts/todoDigest.spec.ts +34 -0
  24. package/ts/todoDigest.ts +21 -5
  25. package/ts/todoStore.spec.ts +48 -0
  26. package/ts/todoStore.ts +19 -3
  27. package/dist/SUPPORTED_CLIS-DtlIWGP2.js +0 -11
  28. package/dist/todoDigest-BDVvC8wJ.js +0 -3
@@ -0,0 +1,11 @@
1
+ import "./ts-QB4DPAk_.js";
2
+ import "./logger-CDIsZ-Pp.js";
3
+ import "./versionChecker-C_CrMn4v.js";
4
+ import "./JsonlStore-Bm5Nj6v_.js";
5
+ import "./globalPidIndex-CoNr7tS8.js";
6
+ import "./pidStore-DCqpU_bI.js";
7
+ import "./messageLog-Bb_Ie3Ck.js";
8
+ import "./todoBlock-C5wUhsSH.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DThRslpE.js";
10
+
11
+ export { SUPPORTED_CLIS };
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-xL_389P-.js";
1
+ import { t as CLIS_CONFIG } from "./ts-QB4DPAk_.js";
2
2
 
3
3
  //#region ts/SUPPORTED_CLIS.ts
4
4
  const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
5
5
 
6
6
  //#endregion
7
7
  export { SUPPORTED_CLIS as t };
8
- //# sourceMappingURL=SUPPORTED_CLIS-5asavJDC.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-DThRslpE.js.map
@@ -2,7 +2,7 @@ import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./messageLog-Bb_Ie3Ck.js";
4
4
  import "./configShared-nnIwDYY-.js";
5
- import { M as resolveOne } from "./subcommands-DNEyI_ft.js";
5
+ import { M as resolveOne } from "./subcommands-DHC1a4y2.js";
6
6
  import "./e2e-D5jaSHyY.js";
7
7
  import "./webrtcLink-DknpJQ0y.js";
8
8
  import "./remotes-D-jPl9Fj.js";
@@ -229,4 +229,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
229
229
 
230
230
  //#endregion
231
231
  export { createScopedShare, listShares, revokeAllShares, revokeShare };
232
- //# sourceMappingURL=agentShare-CE3boH9f.js.map
232
+ //# sourceMappingURL=agentShare-CX0Yx0xV.js.map
@@ -2,11 +2,11 @@ import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./messageLog-Bb_Ie3Ck.js";
4
4
  import "./configShared-nnIwDYY-.js";
5
- import "./subcommands-DNEyI_ft.js";
5
+ import "./subcommands-DHC1a4y2.js";
6
6
  import "./e2e-D5jaSHyY.js";
7
7
  import "./webrtcLink-DknpJQ0y.js";
8
8
  import "./remotes-D-jPl9Fj.js";
9
9
  import "./callbackCore-CgnOT1Cp.js";
10
- import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-BtoB1O6q.js";
10
+ import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-CvMtnvHj.js";
11
11
 
12
12
  export { cmdCallback };
@@ -1,5 +1,5 @@
1
1
  import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
2
- import { M as resolveOne } from "./subcommands-DNEyI_ft.js";
2
+ import { M as resolveOne } from "./subcommands-DHC1a4y2.js";
3
3
  import { a as mintCapability, o as parseExpires } from "./callbackCore-CgnOT1Cp.js";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { mkdir, readFile, writeFile } from "node:fs/promises";
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
72
72
  if (flag) return flag;
73
73
  if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
74
74
  try {
75
- const { resolveLocalServeUrl } = await import("./serve-Ds16KtBb.js");
75
+ const { resolveLocalServeUrl } = await import("./serve-BeChfwBV.js");
76
76
  const url = await resolveLocalServeUrl();
77
77
  if (url) return url;
78
78
  } catch {}
@@ -187,4 +187,4 @@ async function cmdCallback(rest) {
187
187
 
188
188
  //#endregion
189
189
  export { loadOrCreateCallbackSecret as i, isCallbackRevoked as n, loadCallbackSecretReadOnly as r, cmdCallback as t };
190
- //# sourceMappingURL=callback-BtoB1O6q.js.map
190
+ //# sourceMappingURL=callback-CvMtnvHj.js.map
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
  import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
3
3
  import { n as logger } from "./logger-CDIsZ-Pp.js";
4
- import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-B3YbJSF2.js";
5
- import { n as getRustBinary } from "./rustBinary-Dy4Ihc_-.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-C_CrMn4v.js";
5
+ import { n as getRustBinary } from "./rustBinary-Dt7076RL.js";
6
6
  import { argv } from "process";
7
7
  import { spawn } from "child_process";
8
8
  import ms from "ms";
@@ -285,7 +285,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
285
285
  const rawArg = process.argv[2];
286
286
  const managerCommands = !invokedCliName(process.argv);
287
287
  const isHelpFlag = rawArg === "-h" || rawArg === "--help";
288
- const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-DTfe_MGc.js");
288
+ const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-DXRmodQq.js");
289
289
  if (isHelpFlag && process.argv.length === 3) {
290
290
  await cmdHelp(managerCommands);
291
291
  process.exit(0);
@@ -327,7 +327,7 @@ if (config.useRust) {
327
327
  }
328
328
  }
329
329
  if (rustBinary) {
330
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-DtlIWGP2.js");
330
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CRNfIM9q.js");
331
331
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
332
332
  if (config.verbose) {
333
333
  console.log(`[rust] Using binary: ${rustBinary}`);
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { i as AgentContext, n as agentYes, o as removeControlCharacters, r as config, t as CLIS_CONFIG } from "./ts-xL_389P-.js";
1
+ import { i as AgentContext, n as agentYes, o as removeControlCharacters, r as config, t as CLIS_CONFIG } from "./ts-QB4DPAk_.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-B3YbJSF2.js";
3
+ import "./versionChecker-C_CrMn4v.js";
4
4
  import "./JsonlStore-Bm5Nj6v_.js";
5
5
  import "./globalPidIndex-CoNr7tS8.js";
6
6
  import "./pidStore-DCqpU_bI.js";
7
7
  import "./messageLog-Bb_Ie3Ck.js";
8
- import { a as unblockedTasks, c as canTransition, d as nextStates, f as requiredGate, i as renderTree, l as initialState, n as openBlockers, p as statesOf, r as renderDigest, s as LIFECYCLES, u as isKnownKind } from "./todoDigest-DvG0AVQ7.js";
9
- import { a as openStore, i as TodoStore, n as monitorHint, r as CycleError, t as describeBlock } from "./todoBlock-N6Kr9HnP.js";
8
+ import { a as unblockedTasks, c as canTransition, d as nextStates, f as requiredGate, i as renderTree, l as initialState, n as openBlockers, p as statesOf, r as renderDigest, s as LIFECYCLES, u as isKnownKind } from "./todoDigest-DaEklQg1.js";
9
+ import { a as openStore, i as TodoStore, n as monitorHint, r as CycleError, t as describeBlock } from "./todoBlock-C5wUhsSH.js";
10
10
 
11
11
  export { AgentContext, CLIS_CONFIG, CycleError, LIFECYCLES, TodoStore, canTransition, config, agentYes as default, describeBlock, initialState, isKnownKind, monitorHint, nextStates, openBlockers, openStore, removeControlCharacters, renderDigest, renderTree, requiredGate, statesOf, unblockedTasks };
@@ -2,7 +2,7 @@ import { n as logger } from "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./messageLog-Bb_Ie3Ck.js";
4
4
  import "./configShared-nnIwDYY-.js";
5
- import { $ as daemonLockOwnerPath, G as gcInboxes, J as listInboxParents, K as hostId, Q as daemonLockDir, S as listRecords, W as appendEvent, X as readInbox, Y as liveWatchers, Z as shouldStealLock, _ as isPidAlive, c as deriveLiveState, et as notifyDir, k as renderLogTailLines } from "./subcommands-DNEyI_ft.js";
5
+ import { $ as daemonLockOwnerPath, G as gcInboxes, J as listInboxParents, K as hostId, Q as daemonLockDir, S as listRecords, W as appendEvent, X as readInbox, Y as liveWatchers, Z as shouldStealLock, _ as isPidAlive, c as deriveLiveState, et as notifyDir, k as renderLogTailLines } from "./subcommands-DHC1a4y2.js";
6
6
  import "./e2e-D5jaSHyY.js";
7
7
  import "./webrtcLink-DknpJQ0y.js";
8
8
  import "./remotes-D-jPl9Fj.js";
@@ -589,4 +589,4 @@ async function ensureDaemon() {
589
589
 
590
590
  //#endregion
591
591
  export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
592
- //# sourceMappingURL=notifyDaemon-BGN6c7NX.js.map
592
+ //# sourceMappingURL=notifyDaemon-Bn0fdB-q.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-B3YbJSF2.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-C_CrMn4v.js";
2
2
  import { execFileSync } from "child_process";
3
3
  import { existsSync, mkdirSync, unlinkSync } from "fs";
4
4
  import { chmod, copyFile } from "fs/promises";
@@ -225,4 +225,4 @@ async function getRustBinary(options = {}) {
225
225
 
226
226
  //#endregion
227
227
  export { getRustBinary as n, findSpawnHiddenLauncher as t };
228
- //# sourceMappingURL=rustBinary-Dy4Ihc_-.js.map
228
+ //# sourceMappingURL=rustBinary-Dt7076RL.js.map
@@ -1,12 +1,12 @@
1
- import "./ts-xL_389P-.js";
1
+ import "./ts-QB4DPAk_.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-B3YbJSF2.js";
3
+ import "./versionChecker-C_CrMn4v.js";
4
4
  import "./JsonlStore-Bm5Nj6v_.js";
5
5
  import "./globalPidIndex-CoNr7tS8.js";
6
6
  import "./pidStore-DCqpU_bI.js";
7
7
  import "./messageLog-Bb_Ie3Ck.js";
8
- import "./todoBlock-N6Kr9HnP.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-5asavJDC.js";
8
+ import "./todoBlock-C5wUhsSH.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DThRslpE.js";
10
10
  import { d as resolveSpawnCwd } from "./workspaceConfig-dHHBQh0F.js";
11
11
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-DoBOoeUW.js";
12
12
  import { createHash } from "node:crypto";
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
153
153
 
154
154
  //#endregion
155
155
  export { cmdSchedule };
156
- //# sourceMappingURL=schedule-1h-bLkTA.js.map
156
+ //# sourceMappingURL=schedule-CibcxLts.js.map
@@ -1,22 +1,22 @@
1
- import { a as CLAUDE_SESSION_PIN_ENV } from "./ts-xL_389P-.js";
1
+ import { a as CLAUDE_SESSION_PIN_ENV } from "./ts-QB4DPAk_.js";
2
2
  import "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-B3YbJSF2.js";
4
- import { t as findSpawnHiddenLauncher } from "./rustBinary-Dy4Ihc_-.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-C_CrMn4v.js";
4
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-Dt7076RL.js";
5
5
  import { t as agentYesHome$1 } from "./agentYesHome-CtHb5b71.js";
6
6
  import "./JsonlStore-Bm5Nj6v_.js";
7
7
  import { a as updateGlobalPidStatus } from "./globalPidIndex-CoNr7tS8.js";
8
8
  import "./pidStore-DCqpU_bI.js";
9
9
  import { r as recordInbox } from "./messageLog-Bb_Ie3Ck.js";
10
10
  import { t as pgidForWrapper } from "./reaper-BNKvujYy.js";
11
- import "./todoBlock-N6Kr9HnP.js";
11
+ import "./todoBlock-C5wUhsSH.js";
12
12
  import "./configShared-nnIwDYY-.js";
13
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-5asavJDC.js";
14
- import { A as renderRawLog, D as recentMessageEdges, E as readPtysize, L as snapshotStatus, M as resolveOne, O as recentReadEdges, S as listRecords, T as readNotes, U as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, q as isTransientLockMkdirError, tt as TYPING_BADGE, u as extractBadges } from "./subcommands-DNEyI_ft.js";
13
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DThRslpE.js";
14
+ import { A as renderRawLog, D as recentMessageEdges, E as readPtysize, L as snapshotStatus, M as resolveOne, O as recentReadEdges, S as listRecords, T as readNotes, U as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, q as isTransientLockMkdirError, tt as TYPING_BADGE, u as extractBadges } from "./subcommands-DHC1a4y2.js";
15
15
  import "./e2e-D5jaSHyY.js";
16
16
  import "./webrtcLink-DknpJQ0y.js";
17
17
  import "./remotes-D-jPl9Fj.js";
18
18
  import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-CgnOT1Cp.js";
19
- import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-BtoB1O6q.js";
19
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-CvMtnvHj.js";
20
20
  import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-dHHBQh0F.js";
21
21
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-DoBOoeUW.js";
22
22
  import { r as spawnRejectionReason } from "./spawnGate-Vmd1d9OQ.js";
@@ -1992,7 +1992,7 @@ Options:
1992
1992
  }
1993
1993
  });
1994
1994
  if (req.method === "GET" && p === "/api/ws") {
1995
- const ws = await import("./ws-VOsw_etQ.js");
1995
+ const ws = await import("./ws-BYkQq5aZ.js");
1996
1996
  try {
1997
1997
  await ws.loadProvision();
1998
1998
  } catch (e) {
@@ -2012,7 +2012,7 @@ Options:
2012
2012
  if (req.method === "GET" && p === "/api/ws/status") {
2013
2013
  const dirRaw = url.searchParams.get("path");
2014
2014
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2015
- const ws = await import("./ws-VOsw_etQ.js");
2015
+ const ws = await import("./ws-BYkQq5aZ.js");
2016
2016
  let prov;
2017
2017
  try {
2018
2018
  prov = await ws.loadProvision();
@@ -2601,7 +2601,7 @@ Options:
2601
2601
  const perm = body.perm ?? "r";
2602
2602
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
2603
2603
  try {
2604
- const { createScopedShare } = await import("./agentShare-CE3boH9f.js");
2604
+ const { createScopedShare } = await import("./agentShare-CX0Yx0xV.js");
2605
2605
  const share = await createScopedShare({
2606
2606
  agent: body.agent,
2607
2607
  perm,
@@ -2616,12 +2616,12 @@ Options:
2616
2616
  }
2617
2617
  }
2618
2618
  if (req.method === "GET" && p === "/api/shares") {
2619
- const { listShares } = await import("./agentShare-CE3boH9f.js");
2619
+ const { listShares } = await import("./agentShare-CX0Yx0xV.js");
2620
2620
  return Response.json(listShares());
2621
2621
  }
2622
2622
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
2623
2623
  if (req.method === "DELETE" && revokeM) {
2624
- const { revokeShare } = await import("./agentShare-CE3boH9f.js");
2624
+ const { revokeShare } = await import("./agentShare-CX0Yx0xV.js");
2625
2625
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
2626
2626
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
2627
2627
  }
@@ -2923,7 +2923,7 @@ Options:
2923
2923
  const shutdown = (resolve) => {
2924
2924
  if (heartbeat) clearInterval(heartbeat);
2925
2925
  closeShare?.();
2926
- import("./agentShare-CE3boH9f.js").then((m) => m.revokeAllShares()).catch(() => {});
2926
+ import("./agentShare-CX0Yx0xV.js").then((m) => m.revokeAllShares()).catch(() => {});
2927
2927
  server?.stop();
2928
2928
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
2929
2929
  };
@@ -2936,4 +2936,4 @@ Options:
2936
2936
 
2937
2937
  //#endregion
2938
2938
  export { cmdServe, resolveLocalServeUrl };
2939
- //# sourceMappingURL=serve-Ds16KtBb.js.map
2939
+ //# sourceMappingURL=serve-BeChfwBV.js.map
@@ -32,7 +32,7 @@ async function cmdSetup(rest) {
32
32
  if (!existsSync(abs)) process.stderr.write(` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`);
33
33
  if (noShare) return 0;
34
34
  process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
35
- const { cmdServe } = await import("./serve-Ds16KtBb.js");
35
+ const { cmdServe } = await import("./serve-BeChfwBV.js");
36
36
  return cmdServe([
37
37
  "install",
38
38
  "--share",
@@ -42,4 +42,4 @@ async function cmdSetup(rest) {
42
42
 
43
43
  //#endregion
44
44
  export { cmdSetup };
45
- //# sourceMappingURL=setup-DexcDADP.js.map
45
+ //# sourceMappingURL=setup-MPt6wg7U.js.map
@@ -1239,23 +1239,23 @@ async function runSubcommand(argv) {
1239
1239
  case "restart": return await cmdRestart(rest);
1240
1240
  case "note": return await cmdNote(rest);
1241
1241
  case "todo": {
1242
- const { runTodoSubcommand } = await import("./todoCli-DXY3TEnZ.js");
1242
+ const { runTodoSubcommand } = await import("./todoCli-BdJaiX1x.js");
1243
1243
  return runTodoSubcommand(rest);
1244
1244
  }
1245
1245
  case "serve": {
1246
- const { cmdServe } = await import("./serve-Ds16KtBb.js");
1246
+ const { cmdServe } = await import("./serve-BeChfwBV.js");
1247
1247
  return cmdServe(rest);
1248
1248
  }
1249
1249
  case "setup": {
1250
- const { cmdSetup } = await import("./setup-DexcDADP.js");
1250
+ const { cmdSetup } = await import("./setup-MPt6wg7U.js");
1251
1251
  return cmdSetup(rest);
1252
1252
  }
1253
1253
  case "ws": {
1254
- const { cmdWs } = await import("./ws-VOsw_etQ.js");
1254
+ const { cmdWs } = await import("./ws-BYkQq5aZ.js");
1255
1255
  return cmdWs(rest);
1256
1256
  }
1257
1257
  case "schedule": {
1258
- const { cmdSchedule } = await import("./schedule-1h-bLkTA.js");
1258
+ const { cmdSchedule } = await import("./schedule-CibcxLts.js");
1259
1259
  return cmdSchedule(rest);
1260
1260
  }
1261
1261
  case "remote": {
@@ -1267,7 +1267,7 @@ async function runSubcommand(argv) {
1267
1267
  return cmdExpose(rest);
1268
1268
  }
1269
1269
  case "callback": {
1270
- const { cmdCallback } = await import("./callback-C77nNtIx.js");
1270
+ const { cmdCallback } = await import("./callback-BS1sVPyI.js");
1271
1271
  return cmdCallback(rest);
1272
1272
  }
1273
1273
  case "reap":
@@ -4279,7 +4279,7 @@ async function cmdNotify(rest) {
4279
4279
  }
4280
4280
  const ensure = async () => {
4281
4281
  if (!argv["ensure-daemon"]) return;
4282
- const { ensureDaemon } = await import("./notifyDaemon-BGN6c7NX.js");
4282
+ const { ensureDaemon } = await import("./notifyDaemon-Bn0fdB-q.js");
4283
4283
  await ensureDaemon().catch(() => null);
4284
4284
  };
4285
4285
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4353,7 +4353,7 @@ async function cmdNotifyCursor(args) {
4353
4353
  }
4354
4354
  async function cmdNotifyd(rest) {
4355
4355
  const sub = rest[0] ?? "status";
4356
- const daemon = await import("./notifyDaemon-BGN6c7NX.js");
4356
+ const daemon = await import("./notifyDaemon-Bn0fdB-q.js");
4357
4357
  switch (sub) {
4358
4358
  case "run": return daemon.runDaemon();
4359
4359
  case "once": return daemon.runDaemon({ once: true });
@@ -4380,4 +4380,4 @@ async function cmdNotifyd(rest) {
4380
4380
 
4381
4381
  //#endregion
4382
4382
  export { daemonLockOwnerPath as $, renderRawLog as A, submitAndConfirm as B, matchKeyword as C, recentMessageEdges as D, readPtysize as E, restartHintLines as F, gcInboxes as G, writeKeysPaced as H, runSubcommand as I, listInboxParents as J, hostId as K, snapshotStatus as L, resolveOne as M, resolveReadWindow as N, recentReadEdges as O, resolveResumeArgs as P, daemonLockDir as Q, stdinActivityPath as R, listRecords as S, readNotes as T, writeToIpc as U, waitForLogQuiet as V, appendEvent as W, readInbox as X, liveWatchers as Y, shouldStealLock as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, notifyDir as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderRawLogLines as j, renderLogTailLines as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, controlCodeFromName as o, extractTaskCounts as p, isTransientLockMkdirError as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, TYPING_BADGE as tt, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, stopTipForCli as z };
4383
- //# sourceMappingURL=subcommands-DNEyI_ft.js.map
4383
+ //# sourceMappingURL=subcommands-DHC1a4y2.js.map
@@ -2,7 +2,7 @@ import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./messageLog-Bb_Ie3Ck.js";
4
4
  import "./configShared-nnIwDYY-.js";
5
- import { A as renderRawLog, B as submitAndConfirm, C as matchKeyword, D as recentMessageEdges, E as readPtysize, F as restartHintLines, H as writeKeysPaced, I as runSubcommand, L as snapshotStatus, M as resolveOne, N as resolveReadWindow, O as recentReadEdges, P as resolveResumeArgs, R as stdinActivityPath, S as listRecords, T as readNotes, U as writeToIpc, V as waitForLogQuiet, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stopTipForCli } from "./subcommands-DNEyI_ft.js";
5
+ import { A as renderRawLog, B as submitAndConfirm, C as matchKeyword, D as recentMessageEdges, E as readPtysize, F as restartHintLines, H as writeKeysPaced, I as runSubcommand, L as snapshotStatus, M as resolveOne, N as resolveReadWindow, O as recentReadEdges, P as resolveResumeArgs, R as stdinActivityPath, S as listRecords, T as readNotes, U as writeToIpc, V as waitForLogQuiet, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stopTipForCli } from "./subcommands-DHC1a4y2.js";
6
6
  import "./e2e-D5jaSHyY.js";
7
7
  import "./webrtcLink-DknpJQ0y.js";
8
8
  import "./remotes-D-jPl9Fj.js";
@@ -1,5 +1,5 @@
1
1
  import { t as JsonlStore } from "./JsonlStore-Bm5Nj6v_.js";
2
- import { c as canTransition, f as requiredGate, l as initialState, o as DONE_STATE, s as LIFECYCLES } from "./todoDigest-DvG0AVQ7.js";
2
+ import { c as canTransition, f as requiredGate, l as initialState, o as DONE_STATE, s as LIFECYCLES } from "./todoDigest-DaEklQg1.js";
3
3
  import path from "path";
4
4
  import { lock } from "proper-lockfile";
5
5
 
@@ -232,10 +232,11 @@ var TodoStore = class TodoStore {
232
232
  const satisfied = new Set(rec.satisfiedGates);
233
233
  satisfied.add(gateName);
234
234
  const evidenceEntry = {
235
+ note: evidence?.note,
236
+ link: evidence?.link,
235
237
  gate: gateName,
236
238
  passedAt: (/* @__PURE__ */ new Date()).toISOString(),
237
- validator,
238
- ...evidence
239
+ validator
239
240
  };
240
241
  await this.jsonl.updateById(id, {
241
242
  satisfiedGates: [...satisfied],
@@ -278,7 +279,7 @@ var TodoStore = class TodoStore {
278
279
  if (!impl) throw new Error(`task ${id}: gate "${targetEdge.gate}" is not registered — call registerGate() first`);
279
280
  const isPrimaryEdge = edges[0] === targetEdge;
280
281
  const stateAtCheckStart = rec.state;
281
- const result = await impl.check();
282
+ const result = await impl.check(rec);
282
283
  const precondition = (fresh) => {
283
284
  if (fresh.state !== stateAtCheckStart) throw new Error(`task ${id}: state changed from "${stateAtCheckStart}" to "${fresh.state}" while gate "${targetEdge.gate}" was being checked — refusing to apply a transition computed against the old state; re-run verify()`);
284
285
  };
@@ -406,4 +407,4 @@ function describeBlock(block) {
406
407
 
407
408
  //#endregion
408
409
  export { openStore as a, TodoStore as i, monitorHint as n, CycleError as r, describeBlock as t };
409
- //# sourceMappingURL=todoBlock-N6Kr9HnP.js.map
410
+ //# sourceMappingURL=todoBlock-C5wUhsSH.js.map
@@ -1,7 +1,7 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./JsonlStore-Bm5Nj6v_.js";
3
- import { i as renderTree, r as renderDigest, s as LIFECYCLES, u as isKnownKind } from "./todoDigest-DvG0AVQ7.js";
4
- import { a as openStore, r as CycleError, t as describeBlock } from "./todoBlock-N6Kr9HnP.js";
3
+ import { i as renderTree, r as renderDigest, s as LIFECYCLES, u as isKnownKind } from "./todoDigest-DaEklQg1.js";
4
+ import { a as openStore, r as CycleError, t as describeBlock } from "./todoBlock-C5wUhsSH.js";
5
5
  import yargs from "yargs";
6
6
 
7
7
  //#region ts/todoCli.ts
@@ -274,7 +274,7 @@ async function runTodoSubcommand(rest0) {
274
274
  const rootId = a._[0] !== void 0 ? String(a._[0]) : void 0;
275
275
  const tasks = store.all();
276
276
  if (opts.format === "json") {
277
- const { buildTreeJSON } = await import("./todoDigest-BDVvC8wJ.js");
277
+ const { buildTreeJSON } = await import("./todoDigest-CAi1HHla.js");
278
278
  emit(opts, buildTreeJSON(tasks, rootId), "");
279
279
  } else process.stdout.write(renderTree(tasks, rootId) + "\n");
280
280
  return 0;
@@ -283,7 +283,7 @@ async function runTodoSubcommand(rest0) {
283
283
  const opts = commonOptsOf(await commonOptions(yargs(args)).help(false).exitProcess(false).parseAsync());
284
284
  const tasks = (await openStore(opts.root)).all();
285
285
  if (opts.format === "json") {
286
- const { unblockedTasks } = await import("./todoDigest-BDVvC8wJ.js");
286
+ const { unblockedTasks } = await import("./todoDigest-CAi1HHla.js");
287
287
  emit(opts, {
288
288
  tasks,
289
289
  unblocked: unblockedTasks(tasks).map((t) => t._id)
@@ -297,4 +297,4 @@ async function runTodoSubcommand(rest0) {
297
297
 
298
298
  //#endregion
299
299
  export { runTodoSubcommand };
300
- //# sourceMappingURL=todoCli-DXY3TEnZ.js.map
300
+ //# sourceMappingURL=todoCli-BdJaiX1x.js.map
@@ -0,0 +1,3 @@
1
+ import { a as unblockedTasks, i as renderTree, n as openBlockers, r as renderDigest, t as buildTreeJSON } from "./todoDigest-DaEklQg1.js";
2
+
3
+ export { buildTreeJSON, unblockedTasks };
@@ -148,8 +148,22 @@ function isKnownKind(value) {
148
148
  * from `todoLifecycle.ts` instead of a hardcoded status string.
149
149
  */
150
150
  /**
151
- * A task is "unblocked" when it is not itself finished, it declares
152
- * `blockedBy` dependencies, and every one of them has reached `done`.
151
+ * The full set of task ids `t` is waiting on: the structural `blockedBy`
152
+ * array PLUS, if `t.block` is a `blocked-by-task` shape, that block's own
153
+ * `taskId`. Without folding the latter in, a task blocked via
154
+ * `ay todo block --type blocked-by-task --task X` would never be detected
155
+ * as resolved once X reaches `done` — contradicting `todoBlock.ts`'s own
156
+ * documented promise that this block type "clears itself... pure data, no
157
+ * monitor needed" (codex-review Important: the two mechanisms didn't
158
+ * actually talk to each other, making `blocked-by-task` blocks inert).
159
+ */
160
+ function declaredTaskDeps(t) {
161
+ return t.block?.type === "blocked-by-task" ? [...t.blockedBy, t.block.taskId] : t.blockedBy;
162
+ }
163
+ /**
164
+ * A task is "unblocked" when it is not itself finished, it declares task
165
+ * dependencies (via `blockedBy` and/or a `blocked-by-task` block), and
166
+ * every one of them has reached `done`.
153
167
  * Surfaced for a caller to act on — never auto-applied here (deciding to
154
168
  * resume a task is left to automation, a later milestone, or a human).
155
169
  */
@@ -157,13 +171,14 @@ function unblockedTasks(tasks) {
157
171
  const byId = new Map(tasks.map((t) => [t._id, t]));
158
172
  return tasks.filter((t) => {
159
173
  if (t.state === DONE_STATE) return false;
160
- if (t.blockedBy.length === 0) return false;
161
- return t.blockedBy.every((d) => byId.get(d)?.state === DONE_STATE);
174
+ const deps = declaredTaskDeps(t);
175
+ if (deps.length === 0) return false;
176
+ return deps.every((d) => byId.get(d)?.state === DONE_STATE);
162
177
  });
163
178
  }
164
179
  /** Blockers of `t` that have not reached `done` yet (a missing id is reported as-is, still "open"). */
165
180
  function openBlockers(t, byId) {
166
- return t.blockedBy.filter((d) => byId.get(d)?.state !== DONE_STATE);
181
+ return declaredTaskDeps(t).filter((d) => byId.get(d)?.state !== DONE_STATE);
167
182
  }
168
183
  function nodeLine(t) {
169
184
  return [`${t._id} [${t.state}] ${t.summary}`, ...t.owner ? [`owner:${t.owner}`] : []].join(" ");
@@ -257,4 +272,4 @@ function renderDigest(tasks) {
257
272
 
258
273
  //#endregion
259
274
  export { unblockedTasks as a, canTransition as c, nextStates as d, requiredGate as f, renderTree as i, initialState as l, openBlockers as n, DONE_STATE as o, statesOf as p, renderDigest as r, LIFECYCLES as s, buildTreeJSON as t, isKnownKind as u };
260
- //# sourceMappingURL=todoDigest-DvG0AVQ7.js.map
275
+ //# sourceMappingURL=todoDigest-DaEklQg1.js.map
@@ -1,5 +1,5 @@
1
1
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-B3YbJSF2.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-C_CrMn4v.js";
3
3
  import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
4
4
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CNMl13dC.js";
5
5
  import { i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
@@ -1919,4 +1919,4 @@ function sleep(ms) {
1919
1919
 
1920
1920
  //#endregion
1921
1921
  export { CLAUDE_SESSION_PIN_ENV as a, AgentContext as i, agentYes as n, removeControlCharacters as o, config as r, CLIS_CONFIG as t };
1922
- //# sourceMappingURL=ts-xL_389P-.js.map
1922
+ //# sourceMappingURL=ts-QB4DPAk_.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.224.0";
10
+ var version = "1.224.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-B3YbJSF2.js.map
218
+ //# sourceMappingURL=versionChecker-C_CrMn4v.js.map
@@ -2,7 +2,7 @@ import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-CoNr7tS8.js";
3
3
  import "./messageLog-Bb_Ie3Ck.js";
4
4
  import "./configShared-nnIwDYY-.js";
5
- import { S as listRecords } from "./subcommands-DNEyI_ft.js";
5
+ import { S as listRecords } from "./subcommands-DHC1a4y2.js";
6
6
  import "./e2e-D5jaSHyY.js";
7
7
  import "./webrtcLink-DknpJQ0y.js";
8
8
  import "./remotes-D-jPl9Fj.js";
@@ -418,4 +418,4 @@ async function cmdWs(args) {
418
418
 
419
419
  //#endregion
420
420
  export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
421
- //# sourceMappingURL=ws-VOsw_etQ.js.map
421
+ //# sourceMappingURL=ws-BYkQq5aZ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.224.0",
3
+ "version": "1.224.1",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
@@ -39,6 +39,40 @@ describe("unblockedTasks", () => {
39
39
  });
40
40
  });
41
41
 
42
+ describe("unblockedTasks with a blocked-by-task block", () => {
43
+ it("treats block:{type:blocked-by-task,taskId} as an additional dependency, so it self-clears once the target reaches done, matching todoBlock.ts's documented promise (codex-review round-6 Important — this was previously inert)", () => {
44
+ const tasks = [
45
+ task({ _id: "T1", state: "done" }),
46
+ task({
47
+ _id: "T2",
48
+ state: "doing",
49
+ block: { type: "blocked-by-task", taskId: "T1" },
50
+ }),
51
+ task({
52
+ _id: "T3",
53
+ state: "doing",
54
+ block: { type: "blocked-by-task", taskId: "T4" },
55
+ }),
56
+ task({ _id: "T4", state: "doing" }), // T3's target not done yet -> still blocked
57
+ ];
58
+ expect(unblockedTasks(tasks).map((t) => t._id)).toEqual(["T2"]);
59
+ });
60
+
61
+ it("folds a blocked-by-task block in ALONGSIDE blockedBy — both must clear", () => {
62
+ const tasks = [
63
+ task({ _id: "T1", state: "done" }),
64
+ task({ _id: "T2", state: "doing" }), // not done
65
+ task({
66
+ _id: "T3",
67
+ state: "doing",
68
+ blockedBy: ["T2"],
69
+ block: { type: "blocked-by-task", taskId: "T1" },
70
+ }),
71
+ ];
72
+ expect(unblockedTasks(tasks)).toEqual([]); // T2 still open
73
+ });
74
+ });
75
+
42
76
  describe("openBlockers", () => {
43
77
  it("reports only the not-yet-done blockers, including a missing id as open", () => {
44
78
  const byId = new Map([
package/ts/todoDigest.ts CHANGED
@@ -15,8 +15,23 @@ import { DONE_STATE } from "./todoLifecycle.ts";
15
15
  import type { TodoRecord } from "./todoStore.ts";
16
16
 
17
17
  /**
18
- * A task is "unblocked" when it is not itself finished, it declares
19
- * `blockedBy` dependencies, and every one of them has reached `done`.
18
+ * The full set of task ids `t` is waiting on: the structural `blockedBy`
19
+ * array PLUS, if `t.block` is a `blocked-by-task` shape, that block's own
20
+ * `taskId`. Without folding the latter in, a task blocked via
21
+ * `ay todo block --type blocked-by-task --task X` would never be detected
22
+ * as resolved once X reaches `done` — contradicting `todoBlock.ts`'s own
23
+ * documented promise that this block type "clears itself... pure data, no
24
+ * monitor needed" (codex-review Important: the two mechanisms didn't
25
+ * actually talk to each other, making `blocked-by-task` blocks inert).
26
+ */
27
+ function declaredTaskDeps(t: TodoRecord): string[] {
28
+ return t.block?.type === "blocked-by-task" ? [...t.blockedBy, t.block.taskId] : t.blockedBy;
29
+ }
30
+
31
+ /**
32
+ * A task is "unblocked" when it is not itself finished, it declares task
33
+ * dependencies (via `blockedBy` and/or a `blocked-by-task` block), and
34
+ * every one of them has reached `done`.
20
35
  * Surfaced for a caller to act on — never auto-applied here (deciding to
21
36
  * resume a task is left to automation, a later milestone, or a human).
22
37
  */
@@ -24,14 +39,15 @@ export function unblockedTasks(tasks: TodoRecord[]): TodoRecord[] {
24
39
  const byId = new Map(tasks.map((t) => [t._id, t]));
25
40
  return tasks.filter((t) => {
26
41
  if (t.state === DONE_STATE) return false;
27
- if (t.blockedBy.length === 0) return false;
28
- return t.blockedBy.every((d) => byId.get(d)?.state === DONE_STATE);
42
+ const deps = declaredTaskDeps(t);
43
+ if (deps.length === 0) return false;
44
+ return deps.every((d) => byId.get(d)?.state === DONE_STATE);
29
45
  });
30
46
  }
31
47
 
32
48
  /** Blockers of `t` that have not reached `done` yet (a missing id is reported as-is, still "open"). */
33
49
  export function openBlockers(t: TodoRecord, byId: Map<string, TodoRecord>): string[] {
34
- return t.blockedBy.filter((d) => byId.get(d)?.state !== DONE_STATE);
50
+ return declaredTaskDeps(t).filter((d) => byId.get(d)?.state !== DONE_STATE);
35
51
  }
36
52
 
37
53
  function nodeLine(t: TodoRecord): string {
@@ -107,6 +107,30 @@ describe("TodoStore", () => {
107
107
  expect(done.verifyEvidence).toHaveLength(1);
108
108
  });
109
109
 
110
+ it("approve() cannot have its audit trail falsified via the evidence argument — gate/validator/passedAt are trusted, never caller-overridable (codex-review round-6 Important)", async () => {
111
+ const s = await openStore(TEST_ROOT);
112
+ const t = await s.create({ summary: "x", kind: "doc", owner: "worker" });
113
+ await s.transition(t._id, "review");
114
+ // evidence is typed to only note/link, but an untyped JS caller (or a
115
+ // bug) could still pass extra fields at runtime; the store must not let
116
+ // them win regardless of what TypeScript alone would forbid, so this
117
+ // simulates that via an untyped value rather than fighting the compiler.
118
+ const forgedEvidence = {
119
+ note: "legit note",
120
+ link: "https://example/legit",
121
+ gate: "forged-gate",
122
+ validator: "forged-validator",
123
+ passedAt: "1999-01-01T00:00:00.000Z",
124
+ } as unknown as { note?: string; link?: string };
125
+ const approved = await s.approve(t._id, "human-approved", "reviewer", forgedEvidence);
126
+ const entry = approved.verifyEvidence[0]!;
127
+ expect(entry.gate).toBe("human-approved");
128
+ expect(entry.validator).toBe("reviewer");
129
+ expect(entry.passedAt).not.toBe("1999-01-01T00:00:00.000Z");
130
+ expect(entry.note).toBe("legit note");
131
+ expect(entry.link).toBe("https://example/legit");
132
+ });
133
+
110
134
  it("approve() with an empty owner allows any validator (nothing to compare against) but still requires one", async () => {
111
135
  const s = await openStore(TEST_ROOT);
112
136
  const t = await s.create({ summary: "x", kind: "doc" }); // no owner
@@ -184,6 +208,30 @@ describe("TodoStore", () => {
184
208
  });
185
209
  });
186
210
 
211
+ it("verify() passes the task record being checked to the registered gate's check(), so one shared gate name can distinguish between concurrently-verified tasks (codex-review round-6 Important)", async () => {
212
+ const s = await openStore(TEST_ROOT);
213
+ const seen: string[] = [];
214
+ s.registerGate({
215
+ name: "verify-green",
216
+ check: async (record) => {
217
+ seen.push(record._id);
218
+ return { passed: true, note: `checked ${record.summary}` };
219
+ },
220
+ });
221
+ const a = await s.create({ summary: "task a", kind: "code", owner: "worker" });
222
+ const b = await s.create({ summary: "task b", kind: "code", owner: "worker" });
223
+ for (const t of [a, b]) {
224
+ await s.transition(t._id, "merged");
225
+ await s.transition(t._id, "shipped");
226
+ await s.transition(t._id, "verifying");
227
+ }
228
+ const verifiedA = await s.verify(a._id);
229
+ const verifiedB = await s.verify(b._id);
230
+ expect(verifiedA.verifyEvidence.at(-1)?.note).toBe("checked task a");
231
+ expect(verifiedB.verifyEvidence.at(-1)?.note).toBe("checked task b");
232
+ expect(seen).toEqual([a._id, b._id]);
233
+ });
234
+
187
235
  it("verify() with a failing check takes the SIBLING edge (verify-failed), not done — the failure is a real distinct state, not silently dropped", async () => {
188
236
  const s = await openStore(TEST_ROOT);
189
237
  s.registerGate({
package/ts/todoStore.ts CHANGED
@@ -103,7 +103,16 @@ export interface ListFilter {
103
103
  export interface GateRegistration {
104
104
  /** Opaque name supplied BY the consuming project — this module never inspects or hardcodes it. */
105
105
  name: string;
106
- check: () => Promise<{ passed: boolean; note?: string; link?: string }>;
106
+ /**
107
+ * Receives the task record being verified (as of the moment `verify()`
108
+ * started checking it), so a project's gate implementation can act on the
109
+ * specific task — e.g. derive a commit/branch from its fields — instead of
110
+ * relying on external mutable state to figure out which task this call is
111
+ * for. Without the record, one registered gate name shared by concurrent
112
+ * verify() calls on DIFFERENT tasks would have no way to tell them apart
113
+ * (codex-review Important).
114
+ */
115
+ check: (record: TodoRecord) => Promise<{ passed: boolean; note?: string; link?: string }>;
107
116
  }
108
117
 
109
118
  export class CycleError extends Error {}
@@ -378,11 +387,18 @@ export class TodoStore {
378
387
  }
379
388
  const satisfied = new Set(rec.satisfiedGates);
380
389
  satisfied.add(gateName);
390
+ // Trusted fields (gate/passedAt/validator) are spread LAST so a
391
+ // caller-supplied `evidence` object cannot override them — only
392
+ // `note`/`link` are ever taken from it. Spreading `evidence` last (the
393
+ // previous order) let a caller pass e.g. `{ validator: "...", gate:
394
+ // "..." }` and silently falsify the audit trail (codex-review
395
+ // Important).
381
396
  const evidenceEntry: GateEvidence = {
397
+ note: evidence?.note,
398
+ link: evidence?.link,
382
399
  gate: gateName,
383
400
  passedAt: new Date().toISOString(),
384
401
  validator,
385
- ...evidence,
386
402
  };
387
403
  await this.jsonl.updateById(id, {
388
404
  satisfiedGates: [...satisfied],
@@ -436,7 +452,7 @@ export class TodoStore {
436
452
  );
437
453
  const isPrimaryEdge = edges[0] === targetEdge;
438
454
  const stateAtCheckStart = rec.state;
439
- const result = await impl.check(); // may be slow (a real CI/QA system) — the task's state can change while this runs
455
+ const result = await impl.check(rec); // may be slow (a real CI/QA system) — the task's state can change while this runs
440
456
  // `impl.check()` can take an arbitrarily long time (a real external
441
457
  // system), and another writer (a concurrent transition/verify/approve)
442
458
  // can change the task's state during that window. The precondition
@@ -1,11 +0,0 @@
1
- import "./ts-xL_389P-.js";
2
- import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-B3YbJSF2.js";
4
- import "./JsonlStore-Bm5Nj6v_.js";
5
- import "./globalPidIndex-CoNr7tS8.js";
6
- import "./pidStore-DCqpU_bI.js";
7
- import "./messageLog-Bb_Ie3Ck.js";
8
- import "./todoBlock-N6Kr9HnP.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-5asavJDC.js";
10
-
11
- export { SUPPORTED_CLIS };
@@ -1,3 +0,0 @@
1
- import { a as unblockedTasks, i as renderTree, n as openBlockers, r as renderDigest, t as buildTreeJSON } from "./todoDigest-DvG0AVQ7.js";
2
-
3
- export { buildTreeJSON, unblockedTasks };