tickmarkr 2.6.4 → 2.6.6

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 (73) hide show
  1. package/README.md +7 -3
  2. package/dist/adapters/catalog-remote.d.ts +23 -0
  3. package/dist/adapters/catalog-remote.js +38 -0
  4. package/dist/adapters/claude-code.d.ts +1 -1
  5. package/dist/adapters/claude-code.js +4 -1
  6. package/dist/adapters/codex-commit-check.d.ts +36 -0
  7. package/dist/adapters/codex-commit-check.js +205 -0
  8. package/dist/adapters/codex.d.ts +1 -0
  9. package/dist/adapters/codex.js +12 -6
  10. package/dist/adapters/model-discovery-check.d.ts +33 -0
  11. package/dist/adapters/model-discovery-check.js +123 -0
  12. package/dist/adapters/model-lints.d.ts +1 -1
  13. package/dist/adapters/model-lints.js +4 -0
  14. package/dist/adapters/prompt.js +3 -2
  15. package/dist/adapters/types.d.ts +10 -0
  16. package/dist/cli/commands/approve.js +10 -4
  17. package/dist/cli/commands/doctor.d.ts +2 -0
  18. package/dist/cli/commands/doctor.js +17 -3
  19. package/dist/cli/commands/fleet.d.ts +10 -1
  20. package/dist/cli/commands/fleet.js +363 -106
  21. package/dist/cli/commands/init.js +10 -3
  22. package/dist/cli/commands/plan.js +76 -4
  23. package/dist/cli/commands/verify.d.ts +1 -1
  24. package/dist/cli/commands/verify.js +65 -15
  25. package/dist/config/fleet-overlay.d.ts +16 -1
  26. package/dist/config/fleet-overlay.js +230 -28
  27. package/dist/drivers/orca.d.ts +34 -2
  28. package/dist/drivers/orca.js +206 -32
  29. package/dist/gates/cache.d.ts +4 -0
  30. package/dist/gates/cache.js +10 -2
  31. package/dist/gates/llm.d.ts +4 -1
  32. package/dist/gates/llm.js +6 -1
  33. package/dist/gates/review.js +8 -3
  34. package/dist/gates/run-gates.d.ts +5 -3
  35. package/dist/gates/run-gates.js +112 -56
  36. package/dist/gates/test-manifest.d.ts +3 -0
  37. package/dist/gates/test-manifest.js +1 -1
  38. package/dist/gates/timeout-shaped.d.ts +3 -0
  39. package/dist/gates/timeout-shaped.js +10 -0
  40. package/dist/run/daemon.js +326 -130
  41. package/dist/run/git.js +9 -0
  42. package/dist/run/journal.d.ts +6 -2
  43. package/dist/run/journal.js +22 -7
  44. package/dist/run/launchservices-check.d.ts +56 -0
  45. package/dist/run/launchservices-check.js +117 -0
  46. package/dist/run/operator-state.d.ts +22 -2
  47. package/dist/run/operator-state.js +20 -3
  48. package/dist/run/title-environment.d.ts +45 -0
  49. package/dist/run/title-environment.js +127 -0
  50. package/dist/run/title-preload.cjs +38 -0
  51. package/dist/run/title-preload.d.cts +1 -0
  52. package/dist/tui/cockpit/board.js +12 -6
  53. package/dist/tui/cockpit/keys.d.ts +8 -0
  54. package/dist/tui/cockpit/keys.js +4 -1
  55. package/dist/tui/cockpit/layout.d.ts +2 -2
  56. package/dist/tui/cockpit/layout.js +2 -2
  57. package/dist/tui/cockpit/live-runtime.js +46 -20
  58. package/dist/tui/cockpit/live-store.d.ts +24 -1
  59. package/dist/tui/cockpit/live-store.js +99 -8
  60. package/dist/tui/cockpit/log-view.d.ts +28 -0
  61. package/dist/tui/cockpit/log-view.js +60 -0
  62. package/dist/tui/cockpit/run-view.js +4 -0
  63. package/dist/tui/cockpit/shell.d.ts +2 -1
  64. package/dist/tui/cockpit/shell.js +6 -4
  65. package/dist/tui/ink/fleet-app.d.ts +37 -10
  66. package/dist/tui/ink/fleet-app.js +65 -21
  67. package/package.json +1 -1
  68. package/skills/tickmarkr-auto/SKILL.md +32 -2
  69. package/skills/tickmarkr-loop/SKILL.md +46 -2
  70. package/skills/tickmarkr-overseer/SKILL.md +83 -8
  71. package/skills/tickmarkr-overseer/scripts/classify-vitest-log.sh +58 -16
  72. package/skills/tickmarkr-overseer/scripts/grade-ci.sh +19 -6
  73. package/skills/tickmarkr-overseer/scripts/watch-parks.sh +121 -64
@@ -51,7 +51,17 @@ export interface AuthHealth {
51
51
  modelAuth?: Record<string, ModelAuth>;
52
52
  modelIdentities?: Record<string, string>;
53
53
  modelRetirements?: Record<string, ModelRetirement | null>;
54
+ codexCommit?: CodexCommitStatus;
55
+ launchServices?: LaunchServicesRecord;
54
56
  }
57
+ export interface LaunchServicesRecord {
58
+ pid: number;
59
+ start: string;
60
+ advisory?: string;
61
+ }
62
+ /** allowed: linked branch commit landed, shared hooks/common root denied · protected: commit denied, controls
63
+ * readable · escape: a unique hostile member was written · unknown: unreadable or contradictory receipts. */
64
+ export type CodexCommitStatus = "allowed" | "protected" | "escape" | "unknown";
55
65
  export declare function modelAuthed(health: AuthHealth | undefined, model: string, allowUnverifiedModels?: boolean): boolean;
56
66
  export interface Invocation {
57
67
  command: string;
@@ -210,11 +210,17 @@ export async function approve(argv, cwd = process.cwd()) {
210
210
  if (namedGate !== undefined && namedGate !== park?.failedGate) {
211
211
  throw new Error(`refusing mismatched gate for ${taskId}: --gate ${namedGate} but park ${bindingToken(parkBinding)} failed ${park?.failedGate ?? "no gate"} — nothing appended`);
212
212
  }
213
- if ((park?.kind === "scope-request" && !decisions) || files !== undefined) {
213
+ // A scope-request park is released one of two ways: --files widens files[], or a nonempty --reason
214
+ // refuses the expansion and funds a plain worker within the current files[] — the reason rides into
215
+ // the next brief as a standing ruling (journaledFailureBrief). No reason, no release: the refusal is
216
+ // a ruling only when it says why. The cockpit menu still offers neither (it has no reason entry).
217
+ const scopeRefusal = park?.kind === "scope-request" && !decisions && files === undefined && Boolean(reason?.trim());
218
+ if ((park?.kind === "scope-request" && !decisions && !scopeRefusal) || files !== undefined) {
214
219
  if (park?.kind !== "scope-request")
215
220
  throw new Error("--files requires a scope-request park");
216
- if (!files?.length)
217
- throw new Error(`scope-request for ${taskId} requires --files <glob,…>`);
221
+ if (!files?.length) {
222
+ throw new Error(`scope-request for ${taskId} requires --files <glob,…> to widen files[], or \`tickmarkr approve ${runId} ${taskId} --reason <text>\` to refuse the expansion and continue within the current files[]`);
223
+ }
218
224
  if (decisions)
219
225
  throw new Error("--files cannot be combined with --waive, --uphold or --recheck");
220
226
  const graph = applyScopeAmendments(loadGraph(cwd), journal, false, engagementReleased(events));
@@ -358,7 +364,7 @@ export async function approve(argv, cwd = process.cwd()) {
358
364
  park: parkBinding,
359
365
  });
360
366
  const token = capPark ? "fresh-budget" : "dispatch";
361
- return disposition(cwd, runId, token, `approved ${taskId} in ${runId} — by ${by}`, serialization.contended);
367
+ return disposition(cwd, runId, token, `approved ${taskId} in ${runId} — by ${by}${scopeRefusal ? "; scope expansion refused, files[] unchanged" : ""}`, serialization.contended);
362
368
  }
363
369
  finally {
364
370
  serialization.release();
@@ -1,6 +1,7 @@
1
1
  import { type ClaudeAlias } from "../../adapters/claude-code.js";
2
2
  import type { WorkerAdapter } from "../../adapters/types.js";
3
3
  import { type KimiDoctorTurnResult } from "../../adapters/kimi.js";
4
+ import { type CodexSandbox } from "../../adapters/codex-commit-check.js";
4
5
  import { type CatalogFetcher, type CatalogReadResult } from "../../adapters/catalog-remote.js";
5
6
  import { type ShResult } from "../../run/git.js";
6
7
  import { type VitestListResult } from "../../gates/acceptance.js";
@@ -17,6 +18,7 @@ export declare function recentReviewDemotions(cwd: string, lastRuns?: number): R
17
18
  export type DoctorOpts = {
18
19
  banner?: boolean;
19
20
  kimiTurnProbe?: (cwd: string) => Promise<KimiDoctorTurnResult>;
21
+ codexSandbox?: CodexSandbox;
20
22
  resolveClaudeAliasIdentity?: (cwd: string, alias: ClaudeAlias) => string | undefined;
21
23
  catalog?: CatalogReadResult;
22
24
  catalogNow?: () => Date;
@@ -14,11 +14,15 @@ import { loadConfig, overlayPreferShapes } from "../../config/config.js";
14
14
  import { HerdrDriver } from "../../drivers/herdr.js";
15
15
  import { ORCA_FIXTURE_VERSION, parseEnvelope, resolveOrcaCliBinary } from "../../drivers/orca.js";
16
16
  import { kimi, probeKimiDoctorTurn } from "../../adapters/kimi.js";
17
+ import { recordCodexCommit } from "../../adapters/codex-commit-check.js";
18
+ import { codex } from "../../adapters/codex.js";
17
19
  import { denyPreferCollisionLine, denyPreferCollisions, disallowedBy, excludedChannels, exclusionLine, observedSeat, preferRanks } from "../../route/preference.js";
18
20
  import { CATALOG_REFRESH_TIMEOUT_MS, LIVEBENCH_TABLE_DATE, formatCatalogRefreshLegs, readCachedCatalog, refreshCatalogCommand } from "../../adapters/catalog-remote.js";
19
21
  import { sh } from "../../run/git.js";
20
22
  import { auditNamedTestOracles, listVitestTests } from "../../gates/acceptance.js";
21
23
  import { readReviewNoVerdictHistory, reviewNoVerdictRows } from "../../run/journal.js";
24
+ import { checkModelDiscovery } from "../../adapters/model-discovery-check.js";
25
+ import { recordLaunchServices } from "../../run/launchservices-check.js";
22
26
  /** Where a newer `table_<date>.csv` is discovered — the deployed site builds filenames by
23
27
  * concatenation and publishes no index, so the release listing is the only enumerable surface. */
24
28
  export const LIVEBENCH_RELEASES_URL = "https://api.github.com/repos/LiveBench/livebench.github.io/contents/public";
@@ -578,6 +582,7 @@ export async function doctor(_argv, cwd = process.cwd(), adapters = allAdapters(
578
582
  };
579
583
  }
580
584
  }
585
+ await recordCodexCommit(adapters, health, cwd, opts.codexSandbox);
581
586
  // MODEL-02: detect models where the adapter exposes a list surface, BEFORE writing doctor.json (write once, below).
582
587
  // Fail OPEN — the inverse of gates' fail-closed: detection is advisory, so a broken list surface NEVER fails doctor.
583
588
  for (const a of adapters) {
@@ -659,12 +664,17 @@ export async function doctor(_argv, cwd = process.cwd(), adapters = allAdapters(
659
664
  }
660
665
  }
661
666
  }
662
- writeDoctor(cwd, health);
667
+ const discovery = await checkModelDiscovery({ cwd, cfg, adapters, health, catalog, resolved: resolvedIdentitySnapshot, mayRefresh: !opts.catalog && !catalogRefreshLine && catalogRefreshAllowed, fetcher: opts.catalogFetcher, now: opts.catalogNow });
668
+ catalog = discovery.catalog;
669
+ aliasDriftFindings.push(...discovery.findings);
670
+ const launchServices = await recordLaunchServices(readDoctor(cwd), health);
671
+ writeDoctor(cwd, launchServices.health);
663
672
  const rows = adapters.map((a) => {
664
673
  const h = health[a.id];
665
674
  // OBS-503: a crash-on-version verdict carries its reason in note — print it instead of the lie.
666
675
  const state = !h.installed ? (h.note ?? "not installed") : `${h.version ?? "installed"}${h.note ? ` (${h.note})` : ""}`;
667
- const healthy = h.installed && (a.id !== kimi.id || h.authed);
676
+ // v2.6.6 T9 (K): a Codex sandbox escape is a BLOCKING security warning — never a passing row
677
+ const healthy = h.installed && (a.id !== kimi.id || h.authed) && !(a.id === codex.id && h.codexCommit === "escape");
668
678
  return alignedStatusRow(healthy ? "pass" : "fail", a.id, state);
669
679
  });
670
680
  const reviewDemotions = recentReviewDemotions(cwd);
@@ -807,6 +817,8 @@ export async function doctor(_argv, cwd = process.cwd(), adapters = allAdapters(
807
817
  lintRows.push(...flagDriftWarnings(adapters, health).map(attentionRow));
808
818
  // OBS-145: resolved-identity drift is advisory display warning.
809
819
  lintRows.push(...aliasDriftFindings.map(attentionRow));
820
+ if (launchServices.line)
821
+ lintRows.push(attentionRow(launchServices.line));
810
822
  const resolvedCatalogModel = (adapter, model) => {
811
823
  if (adapter !== "claude-code" || !(model in CLAUDE_ALIAS_IDENTITY_STAMPS))
812
824
  return undefined;
@@ -895,9 +907,11 @@ export async function doctor(_argv, cwd = process.cwd(), adapters = allAdapters(
895
907
  rows.push(` ${dim(`catalog · ${advisory.display}`)}`);
896
908
  if (!listAllModels && bulk.length) {
897
909
  const uncovered = bulk.filter((adv) => adv.coverage === "uncovered").length;
898
- const evidenceOnly = bulk.length - uncovered;
910
+ const unknown = bulk.filter((adv) => adv.coverage === "unknown").length;
911
+ const evidenceOnly = bulk.length - uncovered - unknown;
899
912
  const parts = [
900
913
  ...(uncovered ? [`${uncovered} uncovered by ${catalog.source === "cache" ? "cached catalogs" : "vendored catalog"}`] : []),
914
+ ...(unknown ? [`${unknown} coverage unknown after a failed refresh`] : []),
901
915
  ...(evidenceOnly ? [`${evidenceOnly} covered without a tier suggestion`] : []),
902
916
  ];
903
917
  rows.push(` ${dim(`catalog · ${parts.join(" · ")} — tickmarkr doctor --models lists each`)}`);
@@ -1,6 +1,7 @@
1
1
  import { type CatalogFetcher, type CatalogReadResult } from "../../adapters/catalog-remote.js";
2
2
  import type { WorkerAdapter } from "../../adapters/types.js";
3
- import type { FleetEditorResult } from "../../tui/ink/fleet-app.js";
3
+ import { type MapEntry, type ModeResolution, type RoutingMode, type TickmarkrConfig } from "../../config/config.js";
4
+ import type { FleetEditorResult, FleetStagedDeny, FleetStagedMetadata } from "../../tui/ink/fleet-app.js";
4
5
  type FleetEditorProps = Parameters<typeof import("../../tui/ink/fleet-app.js").runFleetInkEditor>[0];
5
6
  export type FleetInput = NodeJS.ReadableStream & {
6
7
  isTTY?: boolean;
@@ -44,6 +45,14 @@ export declare function assembleFleetEditor(cwd: string, adapters: WorkerAdapter
44
45
  props: FleetEditorProps;
45
46
  commit: (result: FleetEditorResult) => string;
46
47
  renderWhy: () => string;
48
+ previewConfig: (mode: RoutingMode, map: Record<string, MapEntry>, deny: FleetStagedDeny, stage?: FleetStagedMetadata) => {
49
+ ok: true;
50
+ cfg: TickmarkrConfig;
51
+ mode: ModeResolution;
52
+ } | {
53
+ ok: false;
54
+ error: string;
55
+ };
47
56
  } | {
48
57
  unavailable: string;
49
58
  }>;