tickmarkr 1.84.0 → 1.86.0

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 (87) hide show
  1. package/README.md +4 -2
  2. package/dist/adapters/catalog-remote.d.ts +64 -0
  3. package/dist/adapters/catalog-remote.js +287 -0
  4. package/dist/adapters/catalog.d.ts +96 -0
  5. package/dist/adapters/catalog.js +176 -0
  6. package/dist/adapters/claude-code.d.ts +1 -0
  7. package/dist/adapters/claude-code.js +59 -1
  8. package/dist/adapters/fake.js +42 -4
  9. package/dist/adapters/model-lints.d.ts +25 -5
  10. package/dist/adapters/model-lints.js +184 -50
  11. package/dist/adapters/model-windows.d.ts +31 -0
  12. package/dist/adapters/model-windows.js +69 -0
  13. package/dist/adapters/prompt.d.ts +5 -1
  14. package/dist/adapters/prompt.js +13 -4
  15. package/dist/adapters/registry.d.ts +25 -26
  16. package/dist/adapters/registry.js +173 -110
  17. package/dist/adapters/types.d.ts +3 -0
  18. package/dist/adapters/types.js +36 -3
  19. package/dist/brand.d.ts +5 -1
  20. package/dist/brand.js +18 -2
  21. package/dist/cli/commands/doctor.d.ts +3 -0
  22. package/dist/cli/commands/doctor.js +43 -21
  23. package/dist/cli/commands/fleet.d.ts +7 -0
  24. package/dist/cli/commands/fleet.js +94 -74
  25. package/dist/cli/commands/init.js +118 -5
  26. package/dist/cli/commands/status.js +202 -46
  27. package/dist/compile/collateral.d.ts +86 -2
  28. package/dist/compile/collateral.js +294 -3
  29. package/dist/compile/gsd.d.ts +2 -1
  30. package/dist/compile/gsd.js +68 -2
  31. package/dist/compile/native.d.ts +14 -0
  32. package/dist/compile/native.js +161 -12
  33. package/dist/config/config.d.ts +82 -5
  34. package/dist/config/config.js +253 -66
  35. package/dist/config/fleet-overlay.d.ts +25 -20
  36. package/dist/config/fleet-overlay.js +195 -77
  37. package/dist/config/fleet-why.d.ts +23 -0
  38. package/dist/config/fleet-why.js +42 -0
  39. package/dist/drivers/herdr.d.ts +21 -3
  40. package/dist/drivers/herdr.js +344 -110
  41. package/dist/gates/acceptance.js +7 -2
  42. package/dist/gates/baseline.d.ts +1 -0
  43. package/dist/gates/baseline.js +91 -13
  44. package/dist/gates/llm.d.ts +0 -1
  45. package/dist/gates/llm.js +5 -30
  46. package/dist/gates/review.d.ts +9 -1
  47. package/dist/gates/review.js +105 -10
  48. package/dist/gates/run-gates.d.ts +9 -0
  49. package/dist/gates/run-gates.js +285 -41
  50. package/dist/gates/verdict-cause.d.ts +4 -0
  51. package/dist/gates/verdict-cause.js +63 -0
  52. package/dist/graph/schema.d.ts +6 -0
  53. package/dist/graph/schema.js +8 -5
  54. package/dist/route/router.d.ts +0 -5
  55. package/dist/route/router.js +16 -20
  56. package/dist/run/consult.d.ts +6 -0
  57. package/dist/run/consult.js +35 -25
  58. package/dist/run/daemon.d.ts +48 -2
  59. package/dist/run/daemon.js +1488 -330
  60. package/dist/run/journal.d.ts +56 -3
  61. package/dist/run/journal.js +358 -4
  62. package/dist/run/stall.d.ts +35 -1
  63. package/dist/run/stall.js +118 -8
  64. package/dist/tui/cockpit/capture.d.ts +12 -0
  65. package/dist/tui/cockpit/capture.js +37 -1
  66. package/dist/tui/cockpit/components.d.ts +2 -0
  67. package/dist/tui/cockpit/components.js +8 -8
  68. package/dist/tui/cockpit/derive.d.ts +29 -2
  69. package/dist/tui/cockpit/derive.js +219 -23
  70. package/dist/tui/cockpit/run-cockpit.js +128 -27
  71. package/dist/tui/cockpit/theme.d.ts +32 -26
  72. package/dist/tui/cockpit/theme.js +11 -5
  73. package/dist/tui/ink/components.d.ts +0 -15
  74. package/dist/tui/ink/components.js +0 -17
  75. package/dist/tui/ink/fleet-app.d.ts +4 -1
  76. package/dist/tui/ink/fleet-app.js +134 -13
  77. package/fixtures/sample.native.md +1 -1
  78. package/package.json +1 -1
  79. package/skills/tickmarkr-overseer/SKILL.md +354 -34
  80. package/skills/tickmarkr-overseer/scripts/watch-artifacts.sh +70 -0
  81. package/skills/tickmarkr-overseer/scripts/watch-panes.sh +1 -1
  82. package/dist/tui/ink/studio-app.d.ts +0 -59
  83. package/dist/tui/ink/studio-app.js +0 -320
  84. package/dist/tui/save.d.ts +0 -38
  85. package/dist/tui/save.js +0 -96
  86. package/dist/tui/staging.d.ts +0 -29
  87. package/dist/tui/staging.js +0 -78
@@ -2,7 +2,8 @@ import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { getAdapter } from "../adapters/registry.js";
4
4
  import { bannerShell, paneDispatchCommand } from "../brand.js";
5
- import { augmentFakeVerdictOutput, extractVerdictJson, gateExitTrailer, gatePaneName, generateVerdictNonce, verdictNonceLine } from "../gates/llm.js";
5
+ import { extractVerdictJson, gateExitTrailer, gatePaneName, generateVerdictNonce, verdictNonceLine } from "../gates/llm.js";
6
+ import { classifyVerdictCause } from "../gates/verdict-cause.js";
6
7
  import { sh } from "./git.js";
7
8
  import { redactSecrets } from "./redact.js";
8
9
  import { filterLlmTranscript } from "./stall.js";
@@ -57,6 +58,33 @@ export function augmentRetryBrief(feedback, opts) {
57
58
  return parts.join("\n\n");
58
59
  }
59
60
  const ACTIONS = ["retry", "reroute", "decompose", "human"];
61
+ export function parseConsultVerdict(out, nonce) {
62
+ const v = extractVerdictJson(out, nonce);
63
+ if (!v)
64
+ return { verdict: null, cause: classifyVerdictCause(out, nonce, "action") };
65
+ // A parsed object with an unknown action is a content rejection, not silence. It keeps the existing
66
+ // null result without manufacturing a classifier cause for a state the classifier never saw.
67
+ if (!ACTIONS.includes(v.action))
68
+ return { verdict: null };
69
+ // fail-closed exclusion: only a non-empty string survives. Malformed values (number/array/object/
70
+ // empty) are dropped — the verdict stays a normal channel-level reroute/retry/…, never a crash
71
+ // and never silently forced to human. Unknown adapter ids pass through; the daemon treats a
72
+ // zero-match expansion as channel-level reroute.
73
+ const raw = v.excludeAdapter;
74
+ const excludeAdapter = typeof raw === "string" && raw.length > 0 ? raw : undefined;
75
+ const reason = typeof v.reason === "string" ? v.reason : undefined;
76
+ const guidance = typeof v.guidance === "string" ? v.guidance : undefined;
77
+ const notes = String(v.notes ?? guidance ?? reason ?? "");
78
+ return {
79
+ verdict: {
80
+ action: v.action,
81
+ notes,
82
+ ...(reason ? { reason } : {}),
83
+ ...(guidance ? { guidance } : {}),
84
+ ...(excludeAdapter ? { excludeAdapter } : {}),
85
+ },
86
+ };
87
+ }
60
88
  // v1.65 T2: transcript noise (spinner repaints, CR churn, pass-run spam) is squashed at build time —
61
89
  // the filtered form is what persists to the consults/ artifact AND what the model reads; fail-open.
62
90
  export function buildDossierPrompt(d, nonce) {
@@ -108,7 +136,8 @@ opts = {}) {
108
136
  // consult model reads) is masked at this seam; the in-memory Dossier stays untouched.
109
137
  writeFileSync(promptFile, redactSecrets(buildDossierPrompt(d, nonce)));
110
138
  // One seat = the WHOLE invoke-and-parse unit, both visibility branches (OBS-69 class: a headless-only
111
- // failover would leave the production pane path hard-failing on seat one). null = no parseable verdict.
139
+ // failover would leave the production pane path hard-failing on seat one). A null verdict retains
140
+ // the classifier's cause when extraction failed; parsed content rejections deliberately have none.
112
141
  const invokeSeat = async (seatAdapter, seatModel, seatIdx) => {
113
142
  const adapter = getAdapter(seatAdapter, adapters);
114
143
  let out;
@@ -143,26 +172,7 @@ opts = {}) {
143
172
  await driver.close(slot);
144
173
  }
145
174
  }
146
- out = augmentFakeVerdictOutput(adapter, out, nonce);
147
- const v = extractVerdictJson(out, nonce);
148
- if (!v || !ACTIONS.includes(v.action))
149
- return null;
150
- // fail-closed exclusion: only a non-empty string survives. Malformed values (number/array/object/
151
- // empty) are dropped — the verdict stays a normal channel-level reroute/retry/…, never a crash
152
- // and never silently forced to human. Unknown adapter ids pass through; the daemon treats a
153
- // zero-match expansion as channel-level reroute.
154
- const raw = v.excludeAdapter;
155
- const excludeAdapter = typeof raw === "string" && raw.length > 0 ? raw : undefined;
156
- const reason = typeof v.reason === "string" ? v.reason : undefined;
157
- const guidance = typeof v.guidance === "string" ? v.guidance : undefined;
158
- const notes = String(v.notes ?? guidance ?? reason ?? "");
159
- return {
160
- action: v.action,
161
- notes,
162
- ...(reason ? { reason } : {}),
163
- ...(guidance ? { guidance } : {}),
164
- ...(excludeAdapter ? { excludeAdapter } : {}),
165
- };
175
+ return parseConsultVerdict(out, nonce);
166
176
  };
167
177
  // v1.54 T1: ranked seat failover. Walk consult.prefer (adapter:model entries) to the first entry
168
178
  // whose adapter is in the live channel set; a failed seat or unparseable verdict falls to the next;
@@ -176,9 +186,9 @@ opts = {}) {
176
186
  seats.push({ adapter: cfg.consult.adapter, model: cfg.consult.model });
177
187
  for (const [i, seat] of seats.entries()) {
178
188
  try {
179
- const v = await invokeSeat(seat.adapter, seat.model, i);
180
- if (v)
181
- return v;
189
+ const parsed = await invokeSeat(seat.adapter, seat.model, i);
190
+ if (parsed.verdict)
191
+ return parsed.verdict;
182
192
  }
183
193
  catch {
184
194
  // failed seat (unknown adapter, dead driver/pane, shell error) — fall to the next entry
@@ -1,7 +1,7 @@
1
1
  import { type WorkerAdapter } from "../adapters/types.js";
2
2
  import { type ModeResolution, type RoutingMode, type TickmarkrConfig } from "../config/config.js";
3
3
  import { type ExecutorDriver } from "../drivers/types.js";
4
- import { type JournalEvent } from "./journal.js";
4
+ import { Journal, type JournalEvent } from "./journal.js";
5
5
  export interface RunOptions {
6
6
  runId?: string;
7
7
  resume?: boolean;
@@ -42,13 +42,59 @@ export interface RunSummary {
42
42
  lastMergedTask?: string;
43
43
  }
44
44
  export declare function formatSummary(s: RunSummary): string;
45
+ /**
46
+ * T4 (OBS-265): the journal with the review objections a round did NOT hinge on removed. Judge and
47
+ * review are now launched together, so a round can journal a failed review that the serial walk would
48
+ * never have asked for — it returned at the judge. Those verdicts stay on the record (they are real,
49
+ * and the retry brief carries them), but they must not spend the OPERATOR-facing review round budget:
50
+ * otherwise concurrency alone parks a task rounds early for objections the old pipeline never bought.
51
+ * A round is the gate-result span opened by each `gates` phase-start, per task.
52
+ */
53
+ export declare function decisiveReviewRounds(events: JournalEvent[]): JournalEvent[];
45
54
  export declare const EARLY_LAUNCH_LIVENESS_MS = 60000;
46
55
  /** Test seam — lowers the empty-pane liveness window without sleeping 60s per case. */
47
56
  export declare function setEarlyLaunchLivenessMsForTests(ms: number): void;
48
57
  export declare function resetEarlyLaunchLivenessMsForTests(): void;
49
- export declare const NUDGEABLE_ADAPTERS: Set<string>;
58
+ export { NUDGEABLE_ADAPTERS } from "./stall.js";
50
59
  export declare const WORKER_NUDGE_MESSAGE = "tickmarkr liveness check: if the task is complete, print your TICKMARKR_RESULT completion trailer exactly as specified in your prompt now. If not, state your next concrete action and continue working.";
51
60
  /** Test seam — shrink the nudge gate and grace without minute-long sleeps. */
52
61
  export declare function setNudgeTimingForTests(silentMs: number, graceMs: number): void;
53
62
  export declare function resetNudgeTimingForTests(): void;
63
+ /** Test seam — shrink the quota-banner silence gate without minute-long sleeps. */
64
+ export declare function setQuotaBannerSilentMsForTests(ms: number): void;
65
+ export declare function resetQuotaBannerSilentMsForTests(): void;
66
+ /** Test seam — shrink the repeat-page cadence without minute-long sleeps. */
67
+ export declare function setPageRepeatMsForTests(ms: number): void;
68
+ export declare function resetPageRepeatMsForTests(): void;
69
+ /** Test seam — shrink the fast-kill window without minute-long sleeps. */
70
+ export declare function setDeadChannelFastKillMsForTests(ms: number): void;
71
+ export declare function resetDeadChannelFastKillMsForTests(): void;
72
+ /** Test seam — shrink the harvest silence gate without minute-long sleeps. */
73
+ export declare function setHarvestSilentMsForTests(ms: number): void;
74
+ export declare function resetHarvestSilentMsForTests(): void;
75
+ export declare function harvestCpuFlatWindowMs(resolutionMs: number): number;
76
+ /** Test seam — pin the flat window so a probe case need not sit through a real one. */
77
+ export declare function setHarvestCpuFlatMsForTests(ms: number): void;
78
+ export declare function resetHarvestCpuFlatMsForTests(): void;
79
+ export declare const HARVESTED_RESULT_SUMMARY = "harvested: the worktree carries committed work; the worker emitted no TICKMARKR_RESULT trailer";
80
+ /** T4 (OBS-266): identity of the command SET a tip verify ran — a changed command is a different verify. */
81
+ export declare function commandsHash(commands: Record<string, string>): string;
82
+ /**
83
+ * OBS-34's strict tip verify, but it stops re-paying for an unmoved tip (~334m corpus-wide; 69.5m in
84
+ * one park-heavy run whose 18 resume cycles merged nothing new). The verify journals the SHA it
85
+ * verified and the hash of the command set, so a later run-end can recognize the same verified state:
86
+ * head equals the LAST green verified SHA, commands unchanged, tree clean → journal
87
+ * `tip-verify-cached` and skip. ANY doubt — moved head, changed commands, dirty tree, a gate missing
88
+ * from that cycle's green set, a failure recorded in it, a cycle older than the last one — runs the
89
+ * full verify. The tip-verify-before-green law is untouched: a cached green is a verified green OF
90
+ * THAT EXACT COMMIT, established by the most recent real run of the same commands.
91
+ * Returns whether the tip is failing.
92
+ */
93
+ export declare function verifyIntegrationTipCached(intWt: string, commands: Record<string, string>, journal: Journal, opts?: {
94
+ lastMergedTask?: string;
95
+ }): Promise<boolean>;
96
+ export declare function workerTreeCpuMs(marker: string, cwd: string): Promise<{
97
+ ms: number;
98
+ resolutionMs: number;
99
+ } | undefined>;
54
100
  export declare function runDaemon(repoRoot: string, opts?: RunOptions): Promise<RunSummary>;