tickmarkr 2.6.2 → 2.6.4

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 (79) hide show
  1. package/README.md +12 -2
  2. package/dist/adapters/codex.d.ts +2 -1
  3. package/dist/adapters/codex.js +26 -5
  4. package/dist/adapters/model-lints.d.ts +1 -0
  5. package/dist/adapters/model-lints.js +48 -1
  6. package/dist/adapters/model-windows.d.ts +2 -1
  7. package/dist/adapters/model-windows.js +18 -7
  8. package/dist/adapters/types.d.ts +6 -0
  9. package/dist/cli/commands/approve.d.ts +6 -3
  10. package/dist/cli/commands/approve.js +43 -6
  11. package/dist/cli/commands/doctor.d.ts +8 -2
  12. package/dist/cli/commands/doctor.js +6 -1
  13. package/dist/cli/commands/fleet.js +264 -59
  14. package/dist/cli/commands/init.js +5 -3
  15. package/dist/cli/commands/plan.js +13 -8
  16. package/dist/cli/commands/report.d.ts +40 -2
  17. package/dist/cli/commands/report.js +278 -11
  18. package/dist/cli/commands/resume.js +2 -4
  19. package/dist/cli/commands/run.d.ts +11 -0
  20. package/dist/cli/commands/run.js +33 -5
  21. package/dist/cli/commands/status.js +49 -4
  22. package/dist/cli/commands/verify.js +332 -121
  23. package/dist/compile/native.js +137 -0
  24. package/dist/config/config.d.ts +40 -9
  25. package/dist/config/config.js +133 -15
  26. package/dist/config/fleet-overlay.d.ts +13 -3
  27. package/dist/config/fleet-overlay.js +12 -8
  28. package/dist/drivers/herdr.d.ts +12 -0
  29. package/dist/drivers/herdr.js +51 -0
  30. package/dist/drivers/orca.d.ts +9 -1
  31. package/dist/drivers/orca.js +29 -7
  32. package/dist/drivers/types.d.ts +2 -0
  33. package/dist/drivers/types.js +2 -2
  34. package/dist/gates/acceptance.d.ts +7 -0
  35. package/dist/gates/acceptance.js +27 -5
  36. package/dist/gates/baseline.d.ts +20 -1
  37. package/dist/gates/baseline.js +100 -20
  38. package/dist/gates/cache.d.ts +8 -0
  39. package/dist/gates/cache.js +12 -2
  40. package/dist/gates/llm.d.ts +6 -0
  41. package/dist/gates/llm.js +27 -8
  42. package/dist/gates/review.d.ts +6 -1
  43. package/dist/gates/review.js +122 -32
  44. package/dist/gates/run-gates.d.ts +54 -3
  45. package/dist/gates/run-gates.js +331 -45
  46. package/dist/gates/test-manifest.d.ts +42 -0
  47. package/dist/gates/test-manifest.js +69 -10
  48. package/dist/route/router.d.ts +23 -1
  49. package/dist/route/router.js +54 -16
  50. package/dist/run/consult.d.ts +3 -1
  51. package/dist/run/consult.js +4 -2
  52. package/dist/run/daemon.d.ts +2 -1
  53. package/dist/run/daemon.js +349 -79
  54. package/dist/run/interactive-seed.d.ts +4 -0
  55. package/dist/run/interactive-seed.js +35 -9
  56. package/dist/run/journal.d.ts +123 -1
  57. package/dist/run/journal.js +480 -17
  58. package/dist/run/lease.d.ts +13 -0
  59. package/dist/run/lease.js +45 -0
  60. package/dist/run/protocol.d.ts +15 -0
  61. package/dist/run/protocol.js +11 -1
  62. package/dist/run/receipt-resolver.d.ts +22 -0
  63. package/dist/run/receipt-resolver.js +40 -1
  64. package/dist/run/repair-selection.d.ts +11 -1
  65. package/dist/run/repair-selection.js +17 -9
  66. package/dist/run/wall-budget.d.ts +48 -0
  67. package/dist/run/wall-budget.js +280 -0
  68. package/dist/tui/cockpit/live-store.d.ts +6 -0
  69. package/dist/tui/cockpit/live-store.js +36 -11
  70. package/dist/tui/cockpit/run-cockpit.js +2 -2
  71. package/dist/tui/cockpit/run-view.d.ts +2 -1
  72. package/dist/tui/cockpit/run-view.js +13 -9
  73. package/dist/tui/cockpit/setup-cockpit.d.ts +2 -0
  74. package/dist/tui/cockpit/setup-cockpit.js +4 -0
  75. package/package.json +2 -1
  76. package/schema/config.schema.json +8 -1
  77. package/skills/tickmarkr-auto/SKILL.md +2 -2
  78. package/skills/tickmarkr-loop/SKILL.md +17 -5
  79. package/skills/tickmarkr-overseer/scripts/classify-vitest-log.sh +4 -1
@@ -12,11 +12,13 @@ import { authorsNote, doneAuthors } from "../../run/operator-state.js";
12
12
  import { projectOperatorSummary } from "../../run/operator-summary.js";
13
13
  import { trackJournalRows } from "../../run/protocol.js";
14
14
  import { newestPark, permittedDecisionVerbs } from "./approve.js";
15
+ import { currentOwed, endToEndFirstPass, firstPassText, leadLines, leadRows, needsYouText, wallText } from "./report.js";
15
16
  import { Journal, bindingToken, effectiveEvents, formatJournalNarration, parseJournalText, physicalLine, engagementComparable, isQualityFailureParkKind, parseRunId, preservedRefsByTask, recordedTaskFailureKind, runHasEnded, upheldFeedbackByTask, } from "../../run/journal.js";
16
17
  import { isPidLive, runLockRunId, runStatusLine } from "../../run/lock.js";
17
18
  import { normalizeGateOutcome } from "../../run/outcome.js";
18
19
  import { desiredPanes } from "../../run/reconcile.js";
19
20
  import { normalizeStallSnapshot } from "../../run/stall.js";
21
+ import { formatSpan, wallBudget, wallBudgetFacts } from "../../run/wall-budget.js";
20
22
  import { armWatchSupervision, observeNamedRun, WATCH_OWNER_ENV, readSupervision, supervisionText } from "../../run/supervision.js";
21
23
  import { deriveRunCockpitData, } from "../../tui/cockpit/derive.js";
22
24
  import { cellWidth, fitCells, wrapCells } from "../../tui/cockpit/width.js";
@@ -447,6 +449,8 @@ export const shortGoal = (goal, max) => {
447
449
  };
448
450
  /** Columns the machine row always spends on the task title, however long its machinery segment runs. */
449
451
  const MACHINE_TITLE_FLOOR = 24;
452
+ /** The plain print's own width when none is configured: its machine rows are laid out, and parsed whole, at it. */
453
+ const MACHINE_COLUMNS = 120;
450
454
  // The approved task board derives an area from files[] rather than adding another graph field.
451
455
  // Known tickmarkr domains keep their reviewed names; other repositories fall back to their first
452
456
  // meaningful path segment so the shipped surface never turns a foreign project into UNMAPPED rows.
@@ -1036,7 +1040,7 @@ binaryVersion, now = Date.now(), animationFrame = 0, workerLiveness = new Map(),
1036
1040
  // SUP-01: derived by stat() alone, from THIS frame's clock. status stays a reader — nothing here
1037
1041
  // creates, touches or reaps a beat file, so an absent supervision dir stays absent.
1038
1042
  const supervision = readSupervision(cwd, now);
1039
- const width = process.stdout.columns ?? 120;
1043
+ const width = process.stdout.columns ?? MACHINE_COLUMNS;
1040
1044
  const done = journalRowsOnly
1041
1045
  ? recordedDone(renderedTasks, taskRows)
1042
1046
  : effective.tasks.filter((task) => task.status === "done").length;
@@ -1054,6 +1058,16 @@ binaryVersion, now = Date.now(), animationFrame = 0, workerLiveness = new Map(),
1054
1058
  if (!taskIds.has(taskId))
1055
1059
  phases.delete(taskId);
1056
1060
  const hotPhase = [...phases.values()].sort((a, b) => a.order - b.order).at(-1);
1061
+ // CG1: the three lead lines — finished, wall, needs you from the CURRENT owed-check fold — open
1062
+ // every frame, plain and terminal; the header below keeps every comparability, supersession and verify fact.
1063
+ const lead = runId
1064
+ ? leadLines(events, currentOwed(events, cwd), {
1065
+ // The header's own rule: while the tip is unverified the tally never reads as a finished run.
1066
+ tally: comparable ? tipPhase ? `${done}/${total} tasks done` : `${done}/${total} done` : NOT_COMPARABLE_CLAIM,
1067
+ tip: verify ? `tip ${verify}` : "tip verify pending",
1068
+ notes: supersededBy ? [`superseded by ${supersededBy}`] : [],
1069
+ }).map(sanitizeTaskText)
1070
+ : [];
1057
1071
  // OBS-738: recovery facts stay on the journal's two established reducers. The prefix fold keeps an
1058
1072
  // older journal equally readable by asking upheldFeedbackByTask what was active at that exact
1059
1073
  // restore boundary; current resume-restore rows additionally carry the same task for narration.
@@ -1150,11 +1164,20 @@ binaryVersion, now = Date.now(), animationFrame = 0, workerLiveness = new Map(),
1150
1164
  ? `tickmarkr status${divider}${runLine ?? `run ${runId}`}${zone}${supersededBy ? `${divider}superseded by ${supersededBy}` : ""}${!comparable ? `${divider}${NOT_COMPARABLE_NOTICE}` : ""}${divider}${liveness(events, daemon, now).replaceAll(" · ", divider)}${verify ? `${divider}${verify}` : ""}${divider}${tipPhase ? `${done}/${total} tasks done${divider}run not verified` : `${done}/${total} done`}`
1151
1165
  : `tickmarkr status${zone}${divider}no runs yet${divider}${done}/${total} done`;
1152
1166
  const legendLine = ` gates: ${GATE_NAMES.map((gate) => `${GATE_KEYS[gate]} ${gate}`).join(divider)}`;
1167
+ // At its machine width and wider the plain print keeps each machine row whole — one row per task and
1168
+ // its evidence line after it, which consumers parse. A configured width narrower than that holds for
1169
+ // EVERY row: one that overflows wraps beneath its own indent, its identity kept on the first.
1170
+ const body = [header, legendLine, ` ${supervisionText(supervision, divider)}`, ...rows];
1171
+ const wrapRow = (line) => wrapCells(line, width, { continuationPrefix: `${/^ */u.exec(line)[0]} ` });
1153
1172
  return {
1154
- content: [header, legendLine, ` ${supervisionText(supervision, divider)}`, ...rows].join("\n"),
1173
+ content: [
1174
+ ...leadRows(lead, width),
1175
+ ...(width >= MACHINE_COLUMNS ? body : body.flatMap(wrapRow)),
1176
+ ].join("\n"),
1155
1177
  ...(hotPhase ? { hotPhase } : {}),
1156
1178
  ...(runId ? { runId } : {}),
1157
1179
  workerPhases: [...phases.values()].filter((phase) => phase.phase === "worker"),
1180
+ events,
1158
1181
  };
1159
1182
  }
1160
1183
  // TTY: the operator-approved task table. The daemon gives this surface a ~110-column pane first;
@@ -1347,6 +1370,7 @@ binaryVersion, now = Date.now(), animationFrame = 0, workerLiveness = new Map(),
1347
1370
  const effort = effortPanel(g.tasks, record && !comparable ? undefined : events, boardColumns);
1348
1371
  return {
1349
1372
  content: boardRows([
1373
+ ...leadRows(lead, boardColumns),
1350
1374
  ...headerRows,
1351
1375
  ...nowLine,
1352
1376
  supervisionLegend,
@@ -1364,8 +1388,22 @@ binaryVersion, now = Date.now(), animationFrame = 0, workerLiveness = new Map(),
1364
1388
  ...(hotPhase ? { hotPhase } : {}),
1365
1389
  ...(runId ? { runId } : {}),
1366
1390
  workerPhases: [...phases.values()].filter((phase) => phase.phase === "worker"),
1391
+ events,
1367
1392
  };
1368
1393
  };
1394
+ // OBS-1201: the one-shot print closes with where the run's wall went (src/run/wall-budget.ts). A
1395
+ // window of zero length measured nothing, so it prints nothing; watch frames are untouched. Rows wrap
1396
+ // to the board width, so narrowing costs rows, never columns.
1397
+ const wallBudgetLines = (events) => {
1398
+ const budget = wallBudget(events);
1399
+ if (!budget || budget.wallMs <= 0)
1400
+ return [];
1401
+ const columns = Math.max(40, process.stdout.columns ?? 120);
1402
+ return [
1403
+ ` wall budget ${formatSpan(budget.wallMs)} · each instant once, by priority`,
1404
+ ...wallBudgetFacts(budget).map(([label, fact]) => ` ${label} ${fact}`),
1405
+ ].flatMap((line) => wrapCells(line, columns, { continuationPrefix: " " }));
1406
+ };
1369
1407
  /**
1370
1408
  * The compact form a statusline calls, so journal interpretation happens ONCE, inside the product.
1371
1409
  * (An operator-local bash reimplementation counted `tip-verify` events instead of reading the
@@ -1388,7 +1426,12 @@ const oneLine = (cwd, namedRunId) => {
1388
1426
  `verify ${recordedVerify(record.events)}`,
1389
1427
  ]
1390
1428
  : [NOT_COMPARABLE_CLAIM, "verify unavailable"];
1391
- return sanitizeTaskText([record.runId, ...claims].join(" · "));
1429
+ // CG1: the lead's facts in one line — lineage first pass, the wall window, and what needs you from
1430
+ // the CURRENT fold, so a discharge after run-end moves this line too.
1431
+ const { events } = record;
1432
+ return sanitizeTaskText([
1433
+ record.runId, ...claims, firstPassText(endToEndFirstPass(events)), wallText(events), needsYouText(events, currentOwed(events, cwd)),
1434
+ ].join(" · "));
1392
1435
  };
1393
1436
  export async function status(argv, cwd = process.cwd(), opts = {}) {
1394
1437
  if (argv.some((arg) => arg === "--help" || arg === "-h"))
@@ -1401,7 +1444,9 @@ export async function status(argv, cwd = process.cwd(), opts = {}) {
1401
1444
  // The task-table frame owns its own two-row brand lockup; the four-row global banner would
1402
1445
  // create the second header the approved replacement removes.
1403
1446
  if (!argv.includes("--watch")) {
1404
- return renderFrame(cwd, binaryVersion, opts.now?.() ?? Date.now(), 0, undefined, false, namedRunId).content;
1447
+ const frame = renderFrame(cwd, binaryVersion, opts.now?.() ?? Date.now(), 0, undefined, false, namedRunId);
1448
+ const wall = wallBudgetLines(frame.events);
1449
+ return wall.length ? [frame.content, "", ...wall].join("\n") : frame.content;
1405
1450
  }
1406
1451
  const eventStream = argv.some((arg) => arg === "--events" || arg === "--jsonl" || arg === "--decision-events");
1407
1452
  const webhookUrl = opts.webhookUrl