tickmarkr 1.37.0 → 1.38.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.
- package/README.md +1 -6
- package/dist/adapters/claude-code.js +4 -4
- package/dist/adapters/codex.js +1 -1
- package/dist/adapters/fake.d.ts +2 -2
- package/dist/adapters/fake.js +8 -8
- package/dist/adapters/grok.js +5 -5
- package/dist/adapters/model-lints.d.ts +4 -4
- package/dist/adapters/model-lints.js +1 -1
- package/dist/adapters/prompt.js +8 -13
- package/dist/adapters/registry.d.ts +8 -8
- package/dist/adapters/registry.js +5 -5
- package/dist/adapters/types.d.ts +3 -3
- package/dist/brand.d.ts +2 -0
- package/dist/brand.js +17 -0
- package/dist/cli/commands/approve.js +3 -3
- package/dist/cli/commands/compile.js +1 -1
- package/dist/cli/commands/doctor.js +3 -3
- package/dist/cli/commands/init.js +14 -9
- package/dist/cli/commands/profile.js +6 -6
- package/dist/cli/commands/status.js +2 -1
- package/dist/cli/commands/unlock.js +1 -1
- package/dist/cli/index.d.ts +1 -2
- package/dist/cli/index.js +5 -15
- package/dist/compile/gsd.js +1 -1
- package/dist/compile/index.js +9 -3
- package/dist/compile/native.d.ts +2 -0
- package/dist/compile/native.js +4 -2
- package/dist/config/config.d.ts +6 -6
- package/dist/config/config.js +8 -12
- package/dist/drivers/herdr.js +5 -5
- package/dist/drivers/index.d.ts +2 -2
- package/dist/drivers/subprocess.js +3 -3
- package/dist/drivers/types.js +4 -6
- package/dist/gates/acceptance.js +1 -1
- package/dist/gates/baseline.d.ts +2 -2
- package/dist/gates/llm.js +12 -9
- package/dist/gates/review.d.ts +2 -2
- package/dist/gates/review.js +1 -1
- package/dist/gates/run-gates.d.ts +2 -2
- package/dist/graph/graph.d.ts +2 -2
- package/dist/graph/graph.js +4 -16
- package/dist/plan/prompt.js +1 -1
- package/dist/plan/scope.d.ts +2 -2
- package/dist/plan/scope.js +5 -5
- package/dist/route/preference.d.ts +4 -4
- package/dist/route/router.d.ts +3 -3
- package/dist/run/consult.d.ts +2 -2
- package/dist/run/consult.js +5 -5
- package/dist/run/daemon.js +13 -13
- package/dist/run/git.d.ts +1 -1
- package/dist/run/git.js +5 -9
- package/dist/run/journal.d.ts +2 -2
- package/dist/run/journal.js +4 -4
- package/dist/run/lock.js +11 -11
- package/dist/run/merge.d.ts +2 -2
- package/dist/run/merge.js +3 -3
- package/dist/run/reconcile.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,17 +13,12 @@ cursor-agent, opencode, grok, pi) by cost and capability, dispatches work in iso
|
|
|
13
13
|
with full visibility into routing decisions, worker progress, and gate verdicts — or run headless
|
|
14
14
|
and review the audit trail afterward.
|
|
15
15
|
|
|
16
|
-
<!-- tickmarkr:compat-legacy BEGIN: sanctioned naming residue, unchanged pending shim spec -->
|
|
17
|
-
**Legacy naming (unchanged):** tickmarkr reads existing state from `.drovr/` directories and resumes runs with legacy `drovr/<runId>` branch names recorded in their journals; new engagements write to `tickmarkr/<runId>`. Environment variables `DROVR_*` remain unchanged (e.g., `DROVR_FAKE_SCRIPT`, `DROVR_E2E`). New specs use the `<!-- tickmarkr:spec -->` marker; the historical `<!-- drovr:spec -->` marker is still accepted. These names are pending formalization in a future shim spec; no action required — existing runs and configurations remain fully compatible.
|
|
18
|
-
<!-- tickmarkr:compat-legacy END -->
|
|
19
|
-
|
|
20
16
|
## Invariants
|
|
21
17
|
|
|
22
18
|
These are law; the codebase fails closed around them:
|
|
23
19
|
|
|
24
20
|
- `acceptance[]` required on every task; compile fails without it
|
|
25
|
-
- new engagements consolidate to a `tickmarkr/<runId>` branch — never main
|
|
26
|
-
engagements keeps the branch names recorded in their journal)
|
|
21
|
+
- new engagements consolidate to a `tickmarkr/<runId>` branch — never main
|
|
27
22
|
- gates never trust worker claims; tickmarkr verifies everything itself
|
|
28
23
|
- state is files + git only; no DB, no services
|
|
29
24
|
- worker/judge/review/consult prompts end with machine-parseable trailers
|
|
@@ -6,7 +6,7 @@ import { parseWorkerResult } from "./prompt.js";
|
|
|
6
6
|
import { channelsFromConfig, shq, TokenUsageSchema } from "./types.js";
|
|
7
7
|
// SPEND-01/SPEND-11: claude writes a per-session JSONL to ~/.claude/projects/<slug>/ where slug is the
|
|
8
8
|
// realpath'd cwd with every non-alphanumeric char replaced by "-" (verified 114/114 — 36-DIAGNOSIS.md).
|
|
9
|
-
// The old `/`-only formula missed the "." in `.
|
|
9
|
+
// The old `/`-only formula missed the "." in `.tickmarkr/worktrees/…` — ENOENT on every worktree dispatch.
|
|
10
10
|
// Each assistant message carries a per-record ISO `timestamp` and message.usage. We read it POST-HOC
|
|
11
11
|
// (never the pane, never the trailer) and sum
|
|
12
12
|
// tokens for records whose top-level cwd matches this task's worktree AND whose timestamp is at/after
|
|
@@ -43,9 +43,9 @@ export const claudeCode = {
|
|
|
43
43
|
channels: (cfg) => channelsFromConfig("claude-code", cfg),
|
|
44
44
|
// --strict-mcp-config --mcp-config '{"mcpServers":{}}': pin the MCP surface to empty so fresh-worktree
|
|
45
45
|
// workers/gates don't load project .mcp.json servers (herdr scrapes dialogs as idle — v1.4 incident,
|
|
46
|
-
// memory
|
|
46
|
+
// memory tickmarkr-worker-mcp-dialog-stall). Live-verified 2026-07-10 on claude 2.1.205 (operator check):
|
|
47
47
|
// headless (-p) fully suppressed — exit 0, no dialog. Interactive TUI STILL shows the project
|
|
48
|
-
// MCP-enable dialog (project trust/enablement, not config loading); Esc dismisses it, and
|
|
48
|
+
// MCP-enable dialog (project trust/enablement, not config loading); Esc dismisses it, and tickmarkr's
|
|
49
49
|
// blocked/idle paging surfaces the pane to the operator (same path as cursor's trust dialog).
|
|
50
50
|
// Gotchas (both bit the 2026-07-10 live check): bare '{}' is REJECTED ("mcpServers: expected record"),
|
|
51
51
|
// and --mcp-config is VARIADIC — a positional after it is eaten as a config-file path, so another
|
|
@@ -53,7 +53,7 @@ export const claudeCode = {
|
|
|
53
53
|
headlessCommand: (promptFile, model) => `claude -p "$(cat ${shq(promptFile)})" --model ${shq(model)} --permission-mode bypassPermissions --strict-mcp-config --mcp-config '{"mcpServers":{}}' --output-format text`,
|
|
54
54
|
// HYG-03: the residual first-entry dialog on an interactive TUI is the workspace TRUST dialog (not MCP
|
|
55
55
|
// config loading) — CLI-imposed, no flag to pre-accept, only store is claude's global last-writer-wins
|
|
56
|
-
// ~/.claude.json keyed on the exact path. Closed WON'T-FIX (decision B, 2026-07-10):
|
|
56
|
+
// ~/.claude.json keyed on the exact path. Closed WON'T-FIX (decision B, 2026-07-10): tickmarkr writes nothing
|
|
57
57
|
// to that file (a seed races claude's own writes, nondeterministically). Amortizes to one operator dismissal
|
|
58
58
|
// per stable worktree path; blocked-pane paging surfaces it. Do NOT change this command to "fix" the dialog —
|
|
59
59
|
// see .planning/REQUIREMENTS.md HYG-03 and 21-02-LIVE-CHECK.md. Revisit if upstream ships a --trust flag.
|
package/dist/adapters/codex.js
CHANGED
|
@@ -75,7 +75,7 @@ export function readCodexModelsCache(path) {
|
|
|
75
75
|
return { models: [] };
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
//
|
|
78
|
+
// tickmarkr worktrees keep their gitdir under the MAIN repo's .git/worktrees/<name> — outside the
|
|
79
79
|
// workspace-write sandbox root — so git commit dies on index.lock (incident run-20260709-104447
|
|
80
80
|
// P87-08: "Unable to create …/.git/worktrees/…/index.lock"). Expanded by the pane shell at the
|
|
81
81
|
// worktree cwd; in a plain repo it resolves to ./.git (already writable, harmless).
|
package/dist/adapters/fake.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TickmarkrConfig } from "../config/config.js";
|
|
2
2
|
import type { Task } from "../graph/schema.js";
|
|
3
3
|
import { type Assignment, type AuthHealth, type BillingChannel, type ContextUsage, type Invocation, type SessionRef, type TokenUsage, type WorkerAdapter, type WorkerResult } from "./types.js";
|
|
4
4
|
export interface FakeScript {
|
|
@@ -29,7 +29,7 @@ export declare class FakeAdapter implements WorkerAdapter {
|
|
|
29
29
|
private attempts;
|
|
30
30
|
constructor(scriptPath: string);
|
|
31
31
|
probe(): Promise<AuthHealth>;
|
|
32
|
-
channels(_cfg:
|
|
32
|
+
channels(_cfg: TickmarkrConfig): BillingChannel[];
|
|
33
33
|
private judgeIdx;
|
|
34
34
|
headlessCommand(promptFile: string, _model: string): string;
|
|
35
35
|
resumeCommand(_sessionId: string, promptFile: string, model: string): string;
|
package/dist/adapters/fake.js
CHANGED
|
@@ -22,14 +22,14 @@ export class FakeAdapter {
|
|
|
22
22
|
{ adapter: "fake", vendor: "fake-b", model: "fake-2", channel: "api", tier: "frontier" },
|
|
23
23
|
];
|
|
24
24
|
}
|
|
25
|
-
judgeIdx = 0; // Phase 47: per-instance judge verdict cursor — advances only on
|
|
25
|
+
judgeIdx = 0; // Phase 47: per-instance judge verdict cursor — advances only on TICKMARKR-JUDGE prompts
|
|
26
26
|
headlessCommand(promptFile, _model) {
|
|
27
27
|
// Phase 47 (GATE-09): detect role at COMMAND-BUILD time. runHeadless/runViaDriver write the prompt
|
|
28
28
|
// file BEFORE calling headlessCommand, so it exists here. The counter advances ONLY when the prompt
|
|
29
|
-
// contains
|
|
29
|
+
// contains TICKMARKR-JUDGE — a review/consult prompt never touches it (research Pitfall 3).
|
|
30
30
|
let isJudge = false;
|
|
31
31
|
try {
|
|
32
|
-
isJudge = /
|
|
32
|
+
isJudge = /TICKMARKR-JUDGE/.test(readFileSync(promptFile, "utf8"));
|
|
33
33
|
}
|
|
34
34
|
catch {
|
|
35
35
|
// unreadable promptFile: can't detect role; serve static values (legacy headless-call behavior)
|
|
@@ -45,7 +45,7 @@ export class FakeAdapter {
|
|
|
45
45
|
writeFileSync(p, JSON.stringify(val ?? {}, null, 1));
|
|
46
46
|
return p;
|
|
47
47
|
};
|
|
48
|
-
return `bash -c 'grep -q
|
|
48
|
+
return `bash -c 'grep -q TICKMARKR-JUDGE ${shq(promptFile)} && cat ${shq(serve("judge"))}; grep -q TICKMARKR-REVIEW ${shq(promptFile)} && cat ${shq(serve("review"))}; grep -q TICKMARKR-CONSULT ${shq(promptFile)} && cat ${shq(serve("consult"))}; true'`;
|
|
49
49
|
}
|
|
50
50
|
resumeCommand(_sessionId, promptFile, model) {
|
|
51
51
|
return this.interactiveCommand(promptFile, model) ?? this.headlessCommand(promptFile, model);
|
|
@@ -61,11 +61,11 @@ export class FakeAdapter {
|
|
|
61
61
|
// no ms clock) so the record lands at/after this attempt's dispatch and clears the sinceMs cursor.
|
|
62
62
|
// Written AFTER the step's `git add`/commit ⇒ stays untracked ⇒ invisible to the scope/evidence gates.
|
|
63
63
|
const usageWrite = step.usage
|
|
64
|
-
? `; node -e ${shq(`require("fs").writeFileSync(".
|
|
64
|
+
? `; node -e ${shq(`require("fs").writeFileSync(".tickmarkr-usage.json", JSON.stringify({timestamp:new Date().toISOString(), usage:${JSON.stringify(step.usage)}}))`)}`
|
|
65
65
|
: "";
|
|
66
66
|
const base = !step.result
|
|
67
67
|
? `bash -c ${shq(step.shell)}` // no trailer: scripted stall/quota
|
|
68
|
-
: `bash -c ${shq(step.shell)}; echo ${shq(`
|
|
68
|
+
: `bash -c ${shq(step.shell)}; echo ${shq(`TICKMARKR_RESULT_${nonce} ` + JSON.stringify({ deviations: [], ...step.result }))}`;
|
|
69
69
|
return base + usageWrite;
|
|
70
70
|
}
|
|
71
71
|
// SPEND-01: read the cwd-keyed usage record from DISK (never a pane), honoring the attempt cursor.
|
|
@@ -73,7 +73,7 @@ export class FakeAdapter {
|
|
|
73
73
|
// undefined ⇒ unmetered — never 0, never a thrown error that could fail a healthy task.
|
|
74
74
|
collectUsage(cwd, sinceMs) {
|
|
75
75
|
try {
|
|
76
|
-
const rec = JSON.parse(readFileSync(join(cwd, ".
|
|
76
|
+
const rec = JSON.parse(readFileSync(join(cwd, ".tickmarkr-usage.json"), "utf8"));
|
|
77
77
|
const ts = Date.parse(rec?.timestamp);
|
|
78
78
|
if (!Number.isFinite(ts) || ts < sinceMs)
|
|
79
79
|
return undefined; // cursor honored, fail-open
|
|
@@ -93,7 +93,7 @@ export class FakeAdapter {
|
|
|
93
93
|
// parseWorkerResult(output, nonce) succeeds exactly as before the nonce existed
|
|
94
94
|
nonceFor(promptFile) {
|
|
95
95
|
try {
|
|
96
|
-
return /
|
|
96
|
+
return /TICKMARKR_RESULT_([0-9a-z]+)/.exec(readFileSync(promptFile, "utf8"))?.[1] ?? "";
|
|
97
97
|
}
|
|
98
98
|
catch {
|
|
99
99
|
return "";
|
package/dist/adapters/grok.js
CHANGED
|
@@ -19,11 +19,11 @@ import { channelsFromConfig, MODEL_ID_RE, shq } from "./types.js";
|
|
|
19
19
|
// (4) `grok trace <id> --local` export and ~/.grok/logs/unified.jsonl (1,447 lines) — zero counters.
|
|
20
20
|
// (5) --debug-file traces DO carry real per-turn input_tokens=… output_tokens=… cache_read_tokens=…
|
|
21
21
|
// — a REAL source, REJECTED for stated reasons:
|
|
22
|
-
// (a) it exists ONLY because
|
|
23
|
-
//
|
|
22
|
+
// (a) it exists ONLY because tickmarkr would inject --debug-file into every dispatch — a side-channel
|
|
23
|
+
// tickmarkr creates, not a record the CLI keeps (same class as cursor's rejected --print --trust
|
|
24
24
|
// stdout tee, cursor-agent.ts:25-28);
|
|
25
25
|
// (b) DECISIVE: at DEBUG level the log verbatim-dumps the full OIDC bearer JWT and every MCP server
|
|
26
|
-
// env secret — an actual plaintext SUPABASE_ACCESS_TOKEN was observed —
|
|
26
|
+
// env secret — an actual plaintext SUPABASE_ACCESS_TOKEN was observed — tickmarkr forcing a
|
|
27
27
|
// per-attempt secret-spilling file onto disk to meter a sub channel fails its own security
|
|
28
28
|
// posture;
|
|
29
29
|
// (c) it is tracing diagnostics text with no format contract (xAI can reshape it in any patch).
|
|
@@ -102,11 +102,11 @@ export const grok = {
|
|
|
102
102
|
// 2026-07-11 (40-RESEARCH F-3): trailer intact + unwrapped, exit 0. "$(cat file)" matches every
|
|
103
103
|
// other adapter and is already quoting-proven. --permission-mode bypassPermissions is the
|
|
104
104
|
// autonomous-worker analog of claude's --dangerously-skip-permissions. NEVER pass grok's
|
|
105
|
-
// -w/--worktree flag — grok manages its OWN worktrees; a nested worktree inside
|
|
105
|
+
// -w/--worktree flag — grok manages its OWN worktrees; a nested worktree inside tickmarkr's worktree
|
|
106
106
|
// is scope-gate chaos (src/run/git.ts owns worktrees).
|
|
107
107
|
headlessCommand: (promptFile, model) => `grok -p "$(cat ${shq(promptFile)})" --model ${shq(model)} --permission-mode bypassPermissions --output-format plain`,
|
|
108
108
|
// GROK-02 interactive. Positional prompt seeds the TUI (40-CONTEXT D-01). Same permission flag;
|
|
109
|
-
// NEVER the -w/--worktree flag (see headless comment above —
|
|
109
|
+
// NEVER the -w/--worktree flag (see headless comment above — tickmarkr owns worktrees).
|
|
110
110
|
interactiveCommand: (promptFile, model) => `grok --model ${shq(model)} --permission-mode bypassPermissions "$(cat ${shq(promptFile)})"`,
|
|
111
111
|
invoke(task, _cwd, a, ctx) {
|
|
112
112
|
return { command: this.headlessCommand(ctx.promptFile, a.model) };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type TickmarkrConfig } from "../config/config.js";
|
|
2
2
|
import { type AuthHealth, type WorkerAdapter } from "./types.js";
|
|
3
3
|
export declare const SEED_STAMPED = "2026-07-09";
|
|
4
4
|
export declare const MODEL_STALE_DAYS = 30;
|
|
5
5
|
export declare const ttyVisual: () => boolean;
|
|
6
|
-
export declare function seedPreferLints(cfg:
|
|
7
|
-
export declare function modelLints(cfg:
|
|
6
|
+
export declare function seedPreferLints(cfg: TickmarkrConfig, health: Record<string, AuthHealth>, adapters: WorkerAdapter[], overlayPreferShapes?: ReadonlySet<string>): string[];
|
|
7
|
+
export declare function modelLints(cfg: TickmarkrConfig, health: Record<string, AuthHealth>, adapters: WorkerAdapter[], opts?: {
|
|
8
8
|
tty?: boolean;
|
|
9
9
|
stateDir?: string;
|
|
10
10
|
overlayPreferShapes?: ReadonlySet<string>;
|
|
@@ -14,4 +14,4 @@ export declare function formatModelAuthLine(excluded: {
|
|
|
14
14
|
reason: string;
|
|
15
15
|
probedAt: string;
|
|
16
16
|
}[], tty?: boolean, stateDir?: string): string;
|
|
17
|
-
export declare function suggestOverlay(cfg:
|
|
17
|
+
export declare function suggestOverlay(cfg: TickmarkrConfig, health: Record<string, AuthHealth>, adapters: WorkerAdapter[], stateDir?: string): string;
|
|
@@ -11,7 +11,7 @@ const DAY_MS = 86400000;
|
|
|
11
11
|
const LINT_VARIANT_RE = /^auto$|-(fast|minimal|low|medium|high|xhigh)$/;
|
|
12
12
|
const LINT_CAP = 5;
|
|
13
13
|
const TTY_LINT_CAP = 3;
|
|
14
|
-
const DEFAULT_STATE_DIR = ".
|
|
14
|
+
const DEFAULT_STATE_DIR = ".tickmarkr";
|
|
15
15
|
const doctorJsonRef = (stateDir) => ` — see ${stateDir}/doctor.json`;
|
|
16
16
|
export const ttyVisual = () => process.stdout.isTTY === true && process.env.NO_COLOR === undefined;
|
|
17
17
|
const adapterHasAuthedChannel = (adapterId, shape, cfg, health, adapters) => {
|
package/dist/adapters/prompt.js
CHANGED
|
@@ -18,7 +18,7 @@ ${task.files.length ? `\n## File scope — touch ONLY paths matching:\n${list(ta
|
|
|
18
18
|
- Do not ask questions; you are unattended. Make the smallest correct change.
|
|
19
19
|
${feedback ? `\n## Previous attempt failed gates — fix these specifically\n${feedback}\n` : ""}
|
|
20
20
|
When finished, end your final message with exactly one line (no code fence):
|
|
21
|
-
|
|
21
|
+
TICKMARKR_RESULT_${nonce} {"ok":true|false,"summary":"<one sentence>","deviations":["<path or reason>"]}
|
|
22
22
|
`;
|
|
23
23
|
}
|
|
24
24
|
export function writePrompt(dir, task, attempt, feedback = "", nonce = "") {
|
|
@@ -31,26 +31,21 @@ export function writePrompt(dir, task, attempt, feedback = "", nonce = "") {
|
|
|
31
31
|
// across lines by a TUI renderer ([\s\S] bridges newlines between tokens) — but never the template
|
|
32
32
|
// line above, whose literal `true|false` is not a bool followed by , or }. v1.4: the run-tagged nonce
|
|
33
33
|
// anchors it so displayed source/diffs (which can't know the nonce) can never premature-harvest.
|
|
34
|
-
// v1.16 (REN-02): dual-parse — accepts both the new marker spelling and the legacy alternation, so a
|
|
35
|
-
// worker/fixture still emitting the old marker keeps parsing through the rename.
|
|
36
34
|
export function trailerPattern(nonce) {
|
|
37
|
-
return `
|
|
35
|
+
return `TICKMARKR_RESULT_${nonce} \\{[\\s\\S]{0,120}?"ok":\\s*(true|false)\\s*[,}]`;
|
|
38
36
|
}
|
|
39
|
-
// all start positions of either marker spelling, ascending — merged so "last occurrence" and
|
|
40
|
-
// "scan backward for the first parseable one" work identically across both spellings.
|
|
41
37
|
function trailerTokenPositions(raw, nonce) {
|
|
38
|
+
const token = `TICKMARKR_RESULT_${nonce}`;
|
|
42
39
|
const positions = [];
|
|
43
|
-
for (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return positions.sort((a, b) => a - b);
|
|
40
|
+
for (let i = raw.indexOf(token); i !== -1; i = raw.indexOf(token, i + 1))
|
|
41
|
+
positions.push(i);
|
|
42
|
+
return positions;
|
|
48
43
|
}
|
|
49
44
|
export function parseWorkerResult(raw, nonce) {
|
|
50
45
|
const fail = (summary) => ({ ok: false, summary, deviations: [], raw });
|
|
51
46
|
const positions = trailerTokenPositions(raw, nonce);
|
|
52
47
|
if (positions.length === 0)
|
|
53
|
-
return fail("worker produced no
|
|
48
|
+
return fail("worker produced no TICKMARKR_RESULT trailer");
|
|
54
49
|
// TUIs echo the prompt template, redraw lines, and HARD-wrap the JSON with per-line margins
|
|
55
50
|
// (cursor does; recent-unwrapped can't rejoin hard newlines). Scan occurrences backward — last
|
|
56
51
|
// parseable wins — joining wrapped lines, stripping margin/box chrome, and growing the candidate
|
|
@@ -80,5 +75,5 @@ export function parseWorkerResult(raw, nonce) {
|
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
77
|
}
|
|
83
|
-
return fail("unparseable
|
|
78
|
+
return fail("unparseable TICKMARKR_RESULT trailer");
|
|
84
79
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type TickmarkrConfig } from "../config/config.js";
|
|
2
2
|
import { type RoutingProfile } from "../route/profile.js";
|
|
3
3
|
import { type AuthHealth, type BillingChannel, type WorkerAdapter } from "./types.js";
|
|
4
4
|
export declare function allAdapters(opts?: {
|
|
@@ -14,20 +14,20 @@ export interface AutoPreferDoc {
|
|
|
14
14
|
}
|
|
15
15
|
export declare const pendingAutoPreferKey: unique symbol;
|
|
16
16
|
export declare const DOCTOR_ROUTING_STALE_MS: number;
|
|
17
|
-
export declare function deriveAutoPrefer(cfg:
|
|
17
|
+
export declare function deriveAutoPrefer(cfg: TickmarkrConfig, adapters: WorkerAdapter[], health: Record<string, AuthHealth>, profile?: RoutingProfile): AutoPreferDoc;
|
|
18
18
|
export declare function readAutoPrefer(repoRoot: string): AutoPreferDoc | null;
|
|
19
|
-
export declare function routingPreferContext(repoRoot: string, cfg:
|
|
19
|
+
export declare function routingPreferContext(repoRoot: string, cfg: TickmarkrConfig, opts?: {
|
|
20
20
|
globalDir?: string;
|
|
21
21
|
}): {
|
|
22
22
|
autoPrefer?: AutoPreferDoc;
|
|
23
23
|
doctorFresh: boolean;
|
|
24
24
|
overlayPreferShapes: ReadonlySet<string>;
|
|
25
25
|
};
|
|
26
|
-
export declare function probeModels(cfg:
|
|
26
|
+
export declare function probeModels(cfg: TickmarkrConfig, repoRoot: string, adapters: WorkerAdapter[], health: Record<string, AuthHealth>, onProgress?: ProbeModelProgress): Promise<void>;
|
|
27
27
|
export declare function writeDoctor(repoRoot: string, health: Record<string, AuthHealth>): void;
|
|
28
28
|
export declare function readDoctor(repoRoot: string): Record<string, AuthHealth> | null;
|
|
29
|
-
export declare function discoverChannels(cfg:
|
|
30
|
-
export declare function servableExclusions(cfg:
|
|
29
|
+
export declare function discoverChannels(cfg: TickmarkrConfig, adapters: WorkerAdapter[], health: Record<string, AuthHealth>): BillingChannel[];
|
|
30
|
+
export declare function servableExclusions(cfg: TickmarkrConfig, adapters: WorkerAdapter[], health: Record<string, AuthHealth>): {
|
|
31
31
|
key: string;
|
|
32
32
|
adapter: string;
|
|
33
33
|
}[];
|
|
@@ -35,7 +35,7 @@ export declare function servabilityLine(excluded: {
|
|
|
35
35
|
key: string;
|
|
36
36
|
adapter: string;
|
|
37
37
|
}[]): string;
|
|
38
|
-
export declare function modelAuthExclusions(cfg:
|
|
38
|
+
export declare function modelAuthExclusions(cfg: TickmarkrConfig, adapters: WorkerAdapter[], health: Record<string, AuthHealth>): {
|
|
39
39
|
key: string;
|
|
40
40
|
adapter: string;
|
|
41
41
|
reason: string;
|
|
@@ -54,6 +54,6 @@ export declare function initDoctorReuse(repoRoot: string, fresh: boolean): {
|
|
|
54
54
|
ageMs: number | null;
|
|
55
55
|
health: Record<string, AuthHealth> | null;
|
|
56
56
|
};
|
|
57
|
-
export declare function formatDoctorReport(cwd: string, cfg:
|
|
57
|
+
export declare function formatDoctorReport(cwd: string, cfg: TickmarkrConfig, health: Record<string, AuthHealth>, adapters: WorkerAdapter[], opts?: {
|
|
58
58
|
wrote?: boolean;
|
|
59
59
|
}): string;
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { overlayPreferShapes, TIER_RANK } from "../config/config.js";
|
|
5
5
|
import { modelLints, suggestOverlay } from "./model-lints.js";
|
|
6
6
|
import { HerdrDriver } from "../drivers/herdr.js";
|
|
7
|
-
import {
|
|
7
|
+
import { tickmarkrDir, stateDirName } from "../graph/graph.js";
|
|
8
8
|
import { disallowedBy, excludedChannels, exclusionLine, preferRanks } from "../route/preference.js";
|
|
9
9
|
import { learnedScore } from "../route/profile.js";
|
|
10
10
|
import { marginalCostRank } from "../route/router.js";
|
|
@@ -22,7 +22,7 @@ export function allAdapters(opts = {}) {
|
|
|
22
22
|
// keeps the Phase 6 shape→channel matrix byte-identical; inserting anywhere else silently
|
|
23
23
|
// reassigns shapes on same-tier ties. grok is appended AFTER pi for the same reason.
|
|
24
24
|
const real = [claudeCode, codex, cursorAgent, opencode, pi, grok];
|
|
25
|
-
const fakePath = opts.fakeScriptPath ?? process.env.
|
|
25
|
+
const fakePath = opts.fakeScriptPath ?? process.env.TICKMARKR_FAKE_SCRIPT;
|
|
26
26
|
return fakePath ? [new FakeAdapter(fakePath), ...real] : real;
|
|
27
27
|
}
|
|
28
28
|
export function getAdapter(id, adapters) {
|
|
@@ -131,7 +131,7 @@ export async function probeModels(cfg, repoRoot, adapters, health, onProgress) {
|
|
|
131
131
|
verdict = { authed: false, reason: "headless probe unavailable", probedAt, durationMs: Date.now() - t0 };
|
|
132
132
|
}
|
|
133
133
|
else {
|
|
134
|
-
const promptFile = join(mkdtempSync(join(tmpdir(), "
|
|
134
|
+
const promptFile = join(mkdtempSync(join(tmpdir(), "tickmarkr-auth-")), "probe.md");
|
|
135
135
|
writeFileSync(promptFile, MODEL_PROBE_PROMPT);
|
|
136
136
|
const r = await sh(a.headlessCommand(promptFile, model), probeRoot, MODEL_PROBE_TIMEOUT_MS);
|
|
137
137
|
if (r.timedOut && priorTimedOut) {
|
|
@@ -181,7 +181,7 @@ function readDoctorFile(repoRoot) {
|
|
|
181
181
|
return existsSync(doctorPath(repoRoot)) ? JSON.parse(readFileSync(doctorPath(repoRoot), "utf8")) : null;
|
|
182
182
|
}
|
|
183
183
|
export function writeDoctor(repoRoot, health) {
|
|
184
|
-
|
|
184
|
+
tickmarkrDir(repoRoot);
|
|
185
185
|
const pending = health[pendingAutoPreferKey];
|
|
186
186
|
const payload = { ...health };
|
|
187
187
|
delete payload[pendingAutoPreferKey];
|
|
@@ -327,7 +327,7 @@ export function formatDoctorReport(cwd, cfg, health, adapters, opts = {}) {
|
|
|
327
327
|
let drift = "";
|
|
328
328
|
if (frag) {
|
|
329
329
|
if (visual) {
|
|
330
|
-
const overlayPath = join(
|
|
330
|
+
const overlayPath = join(tickmarkrDir(cwd), "doctor-overlay.yaml");
|
|
331
331
|
writeFileSync(overlayPath, frag);
|
|
332
332
|
drift = `\nmodel drift: unclassified models detected — paste-ready overlay written to ${overlayPath} (advisory; tickmarkr never applies it)`;
|
|
333
333
|
}
|
package/dist/adapters/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import type {
|
|
2
|
+
import type { TickmarkrConfig, Tier } from "../config/config.js";
|
|
3
3
|
import type { Task } from "../graph/schema.js";
|
|
4
4
|
export declare const TokenUsageSchema: z.ZodObject<{
|
|
5
5
|
input: z.ZodNumber;
|
|
@@ -74,7 +74,7 @@ export interface WorkerAdapter {
|
|
|
74
74
|
vendor: string;
|
|
75
75
|
probeCwd?: "repo" | "neutral";
|
|
76
76
|
probe(): Promise<AuthHealth>;
|
|
77
|
-
channels(cfg:
|
|
77
|
+
channels(cfg: TickmarkrConfig): BillingChannel[];
|
|
78
78
|
headlessCommand(promptFile: string, model: string): string;
|
|
79
79
|
interactiveCommand(promptFile: string, model: string): string | null;
|
|
80
80
|
resumeCommand?(sessionId: string, promptFile: string, model: string): string;
|
|
@@ -89,7 +89,7 @@ export interface WorkerAdapter {
|
|
|
89
89
|
trust?(repoRoot: string): TrustVerdict;
|
|
90
90
|
trustDialog?: TrustDialog;
|
|
91
91
|
}
|
|
92
|
-
export declare function channelsFromConfig(adapterId: string, cfg:
|
|
92
|
+
export declare function channelsFromConfig(adapterId: string, cfg: TickmarkrConfig): BillingChannel[];
|
|
93
93
|
export declare function channelKey(c: {
|
|
94
94
|
adapter: string;
|
|
95
95
|
model: string;
|
package/dist/brand.d.ts
ADDED
package/dist/brand.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// TTY-only pixel-tick logo (assets/mark.svg is the image twin — same block geometry).
|
|
2
|
+
// Never printed to pipes — the non-TTY stdout surface is byte-pinned by tests and consumed by machines.
|
|
3
|
+
const B = "\x1b[1m", R = "\x1b[0m";
|
|
4
|
+
const g = (n, s) => `\x1b[38;5;${n}m${s}${R}`; // 256-color green ramp, bright → deep
|
|
5
|
+
export const BANNER = [
|
|
6
|
+
` ${g(84, "▄▄████")}`,
|
|
7
|
+
` ${g(78, "▄▄████▀▀")}`,
|
|
8
|
+
`${g(41, "████▄▄▄▄████▀▀")} ${B}tickmarkr${R}`,
|
|
9
|
+
` ${g(35, "▀▀████▀▀")} spec in, verified work out.`,
|
|
10
|
+
"",
|
|
11
|
+
].join("\n");
|
|
12
|
+
// Shell one-liner that prints the banner inside a pane before a gate command runs. ESC bytes are
|
|
13
|
+
// carried as printf %b escapes (never raw control bytes in a command string crossing the herdr socket).
|
|
14
|
+
export function bannerShell() {
|
|
15
|
+
const printable = BANNER.replaceAll("\x1b", "\\033").replaceAll("\n", "\\n");
|
|
16
|
+
return `printf '%b\\n' '${printable}'`;
|
|
17
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { userInfo } from "node:os";
|
|
2
2
|
import { ATTEMPT_CAP_RELEASE, Journal } from "../../run/journal.js";
|
|
3
|
-
// GATE-08 (v1.12): approve a parked human gate so the next `
|
|
3
|
+
// GATE-08 (v1.12): approve a parked human gate so the next `tickmarkr resume <runId>` dispatches it.
|
|
4
4
|
//
|
|
5
5
|
// The approval is a JOURNAL EVENT (task-approved) carrying who and when — it touches ONLY the
|
|
6
|
-
// append-only journal. Writing it into
|
|
6
|
+
// append-only journal. Writing it into tickmarkr's compiled graph artifact would be silently erased by
|
|
7
7
|
// the next recompile (which re-emits humanGate:true from the plan frontmatter) — Phase 42 D-02.
|
|
8
8
|
//
|
|
9
9
|
// v1.24 OBS-18: when the park was attempt-cap (not a humanGate pre-dispatch park), the event also
|
|
@@ -13,7 +13,7 @@ import { ATTEMPT_CAP_RELEASE, Journal } from "../../run/journal.js";
|
|
|
13
13
|
//
|
|
14
14
|
// Fail-closed (D-05): unknown runId, unknown taskId, a not-parked task, and a double-approve are all
|
|
15
15
|
// LOUD refusals that name the reason and append NO event — never a silent no-op. A handler throw
|
|
16
|
-
// becomes `
|
|
16
|
+
// becomes `tickmarkr approve: <message>` at exit 1 (src/cli/index.ts dispatch).
|
|
17
17
|
//
|
|
18
18
|
// Who/when is truthful, not dressed-up auth (D-03): default actor os.userInfo().username; --by overrides
|
|
19
19
|
// for delegated approval; optional --reason; the event's ts (stamped by Journal.append) is the when.
|
|
@@ -18,7 +18,7 @@ export async function compile(argv, cwd = process.cwd()) {
|
|
|
18
18
|
// as a second daemon. Read-only check — compile never acquires/holds (it's instantaneous).
|
|
19
19
|
const stateDir = stateDirName(cwd);
|
|
20
20
|
if (isRunLockLive(cwd))
|
|
21
|
-
throw new Error(`${stateDir}/graph.lock is held by another
|
|
21
|
+
throw new Error(`${stateDir}/graph.lock is held by another tickmarkr run, or is a stale/garbage lock — refusing to overwrite graph.json. If no run is active, run \`tickmarkr unlock\`.`);
|
|
22
22
|
saveGraph(cwd, g);
|
|
23
23
|
return `compiled ${src} → ${stateDir}/graph.json (${g.tasks.length} tasks, source ${g.spec.source}, hash ${g.spec.hash.slice(0, 12)})`;
|
|
24
24
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { allAdapters, probeAll, probeModels, readAutoPrefer, servableExclusions, servabilityLine, writeDoctor } from "../../adapters/registry.js";
|
|
4
|
-
import {
|
|
4
|
+
import { tickmarkrDir, stateDirName } from "../../graph/graph.js";
|
|
5
5
|
import { modelLints, suggestOverlay, ttyVisual } from "../../adapters/model-lints.js";
|
|
6
6
|
import { DEFAULT_CONFIG, loadConfig, overlayPreferShapes } from "../../config/config.js";
|
|
7
7
|
import { HerdrDriver } from "../../drivers/herdr.js";
|
|
@@ -99,14 +99,14 @@ export async function doctor(_argv, cwd = process.cwd(), adapters = allAdapters(
|
|
|
99
99
|
const servable = servableExclusions(cfg, adapters, health);
|
|
100
100
|
if (servable.length)
|
|
101
101
|
rows.push(` ! ${servabilityLine(servable)}`);
|
|
102
|
-
// MODEL-05/06: print-only drift fragment; advisory, whole-line-commented additions,
|
|
102
|
+
// MODEL-05/06: print-only drift fragment; advisory, whole-line-commented additions, tickmarkr NEVER applies it.
|
|
103
103
|
// TTY gets a one-line summary + the fragment as a file (the full dump drowned everything else,
|
|
104
104
|
// v1.33.1 onboarding); machine/CI surface keeps the inline dump — layout is pinned by tests.
|
|
105
105
|
const frag = suggestOverlay(cfg, health, adapters, stateDirName(cwd));
|
|
106
106
|
let drift = "";
|
|
107
107
|
if (frag) {
|
|
108
108
|
if (visual()) {
|
|
109
|
-
const overlayPath = join(
|
|
109
|
+
const overlayPath = join(tickmarkrDir(cwd), "doctor-overlay.yaml");
|
|
110
110
|
writeFileSync(overlayPath, frag);
|
|
111
111
|
drift = `\nmodel drift: unclassified models detected — paste-ready overlay written to ${overlayPath} (advisory; tickmarkr never applies it)`;
|
|
112
112
|
}
|
|
@@ -4,8 +4,8 @@ import { createInterface } from "node:readline/promises";
|
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import { allAdapters, formatDoctorAgeForInit, formatDoctorReport, initDoctorReuse } from "../../adapters/registry.js";
|
|
6
6
|
import { configTemplate, DEFAULT_CONFIG, globalConfigDir, loadConfig } from "../../config/config.js";
|
|
7
|
-
import { specTemplate } from "../../compile/native.js";
|
|
8
|
-
import {
|
|
7
|
+
import { LEGACY_PREFIX, specTemplate } from "../../compile/native.js";
|
|
8
|
+
import { tickmarkrDir } from "../../graph/graph.js";
|
|
9
9
|
import { doctor } from "./doctor.js";
|
|
10
10
|
const AGENT_SKILLS = ["tickmarkr-loop", "tickmarkr-auto"];
|
|
11
11
|
const DOCS_BEGIN = "<!-- tickmarkr:agent-docs begin -->";
|
|
@@ -52,7 +52,8 @@ async function installAgentFiles(cwd, force, docs, notes) {
|
|
|
52
52
|
const agents = join(cwd, "AGENTS.md");
|
|
53
53
|
const docPath = existsSync(claude) || !existsSync(agents) ? claude : agents;
|
|
54
54
|
const current = existsSync(docPath) ? readFileSync(docPath, "utf8") : "";
|
|
55
|
-
if (current.includes(DOCS_BEGIN) || current.includes(
|
|
55
|
+
if (current.includes(DOCS_BEGIN) || current.includes(`<!-- ${LEGACY_PREFIX}:agent-docs begin -->`)
|
|
56
|
+
|| current.includes(DOCS_END) || current.includes(`<!-- ${LEGACY_PREFIX}:agent-docs end -->`)) {
|
|
56
57
|
notes.push(`kept existing tickmarkr agent docs in ${docPath}`);
|
|
57
58
|
}
|
|
58
59
|
else if (docs || await confirm(`Append tickmarkr agent docs to ${docPath}?`)) {
|
|
@@ -126,7 +127,7 @@ export async function init(argv, cwd = process.cwd()) {
|
|
|
126
127
|
else {
|
|
127
128
|
notes.push(`kept existing ${globalPath}`);
|
|
128
129
|
}
|
|
129
|
-
const repoConfigPath = join(
|
|
130
|
+
const repoConfigPath = join(tickmarkrDir(cwd), "config.yaml");
|
|
130
131
|
const repoConfigExists = existsSync(repoConfigPath);
|
|
131
132
|
if (repoConfigExists)
|
|
132
133
|
notes.push(`kept existing ${repoConfigPath}`);
|
|
@@ -134,12 +135,16 @@ export async function init(argv, cwd = process.cwd()) {
|
|
|
134
135
|
if (existsSync(specPath)) {
|
|
135
136
|
notes.push(`kept existing ${specPath}`);
|
|
136
137
|
}
|
|
137
|
-
else if (existsSync(join(cwd, "drovr.spec.md"))) {
|
|
138
|
-
notes.push(`kept existing ${join(cwd, "drovr.spec.md")}`);
|
|
139
|
-
}
|
|
140
138
|
else {
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
const legacySpec = join(cwd, `${LEGACY_PREFIX}.spec.md`);
|
|
140
|
+
if (existsSync(legacySpec)) {
|
|
141
|
+
writeFileSync(specPath, readFileSync(legacySpec, "utf8"));
|
|
142
|
+
notes.push(`wrote ${specPath}`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
writeFileSync(specPath, specTemplate());
|
|
146
|
+
notes.push(`wrote ${specPath}`);
|
|
147
|
+
}
|
|
143
148
|
}
|
|
144
149
|
const fresh = values.fresh ?? false;
|
|
145
150
|
const { reuse, ageMs, health } = initDoctorReuse(cwd, fresh);
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { loadConfig } from "../../config/config.js";
|
|
4
|
-
import {
|
|
4
|
+
import { tickmarkrDir, stateDirName } from "../../graph/graph.js";
|
|
5
5
|
import { learnedScore, MIN_SAMPLES, cellsOf } from "../../route/profile.js";
|
|
6
6
|
import { Journal, loadRoutingProfile, readProfileCursor, RUNS_WINDOW } from "../../run/journal.js";
|
|
7
|
-
//
|
|
7
|
+
// tickmarkr profile — inspect (show) and forget (reset) the derived learned-routing profile (VIS-03).
|
|
8
8
|
// Read-only class like plan/status/report: no run lock. `reset` writes ONE cursor scalar, nothing else.
|
|
9
9
|
export async function profile(argv, cwd = process.cwd()) {
|
|
10
10
|
return argv[0] === "reset" ? reset(cwd) : show(cwd);
|
|
11
11
|
}
|
|
12
|
-
// Non-destructive reset (T-13-06): a one-line runId cutoff at .
|
|
12
|
+
// Non-destructive reset (T-13-06): a one-line runId cutoff at .tickmarkr/profile-since. NEVER deletes,
|
|
13
13
|
// truncates, or rotates any telemetry — the profile is derived (PROF-01), so there is nothing to delete;
|
|
14
|
-
// the cursor only bounds loadRoutingProfile's telemetry window.
|
|
14
|
+
// the cursor only bounds loadRoutingProfile's telemetry window. tickmarkrDir guarantees .tickmarkr exists and
|
|
15
15
|
// blanket-gitignores it, so the cursor is never git-addable. Opaque string: used only in a runId > compare.
|
|
16
16
|
function reset(cwd) {
|
|
17
17
|
const cursor = Journal.latestRunId(cwd) ?? ""; // empty repo ⇒ empty cursor ⇒ readProfileCursor === undefined
|
|
18
18
|
const stateDir = stateDirName(cwd);
|
|
19
|
-
const path = join(
|
|
19
|
+
const path = join(tickmarkrDir(cwd), "profile-since");
|
|
20
20
|
writeFileSync(path, cursor + "\n");
|
|
21
21
|
return [
|
|
22
22
|
cursor
|
|
@@ -27,7 +27,7 @@ function reset(cwd) {
|
|
|
27
27
|
].join("\n");
|
|
28
28
|
}
|
|
29
29
|
// Inspection surface: preview:true bypasses the routing.learned:off short-circuit so `show` renders the
|
|
30
|
-
// profile even under the default off — same trust ramp as `
|
|
30
|
+
// profile even under the default off — same trust ramp as `tickmarkr plan`. The routing path stays inert.
|
|
31
31
|
function show(cwd) {
|
|
32
32
|
const cfg = loadConfig(cwd);
|
|
33
33
|
const cursor = readProfileCursor(cwd);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BANNER } from "../../brand.js";
|
|
1
2
|
import { blockedTasks, loadGraph, pendingTasks } from "../../graph/graph.js";
|
|
2
3
|
import { GATE_NAMES } from "../../graph/schema.js";
|
|
3
4
|
import { Journal } from "../../run/journal.js";
|
|
@@ -211,7 +212,7 @@ export async function status(argv, cwd = process.cwd(), opts = {}) {
|
|
|
211
212
|
for (let i = 0; i < iterations; i++) {
|
|
212
213
|
const frame = renderFrame(cwd);
|
|
213
214
|
if (tty)
|
|
214
|
-
process.stdout.write(`\x1b[2J\x1b[H${frame}\n\x1b[2m watching · refresh ${REFRESH_MS / 1000}s · ^C to quit\x1b[0m`);
|
|
215
|
+
process.stdout.write(`\x1b[2J\x1b[H${BANNER}${frame}\n\x1b[2m watching · refresh ${REFRESH_MS / 1000}s · ^C to quit\x1b[0m`);
|
|
215
216
|
else
|
|
216
217
|
process.stdout.write(frame + sep);
|
|
217
218
|
if (bounded)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { unlockRun } from "../../run/lock.js";
|
|
2
2
|
// LOCK-03: thin formatter over unlockRun. A live-holder refusal propagates as the throw — the
|
|
3
|
-
// dispatcher prints `
|
|
3
|
+
// dispatcher prints `tickmarkr unlock: …` and exits 1 (src/cli/index.ts).
|
|
4
4
|
export async function unlock(_argv, cwd = process.cwd()) {
|
|
5
5
|
const r = unlockRun(cwd);
|
|
6
6
|
if (!r.held)
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export type CommandMap = Record<string, (argv: string[]) => Promise<string>>;
|
|
3
3
|
export declare const COMMANDS: CommandMap;
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const USAGE = "tickmarkr \u2014 spec-driven orchestration harness for AI coding agents\nusage: tickmarkr <command>\n init guided setup + doctor; init --agent [--force] [--docs] adds agent skills/docs\n doctor re-probe adapters, herdr, auth; print capability matrix\n compile <src> spec \u2192 .drovr/graph.json (fails without acceptance criteria)\n scope <intent> draft a compiled native spec beside an answered intent (--force to overwrite)\n plan dry-run routing table + cost estimate + floor lints\n run execute the graph (--concurrency N --driver herdr|subprocess --route-strict)\n status live run state\n resume <id> continue a run from its journal\n report <id> cost/quality report (--md for committable execution record)\n profile show learned routing profile (profile reset = forget history via cursor, keeps telemetry)\n unlock remove a stale/garbage run lock (refuses if the holder is alive)\n approve <id> <task> approve a parked human gate (--by <name> --reason <text>); takes effect on resume";
|
|
4
|
+
export declare const USAGE = "tickmarkr \u2014 spec-driven orchestration harness for AI coding agents\nusage: tickmarkr <command>\n init guided setup + doctor; init --agent [--force] [--docs] adds agent skills/docs\n doctor re-probe adapters, herdr, auth; print capability matrix\n compile <src> spec \u2192 .tickmarkr/graph.json (fails without acceptance criteria)\n scope <intent> draft a compiled native spec beside an answered intent (--force to overwrite)\n plan dry-run routing table + cost estimate + floor lints\n run execute the graph (--concurrency N --driver herdr|subprocess --route-strict)\n status live run state\n resume <id> continue a run from its journal\n report <id> cost/quality report (--md for committable execution record)\n profile show learned routing profile (profile reset = forget history via cursor, keeps telemetry)\n unlock remove a stale/garbage run lock (refuses if the holder is alive)\n approve <id> <task> approve a parked human gate (--by <name> --reason <text>); takes effect on resume";
|
|
6
5
|
export declare function dispatch(cmd: string | undefined, argv: string[], commands?: CommandMap): Promise<{
|
|
7
6
|
out: string;
|
|
8
7
|
code: number;
|