@outcomeeng/spx 0.6.10 → 0.6.12

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 (3) hide show
  1. package/dist/cli.js +1211 -342
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -289,9 +289,6 @@ async function resolveAgentResumeScopeContext(options) {
289
289
  return { match: (core) => core.branch === target, claudeDirAccepts: () => true };
290
290
  }
291
291
  const invocationRoot = await options.resolveWorktreeRoot(options.invocationDir);
292
- if (invocationRoot === null) {
293
- return null;
294
- }
295
292
  const projectPrefix = claudeProjectDirName(invocationRoot);
296
293
  return {
297
294
  match: (core) => isPathInsideOrEqual(invocationRoot, core.cwd),
@@ -326,11 +323,11 @@ function renderAgentResumeJson(candidates) {
326
323
  }
327
324
  async function recentStoreFiles(paths, fs8, nowMs) {
328
325
  const stats = await mapWithConcurrency(paths, AGENT_RESUME_LIMITS.READ_CONCURRENCY, async (path7) => {
329
- const stat8 = await fs8.stat(path7).catch(() => null);
330
- if (stat8 === null || !isRecentAgentSessionMtime(stat8.mtimeMs, nowMs)) {
326
+ const stat9 = await fs8.stat(path7).catch(() => null);
327
+ if (stat9 === null || !isRecentAgentSessionMtime(stat9.mtimeMs, nowMs)) {
331
328
  return null;
332
329
  }
333
- return { path: path7, modifiedAtMs: stat8.mtimeMs };
330
+ return { path: path7, modifiedAtMs: stat9.mtimeMs };
334
331
  });
335
332
  return stats.filter((file) => file !== null).sort((left, right) => right.modifiedAtMs - left.modifiedAtMs || left.path.localeCompare(right.path));
336
333
  }
@@ -529,6 +526,195 @@ async function mapWithConcurrency(items, concurrency, mapper) {
529
526
  return results;
530
527
  }
531
528
 
529
+ // src/domains/session/types.ts
530
+ var SESSION_PRIORITY = {
531
+ HIGH: "high",
532
+ MEDIUM: "medium",
533
+ LOW: "low"
534
+ };
535
+ var SESSION_STATUSES = ["todo", "doing", "archive"];
536
+ var DEFAULT_LIST_STATUSES = ["doing", "todo"];
537
+ var SESSION_FILE_ENCODING = "utf-8";
538
+ var SESSION_FILE_ERROR_CODE = {
539
+ NOT_FOUND: "ENOENT"
540
+ };
541
+ var SESSION_OUTPUT_MARKER = {
542
+ HANDOFF_ID: "HANDOFF_ID",
543
+ PICKUP_ID: "PICKUP_ID",
544
+ SESSION_FILE: "SESSION_FILE"
545
+ };
546
+ function formatSessionOutputMarker(marker, value) {
547
+ return `<${marker}>${value}</${marker}>`;
548
+ }
549
+ var CLAIMABLE_STATUS = SESSION_STATUSES[0];
550
+ var PRIORITY_ORDER = {
551
+ [SESSION_PRIORITY.HIGH]: 0,
552
+ [SESSION_PRIORITY.MEDIUM]: 1,
553
+ [SESSION_PRIORITY.LOW]: 2
554
+ };
555
+ var DEFAULT_PRIORITY = SESSION_PRIORITY.MEDIUM;
556
+ var SESSION_FRONT_MATTER = {
557
+ PRIORITY: "priority",
558
+ GIT_REF: "git_ref",
559
+ GOAL: "goal",
560
+ NEXT_STEP: "next_step",
561
+ CREATED_AT: "created_at",
562
+ AGENT_SESSION_ID: "agent_session_id",
563
+ SPECS: "specs",
564
+ FILES: "files"
565
+ };
566
+
567
+ // src/domains/agent/search.ts
568
+ var AGENT_SEARCH_DEFAULT_LIMIT = 20;
569
+ var AGENT_SEARCH_MATCH_REASON = {
570
+ ALL: "all",
571
+ PICKUP_ID: "pickup-id",
572
+ CONTAINS: "contains",
573
+ SESSION_ID: "session-id",
574
+ AGENT: "agent",
575
+ BRANCH: "branch"
576
+ };
577
+ function pickupIdSearchLiteral(pickupId) {
578
+ return formatSessionOutputMarker(SESSION_OUTPUT_MARKER.PICKUP_ID, pickupId);
579
+ }
580
+ function agentSearchQueryFromOptions(options) {
581
+ const contentNeedles = [];
582
+ if (options.pickupId !== void 0) {
583
+ contentNeedles.push({
584
+ reason: AGENT_SEARCH_MATCH_REASON.PICKUP_ID,
585
+ value: pickupIdSearchLiteral(options.pickupId)
586
+ });
587
+ }
588
+ if (options.contains !== void 0) {
589
+ contentNeedles.push({ reason: AGENT_SEARCH_MATCH_REASON.CONTAINS, value: options.contains });
590
+ }
591
+ return {
592
+ contentNeedles,
593
+ sessionId: options.sessionId ?? null,
594
+ branch: options.branch ?? null,
595
+ agent: options.agent ?? null,
596
+ includeAll: options.all === true,
597
+ limit: options.limit ?? AGENT_SEARCH_DEFAULT_LIMIT
598
+ };
599
+ }
600
+ async function searchAgentSessions(options) {
601
+ const selectedAgents = options.query.agent === null ? [AGENT_SESSION_KIND.CODEX, AGENT_SESSION_KIND.CLAUDE_CODE] : [options.query.agent];
602
+ const perAgent = await Promise.all(
603
+ selectedAgents.map((agent) => searchAgentStore(agent, options))
604
+ );
605
+ return perAgent.flat().sort(compareSearchResults).slice(0, Math.max(0, options.query.limit));
606
+ }
607
+ function renderAgentSearchJson(results) {
608
+ return JSON.stringify(results, null, 2);
609
+ }
610
+ function renderAgentSearchList(results) {
611
+ if (results.length === 0) {
612
+ return "No matching agent sessions found.";
613
+ }
614
+ return results.map((result) => {
615
+ const updatedAt = result.updatedAt ?? new Date(result.modifiedAtMs).toISOString();
616
+ return `${updatedAt} ${AGENT_SESSION_LABEL[result.agent]} ${result.sessionId} ${result.cwd}`;
617
+ }).join("\n");
618
+ }
619
+ async function searchAgentStore(agent, options) {
620
+ const paths = agent === AGENT_SESSION_KIND.CODEX ? await collectJsonlFiles(codexSessionStoreDir(options.homeDir), options.fs) : await claudeTranscriptFiles(
621
+ claudeCodeSessionStoreDir(options.homeDir),
622
+ options.fs,
623
+ claudeDirAcceptsProductScope(options.productScopeRoot)
624
+ );
625
+ const files = await storeFiles(paths, options.fs, options.nowMs, options.query.includeAll);
626
+ const parser = agent === AGENT_SESSION_KIND.CODEX ? parseCodexHead : parseClaudeHead;
627
+ return collectMatchingSessions(agent, files, options, parser);
628
+ }
629
+ function claudeDirAcceptsProductScope(productScopeRoot) {
630
+ const projectPrefix = claudeProjectDirName(productScopeRoot);
631
+ return (dirName) => dirName === projectPrefix || dirName.startsWith(`${projectPrefix}${CLAUDE_PROJECT_ENCODED_SEPARATOR}`);
632
+ }
633
+ async function collectMatchingSessions(agent, files, options, parseHead) {
634
+ const results = [];
635
+ const seen = /* @__PURE__ */ new Set();
636
+ for (const file of files) {
637
+ const head = await options.fs.readHead(file.path, AGENT_RESUME_LIMITS.METADATA_HEAD_BYTES).catch(() => null);
638
+ if (head === null) continue;
639
+ const core = parseHead(head);
640
+ if (core === null || !core.interactive || seen.has(core.sessionId)) continue;
641
+ if (!coreMatchesProductScope(core, options.productScopeRoot)) continue;
642
+ const matches = await matchReasons(agent, core, file.path, options);
643
+ if (matches.length === 0) continue;
644
+ seen.add(core.sessionId);
645
+ results.push({
646
+ agent,
647
+ sessionId: core.sessionId,
648
+ cwd: core.cwd,
649
+ sourcePath: file.path,
650
+ modifiedAtMs: file.modifiedAtMs,
651
+ updatedAt: core.updatedAt,
652
+ branch: core.branch,
653
+ matches
654
+ });
655
+ }
656
+ return results;
657
+ }
658
+ async function matchReasons(agent, core, path7, options) {
659
+ if (!hasSearchSelector(options.query)) {
660
+ return [AGENT_SEARCH_MATCH_REASON.ALL];
661
+ }
662
+ const metadataMatches = metadataMatchReasons(agent, core, options.query);
663
+ const contentMatches = await contentMatchReasons(path7, options);
664
+ if (metadataMatches === null || contentMatches === null) {
665
+ return [];
666
+ }
667
+ return [...metadataMatches, ...contentMatches];
668
+ }
669
+ function hasSearchSelector(query) {
670
+ return query.contentNeedles.length > 0 || query.sessionId !== null || query.branch !== null || query.agent !== null;
671
+ }
672
+ function metadataMatchReasons(agent, core, query) {
673
+ const matches = [];
674
+ if (query.agent !== null) {
675
+ if (agent !== query.agent) return null;
676
+ matches.push(AGENT_SEARCH_MATCH_REASON.AGENT);
677
+ }
678
+ if (query.sessionId !== null && core.sessionId === query.sessionId) {
679
+ matches.push(AGENT_SEARCH_MATCH_REASON.SESSION_ID);
680
+ } else if (query.sessionId !== null) {
681
+ return null;
682
+ }
683
+ if (query.branch !== null) {
684
+ if (core.branch !== query.branch) return null;
685
+ matches.push(AGENT_SEARCH_MATCH_REASON.BRANCH);
686
+ }
687
+ return matches;
688
+ }
689
+ async function contentMatchReasons(path7, options) {
690
+ if (options.query.contentNeedles.length === 0) {
691
+ return [];
692
+ }
693
+ const content = await options.fs.readText(path7).catch(() => null);
694
+ return content === null ? null : matchingContentNeedles(content, options.query.contentNeedles);
695
+ }
696
+ function matchingContentNeedles(content, needles) {
697
+ const matches = needles.filter((needle) => content.includes(needle.value)).map((needle) => needle.reason);
698
+ return matches.length === needles.length ? matches : null;
699
+ }
700
+ function coreMatchesProductScope(core, productScopeRoot) {
701
+ return isPathInsideOrEqual(productScopeRoot, core.cwd);
702
+ }
703
+ async function storeFiles(paths, fs8, nowMs, includeAll) {
704
+ const files = await mapWithConcurrency(paths, AGENT_RESUME_LIMITS.READ_CONCURRENCY, async (path7) => {
705
+ const stat9 = await fs8.stat(path7).catch(() => null);
706
+ if (stat9 === null) return null;
707
+ if (!includeAll && !isRecentAgentSessionMtime(stat9.mtimeMs, nowMs)) return null;
708
+ return { path: path7, modifiedAtMs: stat9.mtimeMs };
709
+ });
710
+ return files.filter((file) => file !== null).sort((left, right) => right.modifiedAtMs - left.modifiedAtMs || left.path.localeCompare(right.path));
711
+ }
712
+ function compareSearchResults(left, right) {
713
+ const modifiedDiff = right.modifiedAtMs - left.modifiedAtMs;
714
+ if (modifiedDiff !== 0) return modifiedDiff;
715
+ return `${left.agent}:${left.sessionId}`.localeCompare(`${right.agent}:${right.sessionId}`);
716
+ }
717
+
532
718
  // src/git/root.ts
533
719
  import { execa } from "execa";
534
720
  import { basename, dirname, isAbsolute as isAbsolute2, join, resolve as resolve4 } from "path";
@@ -917,9 +1103,9 @@ var defaultAgentResumeCommandDeps = {
917
1103
  fs: nodeAgentSessionFileSystem,
918
1104
  homeDir: homedir,
919
1105
  nowMs: Date.now,
920
- resolveWorktreeRoot: async (cwd) => {
1106
+ resolveWorktreeRoot: async (cwd, fallbackWorktreeRoot) => {
921
1107
  const result = await detectWorktreeProductRoot(cwd);
922
- return result.isGitRepo ? result.productDir : null;
1108
+ return result.isGitRepo ? result.productDir : fallbackWorktreeRoot;
923
1109
  }
924
1110
  };
925
1111
  async function loadAgentResumeCandidates(options) {
@@ -930,7 +1116,7 @@ async function loadAgentResumeCandidates(options) {
930
1116
  nowMs: deps.nowMs(),
931
1117
  scope: options.scope,
932
1118
  fs: deps.fs,
933
- resolveWorktreeRoot: deps.resolveWorktreeRoot
1119
+ resolveWorktreeRoot: (cwd) => deps.resolveWorktreeRoot(cwd, options.fallbackWorktreeRoot)
934
1120
  });
935
1121
  }
936
1122
  async function listAgentResumeSessions(options) {
@@ -940,6 +1126,63 @@ async function jsonAgentResumeSessions(options) {
940
1126
  return renderAgentResumeJson(await loadAgentResumeCandidates(options));
941
1127
  }
942
1128
 
1129
+ // src/commands/agent/search.ts
1130
+ import { open as open2, readdir as readdir2, readFile, stat as stat2 } from "fs/promises";
1131
+ import { homedir as homedir2 } from "os";
1132
+ var nodeAgentSearchFileSystem = {
1133
+ async readDir(path7) {
1134
+ const entries = await readdir2(path7, { withFileTypes: true });
1135
+ return entries.map((entry) => ({
1136
+ name: entry.name,
1137
+ isDirectory: entry.isDirectory(),
1138
+ isFile: entry.isFile()
1139
+ }));
1140
+ },
1141
+ async readHead(path7, maxBytes) {
1142
+ const handle = await open2(path7, "r");
1143
+ try {
1144
+ const buffer = Buffer.alloc(maxBytes);
1145
+ const { bytesRead } = await handle.read(buffer, 0, maxBytes, 0);
1146
+ return buffer.toString(AGENT_SESSION_STORE.TEXT_ENCODING, 0, bytesRead);
1147
+ } finally {
1148
+ await handle.close();
1149
+ }
1150
+ },
1151
+ async readText(path7) {
1152
+ return readFile(path7, AGENT_SESSION_STORE.TEXT_ENCODING);
1153
+ },
1154
+ async stat(path7) {
1155
+ const result = await stat2(path7);
1156
+ return { mtimeMs: result.mtimeMs };
1157
+ }
1158
+ };
1159
+ var defaultAgentSearchCommandDeps = {
1160
+ fs: nodeAgentSearchFileSystem,
1161
+ homeDir: homedir2,
1162
+ nowMs: Date.now,
1163
+ resolveProductScopeRoot: resolveAgentSearchProductScopeRoot
1164
+ };
1165
+ async function resolveAgentSearchProductScopeRoot(cwd, fallbackProductScopeRoot, gitDeps = defaultGitDependencies) {
1166
+ const result = await detectWorktreeProductRoot(cwd, gitDeps);
1167
+ return result.isGitRepo ? result.productDir : fallbackProductScopeRoot;
1168
+ }
1169
+ async function loadAgentSearchResults(options) {
1170
+ const deps = options.deps ?? defaultAgentSearchCommandDeps;
1171
+ return searchAgentSessions({
1172
+ homeDir: deps.homeDir(),
1173
+ nowMs: deps.nowMs(),
1174
+ productScopeRoot: await deps.resolveProductScopeRoot(options.cwd, options.fallbackProductScopeRoot),
1175
+ fs: deps.fs,
1176
+ query: options.query
1177
+ });
1178
+ }
1179
+ async function listAgentSearchSessions(options) {
1180
+ return renderAgentSearchList(await loadAgentSearchResults(options));
1181
+ }
1182
+ async function jsonAgentSearchSessions(options) {
1183
+ return renderAgentSearchJson(await loadAgentSearchResults(options));
1184
+ }
1185
+
943
1186
  // src/lib/process-lifecycle/exit-codes.ts
944
1187
  var SIGINT_EXIT_CODE = 130;
945
1188
  var SIGTERM_EXIT_CODE = 143;
@@ -1118,6 +1361,50 @@ function spawnManagedSubprocess(runner, command, args, options) {
1118
1361
  });
1119
1362
  }
1120
1363
 
1364
+ // src/lib/sanitize-cli-argument.ts
1365
+ var MAX_CLI_ARGUMENT_DISPLAY_LENGTH = 120;
1366
+ var ELLIPSIS_TOKEN = "...";
1367
+ var SENTINEL_UNDEFINED = "<undefined>";
1368
+ var SENTINEL_NULL = "<null>";
1369
+ var SENTINEL_EMPTY = "<empty>";
1370
+ var CONTROL_CHAR_UPPER_BOUND = 31;
1371
+ var DEL_CHAR_CODE = 127;
1372
+ var HEX_RADIX = 16;
1373
+ var HEX_PAD = 2;
1374
+ function formatHexEscape(code) {
1375
+ return String.raw`\x${code.toString(HEX_RADIX).padStart(HEX_PAD, "0")}`;
1376
+ }
1377
+ function nonStringSentinel(type) {
1378
+ return `<non-string:${type}>`;
1379
+ }
1380
+ function sanitizeCliArgument(input) {
1381
+ return truncate(escapeCliArgument(input));
1382
+ }
1383
+ function escapeCliArgument(input) {
1384
+ if (input === void 0) return SENTINEL_UNDEFINED;
1385
+ if (input === null) return SENTINEL_NULL;
1386
+ if (typeof input !== "string") return nonStringSentinel(typeof input);
1387
+ if (input.length === 0) return SENTINEL_EMPTY;
1388
+ return escapeControlCharacters(input);
1389
+ }
1390
+ function escapeControlCharacters(value) {
1391
+ let out = "";
1392
+ for (const char of value) {
1393
+ const code = char.codePointAt(0);
1394
+ if (code === void 0) continue;
1395
+ if (code <= CONTROL_CHAR_UPPER_BOUND || code === DEL_CHAR_CODE) {
1396
+ out += formatHexEscape(code);
1397
+ } else {
1398
+ out += char;
1399
+ }
1400
+ }
1401
+ return out;
1402
+ }
1403
+ function truncate(value) {
1404
+ if (value.length <= MAX_CLI_ARGUMENT_DISPLAY_LENGTH) return value;
1405
+ return value.slice(0, MAX_CLI_ARGUMENT_DISPLAY_LENGTH - ELLIPSIS_TOKEN.length) + ELLIPSIS_TOKEN;
1406
+ }
1407
+
1121
1408
  // src/interfaces/cli/foreground-launch.ts
1122
1409
  var FOREGROUND_LAUNCH_STDIO = "inherit";
1123
1410
  var LAUNCH_FAILURE_STATUS = 1;
@@ -1240,14 +1527,26 @@ async function runAgentResumePicker(candidates, renderPicker = render) {
1240
1527
  var AGENT_CLI = {
1241
1528
  commandName: "agent",
1242
1529
  resumeCommandName: "resume",
1530
+ searchCommandName: "search",
1243
1531
  flags: {
1244
1532
  latest: "--latest",
1245
1533
  list: "--list",
1246
1534
  json: "--json",
1247
- branch: "--branch"
1535
+ branch: "--branch",
1536
+ all: "--all",
1537
+ pickupId: "--pickup-id",
1538
+ contains: "--contains",
1539
+ sessionId: "--session-id",
1540
+ agent: "--agent",
1541
+ limit: "--limit"
1248
1542
  },
1249
1543
  optionArgs: {
1250
- branch: "--branch <name>"
1544
+ branch: "--branch <name>",
1545
+ pickupId: "--pickup-id <id>",
1546
+ contains: "--contains <literal>",
1547
+ sessionId: "--session-id <id>",
1548
+ agent: "--agent <kind>",
1549
+ limit: "--limit <count>"
1251
1550
  }
1252
1551
  };
1253
1552
  var AGENT_CLI_EXIT = {
@@ -1265,6 +1564,7 @@ var DEFAULT_AGENT_CLI_DEPENDENCIES = {
1265
1564
  );
1266
1565
  }
1267
1566
  };
1567
+ var POSITIVE_DECIMAL_INTEGER_PATTERN = /^[1-9][0-9]*$/;
1268
1568
  function writeOutput(invocation, output) {
1269
1569
  invocation.io.writeStdout(`${output}
1270
1570
  `);
@@ -1281,6 +1581,33 @@ function handleError(invocation, error) {
1281
1581
  function resumeScopeFromOptions(options) {
1282
1582
  return options.branch === void 0 ? worktreeResumeScope() : branchResumeScope(options.branch);
1283
1583
  }
1584
+ function parseSearchLimit(value) {
1585
+ if (!POSITIVE_DECIMAL_INTEGER_PATTERN.test(value)) {
1586
+ throw new Error(`agent search limit must be a positive integer: ${sanitizeCliArgument(value)}`);
1587
+ }
1588
+ const parsed = Number.parseInt(value, 10);
1589
+ if (!Number.isSafeInteger(parsed)) {
1590
+ throw new Error(`agent search limit must be a positive integer: ${sanitizeCliArgument(value)}`);
1591
+ }
1592
+ return parsed;
1593
+ }
1594
+ function parseSearchAgentKind(value) {
1595
+ if (value === AGENT_SESSION_KIND.CODEX || value === AGENT_SESSION_KIND.CLAUDE_CODE) {
1596
+ return value;
1597
+ }
1598
+ throw new Error(`agent search kind must be codex or claude-code: ${sanitizeCliArgument(value)}`);
1599
+ }
1600
+ function searchQueryFromOptions(options) {
1601
+ return {
1602
+ pickupId: options.pickupId,
1603
+ contains: options.contains,
1604
+ sessionId: options.sessionId,
1605
+ branch: options.branch,
1606
+ agent: options.agent === void 0 ? void 0 : parseSearchAgentKind(options.agent),
1607
+ all: options.all,
1608
+ limit: options.limit === void 0 ? AGENT_SEARCH_DEFAULT_LIMIT : parseSearchLimit(options.limit)
1609
+ };
1610
+ }
1284
1611
  async function dispatchInteractiveResume(mode, commandOptions, deps, invocation) {
1285
1612
  const candidates = await loadAgentResumeCandidates(commandOptions);
1286
1613
  if (candidates.length === 0) {
@@ -1307,12 +1634,14 @@ function createAgentDomain(deps = {}) {
1307
1634
  let requestedExitCode = AGENT_CLI_EXIT.SUCCESS;
1308
1635
  try {
1309
1636
  const mode = resolveAgentResumeMode(options);
1637
+ const productContext = invocation.resolveProductContext();
1310
1638
  if (mode === AGENT_RESUME_MODE.PICK && !resolvedDeps.isInteractiveTerminal()) {
1311
1639
  writeError(invocation, AGENT_RESUME_TEXT.INTERACTIVE_REQUIRED);
1312
1640
  requestedExitCode = AGENT_CLI_EXIT.FAILURE;
1313
1641
  } else {
1314
1642
  const commandOptions = {
1315
- cwd: invocation.resolveEffectiveInvocationDir(),
1643
+ cwd: productContext.effectiveInvocationDir,
1644
+ fallbackWorktreeRoot: productContext.productDir,
1316
1645
  scope: resumeScopeFromOptions(options),
1317
1646
  deps: resolvedDeps.resumeDeps
1318
1647
  };
@@ -1331,6 +1660,21 @@ function createAgentDomain(deps = {}) {
1331
1660
  }
1332
1661
  return invocation.io.exit(requestedExitCode);
1333
1662
  });
1663
+ agentCmd.command(AGENT_CLI.searchCommandName).description("Search Codex and Claude Code agent session transcripts for this product").option(AGENT_CLI.optionArgs.pickupId, "Search for an exact SPX pickup marker").option(AGENT_CLI.optionArgs.contains, "Search transcript content for a literal string").option(AGENT_CLI.optionArgs.sessionId, "Search for an agent session id").option(AGENT_CLI.optionArgs.branch, "Search for sessions started on the named branch").option(AGENT_CLI.optionArgs.agent, "Search only one agent kind").option(AGENT_CLI.flags.all, "Include sessions outside the recent-session window").option(AGENT_CLI.optionArgs.limit, "Maximum number of results").option(AGENT_CLI.flags.json, "Print matching sessions as JSON").action(async (options) => {
1664
+ try {
1665
+ const productContext = invocation.resolveProductContext();
1666
+ const commandOptions = {
1667
+ cwd: productContext.effectiveInvocationDir,
1668
+ fallbackProductScopeRoot: productContext.productDir,
1669
+ query: agentSearchQueryFromOptions(searchQueryFromOptions(options)),
1670
+ deps: resolvedDeps.searchDeps
1671
+ };
1672
+ const output = options.json === true ? await jsonAgentSearchSessions(commandOptions) : await listAgentSearchSessions(commandOptions);
1673
+ writeOutput(invocation, output);
1674
+ } catch (error) {
1675
+ handleError(invocation, error);
1676
+ }
1677
+ });
1334
1678
  }
1335
1679
  };
1336
1680
  }
@@ -1443,6 +1787,7 @@ import {
1443
1787
  mkdir as nodeMkdir,
1444
1788
  open as nodeOpen,
1445
1789
  readdir as nodeReaddir,
1790
+ rename as nodeRename,
1446
1791
  rm as nodeRm
1447
1792
  } from "fs/promises";
1448
1793
  import { dirname as dirname2, join as join2 } from "path";
@@ -1536,6 +1881,9 @@ var defaultFileSystem = {
1536
1881
  },
1537
1882
  readdir: nodeReaddir,
1538
1883
  lstat: nodeLstat,
1884
+ rename: async (from, to) => {
1885
+ await nodeRename(from, to);
1886
+ },
1539
1887
  rm: async (path7, options) => {
1540
1888
  await nodeRm(path7, options);
1541
1889
  }
@@ -1628,8 +1976,8 @@ function formatRunTimestamp(date) {
1628
1976
  );
1629
1977
  return `${year}-${month}-${day}${RUN_TIMESTAMP_SEPARATOR}${hours}-${minutes}-${seconds}-${milliseconds}`;
1630
1978
  }
1631
- function generateRunId(randomBytes2 = nodeRandomBytes) {
1632
- return randomBytes2(STATE_STORE_RUN_TOKEN.ID_BYTES).toString(HEX_ENCODING);
1979
+ function generateRunId(randomBytes3 = nodeRandomBytes) {
1980
+ return randomBytes3(STATE_STORE_RUN_TOKEN.ID_BYTES).toString(HEX_ENCODING);
1633
1981
  }
1634
1982
  function createStateStoreRunToken(options) {
1635
1983
  const startedAt = formatRunTimestamp(options.date);
@@ -1651,7 +1999,7 @@ async function createJsonlRunFile(scopeDir, domainName, options = {}) {
1651
1999
  if (!domainRunsDir.ok) return domainRunsDir;
1652
2000
  const maxAttempts = options.maxAttempts ?? RUN_FILE_CREATE_ATTEMPTS;
1653
2001
  const startedDate = (options.now ?? (() => /* @__PURE__ */ new Date()))();
1654
- const randomBytes2 = options.randomBytes ?? nodeRandomBytes;
2002
+ const randomBytes3 = options.randomBytes ?? nodeRandomBytes;
1655
2003
  try {
1656
2004
  await fs8.mkdir(domainRunsDir.value, { recursive: true });
1657
2005
  } catch (error) {
@@ -1661,7 +2009,7 @@ async function createJsonlRunFile(scopeDir, domainName, options = {}) {
1661
2009
  };
1662
2010
  }
1663
2011
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
1664
- const token = createStateStoreRunToken({ date: startedDate, randomBytes: randomBytes2 });
2012
+ const token = createStateStoreRunToken({ date: startedDate, randomBytes: randomBytes3 });
1665
2013
  const name = runFileName(token.runToken);
1666
2014
  const path7 = join2(domainRunsDir.value, name);
1667
2015
  try {
@@ -2184,8 +2532,8 @@ import path2 from "path";
2184
2532
  // src/lib/atomic-file-write.ts
2185
2533
  var TEMP_TOKEN_BYTES = 8;
2186
2534
  var TEMP_SUFFIX = ".tmp";
2187
- function atomicWriteTempPath(targetPath, randomBytes2) {
2188
- const token = randomBytes2(TEMP_TOKEN_BYTES).toString("hex");
2535
+ function atomicWriteTempPath(targetPath, randomBytes3) {
2536
+ const token = randomBytes3(TEMP_TOKEN_BYTES).toString("hex");
2189
2537
  return `${targetPath}.${token}${TEMP_SUFFIX}`;
2190
2538
  }
2191
2539
  async function writeFileAtomic(targetPath, content, options) {
@@ -2545,14 +2893,14 @@ async function compactRetrieveCommand(options) {
2545
2893
  }
2546
2894
 
2547
2895
  // src/commands/compact/store.ts
2548
- import { readFile } from "fs/promises";
2896
+ import { readFile as readFile2 } from "fs/promises";
2549
2897
  var UTF8_ENCODING = "utf8";
2550
2898
  async function compactStoreCommand(options) {
2551
2899
  const sessionToken = resolveCompactSessionToken(options.sessionId, options.env ?? process.env);
2552
2900
  if (sessionToken === void 0) return 1;
2553
2901
  let transcript;
2554
2902
  try {
2555
- transcript = await readFile(options.transcript, UTF8_ENCODING);
2903
+ transcript = await readFile2(options.transcript, UTF8_ENCODING);
2556
2904
  } catch {
2557
2905
  return 1;
2558
2906
  }
@@ -2608,7 +2956,7 @@ var compactDomain = {
2608
2956
  };
2609
2957
 
2610
2958
  // src/config/index.ts
2611
- import { readFile as readFile2 } from "fs/promises";
2959
+ import { readFile as readFile3 } from "fs/promises";
2612
2960
  import { join as join4 } from "path";
2613
2961
  import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
2614
2962
  import { parse as parseYaml, parseDocument as parseYamlDocument, stringify as stringifyYaml } from "yaml";
@@ -2879,37 +3227,37 @@ function validateAgents(raw) {
2879
3227
  }
2880
3228
  return { ok: true, value: agents };
2881
3229
  }
2882
- function validateAgentConfig(path7, raw, defaults5) {
3230
+ function validateAgentConfig(path7, raw, defaults6) {
2883
3231
  if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
2884
3232
  const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_AGENT_CONFIG_ALLOWED_FIELDS);
2885
3233
  if (!unknown.ok) return unknown;
2886
3234
  const enabledRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED];
2887
- const enabled = enabledRaw === void 0 ? { ok: true, value: defaults5.enabled } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED}`, enabledRaw);
3235
+ const enabled = enabledRaw === void 0 ? { ok: true, value: defaults6.enabled } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED}`, enabledRaw);
2888
3236
  if (!enabled.ok) return enabled;
2889
3237
  const hooksRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS];
2890
- const hooks = hooksRaw === void 0 ? { ok: true, value: defaults5.hooks } : validateAgentHooks(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS}`, hooksRaw, defaults5.hooks);
3238
+ const hooks = hooksRaw === void 0 ? { ok: true, value: defaults6.hooks } : validateAgentHooks(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS}`, hooksRaw, defaults6.hooks);
2891
3239
  if (!hooks.ok) return hooks;
2892
3240
  return { ok: true, value: { enabled: enabled.value, hooks: hooks.value } };
2893
3241
  }
2894
- function validateAgentHooks(path7, raw, defaults5) {
3242
+ function validateAgentHooks(path7, raw, defaults6) {
2895
3243
  if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
2896
3244
  const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_AGENT_HOOKS_ALLOWED_FIELDS);
2897
3245
  if (!unknown.ok) return unknown;
2898
3246
  const sessionStartRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.SESSION_START];
2899
- const sessionStart = sessionStartRaw === void 0 ? { ok: true, value: defaults5.sessionStart } : validateSessionStartHooks(
3247
+ const sessionStart = sessionStartRaw === void 0 ? { ok: true, value: defaults6.sessionStart } : validateSessionStartHooks(
2900
3248
  `${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.SESSION_START}`,
2901
3249
  sessionStartRaw,
2902
- defaults5.sessionStart
3250
+ defaults6.sessionStart
2903
3251
  );
2904
3252
  if (!sessionStart.ok) return sessionStart;
2905
3253
  return { ok: true, value: { sessionStart: sessionStart.value } };
2906
3254
  }
2907
- function validateSessionStartHooks(path7, raw, defaults5) {
3255
+ function validateSessionStartHooks(path7, raw, defaults6) {
2908
3256
  if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
2909
3257
  const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_SESSION_START_HOOKS_ALLOWED_FIELDS);
2910
3258
  if (!unknown.ok) return unknown;
2911
3259
  const compactStdoutRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT];
2912
- const compactStdout = compactStdoutRaw === void 0 ? { ok: true, value: defaults5.compactStdout } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT}`, compactStdoutRaw);
3260
+ const compactStdout = compactStdoutRaw === void 0 ? { ok: true, value: defaults6.compactStdout } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT}`, compactStdoutRaw);
2913
3261
  if (!compactStdout.ok) return compactStdout;
2914
3262
  return { ok: true, value: { compactStdout: compactStdout.value } };
2915
3263
  }
@@ -2982,8 +3330,8 @@ function validatePluginBootstrap(raw) {
2982
3330
  }
2983
3331
  };
2984
3332
  }
2985
- function validateEntryArray(path7, raw, validateEntry, defaults5) {
2986
- if (raw === void 0) return { ok: true, value: defaults5 };
3333
+ function validateEntryArray(path7, raw, validateEntry, defaults6) {
3334
+ if (raw === void 0) return { ok: true, value: defaults6 };
2987
3335
  if (!Array.isArray(raw)) return { ok: false, error: `${path7} must be an array` };
2988
3336
  const entries = [];
2989
3337
  for (const [index, entry] of raw.entries()) {
@@ -3274,6 +3622,36 @@ var diagnoseConfigDescriptor = {
3274
3622
  validate: validate2
3275
3623
  };
3276
3624
 
3625
+ // src/lib/agent-run-journal/config.ts
3626
+ var RUNTIME_SECTION = "runtime";
3627
+ var RUNTIME_CONFIG_FIELDS = {
3628
+ EVENT_NAMESPACE: "eventNamespace"
3629
+ };
3630
+ var RUNTIME_EVENT_NAMESPACE_DEFAULT = "sh.spx";
3631
+ var defaults2 = { eventNamespace: RUNTIME_EVENT_NAMESPACE_DEFAULT };
3632
+ function validate3(value) {
3633
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3634
+ return { ok: false, error: `${RUNTIME_SECTION} section must be an object` };
3635
+ }
3636
+ const candidate = value;
3637
+ const raw = candidate[RUNTIME_CONFIG_FIELDS.EVENT_NAMESPACE];
3638
+ if (raw === void 0) {
3639
+ return { ok: true, value: { eventNamespace: RUNTIME_EVENT_NAMESPACE_DEFAULT } };
3640
+ }
3641
+ if (typeof raw !== "string" || raw.trim().length === 0) {
3642
+ return {
3643
+ ok: false,
3644
+ error: `${RUNTIME_SECTION}.${RUNTIME_CONFIG_FIELDS.EVENT_NAMESPACE} must be a non-empty string`
3645
+ };
3646
+ }
3647
+ return { ok: true, value: { eventNamespace: raw } };
3648
+ }
3649
+ var runtimeConfigDescriptor = {
3650
+ section: RUNTIME_SECTION,
3651
+ defaults: defaults2,
3652
+ validate: validate3
3653
+ };
3654
+
3277
3655
  // src/lib/file-inclusion/adapters/eslint.ts
3278
3656
  function eslintAdapter(scope2, config) {
3279
3657
  return scope2.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);
@@ -3334,7 +3712,7 @@ var DEFAULT_SCOPE_CONFIG = {};
3334
3712
  var DEFAULT_TOOLS_CONFIG = Object.fromEntries(
3335
3713
  Object.entries(TOOL_DEFAULT_FLAGS).map(([name, flag]) => [name, { ignoreFlag: flag }])
3336
3714
  );
3337
- var defaults2 = {
3715
+ var defaults3 = {
3338
3716
  scope: DEFAULT_SCOPE_CONFIG,
3339
3717
  tools: DEFAULT_TOOLS_CONFIG
3340
3718
  };
@@ -3406,7 +3784,7 @@ function validateTools(raw) {
3406
3784
  }
3407
3785
  return { ok: true, value: tools };
3408
3786
  }
3409
- function validate3(value) {
3787
+ function validate4(value) {
3410
3788
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3411
3789
  return { ok: false, error: `${FILE_INCLUSION_SECTION} section must be an object` };
3412
3790
  }
@@ -3433,8 +3811,8 @@ function validate3(value) {
3433
3811
  }
3434
3812
  var fileInclusionConfigDescriptor = {
3435
3813
  section: FILE_INCLUSION_SECTION,
3436
- defaults: defaults2,
3437
- validate: validate3
3814
+ defaults: defaults3,
3815
+ validate: validate4
3438
3816
  };
3439
3817
 
3440
3818
  // src/config/source-roots.ts
@@ -3457,7 +3835,7 @@ var PRECOMMIT_DEFAULTS = {
3457
3835
  sourceDirs: TEST_RELEVANT_SOURCE_ROOT_PREFIXES,
3458
3836
  testPattern: ".test.ts"
3459
3837
  };
3460
- function validate4(value) {
3838
+ function validate5(value) {
3461
3839
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3462
3840
  return { ok: false, error: `${PRECOMMIT_SECTION} section must be an object` };
3463
3841
  }
@@ -3487,7 +3865,7 @@ function validate4(value) {
3487
3865
  var precommitConfigDescriptor = {
3488
3866
  section: PRECOMMIT_SECTION,
3489
3867
  defaults: PRECOMMIT_DEFAULTS,
3490
- validate: validate4
3868
+ validate: validate5
3491
3869
  };
3492
3870
 
3493
3871
  // src/lib/spec-tree/config.ts
@@ -3678,7 +4056,7 @@ function buildConfigFromKindNames(kindNames) {
3678
4056
  const entries = kindNames.map((kind) => [kind, KIND_REGISTRY[kind]]);
3679
4057
  return { kinds: Object.fromEntries(entries) };
3680
4058
  }
3681
- function validate5(value) {
4059
+ function validate6(value) {
3682
4060
  if (typeof value !== "object" || value === null) {
3683
4061
  return { ok: false, error: `${SPEC_TREE_SECTION} section must be an object` };
3684
4062
  }
@@ -3777,7 +4155,7 @@ function validateKindDefinitionMap(kindEntries) {
3777
4155
  var specTreeConfigDescriptor = {
3778
4156
  section: SPEC_TREE_SECTION,
3779
4157
  defaults: buildDefaults(),
3780
- validate: validate5
4158
+ validate: validate6
3781
4159
  };
3782
4160
 
3783
4161
  // src/config/primitives/path-filter.ts
@@ -3850,7 +4228,7 @@ var TESTING_CONFIG_FIELDS = {
3850
4228
  PASSING_SCOPE: "passingScope"
3851
4229
  };
3852
4230
  var DEFAULT_PASSING_SCOPE = resolveDefaultPassingScope();
3853
- var defaults3 = {
4231
+ var defaults4 = {
3854
4232
  passingScope: DEFAULT_PASSING_SCOPE
3855
4233
  };
3856
4234
  function resolveDefaultPassingScope() {
@@ -3863,14 +4241,14 @@ function resolveDefaultPassingScope() {
3863
4241
  }
3864
4242
  return result.value;
3865
4243
  }
3866
- function validate6(value) {
4244
+ function validate7(value) {
3867
4245
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3868
4246
  return { ok: false, error: `${TESTING_SECTION} section must be an object` };
3869
4247
  }
3870
4248
  const candidate = value;
3871
4249
  const passingScopeRaw = candidate[TESTING_CONFIG_FIELDS.PASSING_SCOPE];
3872
4250
  if (passingScopeRaw === void 0) {
3873
- return { ok: true, value: defaults3 };
4251
+ return { ok: true, value: defaults4 };
3874
4252
  }
3875
4253
  const passingScopeResult = validatePathFilterConfig(
3876
4254
  passingScopeRaw,
@@ -3886,8 +4264,8 @@ function validate6(value) {
3886
4264
  }
3887
4265
  var testingConfigDescriptor = {
3888
4266
  section: TESTING_SECTION,
3889
- defaults: defaults3,
3890
- validate: validate6
4267
+ defaults: defaults4,
4268
+ validate: validate7
3891
4269
  };
3892
4270
 
3893
4271
  // src/validation/literal/config.ts
@@ -3951,7 +4329,7 @@ var LITERAL_DEFAULTS = {
3951
4329
  function isNonNegativeInteger(value) {
3952
4330
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
3953
4331
  }
3954
- function validate7(value) {
4332
+ function validate8(value) {
3955
4333
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3956
4334
  return { ok: false, error: `${LITERAL_SECTION} section must be an object` };
3957
4335
  }
@@ -4015,7 +4393,7 @@ function isStringArray(value) {
4015
4393
  var literalConfigDescriptor = {
4016
4394
  section: LITERAL_SECTION,
4017
4395
  defaults: LITERAL_DEFAULTS,
4018
- validate: validate7
4396
+ validate: validate8
4019
4397
  };
4020
4398
 
4021
4399
  // src/validation/config/descriptor.ts
@@ -4034,7 +4412,7 @@ var VALIDATION_PATH_TOOL_SUBSECTIONS = {
4034
4412
  LITERAL: "literal",
4035
4413
  FORMATTING: "formatting"
4036
4414
  };
4037
- var defaults4 = {
4415
+ var defaults5 = {
4038
4416
  paths: {},
4039
4417
  literal: {
4040
4418
  enabled: true,
@@ -4074,7 +4452,7 @@ function validateLiteral(raw) {
4074
4452
  };
4075
4453
  }
4076
4454
  const candidate = raw;
4077
- const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults4.literal.enabled;
4455
+ const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults5.literal.enabled;
4078
4456
  if (typeof enabledRaw !== "boolean") {
4079
4457
  return {
4080
4458
  ok: false,
@@ -4099,7 +4477,7 @@ function validateKnip(raw) {
4099
4477
  };
4100
4478
  }
4101
4479
  const candidate = raw;
4102
- const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults4.knip.enabled;
4480
+ const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults5.knip.enabled;
4103
4481
  if (typeof enabledRaw !== "boolean") {
4104
4482
  return {
4105
4483
  ok: false,
@@ -4108,7 +4486,7 @@ function validateKnip(raw) {
4108
4486
  }
4109
4487
  return { ok: true, value: { enabled: enabledRaw } };
4110
4488
  }
4111
- function validate8(value) {
4489
+ function validate9(value) {
4112
4490
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4113
4491
  return { ok: false, error: `${VALIDATION_SECTION} section must be an object` };
4114
4492
  }
@@ -4126,8 +4504,8 @@ function validate8(value) {
4126
4504
  }
4127
4505
  var validationConfigDescriptor = {
4128
4506
  section: VALIDATION_SECTION,
4129
- defaults: defaults4,
4130
- validate: validate8
4507
+ defaults: defaults5,
4508
+ validate: validate9
4131
4509
  };
4132
4510
 
4133
4511
  // src/config/registry.ts
@@ -4138,15 +4516,16 @@ var productionRegistry = [
4138
4516
  fileInclusionConfigDescriptor,
4139
4517
  precommitConfigDescriptor,
4140
4518
  harnessEnvironmentConfigDescriptor,
4141
- diagnoseConfigDescriptor
4519
+ diagnoseConfigDescriptor,
4520
+ runtimeConfigDescriptor
4142
4521
  ];
4143
4522
 
4144
4523
  // src/config/descriptor-digest.ts
4145
4524
  import { createHash as createHash3 } from "crypto";
4146
4525
  var DEFAULT_DESCRIPTOR_PATH = "descriptor section";
4147
- var SHA256_ALGORITHM2 = "sha256";
4526
+ var DESCRIPTOR_DIGEST_SHA256_ALGORITHM = "sha256";
4148
4527
  var UTF8_ENCODING2 = "utf8";
4149
- var HEX_ENCODING2 = "hex";
4528
+ var DESCRIPTOR_DIGEST_HEX_ENCODING = "hex";
4150
4529
  function canonicalDescriptorJson(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
4151
4530
  const normalized = normalizeDescriptorJsonValue(value, path7, /* @__PURE__ */ new WeakSet());
4152
4531
  if (!normalized.ok) return normalized;
@@ -4155,7 +4534,7 @@ function canonicalDescriptorJson(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
4155
4534
  function digestDescriptorSection(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
4156
4535
  const canonical = canonicalDescriptorJson(value, path7);
4157
4536
  if (!canonical.ok) return canonical;
4158
- const sha256 = createHash3(SHA256_ALGORITHM2).update(Buffer.from(canonical.value, UTF8_ENCODING2)).digest(HEX_ENCODING2);
4537
+ const sha256 = createHash3(DESCRIPTOR_DIGEST_SHA256_ALGORITHM).update(Buffer.from(canonical.value, UTF8_ENCODING2)).digest(DESCRIPTOR_DIGEST_HEX_ENCODING);
4159
4538
  return {
4160
4539
  ok: true,
4161
4540
  value: {
@@ -4269,7 +4648,7 @@ async function readProductConfigFile(productDir) {
4269
4648
  const path7 = join4(productDir, filename);
4270
4649
  let raw;
4271
4650
  try {
4272
- raw = await readFile2(path7, "utf8");
4651
+ raw = await readFile3(path7, "utf8");
4273
4652
  } catch (error) {
4274
4653
  if (isFileNotFound(error)) continue;
4275
4654
  return { ok: false, error: `failed to read ${filename}: ${toMessage(error)}` };
@@ -4553,7 +4932,7 @@ var configDomain = {
4553
4932
  };
4554
4933
 
4555
4934
  // src/interfaces/cli/diagnose.ts
4556
- import { readFile as readFile3 } from "fs/promises";
4935
+ import { readFile as readFile4 } from "fs/promises";
4557
4936
  import { Option } from "commander";
4558
4937
 
4559
4938
  // src/domains/diagnose/types.ts
@@ -5898,7 +6277,7 @@ import {
5898
6277
  mkdir as nodeMkdir2,
5899
6278
  readFile as nodeReadFile,
5900
6279
  readlink as nodeReadlink,
5901
- rename as nodeRename,
6280
+ rename as nodeRename2,
5902
6281
  rm as nodeRm2,
5903
6282
  symlink as nodeSymlink,
5904
6283
  writeFile as nodeWriteFile
@@ -5910,7 +6289,7 @@ var defaultOccupancyFileSystem = {
5910
6289
  writeFile: async (path7, data) => {
5911
6290
  await nodeWriteFile(path7, data);
5912
6291
  },
5913
- rename: nodeRename,
6292
+ rename: nodeRename2,
5914
6293
  symlink: nodeSymlink,
5915
6294
  readlink: nodeReadlink,
5916
6295
  readFile: nodeReadFile,
@@ -6251,50 +6630,6 @@ var defaultSpxReachabilityProbe = {
6251
6630
  }
6252
6631
  };
6253
6632
 
6254
- // src/lib/sanitize-cli-argument.ts
6255
- var MAX_CLI_ARGUMENT_DISPLAY_LENGTH = 120;
6256
- var ELLIPSIS_TOKEN = "...";
6257
- var SENTINEL_UNDEFINED = "<undefined>";
6258
- var SENTINEL_NULL = "<null>";
6259
- var SENTINEL_EMPTY = "<empty>";
6260
- var CONTROL_CHAR_UPPER_BOUND = 31;
6261
- var DEL_CHAR_CODE = 127;
6262
- var HEX_RADIX = 16;
6263
- var HEX_PAD = 2;
6264
- function formatHexEscape(code) {
6265
- return String.raw`\x${code.toString(HEX_RADIX).padStart(HEX_PAD, "0")}`;
6266
- }
6267
- function nonStringSentinel(type) {
6268
- return `<non-string:${type}>`;
6269
- }
6270
- function sanitizeCliArgument(input) {
6271
- return truncate(escapeCliArgument(input));
6272
- }
6273
- function escapeCliArgument(input) {
6274
- if (input === void 0) return SENTINEL_UNDEFINED;
6275
- if (input === null) return SENTINEL_NULL;
6276
- if (typeof input !== "string") return nonStringSentinel(typeof input);
6277
- if (input.length === 0) return SENTINEL_EMPTY;
6278
- return escapeControlCharacters(input);
6279
- }
6280
- function escapeControlCharacters(value) {
6281
- let out = "";
6282
- for (const char of value) {
6283
- const code = char.codePointAt(0);
6284
- if (code === void 0) continue;
6285
- if (code <= CONTROL_CHAR_UPPER_BOUND || code === DEL_CHAR_CODE) {
6286
- out += formatHexEscape(code);
6287
- } else {
6288
- out += char;
6289
- }
6290
- }
6291
- return out;
6292
- }
6293
- function truncate(value) {
6294
- if (value.length <= MAX_CLI_ARGUMENT_DISPLAY_LENGTH) return value;
6295
- return value.slice(0, MAX_CLI_ARGUMENT_DISPLAY_LENGTH - ELLIPSIS_TOKEN.length) + ELLIPSIS_TOKEN;
6296
- }
6297
-
6298
6633
  // src/interfaces/cli/diagnose.ts
6299
6634
  var DIAGNOSE_CLI = {
6300
6635
  COMMAND: "diagnose",
@@ -6341,7 +6676,7 @@ var diagnoseDomain = {
6341
6676
  isTty: Boolean(process.stdout.isTTY)
6342
6677
  }),
6343
6678
  registry: defaultRegistry(),
6344
- fs: { readFile: (path7) => readFile3(path7, "utf8") }
6679
+ fs: { readFile: (path7) => readFile4(path7, "utf8") }
6345
6680
  });
6346
6681
  if (!result.ok) {
6347
6682
  handleError2(result.error, invocation.io);
@@ -6845,9 +7180,9 @@ var JOURNAL_RUN_STATE_INCOMPLETE_REASON = {
6845
7180
  };
6846
7181
  var JOURNAL_RUN_EVENT = {
6847
7182
  SOURCE: "/spx/journal",
6848
- STARTED_TYPE: "com.outcomeeng.spx.journal.run.started",
6849
- PROGRESS_TYPE: "com.outcomeeng.spx.journal.run.progress",
6850
- COMPLETED_TYPE: "com.outcomeeng.spx.journal.run.completed"
7183
+ STARTED_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.started`,
7184
+ PROGRESS_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.progress`,
7185
+ COMPLETED_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.completed`
6851
7186
  };
6852
7187
  var JOURNAL_RUN_STATE_FIELDS = {
6853
7188
  BRANCH_NAME: "branchName",
@@ -6866,13 +7201,18 @@ var JOURNAL_RUN_STATE_FIELDS = {
6866
7201
  STATUS: "status"
6867
7202
  };
6868
7203
  function foldJournalRunState(events, sealed) {
6869
- if (!sealed) return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.UNSEALED };
7204
+ if (!sealed) {
7205
+ return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.UNSEALED };
7206
+ }
6870
7207
  let completed;
6871
7208
  for (const event of events) {
6872
7209
  if (event.type === JOURNAL_RUN_EVENT.COMPLETED_TYPE) completed = event;
6873
7210
  }
6874
7211
  if (completed === void 0) {
6875
- return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.MISSING_STATE };
7212
+ return {
7213
+ ok: false,
7214
+ reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.MISSING_STATE
7215
+ };
6876
7216
  }
6877
7217
  const validated = validateJournalRunState(completed.data);
6878
7218
  if (!validated.ok) {
@@ -6885,13 +7225,17 @@ function foldJournalRunState(events, sealed) {
6885
7225
  return validated;
6886
7226
  }
6887
7227
  function isJournalRunStateStatus(value) {
6888
- return typeof value === "string" && Object.values(JOURNAL_RUN_STATE_STATUS).includes(value);
7228
+ return typeof value === "string" && Object.values(JOURNAL_RUN_STATE_STATUS).includes(
7229
+ value
7230
+ );
6889
7231
  }
6890
7232
  function isJournalTargetKind(value) {
6891
7233
  return typeof value === "string" && Object.values(JOURNAL_TARGET_KIND).includes(value);
6892
7234
  }
6893
7235
  function validateJournalRunState(value) {
6894
- if (!isRecord5(value)) return { ok: false, error: "journal run state must be an object" };
7236
+ if (!isRecord5(value)) {
7237
+ return { ok: false, error: "journal run state must be an object" };
7238
+ }
6895
7239
  const identity = readRunStateIdentity(value);
6896
7240
  if (!identity.ok) return identity;
6897
7241
  const body = readRunStateBody(value);
@@ -6903,9 +7247,15 @@ function readRunStateIdentity(value) {
6903
7247
  if (!branchName.ok) return branchName;
6904
7248
  const branchSlug = readString(value, JOURNAL_RUN_STATE_FIELDS.BRANCH_SLUG);
6905
7249
  if (!branchSlug.ok) return branchSlug;
6906
- const targetKind = readTargetKind(value, JOURNAL_RUN_STATE_FIELDS.TARGET_KIND);
7250
+ const targetKind = readTargetKind(
7251
+ value,
7252
+ JOURNAL_RUN_STATE_FIELDS.TARGET_KIND
7253
+ );
6907
7254
  if (!targetKind.ok) return targetKind;
6908
- const pullRequestNumber = readOptionalNonNegativeInteger(value, JOURNAL_RUN_STATE_FIELDS.PULL_REQUEST_NUMBER);
7255
+ const pullRequestNumber = readOptionalNonNegativeInteger(
7256
+ value,
7257
+ JOURNAL_RUN_STATE_FIELDS.PULL_REQUEST_NUMBER
7258
+ );
6909
7259
  if (!pullRequestNumber.ok) return pullRequestNumber;
6910
7260
  const headSha = readString(value, JOURNAL_RUN_STATE_FIELDS.HEAD_SHA);
6911
7261
  if (!headSha.ok) return headSha;
@@ -6927,9 +7277,15 @@ function readRunStateIdentity(value) {
6927
7277
  };
6928
7278
  }
6929
7279
  function readRunStateBody(value) {
6930
- const configDigest = readString(value, JOURNAL_RUN_STATE_FIELDS.CONFIG_DIGEST);
7280
+ const configDigest = readString(
7281
+ value,
7282
+ JOURNAL_RUN_STATE_FIELDS.CONFIG_DIGEST
7283
+ );
6931
7284
  if (!configDigest.ok) return configDigest;
6932
- const participants = readStringArray(value, JOURNAL_RUN_STATE_FIELDS.PARTICIPANTS);
7285
+ const participants = readStringArray(
7286
+ value,
7287
+ JOURNAL_RUN_STATE_FIELDS.PARTICIPANTS
7288
+ );
6933
7289
  if (!participants.ok) return participants;
6934
7290
  const scope2 = readPathFilter(value, JOURNAL_RUN_STATE_FIELDS.SCOPE);
6935
7291
  if (!scope2.ok) return scope2;
@@ -6937,7 +7293,10 @@ function readRunStateBody(value) {
6937
7293
  if (!startedAt.ok) return startedAt;
6938
7294
  const completedAt = readString(value, JOURNAL_RUN_STATE_FIELDS.COMPLETED_AT);
6939
7295
  if (!completedAt.ok) return completedAt;
6940
- const outputPaths = readStringArray(value, JOURNAL_RUN_STATE_FIELDS.OUTPUT_PATHS);
7296
+ const outputPaths = readStringArray(
7297
+ value,
7298
+ JOURNAL_RUN_STATE_FIELDS.OUTPUT_PATHS
7299
+ );
6941
7300
  if (!outputPaths.ok) return outputPaths;
6942
7301
  const status = readStatus(value, JOURNAL_RUN_STATE_FIELDS.STATUS);
6943
7302
  if (!status.ok) return status;
@@ -6966,7 +7325,10 @@ function readOptionalString(value, field) {
6966
7325
  function readOptionalNonNegativeInteger(value, field) {
6967
7326
  const raw = value[field];
6968
7327
  if (raw === void 0) return { ok: true, value: void 0 };
6969
- return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? { ok: true, value: raw } : { ok: false, error: `${field} must be a non-negative integer when present` };
7328
+ return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? { ok: true, value: raw } : {
7329
+ ok: false,
7330
+ error: `${field} must be a non-negative integer when present`
7331
+ };
6970
7332
  }
6971
7333
  function readStringArray(value, field) {
6972
7334
  const raw = value[field];
@@ -7208,6 +7570,7 @@ function createJournal(backend, identity) {
7208
7570
 
7209
7571
  // src/lib/appendable-journal-store/index.ts
7210
7572
  var SEAL_MARKER_SUFFIX = ".sealed";
7573
+ var APPENDABLE_JOURNAL_SEAL_MARKER_CONTENT = "";
7211
7574
  var LINE_SEPARATOR3 = "\n";
7212
7575
  function appendableJournalSealMarkerPath(runFilePath) {
7213
7576
  return `${runFilePath}${SEAL_MARKER_SUFFIX}`;
@@ -7247,7 +7610,7 @@ function createAppendableJournalStore(options) {
7247
7610
  readAll,
7248
7611
  async seal() {
7249
7612
  await fs8.mkdir(dirname5(sealMarkerPath), { recursive: true });
7250
- await fs8.writeFile(sealMarkerPath, "");
7613
+ await fs8.writeFile(sealMarkerPath, APPENDABLE_JOURNAL_SEAL_MARKER_CONTENT);
7251
7614
  },
7252
7615
  async isSealed() {
7253
7616
  return await readFileOrUndefined(fs8, sealMarkerPath) !== void 0;
@@ -7658,6 +8021,18 @@ async function readSealedJournalRunSet(scope2, options = {}) {
7658
8021
  }))
7659
8022
  };
7660
8023
  }
8024
+ async function findJournalRunBranchSlugs(scope2, options = {}) {
8025
+ const fs8 = options.fs ?? defaultFileSystem;
8026
+ const branches = await branchSlugs(scope2, fs8);
8027
+ if (!branches.ok) return branches;
8028
+ const matches = [];
8029
+ for (const branchSlug of branches.value) {
8030
+ const runFilePath = bindRunFilePath({ ...scope2, branchSlug });
8031
+ if (!runFilePath.ok) return runFilePath;
8032
+ if (await runFileExists(fs8, runFilePath.value)) matches.push(branchSlug);
8033
+ }
8034
+ return { ok: true, value: matches };
8035
+ }
7661
8036
  async function appendJournalEvent(ref, input, sink, options = {}) {
7662
8037
  const bound = await bindJournal(ref, options.fs);
7663
8038
  if (!bound.ok) return bound;
@@ -7692,6 +8067,20 @@ async function sealJournalRun(ref, options = {}) {
7692
8067
  return { ok: false, error: `${JOURNAL_RUNTIME_ERROR.SEAL_FAILED}: ${toMessage(error)}` };
7693
8068
  }
7694
8069
  }
8070
+ async function isJournalRunSealed(ref, options = {}) {
8071
+ const runFilePath = bindRunFilePath(ref);
8072
+ if (!runFilePath.ok) return runFilePath;
8073
+ const fs8 = options.fs ?? defaultFileSystem;
8074
+ if (!await runFileExists(fs8, runFilePath.value)) {
8075
+ return { ok: false, error: JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND };
8076
+ }
8077
+ const store = createAppendableJournalStore({ runFilePath: runFilePath.value, fs: fs8 });
8078
+ try {
8079
+ return { ok: true, value: await store.isSealed() };
8080
+ } catch (error) {
8081
+ return { ok: false, error: `${JOURNAL_RUNTIME_ERROR.READ_FAILED}: ${toMessage(error)}` };
8082
+ }
8083
+ }
7695
8084
  async function renderJournalRun(ref, projection, options = {}) {
7696
8085
  const bound = await bindJournal(ref, options.fs);
7697
8086
  if (!bound.ok) return bound;
@@ -7736,6 +8125,7 @@ var JOURNAL_CLI_ERROR = {
7736
8125
  INVALID_READ_SET_EVENT_LIMIT: "journal read-set event limit must be a positive whole integer",
7737
8126
  INVALID_SEALED_FILTER: "journal list sealed filter is not registered",
7738
8127
  INVALID_TERMINAL_STATE_FILTER: "journal list terminal-state filter is not registered",
8128
+ RUN_TOKEN_AMBIGUOUS: "journal run token matches multiple branch scopes; rerun with --branch-slug",
7739
8129
  OPEN_HYDRATION_FAILED: "journal open failed to hydrate the pull request's prior runs"
7740
8130
  };
7741
8131
  var CURSOR_PATTERN = /^\d+$/;
@@ -7858,6 +8248,34 @@ function verbOptions(deps) {
7858
8248
  function runRef(context, runToken) {
7859
8249
  return { productDir: context.productDir, branchSlug: context.branchSlug, type: context.type, runToken };
7860
8250
  }
8251
+ async function inspectionRunRef(scope2, deps) {
8252
+ const context = await resolveJournalRunContext(scope2, deps);
8253
+ if (!context.ok) return context;
8254
+ if (scope2.branchSlug !== void 0) return { ok: true, value: runRef(context.value, scope2.runToken) };
8255
+ const branches = await findJournalRunBranchSlugs(
8256
+ {
8257
+ productDir: context.value.productDir,
8258
+ type: context.value.type,
8259
+ runToken: scope2.runToken
8260
+ },
8261
+ verbOptions(deps)
8262
+ );
8263
+ if (!branches.ok) return branches;
8264
+ if (branches.value.length === 1) {
8265
+ const branchSlug = branches.value[0];
8266
+ return {
8267
+ ok: true,
8268
+ value: {
8269
+ productDir: context.value.productDir,
8270
+ branchSlug,
8271
+ type: context.value.type,
8272
+ runToken: scope2.runToken
8273
+ }
8274
+ };
8275
+ }
8276
+ if (branches.value.length > 1) return { ok: false, error: JOURNAL_CLI_ERROR.RUN_TOKEN_AMBIGUOUS };
8277
+ return { ok: true, value: runRef(context.value, scope2.runToken) };
8278
+ }
7861
8279
  function okResult(output) {
7862
8280
  return { exitCode: JOURNAL_CLI_EXIT_CODE.OK, output };
7863
8281
  }
@@ -7974,9 +8392,9 @@ async function journalAppendCommand(scope2, input, binding, deps = {}) {
7974
8392
  async function journalReadCommand(scope2, fromCursor, deps = {}) {
7975
8393
  const cursor = parseJournalCursor(fromCursor);
7976
8394
  if (!cursor.ok) return errorResult(cursor.error);
7977
- const context = await resolveJournalRunContext(scope2, deps);
7978
- if (!context.ok) return errorResult(context.error);
7979
- const events = await readJournalEvents(runRef(context.value, scope2.runToken), cursor.value, verbOptions(deps));
8395
+ const ref = await inspectionRunRef(scope2, deps);
8396
+ if (!ref.ok) return errorResult(ref.error);
8397
+ const events = await readJournalEvents(ref.value, cursor.value, verbOptions(deps));
7980
8398
  if (!events.ok) return errorResult(events.error);
7981
8399
  return okResult(JSON.stringify(events.value));
7982
8400
  }
@@ -8025,10 +8443,10 @@ async function journalSealCommand(scope2, deps = {}) {
8025
8443
  return okResult(JSON.stringify({ sealed: true }));
8026
8444
  }
8027
8445
  async function journalRenderCommand(scope2, deps = {}) {
8028
- const context = await resolveJournalRunContext(scope2, deps);
8029
- if (!context.ok) return errorResult(context.error);
8446
+ const ref = await inspectionRunRef(scope2, deps);
8447
+ if (!ref.ok) return errorResult(ref.error);
8030
8448
  const rendered = await renderJournalRun(
8031
- runRef(context.value, scope2.runToken),
8449
+ ref.value,
8032
8450
  (events) => [...events],
8033
8451
  verbOptions(deps)
8034
8452
  );
@@ -8354,7 +8772,7 @@ function sessionOptionToken(option) {
8354
8772
  }
8355
8773
 
8356
8774
  // src/commands/session/archive.ts
8357
- import { mkdir, rename, stat as stat2 } from "fs/promises";
8775
+ import { mkdir, rename, stat as stat3 } from "fs/promises";
8358
8776
  import { dirname as dirname7, join as join8 } from "path";
8359
8777
 
8360
8778
  // src/domains/session/archive.ts
@@ -8667,7 +9085,7 @@ var SessionAlreadyArchivedError = class extends Error {
8667
9085
  };
8668
9086
  async function fileExists(path7) {
8669
9087
  try {
8670
- const stats = await stat2(path7);
9088
+ const stats = await stat3(path7);
8671
9089
  return stats.isFile();
8672
9090
  } catch {
8673
9091
  return false;
@@ -8709,7 +9127,7 @@ async function archiveCommand(options) {
8709
9127
  }
8710
9128
 
8711
9129
  // src/commands/session/delete.ts
8712
- import { stat as stat3, unlink } from "fs/promises";
9130
+ import { stat as stat4, unlink } from "fs/promises";
8713
9131
 
8714
9132
  // src/domains/session/delete.ts
8715
9133
  function resolveDeletePath(sessionId, existingPaths) {
@@ -8882,44 +9300,6 @@ function parseSessionId(id) {
8882
9300
  return date;
8883
9301
  }
8884
9302
 
8885
- // src/domains/session/types.ts
8886
- var SESSION_PRIORITY = {
8887
- HIGH: "high",
8888
- MEDIUM: "medium",
8889
- LOW: "low"
8890
- };
8891
- var SESSION_STATUSES = ["todo", "doing", "archive"];
8892
- var DEFAULT_LIST_STATUSES = ["doing", "todo"];
8893
- var SESSION_FILE_ENCODING = "utf-8";
8894
- var SESSION_FILE_ERROR_CODE = {
8895
- NOT_FOUND: "ENOENT"
8896
- };
8897
- var SESSION_OUTPUT_MARKER = {
8898
- HANDOFF_ID: "HANDOFF_ID",
8899
- PICKUP_ID: "PICKUP_ID",
8900
- SESSION_FILE: "SESSION_FILE"
8901
- };
8902
- function formatSessionOutputMarker(marker, value) {
8903
- return `<${marker}>${value}</${marker}>`;
8904
- }
8905
- var CLAIMABLE_STATUS = SESSION_STATUSES[0];
8906
- var PRIORITY_ORDER = {
8907
- [SESSION_PRIORITY.HIGH]: 0,
8908
- [SESSION_PRIORITY.MEDIUM]: 1,
8909
- [SESSION_PRIORITY.LOW]: 2
8910
- };
8911
- var DEFAULT_PRIORITY = SESSION_PRIORITY.MEDIUM;
8912
- var SESSION_FRONT_MATTER = {
8913
- PRIORITY: "priority",
8914
- GIT_REF: "git_ref",
8915
- GOAL: "goal",
8916
- NEXT_STEP: "next_step",
8917
- CREATED_AT: "created_at",
8918
- AGENT_SESSION_ID: "agent_session_id",
8919
- SPECS: "specs",
8920
- FILES: "files"
8921
- };
8922
-
8923
9303
  // src/domains/session/list.ts
8924
9304
  var FRONT_MATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n(?:---|\.\.\.)\r?\n?/;
8925
9305
  var SESSION_PRIORITY_VALUES = Object.values(SESSION_PRIORITY);
@@ -9158,7 +9538,7 @@ async function findExistingPaths(paths) {
9158
9538
  const existing = [];
9159
9539
  for (const path7 of paths) {
9160
9540
  try {
9161
- const stats = await stat3(path7);
9541
+ const stats = await stat4(path7);
9162
9542
  if (stats.isFile()) {
9163
9543
  existing.push(path7);
9164
9544
  }
@@ -9180,7 +9560,7 @@ async function deleteCommand(options) {
9180
9560
  }
9181
9561
 
9182
9562
  // src/commands/session/handoff.ts
9183
- import { mkdir as mkdir2, stat as stat4, writeFile } from "fs/promises";
9563
+ import { mkdir as mkdir2, stat as stat5, writeFile } from "fs/promises";
9184
9564
  import { join as join10, resolve as resolve6 } from "path";
9185
9565
  import { stringify as stringifyYaml3 } from "yaml";
9186
9566
 
@@ -9431,7 +9811,7 @@ async function rejectDirectoryInjectionEntries(entries, cwd) {
9431
9811
  if (entry.length === 0) continue;
9432
9812
  let entryIsDirectory = false;
9433
9813
  try {
9434
- entryIsDirectory = (await stat4(resolve6(cwd, entry))).isDirectory();
9814
+ entryIsDirectory = (await stat5(resolve6(cwd, entry))).isDirectory();
9435
9815
  } catch {
9436
9816
  continue;
9437
9817
  }
@@ -9489,7 +9869,7 @@ ${formatSessionOutputMarker(SESSION_OUTPUT_MARKER.SESSION_FILE, absolutePath)}`;
9489
9869
  }
9490
9870
 
9491
9871
  // src/commands/session/list.ts
9492
- import { readdir as readdir2, readFile as readFile4 } from "fs/promises";
9872
+ import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
9493
9873
  import { join as join11 } from "path";
9494
9874
  var SESSION_LIST_FORMAT = {
9495
9875
  TEXT: "text",
@@ -9498,13 +9878,13 @@ var SESSION_LIST_FORMAT = {
9498
9878
  var SESSION_LIST_EMPTY_TEXT = "(no sessions)";
9499
9879
  async function loadSessionsFromDir(dir, status) {
9500
9880
  try {
9501
- const files = await readdir2(dir);
9881
+ const files = await readdir3(dir);
9502
9882
  const sessions = [];
9503
9883
  for (const file of files) {
9504
9884
  if (!file.endsWith(".md")) continue;
9505
9885
  const id = file.replace(".md", "");
9506
9886
  const filePath = join11(dir, file);
9507
- const content = await readFile4(filePath, SESSION_FILE_ENCODING);
9887
+ const content = await readFile5(filePath, SESSION_FILE_ENCODING);
9508
9888
  const metadata = parseSessionMetadata(content);
9509
9889
  sessions.push({
9510
9890
  id,
@@ -9567,7 +9947,7 @@ async function listCommand(options) {
9567
9947
  }
9568
9948
 
9569
9949
  // src/commands/session/pickup.ts
9570
- import { mkdir as mkdir3, readdir as readdir3, readFile as readFile5, rename as rename2 } from "fs/promises";
9950
+ import { mkdir as mkdir3, readdir as readdir4, readFile as readFile6, rename as rename2 } from "fs/promises";
9571
9951
  import { join as join12, resolve as resolve7 } from "path";
9572
9952
 
9573
9953
  // src/domains/session/pickup.ts
@@ -9607,8 +9987,8 @@ function selectBestSession(sessions) {
9607
9987
  var PICKUP_TARGET_STATUS = SESSION_STATUSES[1];
9608
9988
  var PICKUP_DEPS = {
9609
9989
  mkdir: mkdir3,
9610
- readdir: readdir3,
9611
- readFile: readFile5,
9990
+ readdir: readdir4,
9991
+ readFile: readFile6,
9612
9992
  rename: rename2
9613
9993
  };
9614
9994
  async function loadTodoSessions(config) {
@@ -9717,7 +10097,7 @@ async function loadPickCandidates(options) {
9717
10097
  }
9718
10098
 
9719
10099
  // src/commands/session/prune.ts
9720
- import { readdir as readdir4, readFile as readFile6, unlink as unlink2 } from "fs/promises";
10100
+ import { readdir as readdir5, readFile as readFile7, unlink as unlink2 } from "fs/promises";
9721
10101
  import { join as join13 } from "path";
9722
10102
 
9723
10103
  // src/domains/session/prune.ts
@@ -9762,13 +10142,13 @@ function validatePruneOptions(options) {
9762
10142
  }
9763
10143
  async function loadArchiveSessions(config) {
9764
10144
  try {
9765
- const files = await readdir4(config.archiveDir);
10145
+ const files = await readdir5(config.archiveDir);
9766
10146
  const sessions = [];
9767
10147
  for (const file of files) {
9768
10148
  if (!file.endsWith(".md")) continue;
9769
10149
  const id = file.replace(".md", "");
9770
10150
  const filePath = join13(config.archiveDir, file);
9771
- const content = await readFile6(filePath, SESSION_FILE_ENCODING);
10151
+ const content = await readFile7(filePath, SESSION_FILE_ENCODING);
9772
10152
  const metadata = parseSessionMetadata(content);
9773
10153
  sessions.push({
9774
10154
  id,
@@ -9817,7 +10197,7 @@ async function pruneCommand(options) {
9817
10197
  }
9818
10198
 
9819
10199
  // src/commands/session/release.ts
9820
- import { readdir as readdir5, rename as rename3 } from "fs/promises";
10200
+ import { readdir as readdir6, rename as rename3 } from "fs/promises";
9821
10201
 
9822
10202
  // src/domains/session/release.ts
9823
10203
  function buildReleasePaths(sessionId, config) {
@@ -9848,7 +10228,7 @@ var SESSION_RELEASE_OUTPUT = {
9848
10228
  };
9849
10229
  async function loadDoingSessions(config) {
9850
10230
  try {
9851
- const files = await readdir5(config.doingDir);
10231
+ const files = await readdir6(config.doingDir);
9852
10232
  return files.filter((file) => file.endsWith(".md")).map((file) => ({ id: file.replace(".md", "") }));
9853
10233
  } catch (error) {
9854
10234
  if (error instanceof Error && "code" in error && error.code === SESSION_FILE_ERROR_CODE.NOT_FOUND) {
@@ -9885,12 +10265,12 @@ async function releaseCommand(options) {
9885
10265
  }
9886
10266
 
9887
10267
  // src/commands/session/show.ts
9888
- import { readFile as readFile7, stat as stat5 } from "fs/promises";
10268
+ import { readFile as readFile8, stat as stat6 } from "fs/promises";
9889
10269
  async function findExistingPath(paths, _config) {
9890
10270
  for (let i = 0; i < paths.length; i++) {
9891
10271
  const filePath = paths[i];
9892
10272
  try {
9893
- const stats = await stat5(filePath);
10273
+ const stats = await stat6(filePath);
9894
10274
  if (stats.isFile()) {
9895
10275
  return { path: filePath, status: SEARCH_ORDER[i] };
9896
10276
  }
@@ -9905,7 +10285,7 @@ async function resolveSession(sessionId, config) {
9905
10285
  if (!found) {
9906
10286
  throw new SessionNotFoundError(sessionId);
9907
10287
  }
9908
- const content = await readFile7(found.path, SESSION_FILE_ENCODING);
10288
+ const content = await readFile8(found.path, SESSION_FILE_ENCODING);
9909
10289
  return { status: found.status, path: found.path, content };
9910
10290
  }
9911
10291
  async function showSingle(sessionId, config) {
@@ -10569,7 +10949,7 @@ var sessionDomain = {
10569
10949
  };
10570
10950
 
10571
10951
  // src/lib/spec-tree/index.ts
10572
- import { readdir as readdir6, readFile as readFile8 } from "fs/promises";
10952
+ import { readdir as readdir7, readFile as readFile9 } from "fs/promises";
10573
10953
  import { join as join14 } from "path";
10574
10954
  var SPEC_TREE_FIELD_KEY = {
10575
10955
  VERSION: "version",
@@ -10654,7 +11034,7 @@ function createFilesystemSpecTreeSource(options) {
10654
11034
  if (ref.path === void 0) {
10655
11035
  throw new Error("Filesystem source refs require a path");
10656
11036
  }
10657
- return readFile8(join14(options.productDir, ref.path), SPEC_TREE_TEXT_ENCODING);
11037
+ return readFile9(join14(options.productDir, ref.path), SPEC_TREE_TEXT_ENCODING);
10658
11038
  }
10659
11039
  };
10660
11040
  }
@@ -10945,7 +11325,7 @@ async function* readFilesystemSourceEntries(productDir, registry, schemaVersions
10945
11325
  async function* walkFilesystemDirectory(context) {
10946
11326
  let entries;
10947
11327
  try {
10948
- entries = await readdir6(context.absolutePath, { withFileTypes: true });
11328
+ entries = await readdir7(context.absolutePath, { withFileTypes: true });
10949
11329
  } catch (error) {
10950
11330
  if (isFileNotFound2(error)) return;
10951
11331
  throw error;
@@ -11117,7 +11497,7 @@ function formatNextNode(node) {
11117
11497
  }
11118
11498
 
11119
11499
  // src/commands/test/discovery.ts
11120
- import { readdir as readdir7 } from "fs/promises";
11500
+ import { readdir as readdir8 } from "fs/promises";
11121
11501
  import { join as join15, relative as relative2, sep as sep2 } from "path";
11122
11502
  var TESTS_DIRECTORY_NAME = SPEC_TREE_EVIDENCE_FILE.DIRECTORY_NAME;
11123
11503
  var SPEC_ROOT_DIRECTORY = SPEC_TREE_CONFIG.ROOT_DIRECTORY;
@@ -11131,7 +11511,7 @@ async function discoverTestFiles(productDir) {
11131
11511
  async function collectTestFiles(directory, insideTestsDir, found) {
11132
11512
  let entries;
11133
11513
  try {
11134
- entries = await readdir7(directory, { withFileTypes: true });
11514
+ entries = await readdir8(directory, { withFileTypes: true });
11135
11515
  } catch (error) {
11136
11516
  if (hasErrorCode2(error, ERROR_CODE_NOT_FOUND2)) return;
11137
11517
  throw error;
@@ -11380,8 +11760,8 @@ var PRODUCT_INPUT_DIGEST_FIELDS = {
11380
11760
  DESCRIPTOR_ID: "descriptorId",
11381
11761
  DIGEST: "digest"
11382
11762
  };
11383
- var SHA256_ALGORITHM3 = "sha256";
11384
- var HEX_ENCODING3 = "hex";
11763
+ var SHA256_ALGORITHM2 = "sha256";
11764
+ var HEX_ENCODING2 = "hex";
11385
11765
  var SEGMENT_SEPARATOR = "-";
11386
11766
  var defaultFileSystem2 = defaultFileSystem;
11387
11767
  function formatTestRunTimestamp(date) {
@@ -11657,7 +12037,7 @@ function isRecord6(value) {
11657
12037
  return typeof value === "object" && value !== null && !Array.isArray(value);
11658
12038
  }
11659
12039
  function sha256Hex2(value) {
11660
- return createHash4(SHA256_ALGORITHM3).update(value).digest(HEX_ENCODING3);
12040
+ return createHash4(SHA256_ALGORITHM2).update(value).digest(HEX_ENCODING2);
11661
12041
  }
11662
12042
  var UNKNOWN_ERROR_MESSAGE = "unknown error";
11663
12043
  function toErrorMessage3(error) {
@@ -12542,7 +12922,7 @@ function createNodeStatusProvider(productDir) {
12542
12922
  }
12543
12923
 
12544
12924
  // src/lib/node-status/update.ts
12545
- import { mkdir as mkdir4, readdir as readdir8, rm, writeFile as writeFile2 } from "fs/promises";
12925
+ import { mkdir as mkdir4, readdir as readdir9, rm, writeFile as writeFile2 } from "fs/promises";
12546
12926
  import { dirname as dirname8, join as join21 } from "path";
12547
12927
 
12548
12928
  // src/git/tracked-paths.ts
@@ -12666,7 +13046,7 @@ async function collectNodeStatusFiles(directory) {
12666
13046
  }
12667
13047
  async function readDirectoryEntries(directory) {
12668
13048
  try {
12669
- return await readdir8(directory, { withFileTypes: true });
13049
+ return await readdir9(directory, { withFileTypes: true });
12670
13050
  } catch (error) {
12671
13051
  if (isNodeError3(error) && error.code === "ENOENT") return [];
12672
13052
  throw error;
@@ -13275,7 +13655,7 @@ var testingRegistry = {
13275
13655
 
13276
13656
  // src/interfaces/cli/test-runner-deps.ts
13277
13657
  import { createWriteStream } from "fs";
13278
- import { mkdtemp, readFile as readFile9 } from "fs/promises";
13658
+ import { mkdtemp, readFile as readFile10 } from "fs/promises";
13279
13659
  import { tmpdir } from "os";
13280
13660
  import { join as join23 } from "path";
13281
13661
  import { finished } from "stream/promises";
@@ -13325,7 +13705,7 @@ function createRunnerDepsFor(productDir, outStream = process.stdout) {
13325
13705
  }
13326
13706
  function createRelatedDepsFor(productDir) {
13327
13707
  const runCommand = createRelatedCommandRunner(productDir);
13328
- return () => ({ runCommand, readFile: (path7) => readFile9(join23(productDir, path7), "utf8") });
13708
+ return () => ({ runCommand, readFile: (path7) => readFile10(join23(productDir, path7), "utf8") });
13329
13709
  }
13330
13710
  function artifactFileName(index, suffix) {
13331
13711
  return `${index.toString(ARTIFACT_INDEX_RADIX).padStart(ARTIFACT_INDEX_WIDTH, "0")}-${suffix}`;
@@ -17025,11 +17405,11 @@ function formatLintResult(result, quiet, durationMs) {
17025
17405
  }
17026
17406
 
17027
17407
  // src/validation/literal/index.ts
17028
- import { readFile as readFile11 } from "fs/promises";
17408
+ import { readFile as readFile12 } from "fs/promises";
17029
17409
  import { isAbsolute as isAbsolute9, relative as relative7, resolve as resolve10 } from "path";
17030
17410
 
17031
17411
  // src/lib/file-inclusion/pipeline.ts
17032
- import { readdir as readdir9, readFile as readFile10, stat as stat6 } from "fs/promises";
17412
+ import { readdir as readdir10, readFile as readFile11, stat as stat7 } from "fs/promises";
17033
17413
  import { join as join33, relative as relative6, sep as sep3 } from "path";
17034
17414
 
17035
17415
  // src/lib/file-inclusion/ignore-source.ts
@@ -17335,7 +17715,7 @@ function isNodeError4(err) {
17335
17715
  }
17336
17716
  async function isDirectory(absolutePath) {
17337
17717
  try {
17338
- return (await stat6(absolutePath)).isDirectory();
17718
+ return (await stat7(absolutePath)).isDirectory();
17339
17719
  } catch (err) {
17340
17720
  if (isNodeError4(err) && (err.code === "ENOENT" || err.code === "ENOTDIR")) {
17341
17721
  return false;
@@ -17345,7 +17725,7 @@ async function isDirectory(absolutePath) {
17345
17725
  }
17346
17726
  async function isGitdirPointerFile(absolutePath) {
17347
17727
  try {
17348
- const content = await readFile10(absolutePath, "utf8");
17728
+ const content = await readFile11(absolutePath, "utf8");
17349
17729
  return content.startsWith(GITDIR_POINTER_PREFIX);
17350
17730
  } catch (err) {
17351
17731
  if (isNodeError4(err) && (err.code === "ENOENT" || err.code === "ENOTDIR")) {
@@ -17356,7 +17736,7 @@ async function isGitdirPointerFile(absolutePath) {
17356
17736
  }
17357
17737
  async function readDirectoryEntries2(absoluteDir) {
17358
17738
  try {
17359
- return await readdir9(absoluteDir, { withFileTypes: true });
17739
+ return await readdir10(absoluteDir, { withFileTypes: true });
17360
17740
  } catch (err) {
17361
17741
  if (isNodeError4(err) && (err.code === "ENOENT" || err.code === "ENOTDIR")) {
17362
17742
  return [];
@@ -17969,7 +18349,7 @@ async function validateLiteralReuse(input) {
17969
18349
  }
17970
18350
  async function readSafe(path7) {
17971
18351
  try {
17972
- return await readFile11(path7, "utf8");
18352
+ return await readFile12(path7, "utf8");
17973
18353
  } catch (err) {
17974
18354
  if (typeof err === "object" && err !== null && "code" in err) {
17975
18355
  const code = err.code;
@@ -19115,13 +19495,13 @@ async function persistVerificationContext(scope2, document, options = {}) {
19115
19495
  const existing = await readExistingContext(fs8, contextPath.value);
19116
19496
  if (!existing.ok) return existing;
19117
19497
  if (existing.value === document.canonicalJson) {
19118
- return { ok: true, value: { digest: document.digest, contextPath: contextPath.value } };
19498
+ return { ok: true, value: { digest: document.digest, contextPath: contextPath.value, created: false } };
19119
19499
  }
19120
19500
  return { ok: false, error: VERIFICATION_CONTEXT_RUNTIME_ERROR.CONTENT_MISMATCH };
19121
19501
  }
19122
19502
  return { ok: false, error: `${VERIFICATION_CONTEXT_RUNTIME_ERROR.WRITE_FAILED}: ${toMessage(error)}` };
19123
19503
  }
19124
- return { ok: true, value: { digest: document.digest, contextPath: contextPath.value } };
19504
+ return { ok: true, value: { digest: document.digest, contextPath: contextPath.value, created: true } };
19125
19505
  }
19126
19506
  async function readExistingContext(fs8, contextPath) {
19127
19507
  try {
@@ -19264,9 +19644,10 @@ var verificationContextDomain = {
19264
19644
  };
19265
19645
 
19266
19646
  // src/interfaces/cli/verify.ts
19267
- import { readFile as readFile12 } from "fs/promises";
19647
+ import { readFile as readFile13 } from "fs/promises";
19268
19648
 
19269
19649
  // src/commands/verify/cli.ts
19650
+ import { randomBytes as randomBytes2 } from "crypto";
19270
19651
  import { dirname as dirname12 } from "path";
19271
19652
 
19272
19653
  // src/domains/verify/verify.ts
@@ -19279,18 +19660,35 @@ var VERIFY_VERB = {
19279
19660
  START: "start",
19280
19661
  INPUT: "input",
19281
19662
  APPEND_SCOPE: "append-scope",
19282
- APPEND_FINDING: "append-finding"
19663
+ APPEND_FINDING: "append-finding",
19664
+ FINISH: "finish",
19665
+ STATUS: "status",
19666
+ RENDER: "render"
19283
19667
  };
19668
+ var VERIFY_LIFECYCLE_ACTION = {
19669
+ SCOPE_ADD: "scope add",
19670
+ FINDING_ADD: "finding add",
19671
+ FINISH: VERIFY_VERB.FINISH
19672
+ };
19673
+ var UNSEALED_NEXT_ACTIONS = [
19674
+ VERIFY_LIFECYCLE_ACTION.SCOPE_ADD,
19675
+ VERIFY_LIFECYCLE_ACTION.FINDING_ADD,
19676
+ VERIFY_LIFECYCLE_ACTION.FINISH
19677
+ ];
19284
19678
  var VERIFY_VERIFICATION_TYPE = {
19285
19679
  REVIEW: "review"
19286
19680
  };
19681
+ var VERIFY_VERIFICATION_TYPES = new Set(Object.values(VERIFY_VERIFICATION_TYPE));
19682
+ function isVerifyVerificationType(value) {
19683
+ return VERIFY_VERIFICATION_TYPES.has(value);
19684
+ }
19287
19685
  var REVIEW_FINDING_DISPOSITION = {
19288
19686
  BLOCKING: "BLOCKING",
19289
19687
  DEBT: "DEBT"
19290
19688
  };
19291
19689
  var VERIFY_APPEND_EVENT_TYPE = {
19292
- SCOPE: "io.spx.verify.scope",
19293
- FINDING: "io.spx.verify.finding"
19690
+ SCOPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.scope`,
19691
+ FINDING: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.finding`
19294
19692
  };
19295
19693
  var VERIFY_EVENT_SOURCE = "/spx/verify";
19296
19694
  var VERIFY_APPEND_EVENT_FIELD = {
@@ -19308,7 +19706,9 @@ var VERIFY_SCOPE_ERROR = {
19308
19706
  var VERIFY_INPUT_DIGEST_PATH = "verify run input";
19309
19707
  function parseChangesetScope(scope2) {
19310
19708
  const separatorIndex = scope2.indexOf(VERIFY_SCOPE_SEPARATOR);
19311
- if (separatorIndex < 0) return { ok: false, error: VERIFY_SCOPE_ERROR.MALFORMED_CHANGESET };
19709
+ if (separatorIndex < 0) {
19710
+ return { ok: false, error: VERIFY_SCOPE_ERROR.MALFORMED_CHANGESET };
19711
+ }
19312
19712
  const base = scope2.slice(0, separatorIndex);
19313
19713
  const head = scope2.slice(separatorIndex + VERIFY_SCOPE_SEPARATOR.length);
19314
19714
  if (base.length === 0 || head.length === 0 || head.includes(VERIFY_SCOPE_SEPARATOR)) {
@@ -19328,7 +19728,10 @@ function buildRunLocator(parts) {
19328
19728
  };
19329
19729
  }
19330
19730
  function digestRunInput(source, content) {
19331
- const digest = digestDescriptorSection({ source, content }, VERIFY_INPUT_DIGEST_PATH);
19731
+ const digest = digestDescriptorSection(
19732
+ { source, content },
19733
+ VERIFY_INPUT_DIGEST_PATH
19734
+ );
19332
19735
  if (!digest.ok) return digest;
19333
19736
  return { ok: true, value: digest.value.sha256 };
19334
19737
  }
@@ -19348,7 +19751,10 @@ function verifyInputRecordPath(scope2) {
19348
19751
  if (!token.ok) return token;
19349
19752
  return {
19350
19753
  ok: true,
19351
- value: join36(runs.value, `${VERIFY_INPUT_RECORD.PREFIX}${token.value}${VERIFY_INPUT_RECORD.SUFFIX}`)
19754
+ value: join36(
19755
+ runs.value,
19756
+ `${VERIFY_INPUT_RECORD.PREFIX}${token.value}${VERIFY_INPUT_RECORD.SUFFIX}`
19757
+ )
19352
19758
  };
19353
19759
  }
19354
19760
  var VERIFY_APPEND_ATTEMPT = 1;
@@ -19397,6 +19803,58 @@ function buildAppendEvent(args) {
19397
19803
  }
19398
19804
  };
19399
19805
  }
19806
+ var VERIFY_TERMINAL_EVENT_TYPE = `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.terminal`;
19807
+ var VERIFY_TERMINAL_EVENT_FIELD = {
19808
+ TERMINAL_STATUS: "terminalStatus"
19809
+ };
19810
+ var VERIFY_TERMINAL_EVENT_ID_PREFIX = "verify-terminal-";
19811
+ function isVerifyTerminalStatus(value) {
19812
+ return isJournalRunStateStatus(value);
19813
+ }
19814
+ function buildTerminalEvent(args) {
19815
+ return {
19816
+ id: `${VERIFY_TERMINAL_EVENT_ID_PREFIX}${args.runToken}`,
19817
+ source: VERIFY_EVENT_SOURCE,
19818
+ type: VERIFY_TERMINAL_EVENT_TYPE,
19819
+ time: args.at.toISOString(),
19820
+ attempt: VERIFY_APPEND_ATTEMPT,
19821
+ data: {
19822
+ [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS]: args.terminalStatus
19823
+ }
19824
+ };
19825
+ }
19826
+ var VERIFY_NO_EVENTS_SEQUENCE = 0;
19827
+ function findTerminalEvent(events) {
19828
+ return events.find((event) => event.type === VERIFY_TERMINAL_EVENT_TYPE);
19829
+ }
19830
+ function terminalStatusOf(event) {
19831
+ if (event === void 0 || !isJsonRecord(event.data)) return void 0;
19832
+ const status = event.data[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS];
19833
+ return typeof status === "string" ? status : void 0;
19834
+ }
19835
+ function countVerifyFindings(events) {
19836
+ return events.filter(
19837
+ (event) => event.type === VERIFY_APPEND_EVENT_TYPE.FINDING
19838
+ ).length;
19839
+ }
19840
+ function lastSequenceOf(events) {
19841
+ return events.reduce(
19842
+ (max, event) => event.seq > max ? event.seq : max,
19843
+ VERIFY_NO_EVENTS_SEQUENCE
19844
+ );
19845
+ }
19846
+ function projectVerifyRun(events) {
19847
+ const terminal = findTerminalEvent(events);
19848
+ const terminalStatus = terminalStatusOf(terminal);
19849
+ const sealed = terminal !== void 0;
19850
+ return {
19851
+ sealed,
19852
+ ...terminalStatus === void 0 ? {} : { terminalStatus },
19853
+ findingCount: countVerifyFindings(events),
19854
+ lastSequence: lastSequenceOf(events),
19855
+ nextActions: sealed ? [] : UNSEALED_NEXT_ACTIONS
19856
+ };
19857
+ }
19400
19858
 
19401
19859
  // src/commands/verify/cli.ts
19402
19860
  var VERIFY_CLI_EXIT_CODE = {
@@ -19407,19 +19865,40 @@ var VERIFY_CLI_ENV = {
19407
19865
  BRANCH: SPX_VERIFY_ENV.BRANCH
19408
19866
  };
19409
19867
  var VERIFY_CLI_ERROR = {
19410
- INPUT_REQUIRED: "spx verify start requires --input <input-source>",
19411
- RUN_REQUIRED: "spx verify existing-run verbs require an explicit --run <run-token>",
19412
- RUN_NOT_FOUND: "spx verify could not locate the requested run",
19413
- CHANGED_SCOPE_FAILED: "spx verify could not derive the changeset changed-file scope",
19414
- INPUT_PERSIST_FAILED: "spx verify could not persist the recorded run input",
19415
- INPUT_READ_FAILED: "spx verify could not read the recorded run input",
19416
- PAYLOAD_REQUIRED: "spx verify append verbs require --payload <payload-source>",
19417
- IDEMPOTENCY_KEY_REQUIRED: "spx verify append verbs require --idempotency-key <key>",
19418
- PAYLOAD_READ_FAILED: "spx verify could not read the append payload",
19419
- PAYLOAD_INVALID: "spx verify append payload is not valid JSON",
19420
- FINDING_INVALID: "spx verify append-finding payload failed verification-type validation",
19421
- UNSUPPORTED_VERIFICATION_TYPE: "spx verify append-finding has no finding validator for the verification type",
19422
- APPEND_FAILED: "spx verify could not append the evidence event"
19868
+ INPUT_REQUIRED: "spx verification run start requires --input <input-source>",
19869
+ RUN_REQUIRED: "spx verification run existing-run commands require an explicit --run <run-token>",
19870
+ RUN_NOT_FOUND: "spx verification run could not locate the requested run",
19871
+ RUN_SELECTOR_MISMATCH: "spx verification run selector does not match the recorded run",
19872
+ CHANGED_SCOPE_FAILED: "spx verification run could not derive the changeset changed-file scope",
19873
+ INPUT_PERSIST_FAILED: "spx verification run could not persist the recorded run input",
19874
+ INPUT_READ_FAILED: "spx verification run could not read the recorded run input",
19875
+ PAYLOAD_REQUIRED: "spx verification run evidence-add commands require --payload <payload-source>",
19876
+ IDEMPOTENCY_KEY_REQUIRED: "spx verification run evidence-add commands require --idempotency-key <key>",
19877
+ PAYLOAD_READ_FAILED: "spx verification run could not read the evidence payload",
19878
+ PAYLOAD_INVALID: "spx verification run evidence payload is not valid JSON",
19879
+ RUN_FINISHED: "spx verification run cannot add evidence to a finished run",
19880
+ FINDING_INVALID: "spx verification run finding add payload failed verification-type validation",
19881
+ UNSUPPORTED_VERIFICATION_TYPE: "spx verification run verification type is not registered",
19882
+ APPEND_FAILED: "spx verification run could not append the evidence event",
19883
+ TERMINAL_STATUS_REQUIRED: "spx verification run finish requires --terminal-status <status>",
19884
+ TERMINAL_STATUS_INVALID: "spx verification run finish requires a terminal status in the journal terminal-status vocabulary",
19885
+ FINISH_FAILED: "spx verification run could not record terminal completion",
19886
+ SEAL_FAILED: "spx verification run could not seal the run journal",
19887
+ STATUS_FAILED: "spx verification run could not read the run status",
19888
+ RENDER_FAILED: "spx verification run could not render the run projection"
19889
+ };
19890
+ var VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD = {
19891
+ RUN: "run=",
19892
+ VERIFICATION_TYPE: "verification-type=",
19893
+ SCOPE_TYPE: "scope-type=",
19894
+ SCOPE: "scope=",
19895
+ BACKEND: "backend=",
19896
+ NAMESPACE: "namespace=",
19897
+ TARGET: "target="
19898
+ };
19899
+ var VERIFY_START_ROLLBACK_ARTIFACT = {
19900
+ CONTEXT_FILE: "verification context file",
19901
+ RUN_FILE: "journal run file"
19423
19902
  };
19424
19903
  function okResult3(output) {
19425
19904
  return { exitCode: VERIFY_CLI_EXIT_CODE.OK, output };
@@ -19478,73 +19957,131 @@ async function persistInputRecord(runScope2, record6, deps) {
19478
19957
  const fs8 = deps.fs ?? defaultFileSystem;
19479
19958
  try {
19480
19959
  await fs8.mkdir(dirname12(path7.value), { recursive: true });
19481
- await fs8.writeFile(path7.value, JSON.stringify(record6));
19960
+ await writeFileAtomic(path7.value, JSON.stringify(record6), { fs: fs8, randomBytes: randomBytes2 });
19482
19961
  return { ok: true, value: void 0 };
19483
19962
  } catch (error) {
19484
19963
  return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_PERSIST_FAILED}: ${toMessage2(error)}` };
19485
19964
  }
19486
19965
  }
19966
+ async function readStartInputContent(source, deps) {
19967
+ try {
19968
+ return { ok: true, value: await deps.readInputSource(source) };
19969
+ } catch (error) {
19970
+ return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
19971
+ }
19972
+ }
19973
+ async function removeStartedRunArtifact(path7, label, deps) {
19974
+ const fs8 = deps.fs ?? defaultFileSystem;
19975
+ try {
19976
+ await fs8.rm(path7, { force: true });
19977
+ return { ok: true, value: void 0 };
19978
+ } catch (error) {
19979
+ return {
19980
+ ok: false,
19981
+ error: `${VERIFY_CLI_ERROR.INPUT_PERSIST_FAILED}: rollback failed for ${label}: ${toMessage2(error)}`
19982
+ };
19983
+ }
19984
+ }
19985
+ async function removeStartedRunArtifacts(artifacts, deps) {
19986
+ const rollbackErrors = [];
19987
+ if (artifacts.contextPath !== void 0) {
19988
+ const contextRollback = await removeStartedRunArtifact(
19989
+ artifacts.contextPath,
19990
+ VERIFY_START_ROLLBACK_ARTIFACT.CONTEXT_FILE,
19991
+ deps
19992
+ );
19993
+ if (!contextRollback.ok) rollbackErrors.push(contextRollback.error);
19994
+ }
19995
+ if (artifacts.runFile !== void 0) {
19996
+ const runRollback = await removeStartedRunArtifact(
19997
+ artifacts.runFile,
19998
+ VERIFY_START_ROLLBACK_ARTIFACT.RUN_FILE,
19999
+ deps
20000
+ );
20001
+ if (!runRollback.ok) rollbackErrors.push(runRollback.error);
20002
+ }
20003
+ if (rollbackErrors.length > 0) return { ok: false, error: rollbackErrors.join("; ") };
20004
+ return { ok: true, value: void 0 };
20005
+ }
20006
+ function isStoredRecordedInput(value) {
20007
+ if (typeof value !== "object" || value === null) return false;
20008
+ const record6 = value;
20009
+ return typeof record6.scopeIdentity === "string" && typeof record6.scopeType === "string" && typeof record6.source === "string" && typeof record6.digest === "string" && typeof record6.content === "string";
20010
+ }
20011
+ function parseRecordedInput(content) {
20012
+ try {
20013
+ const parsed = JSON.parse(content);
20014
+ if (!isStoredRecordedInput(parsed)) {
20015
+ return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: recorded input is missing required fields` };
20016
+ }
20017
+ return { ok: true, value: parsed };
20018
+ } catch (error) {
20019
+ return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
20020
+ }
20021
+ }
19487
20022
  async function readInputRecordAt(path7, deps) {
19488
20023
  const fs8 = deps.fs ?? defaultFileSystem;
20024
+ let content;
19489
20025
  try {
19490
- const content = await fs8.readFile(path7, STATE_STORE_TEXT_ENCODING);
19491
- return { ok: true, value: JSON.parse(content) };
20026
+ content = await fs8.readFile(path7, STATE_STORE_TEXT_ENCODING);
19492
20027
  } catch (error) {
19493
20028
  if (hasErrorCode(error, ERROR_CODE_NOT_FOUND)) return { ok: true, value: void 0 };
19494
20029
  return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
19495
20030
  }
20031
+ const parsed = parseRecordedInput(content);
20032
+ if (!parsed.ok) return parsed;
20033
+ return { ok: true, value: parsed.value };
19496
20034
  }
19497
- function verifyRunNotFoundDiagnostic(context) {
20035
+ function verifyRunLocatorDiagnostic(summary, context) {
19498
20036
  return [
19499
- VERIFY_CLI_ERROR.RUN_NOT_FOUND,
19500
- `run=${context.runToken}`,
19501
- `verification-type=${context.verificationType}`,
19502
- `scope-type=${context.scopeType}`,
19503
- `scope=${context.scopeIdentity}`,
19504
- `backend=${context.backendIdentity}`,
19505
- `namespace=${context.storageNamespace}`,
19506
- `target=${context.searchedTarget}`
20037
+ summary,
20038
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.RUN}${context.runToken}`,
20039
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.VERIFICATION_TYPE}${context.verificationType}`,
20040
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.SCOPE_TYPE}${context.scopeType}`,
20041
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.SCOPE}${context.scopeIdentity}`,
20042
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.BACKEND}${context.backendIdentity}`,
20043
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.NAMESPACE}${context.storageNamespace}`,
20044
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.TARGET}${context.searchedTarget}`
19507
20045
  ].join(" ");
19508
20046
  }
19509
- async function verifyStartCommand(options, deps) {
19510
- if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) return errorResult3(VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE);
19511
- if (options.input.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.INPUT_REQUIRED);
19512
- const scope2 = parseChangesetScope(options.scope);
19513
- if (!scope2.ok) return errorResult3(scope2.error);
19514
- const resolved = await resolveVerifyScope(deps);
19515
- if (!resolved.ok) return errorResult3(resolved.error);
19516
- const inputContent = await deps.readInputSource(options.input);
19517
- const inputDigest = digestRunInput(options.input, inputContent);
19518
- if (!inputDigest.ok) return errorResult3(inputDigest.error);
19519
- const context = await verificationContextCreateCommand(
19520
- {
19521
- subject: VERIFICATION_CONTEXT_SUBJECT_KIND.CHANGESET,
19522
- base: scope2.value.base,
19523
- head: scope2.value.head,
19524
- predicate: options.verificationType,
19525
- workflow: options.verificationType
19526
- },
19527
- forwardDeps(deps)
19528
- );
19529
- if (context.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(context.output);
19530
- const contextDigest = JSON.parse(context.output).digest;
20047
+ function verifyRunNotFoundDiagnostic(context) {
20048
+ return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_NOT_FOUND, context);
20049
+ }
20050
+ async function completeVerifyStartCommand(args) {
20051
+ const { options, deps } = args;
19531
20052
  const opened = await journalOpenCommand(
19532
- { type: options.verificationType, branchSlug: resolved.value.branchSlug },
20053
+ { type: options.verificationType, branchSlug: args.branchSlug },
19533
20054
  forwardDeps(deps)
19534
20055
  );
19535
- if (opened.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(opened.output);
20056
+ if (opened.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
20057
+ const rollback = await removeStartedRunArtifacts(
20058
+ { ...args.contextCreated ? { contextPath: args.contextPath } : {} },
20059
+ deps
20060
+ );
20061
+ return errorResult3(rollback.ok ? opened.output : `${opened.output}; ${rollback.error}`);
20062
+ }
19536
20063
  const { runToken, runFile } = JSON.parse(opened.output);
19537
20064
  const runScope2 = {
19538
- productDir: resolved.value.productDir,
19539
- branchSlug: resolved.value.branchSlug,
20065
+ productDir: args.productDir,
20066
+ branchSlug: args.branchSlug,
19540
20067
  type: options.verificationType,
19541
20068
  runToken
19542
20069
  };
19543
- const recorded = { source: options.input, digest: inputDigest.value, content: inputContent };
20070
+ const recorded = {
20071
+ scopeIdentity: options.scope,
20072
+ scopeType: options.scopeType,
20073
+ source: options.input,
20074
+ digest: args.inputDigest,
20075
+ content: args.inputContent
20076
+ };
19544
20077
  const persisted = await persistInputRecord(runScope2, recorded, deps);
19545
- if (!persisted.ok) return errorResult3(persisted.error);
19546
- const changedScope = await resolveChangedScope(scope2.value, deps);
19547
- if (!changedScope.ok) return errorResult3(changedScope.error);
20078
+ if (!persisted.ok) {
20079
+ const rollback = await removeStartedRunArtifacts(
20080
+ { ...args.contextCreated ? { contextPath: args.contextPath } : {}, runFile },
20081
+ deps
20082
+ );
20083
+ return errorResult3(rollback.ok ? persisted.error : `${persisted.error}; ${rollback.error}`);
20084
+ }
19548
20085
  const namespace = verifyRunsDir(runScope2);
19549
20086
  if (!namespace.ok) return errorResult3(namespace.error);
19550
20087
  const locator = buildRunLocator({
@@ -19552,52 +20089,69 @@ async function verifyStartCommand(options, deps) {
19552
20089
  verificationType: options.verificationType,
19553
20090
  scopeType: options.scopeType,
19554
20091
  scopeIdentity: options.scope,
19555
- backendIdentity: resolved.value.backendIdentity,
20092
+ backendIdentity: args.backendIdentity,
19556
20093
  storageNamespace: namespace.value,
19557
20094
  runTarget: runFile
19558
20095
  });
19559
20096
  const report2 = {
19560
20097
  runToken,
19561
- contextDigest,
19562
- changedScope: changedScope.value,
19563
- input: { source: options.input, digest: inputDigest.value },
20098
+ contextDigest: args.contextDigest,
20099
+ changedScope: args.changedScope,
20100
+ input: { source: options.input, digest: args.inputDigest },
19564
20101
  locator
19565
20102
  };
19566
20103
  return okResult3(JSON.stringify(report2));
19567
20104
  }
19568
- async function verifyInputCommand(options, deps) {
19569
- if (options.run.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.RUN_REQUIRED);
20105
+ async function verifyStartCommand(options, deps) {
20106
+ if (!isVerifyVerificationType(options.verificationType)) {
20107
+ return errorResult3(VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE);
20108
+ }
20109
+ if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) return errorResult3(VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE);
20110
+ if (options.input.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.INPUT_REQUIRED);
20111
+ const scope2 = parseChangesetScope(options.scope);
20112
+ if (!scope2.ok) return errorResult3(scope2.error);
19570
20113
  const resolved = await resolveVerifyScope(deps);
19571
20114
  if (!resolved.ok) return errorResult3(resolved.error);
19572
- const runScope2 = {
20115
+ const inputContent = await readStartInputContent(options.input, deps);
20116
+ if (!inputContent.ok) return errorResult3(inputContent.error);
20117
+ const inputDigest = digestRunInput(options.input, inputContent.value);
20118
+ if (!inputDigest.ok) return errorResult3(inputDigest.error);
20119
+ const changedScope = await resolveChangedScope(scope2.value, deps);
20120
+ if (!changedScope.ok) return errorResult3(changedScope.error);
20121
+ const context = await verificationContextCreateCommand(
20122
+ {
20123
+ subject: VERIFICATION_CONTEXT_SUBJECT_KIND.CHANGESET,
20124
+ base: scope2.value.base,
20125
+ head: scope2.value.head,
20126
+ predicate: options.verificationType,
20127
+ workflow: options.verificationType
20128
+ },
20129
+ forwardDeps(deps)
20130
+ );
20131
+ if (context.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(context.output);
20132
+ const { digest: contextDigest, contextPath, created: contextCreated } = JSON.parse(context.output);
20133
+ return completeVerifyStartCommand({
20134
+ options,
20135
+ deps,
19573
20136
  productDir: resolved.value.productDir,
19574
20137
  branchSlug: resolved.value.branchSlug,
19575
- type: options.verificationType,
19576
- runToken: options.run
19577
- };
19578
- const path7 = verifyInputRecordPath(runScope2);
19579
- if (!path7.ok) return errorResult3(path7.error);
19580
- const namespace = verifyRunsDir(runScope2);
19581
- if (!namespace.ok) return errorResult3(namespace.error);
19582
- const record6 = await readInputRecordAt(path7.value, deps);
19583
- if (!record6.ok) return errorResult3(record6.error);
19584
- if (record6.value === void 0) {
19585
- return errorResult3(
19586
- verifyRunNotFoundDiagnostic({
19587
- runToken: options.run,
19588
- verificationType: options.verificationType,
19589
- scopeType: options.scopeType,
19590
- scopeIdentity: options.scope,
19591
- backendIdentity: resolved.value.backendIdentity,
19592
- storageNamespace: namespace.value,
19593
- searchedTarget: path7.value
19594
- })
19595
- );
19596
- }
20138
+ backendIdentity: resolved.value.backendIdentity,
20139
+ changedScope: changedScope.value,
20140
+ inputDigest: inputDigest.value,
20141
+ inputContent: inputContent.value,
20142
+ contextDigest,
20143
+ contextPath,
20144
+ contextCreated
20145
+ });
20146
+ }
20147
+ async function verifyInputCommand(options, deps) {
20148
+ const run = await resolveExistingRun(options, deps);
20149
+ if (!run.ok) return errorResult3(run.error);
20150
+ const record6 = run.value.recordedInput;
19597
20151
  const report2 = {
19598
- source: record6.value.source,
19599
- digest: record6.value.digest,
19600
- content: record6.value.content
20152
+ source: record6.source,
20153
+ digest: record6.digest,
20154
+ content: record6.content
19601
20155
  };
19602
20156
  return okResult3(JSON.stringify(report2));
19603
20157
  }
@@ -19606,12 +20160,36 @@ async function readRunJournalEvents(scope2, deps) {
19606
20160
  if (read.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return { ok: false, error: read.output };
19607
20161
  return { ok: true, value: JSON.parse(read.output) };
19608
20162
  }
20163
+ async function readAppendExistingEvents(options, deps, journalScope, backendIdentity, namespace) {
20164
+ const existingEvents = await readRunJournalEvents(journalScope, deps);
20165
+ if (!existingEvents.ok) {
20166
+ if (existingEvents.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
20167
+ return {
20168
+ ok: false,
20169
+ error: appendRunNotFoundDiagnostic(options, backendIdentity, namespace)
20170
+ };
20171
+ }
20172
+ return { ok: false, error: `${VERIFY_CLI_ERROR.APPEND_FAILED}: ${existingEvents.error}` };
20173
+ }
20174
+ if (findTerminalEvent(existingEvents.value) !== void 0) {
20175
+ return { ok: false, error: VERIFY_CLI_ERROR.RUN_FINISHED };
20176
+ }
20177
+ return existingEvents;
20178
+ }
19609
20179
  async function prepareAppend(options, deps) {
19610
20180
  if (options.run.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.RUN_REQUIRED };
20181
+ if (!isVerifyVerificationType(options.verificationType)) {
20182
+ return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
20183
+ }
19611
20184
  if (options.payload.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.PAYLOAD_REQUIRED };
19612
20185
  if (options.idempotencyKey.trim().length === 0) {
19613
20186
  return { ok: false, error: VERIFY_CLI_ERROR.IDEMPOTENCY_KEY_REQUIRED };
19614
20187
  }
20188
+ if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) {
20189
+ return { ok: false, error: VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE };
20190
+ }
20191
+ const scope2 = parseChangesetScope(options.scope);
20192
+ if (!scope2.ok) return scope2;
19615
20193
  const readPayload = deps.readPayloadSource;
19616
20194
  const binding = deps.journalBinding;
19617
20195
  if (readPayload === void 0 || binding === void 0) return { ok: false, error: VERIFY_CLI_ERROR.APPEND_FAILED };
@@ -19625,25 +20203,53 @@ async function prepareAppend(options, deps) {
19625
20203
  };
19626
20204
  const namespace = verifyRunsDir(runScope2);
19627
20205
  if (!namespace.ok) return namespace;
20206
+ const journalScope = {
20207
+ type: options.verificationType,
20208
+ runToken: options.run,
20209
+ branchSlug: resolved.value.branchSlug
20210
+ };
20211
+ const existingEvents = await readAppendExistingEvents(
20212
+ options,
20213
+ deps,
20214
+ journalScope,
20215
+ resolved.value.backendIdentity,
20216
+ namespace.value
20217
+ );
20218
+ if (!existingEvents.ok) return existingEvents;
19628
20219
  const inputPath = verifyInputRecordPath(runScope2);
19629
20220
  if (!inputPath.ok) return inputPath;
19630
20221
  const inputRecord = await readInputRecordAt(inputPath.value, deps);
19631
20222
  if (!inputRecord.ok) return inputRecord;
19632
20223
  if (inputRecord.value === void 0) {
19633
- return { ok: false, error: appendRunNotFoundDiagnostic(options, resolved.value.backendIdentity, namespace.value) };
20224
+ return {
20225
+ ok: false,
20226
+ error: appendRunNotFoundDiagnostic(options, resolved.value.backendIdentity, namespace.value, inputPath.value)
20227
+ };
20228
+ }
20229
+ if (!recordedSelectorMatches(inputRecord.value, options)) {
20230
+ return {
20231
+ ok: false,
20232
+ error: appendRunSelectorMismatchDiagnostic(
20233
+ options,
20234
+ resolved.value.backendIdentity,
20235
+ namespace.value,
20236
+ inputPath.value
20237
+ )
20238
+ };
19634
20239
  }
19635
20240
  return {
19636
20241
  ok: true,
19637
20242
  value: {
19638
20243
  readPayload,
19639
20244
  binding,
19640
- journalScope: { type: options.verificationType, runToken: options.run, branchSlug: resolved.value.branchSlug },
20245
+ journalScope,
19641
20246
  namespace: namespace.value,
19642
- backendIdentity: resolved.value.backendIdentity
20247
+ backendIdentity: resolved.value.backendIdentity,
20248
+ existingEvents: existingEvents.value
19643
20249
  }
19644
20250
  };
19645
20251
  }
19646
- function appendRunNotFoundDiagnostic(options, backendIdentity, namespace) {
20252
+ function appendRunNotFoundDiagnostic(options, backendIdentity, namespace, searchedTarget = namespace) {
19647
20253
  return verifyRunNotFoundDiagnostic({
19648
20254
  runToken: options.run,
19649
20255
  verificationType: options.verificationType,
@@ -19651,7 +20257,18 @@ function appendRunNotFoundDiagnostic(options, backendIdentity, namespace) {
19651
20257
  scopeIdentity: options.scope,
19652
20258
  backendIdentity,
19653
20259
  storageNamespace: namespace,
19654
- searchedTarget: namespace
20260
+ searchedTarget
20261
+ });
20262
+ }
20263
+ function appendRunSelectorMismatchDiagnostic(options, backendIdentity, namespace, searchedTarget) {
20264
+ return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_SELECTOR_MISMATCH, {
20265
+ runToken: options.run,
20266
+ verificationType: options.verificationType,
20267
+ scopeType: options.scopeType,
20268
+ scopeIdentity: options.scope,
20269
+ backendIdentity,
20270
+ storageNamespace: namespace,
20271
+ searchedTarget
19655
20272
  });
19656
20273
  }
19657
20274
  function validateAppendFinding(verb, verificationType, payload) {
@@ -19667,16 +20284,9 @@ function appendEventType(verb) {
19667
20284
  async function verifyAppend(options, deps, verb) {
19668
20285
  const prepared = await prepareAppend(options, deps);
19669
20286
  if (!prepared.ok) return errorResult3(prepared.error);
19670
- const { readPayload, binding, journalScope, namespace, backendIdentity } = prepared.value;
20287
+ const { readPayload, binding, journalScope, existingEvents } = prepared.value;
19671
20288
  const eventType = appendEventType(verb);
19672
- const before = await readRunJournalEvents(journalScope, deps);
19673
- if (!before.ok) {
19674
- if (before.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
19675
- return errorResult3(appendRunNotFoundDiagnostic(options, backendIdentity, namespace));
19676
- }
19677
- return errorResult3(`${VERIFY_CLI_ERROR.APPEND_FAILED}: ${before.error}`);
19678
- }
19679
- const existing = findAppendedSequence(before.value, options.idempotencyKey, eventType);
20289
+ const existing = findAppendedSequence(existingEvents, options.idempotencyKey, eventType);
19680
20290
  if (existing !== void 0) {
19681
20291
  const report3 = { sequence: existing, idempotent: true };
19682
20292
  return okResult3(JSON.stringify(report3));
@@ -19714,24 +20324,270 @@ async function verifyAppendScopeCommand(options, deps) {
19714
20324
  async function verifyAppendFindingCommand(options, deps) {
19715
20325
  return verifyAppend(options, deps, VERIFY_VERB.APPEND_FINDING);
19716
20326
  }
20327
+ function existingRunNotFound(run, options) {
20328
+ return verifyRunNotFoundDiagnostic({
20329
+ runToken: run.runToken,
20330
+ verificationType: options.verificationType,
20331
+ scopeType: options.scopeType,
20332
+ scopeIdentity: options.scope,
20333
+ backendIdentity: run.backendIdentity,
20334
+ storageNamespace: run.namespace,
20335
+ searchedTarget: run.inputRecordPath
20336
+ });
20337
+ }
20338
+ function existingRunSelectorMismatch(run, options) {
20339
+ return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_SELECTOR_MISMATCH, {
20340
+ runToken: run.runToken,
20341
+ verificationType: options.verificationType,
20342
+ scopeType: options.scopeType,
20343
+ scopeIdentity: options.scope,
20344
+ backendIdentity: run.backendIdentity,
20345
+ storageNamespace: run.namespace,
20346
+ searchedTarget: run.inputRecordPath
20347
+ });
20348
+ }
20349
+ function recordedSelectorMatches(record6, options) {
20350
+ return record6.scopeType === options.scopeType && record6.scopeIdentity === options.scope;
20351
+ }
20352
+ async function readExistingRecordedInput(run, deps) {
20353
+ return readInputRecordAt(run.inputRecordPath, deps);
20354
+ }
20355
+ async function resolveExistingRunAddress(options, deps) {
20356
+ if (!isVerifyVerificationType(options.verificationType)) {
20357
+ return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
20358
+ }
20359
+ if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) {
20360
+ return { ok: false, error: VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE };
20361
+ }
20362
+ const scope2 = parseChangesetScope(options.scope);
20363
+ if (!scope2.ok) return scope2;
20364
+ if (options.run.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.RUN_REQUIRED };
20365
+ const resolved = await resolveVerifyScope(deps);
20366
+ if (!resolved.ok) return resolved;
20367
+ const runScope2 = {
20368
+ productDir: resolved.value.productDir,
20369
+ branchSlug: resolved.value.branchSlug,
20370
+ type: options.verificationType,
20371
+ runToken: options.run
20372
+ };
20373
+ const namespace = verifyRunsDir(runScope2);
20374
+ if (!namespace.ok) return namespace;
20375
+ const inputPath = verifyInputRecordPath(runScope2);
20376
+ if (!inputPath.ok) return inputPath;
20377
+ return {
20378
+ ok: true,
20379
+ value: {
20380
+ productDir: resolved.value.productDir,
20381
+ runToken: options.run,
20382
+ journalScope: { type: options.verificationType, runToken: options.run, branchSlug: resolved.value.branchSlug },
20383
+ namespace: namespace.value,
20384
+ backendIdentity: resolved.value.backendIdentity,
20385
+ inputRecordPath: inputPath.value
20386
+ }
20387
+ };
20388
+ }
20389
+ async function resolveExistingRun(options, deps) {
20390
+ const address = await resolveExistingRunAddress(options, deps);
20391
+ if (!address.ok) return address;
20392
+ const inputRecord = await readExistingRecordedInput(address.value, deps);
20393
+ if (!inputRecord.ok) return inputRecord;
20394
+ if (inputRecord.value === void 0) {
20395
+ return { ok: false, error: existingRunNotFound(address.value, options) };
20396
+ }
20397
+ if (!recordedSelectorMatches(inputRecord.value, options)) {
20398
+ return { ok: false, error: existingRunSelectorMismatch(address.value, options) };
20399
+ }
20400
+ const run = { ...address.value, recordedInput: inputRecord.value };
20401
+ return { ok: true, value: run };
20402
+ }
20403
+ function isRecordedInputReadFailure(error) {
20404
+ return error.startsWith(VERIFY_CLI_ERROR.INPUT_READ_FAILED);
20405
+ }
20406
+ async function readRecordedInputForProjection(run, options, events, deps) {
20407
+ const terminal = findTerminalEvent(events);
20408
+ const inputRecord = await readExistingRecordedInput(run, deps);
20409
+ if (!inputRecord.ok) {
20410
+ if (terminal !== void 0 && isRecordedInputReadFailure(inputRecord.error)) {
20411
+ return { ok: true, value: void 0 };
20412
+ }
20413
+ return inputRecord;
20414
+ }
20415
+ if (inputRecord.value === void 0) return { ok: true, value: void 0 };
20416
+ if (!recordedSelectorMatches(inputRecord.value, options)) {
20417
+ return { ok: false, error: existingRunSelectorMismatch(run, options) };
20418
+ }
20419
+ return { ok: true, value: inputRecord.value };
20420
+ }
20421
+ function verifyFinishReport(runToken, projection) {
20422
+ return {
20423
+ runToken,
20424
+ ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
20425
+ sealed: projection.sealed,
20426
+ findingCount: projection.findingCount,
20427
+ lastSequence: projection.lastSequence
20428
+ };
20429
+ }
20430
+ async function isJournalPhysicallySealed(run, deps) {
20431
+ return isJournalRunSealed(
20432
+ { ...run.journalScope, productDir: run.productDir },
20433
+ { ...deps.fs === void 0 ? {} : { fs: deps.fs } }
20434
+ );
20435
+ }
20436
+ async function sealExistingRun(run, deps) {
20437
+ const sealed = await journalSealCommand(run.journalScope, forwardDeps(deps));
20438
+ if (sealed.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
20439
+ return errorResult3(`${VERIFY_CLI_ERROR.SEAL_FAILED}: ${sealed.output}`);
20440
+ }
20441
+ return void 0;
20442
+ }
20443
+ function finishReadFailure(run, options, error) {
20444
+ if (error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
20445
+ return errorResult3(existingRunNotFound(run, options));
20446
+ }
20447
+ return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${error}`);
20448
+ }
20449
+ async function finishProjectionResult(run, deps) {
20450
+ const events = await readRunJournalEvents(run.journalScope, deps);
20451
+ if (!events.ok) return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${events.error}`);
20452
+ return okResult3(JSON.stringify(verifyFinishReport(run.runToken, projectVerifyRun(events.value))));
20453
+ }
20454
+ async function retrySealForTerminalRun(run, deps) {
20455
+ const physicallySealed = await isJournalPhysicallySealed(run, deps);
20456
+ if (!physicallySealed.ok) return void 0;
20457
+ if (physicallySealed.value) return void 0;
20458
+ return sealExistingRun(run, deps);
20459
+ }
20460
+ async function verifyFinishCommand(options, deps) {
20461
+ if (options.terminalStatus.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.TERMINAL_STATUS_REQUIRED);
20462
+ if (!isVerifyTerminalStatus(options.terminalStatus)) return errorResult3(VERIFY_CLI_ERROR.TERMINAL_STATUS_INVALID);
20463
+ const run = await resolveExistingRunAddress(options, deps);
20464
+ if (!run.ok) return errorResult3(run.error);
20465
+ const before = await readRunJournalEvents(run.value.journalScope, deps);
20466
+ if (!before.ok) {
20467
+ return finishReadFailure(run.value, options, before.error);
20468
+ }
20469
+ const inputRecord = await readRecordedInputForProjection(run.value, options, before.value, deps);
20470
+ if (!inputRecord.ok) return errorResult3(inputRecord.error);
20471
+ if (findTerminalEvent(before.value) !== void 0) {
20472
+ const retrySeal = await retrySealForTerminalRun(run.value, deps);
20473
+ return retrySeal ?? finishProjectionResult(run.value, deps);
20474
+ }
20475
+ if (inputRecord.value === void 0) {
20476
+ return errorResult3(existingRunNotFound(run.value, options));
20477
+ }
20478
+ const binding = deps.journalBinding;
20479
+ if (binding === void 0) return errorResult3(VERIFY_CLI_ERROR.FINISH_FAILED);
20480
+ const event = buildTerminalEvent({
20481
+ runToken: run.value.runToken,
20482
+ terminalStatus: options.terminalStatus,
20483
+ at: deps.now?.() ?? /* @__PURE__ */ new Date()
20484
+ });
20485
+ const appended = await journalAppendCommand(run.value.journalScope, event, binding, forwardDeps(deps));
20486
+ if (appended.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
20487
+ return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${appended.output}`);
20488
+ }
20489
+ const sealResult = await sealExistingRun(run.value, deps);
20490
+ if (sealResult !== void 0) return sealResult;
20491
+ return finishProjectionResult(run.value, deps);
20492
+ }
20493
+ async function verifyStatusCommand(options, deps) {
20494
+ const run = await resolveExistingRunAddress(options, deps);
20495
+ if (!run.ok) return errorResult3(run.error);
20496
+ const events = await readRunJournalEvents(run.value.journalScope, deps);
20497
+ if (!events.ok) {
20498
+ if (events.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
20499
+ return errorResult3(existingRunNotFound(run.value, options));
20500
+ }
20501
+ return errorResult3(`${VERIFY_CLI_ERROR.STATUS_FAILED}: ${events.error}`);
20502
+ }
20503
+ const inputRecord = await readRecordedInputForProjection(run.value, options, events.value, deps);
20504
+ if (!inputRecord.ok) return errorResult3(inputRecord.error);
20505
+ if (inputRecord.value === void 0 && findTerminalEvent(events.value) === void 0) {
20506
+ return errorResult3(existingRunNotFound(run.value, options));
20507
+ }
20508
+ const projection = projectVerifyRun(events.value);
20509
+ const report2 = {
20510
+ runToken: run.value.runToken,
20511
+ verificationType: options.verificationType,
20512
+ scopeType: options.scopeType,
20513
+ sealed: projection.sealed,
20514
+ lastSequence: projection.lastSequence,
20515
+ ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
20516
+ findingCount: projection.findingCount,
20517
+ nextActions: projection.nextActions
20518
+ };
20519
+ return okResult3(JSON.stringify(report2));
20520
+ }
20521
+ async function verifyRenderCommand(options, deps) {
20522
+ const run = await resolveExistingRunAddress(options, deps);
20523
+ if (!run.ok) return errorResult3(run.error);
20524
+ const events = await readRunJournalEvents(run.value.journalScope, deps);
20525
+ if (!events.ok) {
20526
+ if (events.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
20527
+ return errorResult3(existingRunNotFound(run.value, options));
20528
+ }
20529
+ return errorResult3(`${VERIFY_CLI_ERROR.RENDER_FAILED}: ${events.error}`);
20530
+ }
20531
+ const inputRecord = await readRecordedInputForProjection(run.value, options, events.value, deps);
20532
+ if (!inputRecord.ok) return errorResult3(inputRecord.error);
20533
+ if (inputRecord.value === void 0 && findTerminalEvent(events.value) === void 0) {
20534
+ return errorResult3(existingRunNotFound(run.value, options));
20535
+ }
20536
+ const projection = projectVerifyRun(events.value);
20537
+ const report2 = {
20538
+ runToken: run.value.runToken,
20539
+ findingCount: projection.findingCount,
20540
+ sealed: projection.sealed,
20541
+ ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
20542
+ events: events.value
20543
+ };
20544
+ return okResult3(JSON.stringify(report2));
20545
+ }
19717
20546
 
19718
20547
  // src/interfaces/cli/verify.ts
20548
+ var VERIFICATION_RUN_CLI_SURFACE = {
20549
+ addCommandName: "add",
20550
+ findingResourceCommandName: "finding",
20551
+ forbiddenRootCommandName: "verify",
20552
+ forbiddenRunHelpTerms: ["Append", "append"],
20553
+ forbiddenRunCommandNames: ["journal", "event", "append-scope", "append-finding"],
20554
+ rootCommandName: "verification",
20555
+ runCommandName: "run",
20556
+ scopeResourceCommandName: "scope"
20557
+ };
19719
20558
  var VERIFY_CLI = {
19720
- commandName: "verify",
20559
+ addCommandName: VERIFICATION_RUN_CLI_SURFACE.addCommandName,
20560
+ commandName: VERIFICATION_RUN_CLI_SURFACE.rootCommandName,
19721
20561
  description: "Record and replay a typed verification run",
19722
20562
  startCommandName: VERIFY_VERB.START,
19723
20563
  inputCommandName: VERIFY_VERB.INPUT,
19724
- appendScopeCommandName: VERIFY_VERB.APPEND_SCOPE,
19725
- appendFindingCommandName: VERIFY_VERB.APPEND_FINDING,
20564
+ findingCommandName: VERIFICATION_RUN_CLI_SURFACE.findingResourceCommandName,
20565
+ runCommandName: VERIFICATION_RUN_CLI_SURFACE.runCommandName,
20566
+ scopeCommandName: VERIFICATION_RUN_CLI_SURFACE.scopeResourceCommandName,
20567
+ finishCommandName: VERIFY_VERB.FINISH,
20568
+ statusCommandName: VERIFY_VERB.STATUS,
20569
+ renderCommandName: VERIFY_VERB.RENDER,
19726
20570
  verificationTypeOption: "--verification-type <type>",
19727
20571
  scopeTypeOption: "--scope-type <scope-type>",
19728
20572
  scopeOption: "--scope <base>..<head>",
19729
20573
  inputOption: "--input <input-source>",
19730
20574
  runOption: "--run <token>",
19731
20575
  payloadOption: "--payload <payload-source>",
19732
- idempotencyKeyOption: "--idempotency-key <key>"
20576
+ payloadOptionDescription: "Evidence payload source; stdin or a file path",
20577
+ idempotencyKeyOption: "--idempotency-key <key>",
20578
+ idempotencyKeyOptionDescription: "Caller-supplied idempotency key for the evidence add",
20579
+ terminalStatusOption: "--terminal-status <status>"
19733
20580
  };
19734
20581
  var CLI_SOURCE_ENCODING = "utf8";
20582
+ var DEFAULT_VERIFY_CLI_HANDLERS = {
20583
+ appendFinding: verifyAppendFindingCommand,
20584
+ appendScope: verifyAppendScopeCommand,
20585
+ finish: verifyFinishCommand,
20586
+ input: verifyInputCommand,
20587
+ render: verifyRenderCommand,
20588
+ start: verifyStartCommand,
20589
+ status: verifyStatusCommand
20590
+ };
19735
20591
  async function readStdinText() {
19736
20592
  const chunks = [];
19737
20593
  for await (const chunk of process.stdin) {
@@ -19741,35 +20597,48 @@ async function readStdinText() {
19741
20597
  }
19742
20598
  async function readCliSource(source) {
19743
20599
  if (source === VERIFY_INPUT_SOURCE.STDIN) return readStdinText();
19744
- return readFile12(source, CLI_SOURCE_ENCODING);
20600
+ return readFile13(source, CLI_SOURCE_ENCODING);
19745
20601
  }
19746
20602
  var verifyDomain = {
19747
20603
  name: VERIFY_CLI.commandName,
19748
20604
  description: VERIFY_CLI.description,
19749
- register: (program, invocation) => {
19750
- const deps = () => ({
19751
- cwd: invocation.resolveEffectiveInvocationDir(),
19752
- readInputSource: readCliSource,
19753
- readPayloadSource: readCliSource,
19754
- // The append verbs write a single structured JSON result to stdout, so the run's event
19755
- // stream goes to stderr under the local backend rather than sharing the result channel.
19756
- journalBinding: createJournalStreamBinding(invocation.io, stderrStreamSink(invocation.io))
19757
- });
19758
- const command = program.command(VERIFY_CLI.commandName).description(VERIFY_CLI.description);
19759
- command.command(VERIFY_CLI.startCommandName).description("Start a changeset-scoped verification run and report its run locator").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.inputOption, "Verification input source; stdin or a file path").action(async (options) => {
19760
- reportCliResult(await verifyStartCommand(options, deps()), invocation.io);
19761
- });
19762
- command.command(VERIFY_CLI.inputCommandName).description("Replay the verification input recorded at start").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
19763
- reportCliResult(await verifyInputCommand(options, deps()), invocation.io);
19764
- });
19765
- command.command(VERIFY_CLI.appendScopeCommandName).description("Record the inspected scope for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, "Append payload source; stdin or a file path").requiredOption(VERIFY_CLI.idempotencyKeyOption, "Caller-supplied idempotency key for the append").action(async (options) => {
19766
- reportCliResult(await verifyAppendScopeCommand(options, deps()), invocation.io);
19767
- });
19768
- command.command(VERIFY_CLI.appendFindingCommandName).description("Record a validated verification finding for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, "Append payload source; stdin or a file path").requiredOption(VERIFY_CLI.idempotencyKeyOption, "Caller-supplied idempotency key for the append").action(async (options) => {
19769
- reportCliResult(await verifyAppendFindingCommand(options, deps()), invocation.io);
19770
- });
19771
- }
19772
- };
20605
+ register: (program, invocation) => registerVerifyCommands(program, invocation)
20606
+ };
20607
+ function registerVerifyCommands(program, invocation, handlers = DEFAULT_VERIFY_CLI_HANDLERS) {
20608
+ const deps = () => ({
20609
+ cwd: invocation.resolveEffectiveInvocationDir(),
20610
+ readInputSource: readCliSource,
20611
+ readPayloadSource: readCliSource,
20612
+ // The append verbs write a single structured JSON result to stdout, so the run's event
20613
+ // stream goes to stderr under the local backend rather than sharing the result channel.
20614
+ journalBinding: createJournalStreamBinding(invocation.io, stderrStreamSink(invocation.io))
20615
+ });
20616
+ const command = program.command(VERIFY_CLI.commandName).description(VERIFY_CLI.description);
20617
+ const runCommand = command.command(VERIFY_CLI.runCommandName).description("Manage a typed verification run lifecycle");
20618
+ runCommand.command(VERIFY_CLI.startCommandName).description("Start a changeset-scoped verification run and report its run locator").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.inputOption, "Verification input source; stdin or a file path").action(async (options) => {
20619
+ reportCliResult(await handlers.start(options, deps()), invocation.io);
20620
+ });
20621
+ runCommand.command(VERIFY_CLI.inputCommandName).description("Replay the verification input recorded at start").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
20622
+ reportCliResult(await handlers.input(options, deps()), invocation.io);
20623
+ });
20624
+ const scopeCommand = runCommand.command(VERIFY_CLI.scopeCommandName).description("Manage inspected scope evidence for a started verification run");
20625
+ scopeCommand.command(VERIFY_CLI.addCommandName).description("Record the inspected scope for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, VERIFY_CLI.payloadOptionDescription).requiredOption(VERIFY_CLI.idempotencyKeyOption, VERIFY_CLI.idempotencyKeyOptionDescription).action(async (options) => {
20626
+ reportCliResult(await handlers.appendScope(options, deps()), invocation.io);
20627
+ });
20628
+ const findingCommand = runCommand.command(VERIFY_CLI.findingCommandName).description("Manage finding evidence for a started verification run");
20629
+ findingCommand.command(VERIFY_CLI.addCommandName).description("Record a validated verification finding for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, VERIFY_CLI.payloadOptionDescription).requiredOption(VERIFY_CLI.idempotencyKeyOption, VERIFY_CLI.idempotencyKeyOptionDescription).action(async (options) => {
20630
+ reportCliResult(await handlers.appendFinding(options, deps()), invocation.io);
20631
+ });
20632
+ runCommand.command(VERIFY_CLI.finishCommandName).description("Record terminal completion, seal the run journal, and report its terminal projection").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.terminalStatusOption, "Terminal status recorded before sealing").action(async (options) => {
20633
+ reportCliResult(await handlers.finish(options, deps()), invocation.io);
20634
+ });
20635
+ runCommand.command(VERIFY_CLI.statusCommandName).description("Report the run's resumable status projected from its journal history").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
20636
+ reportCliResult(await handlers.status(options, deps()), invocation.io);
20637
+ });
20638
+ runCommand.command(VERIFY_CLI.renderCommandName).description("Render the run's journal projection with its authoritative finding count").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
20639
+ reportCliResult(await handlers.render(options, deps()), invocation.io);
20640
+ });
20641
+ }
19773
20642
 
19774
20643
  // src/interfaces/cli/worktree.ts
19775
20644
  import { randomBytes as nodeRandomBytes4 } from "crypto";
@@ -19927,11 +20796,11 @@ function renderTextStatusChild(record6) {
19927
20796
  }
19928
20797
 
19929
20798
  // src/lib/worktree-path-info.ts
19930
- import { stat as stat7 } from "fs/promises";
20799
+ import { stat as stat8 } from "fs/promises";
19931
20800
  var defaultWorktreePathInfo = {
19932
20801
  isExistingNonDirectory: async (path7) => {
19933
20802
  try {
19934
- const pathStats = await stat7(path7);
20803
+ const pathStats = await stat8(path7);
19935
20804
  return !pathStats.isDirectory();
19936
20805
  } catch {
19937
20806
  return false;