tickmarkr 2.6.0 → 2.6.1
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/dist/adapters/prompt.d.ts +2 -1
- package/dist/adapters/prompt.js +10 -0
- package/dist/adapters/types.d.ts +1 -0
- package/dist/adapters/types.js +10 -0
- package/dist/cli/commands/fleet.js +26 -1
- package/dist/cli/commands/plan.js +7 -3
- package/dist/cli/commands/status.js +13 -3
- package/dist/cli/help.d.ts +2 -0
- package/dist/cli/help.js +2 -0
- package/dist/drivers/orca.js +6 -1
- package/dist/gates/cache.d.ts +3 -1
- package/dist/gates/cache.js +10 -3
- package/dist/gates/llm.js +4 -1
- package/dist/gates/review.js +7 -11
- package/dist/gates/run-gates.d.ts +4 -0
- package/dist/gates/run-gates.js +7 -4
- package/dist/gates/test-manifest.d.ts +12 -0
- package/dist/gates/test-manifest.js +26 -6
- package/dist/graph/graph.d.ts +6 -2
- package/dist/graph/graph.js +15 -4
- package/dist/route/role-pick.d.ts +16 -0
- package/dist/route/role-pick.js +15 -0
- package/dist/route/router.d.ts +14 -0
- package/dist/route/router.js +9 -1
- package/dist/run/consult.js +5 -9
- package/dist/run/daemon.d.ts +9 -0
- package/dist/run/daemon.js +395 -59
- package/dist/run/git.d.ts +36 -1
- package/dist/run/git.js +89 -5
- package/dist/run/host-health.d.ts +20 -0
- package/dist/run/host-health.js +64 -0
- package/dist/run/journal.js +9 -0
- package/dist/run/operator-state.d.ts +24 -2
- package/dist/run/operator-state.js +41 -5
- package/dist/run/stall.d.ts +38 -2
- package/dist/run/stall.js +276 -6
- package/dist/tui/cockpit/board.d.ts +1 -1
- package/dist/tui/cockpit/board.js +27 -19
- package/dist/tui/cockpit/derive.d.ts +2 -0
- package/dist/tui/cockpit/derive.js +4 -0
- package/dist/tui/cockpit/live-store.d.ts +1 -0
- package/dist/tui/cockpit/live-store.js +31 -8
- package/dist/tui/cockpit/run-cockpit.js +2 -1
- package/dist/tui/cockpit/run-view.d.ts +2 -4
- package/dist/tui/cockpit/run-view.js +9 -8
- package/package.json +1 -1
- package/skills/tickmarkr-overseer/SKILL.md +43 -6
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { discoverChannels } from "../adapters/registry.js";
|
|
2
|
+
import { rankPreferredChannels, reviewPreferenceTieBreak } from "./router.js";
|
|
3
|
+
export { preferIndex, rankPreferredChannels, reviewPreferenceTieBreak } from "./router.js";
|
|
4
|
+
/** Strict role selection: no task, author, pin, or default seat is invented. */
|
|
5
|
+
export function pickRole(role, cfg, adapters, health, opts = {}) {
|
|
6
|
+
// Worker preferences belong to shapes; judge currently has only an explicit pin.
|
|
7
|
+
const prefer = role === "review" ? cfg.review.prefer : role === "consult" ? cfg.consult.prefer : undefined;
|
|
8
|
+
if (!prefer?.length)
|
|
9
|
+
return { ok: false, reason: "missing-prefer" };
|
|
10
|
+
const pool = discoverChannels(cfg, adapters, health, role).filter((c) => !opts.excludeVendors?.has(c.vendor) && (opts.eligible?.(c) ?? true));
|
|
11
|
+
const channel = rankPreferredChannels(pool, prefer, {
|
|
12
|
+
tieBreak: role === "review" ? reviewPreferenceTieBreak : undefined,
|
|
13
|
+
})[0];
|
|
14
|
+
return channel ? { ok: true, channel } : { ok: false, reason: "no-eligible-preferred-channel" };
|
|
15
|
+
}
|
package/dist/route/router.d.ts
CHANGED
|
@@ -31,6 +31,19 @@ export declare class RoutingError extends Error {
|
|
|
31
31
|
constructor(msg: string);
|
|
32
32
|
}
|
|
33
33
|
export declare function marginalCostRank(c: BillingChannel): number;
|
|
34
|
+
type ChannelSeat = {
|
|
35
|
+
adapter: string;
|
|
36
|
+
model: string;
|
|
37
|
+
};
|
|
38
|
+
/** Shared adapter | adapter:model grammar; unmatched channels follow every declared entry. */
|
|
39
|
+
export declare function preferIndex(c: ChannelSeat, prefer?: readonly string[]): number;
|
|
40
|
+
/** Rank an already eligible pool. Review alone retains its legacy unpreferred tail. */
|
|
41
|
+
export declare function rankPreferredChannels<C extends ChannelSeat>(channels: readonly C[], prefer?: readonly string[], opts?: {
|
|
42
|
+
includeUnpreferred?: boolean;
|
|
43
|
+
tieBreak?: (a: C, b: C) => number;
|
|
44
|
+
}): C[];
|
|
45
|
+
/** Review preserves its established tier-then-cost order inside a preference band. */
|
|
46
|
+
export declare const reviewPreferenceTieBreak: (a: BillingChannel, b: BillingChannel) => number;
|
|
34
47
|
export declare function route(task: Task, cfg: TickmarkrConfig, channels: BillingChannel[], profile?: RoutingProfile, preferCtx?: RoutingPreferContext, exclude?: ReadonlySet<string>, exploreCtx?: ExploreContext): Route;
|
|
35
48
|
export declare function nextChannel(current: Assignment, task: Task, cfg: TickmarkrConfig, channels: BillingChannel[], tried: string[], profile?: RoutingProfile, exclude?: ReadonlySet<string>): Assignment | null;
|
|
36
49
|
export type ClimbPick = Assignment & {
|
|
@@ -46,3 +59,4 @@ export type ClimbResult = ClimbPick;
|
|
|
46
59
|
* returns nextChannel's same-or-higher pick flagged climbed: false naming the reason.
|
|
47
60
|
*/
|
|
48
61
|
export declare function climbChannel(current: Assignment, task: Task, cfg: TickmarkrConfig, channels: BillingChannel[], tried: string[], profile?: RoutingProfile, exclude?: ReadonlySet<string>): ClimbPick | null;
|
|
62
|
+
export {};
|
package/dist/route/router.js
CHANGED
|
@@ -52,10 +52,18 @@ function resolvePin(pin, channels) {
|
|
|
52
52
|
}
|
|
53
53
|
return c;
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
/** Shared adapter | adapter:model grammar; unmatched channels follow every declared entry. */
|
|
56
|
+
export function preferIndex(c, prefer = []) {
|
|
56
57
|
const i = prefer.findIndex((p) => p === c.adapter || p === channelKey(c));
|
|
57
58
|
return i === -1 ? prefer.length : i;
|
|
58
59
|
}
|
|
60
|
+
/** Rank an already eligible pool. Review alone retains its legacy unpreferred tail. */
|
|
61
|
+
export function rankPreferredChannels(channels, prefer = [], opts = {}) {
|
|
62
|
+
return channels.filter((c) => opts.includeUnpreferred || preferIndex(c, prefer) < prefer.length)
|
|
63
|
+
.sort((a, b) => preferIndex(a, prefer) - preferIndex(b, prefer) || opts.tieBreak?.(a, b) || 0);
|
|
64
|
+
}
|
|
65
|
+
/** Review preserves its established tier-then-cost order inside a preference band. */
|
|
66
|
+
export const reviewPreferenceTieBreak = (a, b) => TIER_RANK[b.tier] - TIER_RANK[a.tier] || Number(a.channel === "api") - Number(b.channel === "api");
|
|
59
67
|
function ladderFor(task, entry) {
|
|
60
68
|
const escalate = task.routingHints?.escalate ?? entry?.escalate ?? true;
|
|
61
69
|
return escalate ? ["retry", "escalate", "consult", "human"] : ["retry", "consult", "human"];
|
package/dist/run/consult.js
CHANGED
|
@@ -4,6 +4,7 @@ import { getAdapter } from "../adapters/registry.js";
|
|
|
4
4
|
import { bannerShell, paneDispatchCommand } from "../brand.js";
|
|
5
5
|
import { dewrapPaneVerdict, extractVerdictJson, gateExitTrailer, gatePaneName, generateVerdictNonce, verdictNonceLine } from "../gates/llm.js";
|
|
6
6
|
import { classifyVerdictCause } from "../gates/verdict-cause.js";
|
|
7
|
+
import { rankPreferredChannels } from "../route/role-pick.js";
|
|
7
8
|
import { disallowedBy, routingModelProvider } from "../route/preference.js";
|
|
8
9
|
import { sh } from "./git.js";
|
|
9
10
|
import { redactSecrets } from "./redact.js";
|
|
@@ -212,15 +213,10 @@ opts = {}) {
|
|
|
212
213
|
}
|
|
213
214
|
return parsed;
|
|
214
215
|
};
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// only WHICH seat answers — per-seat parsing and the fail-safe human action below are untouched.
|
|
220
|
-
const live = new Set((opts.channels ?? []).map((c) => c.adapter));
|
|
221
|
-
const seats = (cfg.consult.prefer ?? [])
|
|
222
|
-
.map((entry) => ({ adapter: entry.slice(0, entry.indexOf(":")), model: entry.slice(entry.indexOf(":") + 1) }))
|
|
223
|
-
.filter((s) => live.has(s.adapter));
|
|
216
|
+
// Rank only exact live models from the daemon's role-scoped discovery pool.
|
|
217
|
+
// The explicit pin remains a caller-owned fallback, outside strict preference selection.
|
|
218
|
+
const live = (opts.channels ?? []).filter((c) => typeof c.model === "string");
|
|
219
|
+
const seats = rankPreferredChannels(live.filter((c) => disallowedBy(c, cfg.routing, "consult") === null), cfg.consult.prefer);
|
|
224
220
|
seats.push({ adapter: cfg.consult.adapter, model: cfg.consult.model });
|
|
225
221
|
// v1.87 T2: a consult seat reads the code, so it passes through the operator's policy exactly like
|
|
226
222
|
// a worker does. The filter runs AFTER the pin is pushed, so the final pinned seat is checked by
|
package/dist/run/daemon.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { type ExecutorDriver, type Slot } from "../drivers/types.js";
|
|
|
5
5
|
import { type Baseline } from "../gates/baseline.js";
|
|
6
6
|
import type { GateResult } from "../gates/types.js";
|
|
7
7
|
import { type RunGraph } from "../graph/schema.js";
|
|
8
|
+
import { type PreserveProducer } from "./git.js";
|
|
8
9
|
import { Journal, type JournalEvent } from "./journal.js";
|
|
9
10
|
export declare function closeLiveSlot(liveSlots: Set<Slot>, driver: Pick<ExecutorDriver, "close">, slot: Slot): Promise<void>;
|
|
10
11
|
/** Optional authoritative transport receipt. Screen text can prove execution, never nonacceptance. */
|
|
@@ -67,6 +68,7 @@ export interface RunSummary {
|
|
|
67
68
|
/** the accepted approvals that never reached a dispatch — named, never left to the park buckets */
|
|
68
69
|
outstandingApprovals?: string[];
|
|
69
70
|
}
|
|
71
|
+
export declare function pendingDaemonApprovalActions(events: JournalEvent[]): Map<string, import("./journal.js").PendingApprovalAction>;
|
|
70
72
|
/**
|
|
71
73
|
* T14, amended by v2.2 T3: approvals the run accepted and never acted on. `approved` above is still
|
|
72
74
|
* built ONCE at startup — replay determinism depends on it — but a live approval is no longer inert:
|
|
@@ -126,6 +128,9 @@ export declare const APPROVAL_POLL_MS = 250;
|
|
|
126
128
|
export declare const APPROVAL_WINDOW_MS = 120000;
|
|
127
129
|
export declare const setApprovalWindowForTests: (ms: number) => void;
|
|
128
130
|
export declare const resetApprovalWindowForTests: () => void;
|
|
131
|
+
/** Test seam — shrink the capacity backoff without minute-long sleeps. */
|
|
132
|
+
export declare function setCapacityBackoffMsForTests(ms: number): void;
|
|
133
|
+
export declare function resetCapacityBackoffMsForTests(): void;
|
|
129
134
|
export declare const EARLY_LAUNCH_LIVENESS_MS = 60000;
|
|
130
135
|
/** Test seam — lowers the empty-pane liveness window without sleeping 60s per case. */
|
|
131
136
|
export declare function setEarlyLaunchLivenessMsForTests(ms: number): void;
|
|
@@ -218,5 +223,9 @@ export declare function liveSuiteCount(repoRoot: string): Promise<number>;
|
|
|
218
223
|
/** Test seam — exercise the production observer's total read bound with a small real tree. */
|
|
219
224
|
export declare function setObserveBudgetBytesForTests(bytes: number): void;
|
|
220
225
|
export declare function resetObserveBudgetBytesForTests(): void;
|
|
226
|
+
/** The attempt whose worker last launched into the task's current checkout; "unknown" once a
|
|
227
|
+
* recreation replaced that tree without a new launch (recheck, gate-only restore) or when no
|
|
228
|
+
* dispatch assignment is on record. Never the newest dispatch by itself. */
|
|
229
|
+
export declare function knownProducer(events: readonly JournalEvent[], taskId: string): PreserveProducer;
|
|
221
230
|
export declare function recordFatalRunEnd(journal: Journal, runId: string, branch: string, err: unknown, graph?: RunGraph, phase?: string): TipProof | undefined;
|
|
222
231
|
export declare function runDaemon(repoRoot: string, opts?: RunOptions): Promise<RunSummary>;
|