@deftai/directive-core 0.93.0 → 0.95.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/dist/authz/classify.js +485 -0
- package/dist/cache/fetch.d.ts +29 -0
- package/dist/cache/fetch.js +131 -4
- package/dist/cache/operations.d.ts +8 -0
- package/dist/cache/operations.js +67 -4
- package/dist/check/cached-orchestrator.js +11 -0
- package/dist/check/consumer-gate-integrity.d.ts +68 -0
- package/dist/check/consumer-gate-integrity.js +265 -0
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/orchestrator.js +10 -0
- package/dist/content-contracts/skills/greptile-detector.d.ts +9 -0
- package/dist/content-contracts/skills/greptile-detector.js +9 -2
- package/dist/doctor/main.js +98 -9
- package/dist/doctor/types.d.ts +2 -2
- package/dist/finish-loop/pr-finish-loop.js +1 -0
- package/dist/freshness/bind.d.ts +67 -0
- package/dist/freshness/bind.js +201 -0
- package/dist/freshness/cli.d.ts +30 -0
- package/dist/freshness/cli.js +180 -0
- package/dist/freshness/compare.d.ts +14 -0
- package/dist/freshness/compare.js +134 -0
- package/dist/freshness/generation.d.ts +44 -0
- package/dist/freshness/generation.js +172 -0
- package/dist/freshness/index.d.ts +13 -0
- package/dist/freshness/index.js +13 -0
- package/dist/freshness/report.d.ts +43 -0
- package/dist/freshness/report.js +139 -0
- package/dist/freshness/types.d.ts +70 -0
- package/dist/freshness/types.js +30 -0
- package/dist/handoff-evidence/index.d.ts +8 -0
- package/dist/handoff-evidence/index.js +7 -0
- package/dist/handoff-evidence/validate.d.ts +105 -0
- package/dist/handoff-evidence/validate.js +423 -0
- package/dist/hooks/dispatcher.d.ts +27 -2
- package/dist/hooks/dispatcher.js +134 -14
- package/dist/hooks/readonly.d.ts +14 -0
- package/dist/hooks/readonly.js +126 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +5 -2
- package/dist/init-deposit/init-deposit.d.ts +7 -1
- package/dist/init-deposit/init-deposit.js +24 -4
- package/dist/init-deposit/refresh.d.ts +9 -1
- package/dist/init-deposit/refresh.js +48 -5
- package/dist/intake/issue-ingest.d.ts +20 -0
- package/dist/intake/issue-ingest.js +58 -0
- package/dist/policy/index.d.ts +4 -0
- package/dist/policy/index.js +50 -1
- package/dist/policy/min-greptile-confidence.d.ts +57 -0
- package/dist/policy/min-greptile-confidence.js +123 -0
- package/dist/pr-merge-readiness/compute.d.ts +11 -1
- package/dist/pr-merge-readiness/compute.js +17 -4
- package/dist/pr-merge-readiness/evaluate.d.ts +8 -1
- package/dist/pr-merge-readiness/evaluate.js +7 -4
- package/dist/pr-merge-readiness/mergeability.d.ts +7 -1
- package/dist/pr-merge-readiness/mergeability.js +14 -2
- package/dist/pr-monitor/main.d.ts +2 -0
- package/dist/pr-monitor/main.js +31 -1
- package/dist/pr-monitor/monitor.js +5 -1
- package/dist/pr-monitor/readiness.js +3 -1
- package/dist/pr-monitor/types.d.ts +8 -0
- package/dist/pr-wait-mergeable/cascade.d.ts +8 -0
- package/dist/pr-wait-mergeable/cascade.js +28 -1
- package/dist/pr-wait-mergeable/main.d.ts +2 -0
- package/dist/pr-wait-mergeable/main.js +16 -0
- package/dist/pr-wait-mergeable/types.d.ts +3 -1
- package/dist/pr-wait-mergeable/wrappers.d.ts +6 -0
- package/dist/pr-wait-mergeable/wrappers.js +3 -0
- package/dist/pr-watch/constants.d.ts +4 -1
- package/dist/pr-watch/constants.js +5 -2
- package/dist/pr-watch/main.js +1 -0
- package/dist/pr-watch/probe.d.ts +1 -1
- package/dist/pr-watch/probe.js +4 -1
- package/dist/pr-watch/types.d.ts +7 -1
- package/dist/pr-watch/watch.js +3 -2
- package/dist/release-e2e/greenfield-python-free-smoke.js +7 -3
- package/dist/review-monitor/index.d.ts +1 -0
- package/dist/review-monitor/index.js +1 -0
- package/dist/review-monitor/l4-owner.d.ts +46 -0
- package/dist/review-monitor/l4-owner.js +262 -0
- package/dist/session/ritual-entrypoint.d.ts +6 -2
- package/dist/session/ritual-entrypoint.js +15 -2
- package/dist/session/session-ready.js +31 -14
- package/dist/session/session-start.d.ts +2 -1
- package/dist/session/session-start.js +66 -3
- package/dist/session/verify-session-ritual.d.ts +4 -2
- package/dist/session/verify-session-ritual.js +11 -11
- package/dist/slash/product-set.js +4 -1
- package/dist/swarm/verify-review-clean.d.ts +4 -3
- package/dist/swarm/verify-review-clean.js +28 -73
- package/dist/tool-events/classify.js +1 -0
- package/dist/triage/classify/index.d.ts +9 -0
- package/dist/triage/classify/index.js +34 -2
- package/dist/triage/classify/label-mirror.d.ts +143 -0
- package/dist/triage/classify/label-mirror.js +684 -0
- package/dist/triage/help/registry-data.d.ts +7 -7
- package/dist/triage/help/registry-data.js +27 -7
- package/dist/triage/queue/show.d.ts +1 -1
- package/dist/triage/queue/show.js +4 -2
- package/dist/triage/welcome/writers.js +16 -7
- package/dist/umbrella-current-shape/index.d.ts +45 -0
- package/dist/umbrella-current-shape/index.js +162 -8
- package/dist/vbrief-reconcile/index.d.ts +2 -2
- package/dist/vbrief-reconcile/index.js +1 -1
- package/dist/vbrief-reconcile/types.d.ts +14 -0
- package/dist/vbrief-reconcile/umbrellas.d.ts +31 -2
- package/dist/vbrief-reconcile/umbrellas.js +231 -19
- package/dist/vbrief-validate/project-definition.js +1 -1
- package/dist/verify-env/agent-hook-readiness.d.ts +42 -0
- package/dist/verify-env/agent-hook-readiness.js +150 -0
- package/dist/verify-env/agent-hooks-live-probe.d.ts +16 -4
- package/dist/verify-env/agent-hooks-live-probe.js +120 -107
- package/dist/verify-env/agent-hooks.js +11 -3
- package/dist/verify-env/index.d.ts +1 -0
- package/dist/verify-env/index.js +1 -0
- package/package.json +7 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { evaluateIntentCeilingFromEnv } from "../policy/intent-ceiling.js";
|
|
2
2
|
import { evaluateAgentMerge, } from "../policy/require-human-merge.js";
|
|
3
|
+
import { reconcileUmbrellas, renderUmbrellasReport } from "../vbrief-reconcile/umbrellas.js";
|
|
3
4
|
import { classifyMonitorOutcome, parseMonitorPayload } from "./classify.js";
|
|
4
5
|
import { EXIT_CONFIG_ERROR, EXIT_MERGED, EXIT_TIMEOUT_OR_ESCALATION } from "./constants.js";
|
|
5
6
|
import { makeResult } from "./result.js";
|
|
@@ -12,6 +13,12 @@ function isProtectedCheckConfigFailure(stderr) {
|
|
|
12
13
|
tail.includes("Cannot find module") ||
|
|
13
14
|
tail.includes("protected-check script not found:"));
|
|
14
15
|
}
|
|
16
|
+
function defaultPostMergeUmbrellaReconcile(projectRoot, repo) {
|
|
17
|
+
const [, umOutcome] = reconcileUmbrellas(projectRoot, { repo });
|
|
18
|
+
if (umOutcome.changed.length > 0 || umOutcome.errors.length > 0) {
|
|
19
|
+
process.stderr.write(`${renderUmbrellasReport(umOutcome)}\n`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
15
22
|
/** Run protected-check -> wait -> merge cascade (#1369). */
|
|
16
23
|
export function waitMergeableAndMerge(prNumber, repo, options) {
|
|
17
24
|
const protectedFn = options.protectedFn ?? runProtectedCheck;
|
|
@@ -93,7 +100,9 @@ export function waitMergeableAndMerge(prNumber, repo, options) {
|
|
|
93
100
|
error: semanticGreen.error,
|
|
94
101
|
});
|
|
95
102
|
}
|
|
96
|
-
const [monRc, monStdout, monStderr] = monitorFn(prNumber, repo, options.capMinutes
|
|
103
|
+
const [monRc, monStdout, monStderr] = monitorFn(prNumber, repo, options.capMinutes, {
|
|
104
|
+
projectRoot,
|
|
105
|
+
});
|
|
97
106
|
const monitorPayload = parseMonitorPayload(monStdout);
|
|
98
107
|
const [outcome, monitorExit] = classifyMonitorOutcome(monRc, monitorPayload);
|
|
99
108
|
if (outcome !== "clean") {
|
|
@@ -114,6 +123,24 @@ export function waitMergeableAndMerge(prNumber, repo, options) {
|
|
|
114
123
|
}
|
|
115
124
|
const [mergeRc, mergeStdout, mergeStderr] = mergeFn(prNumber, repo);
|
|
116
125
|
if (mergeRc === 0) {
|
|
126
|
+
// Best-effort umbrella checklist + current-shape refresh after child merge (#1649).
|
|
127
|
+
// Failures must not flip a successful merge into an error exit.
|
|
128
|
+
// null = skip; undefined = live default (skipped under VITEST unless injected).
|
|
129
|
+
const umbrellaFn = options.umbrellaReconcileFn === null
|
|
130
|
+
? null
|
|
131
|
+
: options.umbrellaReconcileFn !== undefined
|
|
132
|
+
? options.umbrellaReconcileFn
|
|
133
|
+
: process.env.VITEST === "true"
|
|
134
|
+
? null
|
|
135
|
+
: defaultPostMergeUmbrellaReconcile;
|
|
136
|
+
if (umbrellaFn !== null) {
|
|
137
|
+
try {
|
|
138
|
+
umbrellaFn(projectRoot, repo);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* best-effort; merge remains authoritative */
|
|
142
|
+
}
|
|
143
|
+
}
|
|
117
144
|
return makeResult({
|
|
118
145
|
prNumber,
|
|
119
146
|
repo,
|
|
@@ -8,6 +8,8 @@ export interface ParsedWaitMergeableArgs {
|
|
|
8
8
|
readonly cascadeMode: boolean;
|
|
9
9
|
readonly requireMasterCiGreen: boolean;
|
|
10
10
|
readonly baseBranch: string | null;
|
|
11
|
+
/** Project root for minGreptileConfidence (#3095 / #3102). Null = cwd at run. */
|
|
12
|
+
readonly projectRoot: string | null;
|
|
11
13
|
readonly error?: string;
|
|
12
14
|
}
|
|
13
15
|
export declare function parseWaitMergeableArgs(argv: readonly string[]): ParsedWaitMergeableArgs;
|
|
@@ -19,6 +19,7 @@ export function parseWaitMergeableArgs(argv) {
|
|
|
19
19
|
let cascadeMode = false;
|
|
20
20
|
let requireMasterCiGreen = false;
|
|
21
21
|
let baseBranch = null;
|
|
22
|
+
let projectRoot = null;
|
|
22
23
|
const baseReturn = () => ({
|
|
23
24
|
prNumber,
|
|
24
25
|
repo,
|
|
@@ -28,6 +29,7 @@ export function parseWaitMergeableArgs(argv) {
|
|
|
28
29
|
cascadeMode,
|
|
29
30
|
requireMasterCiGreen,
|
|
30
31
|
baseBranch,
|
|
32
|
+
projectRoot,
|
|
31
33
|
});
|
|
32
34
|
for (let i = 0; i < argv.length; i += 1) {
|
|
33
35
|
const arg = argv[i];
|
|
@@ -51,6 +53,17 @@ export function parseWaitMergeableArgs(argv) {
|
|
|
51
53
|
else if (arg?.startsWith("--base-branch=")) {
|
|
52
54
|
baseBranch = arg.slice("--base-branch=".length);
|
|
53
55
|
}
|
|
56
|
+
else if (arg === "--project-root") {
|
|
57
|
+
const value = argv[i + 1];
|
|
58
|
+
if (value === undefined) {
|
|
59
|
+
return { ...baseReturn(), error: "argument --project-root: expected one argument" };
|
|
60
|
+
}
|
|
61
|
+
projectRoot = value;
|
|
62
|
+
i += 1;
|
|
63
|
+
}
|
|
64
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
65
|
+
projectRoot = arg.slice("--project-root=".length);
|
|
66
|
+
}
|
|
54
67
|
else if (arg === "--repo") {
|
|
55
68
|
const value = argv[i + 1];
|
|
56
69
|
if (value === undefined) {
|
|
@@ -154,6 +167,9 @@ export function runWaitMergeable(argv, options = {}) {
|
|
|
154
167
|
cascadeMode: args.cascadeMode,
|
|
155
168
|
requireMasterCiGreen: args.requireMasterCiGreen,
|
|
156
169
|
baseBranch: args.baseBranch,
|
|
170
|
+
// Explicit CLI root (or cwd) so remote-target cascade does not resolve
|
|
171
|
+
// minGreptileConfidence from an unrelated directory (#3102).
|
|
172
|
+
projectRoot: args.projectRoot ?? process.cwd(),
|
|
157
173
|
});
|
|
158
174
|
const summaryLabel = summaryLabelForExit(result.exitCode);
|
|
159
175
|
process.stderr.write(`[pr_wait_mergeable] PR #${result.prNumber} repo=${result.repo} ` +
|
|
@@ -12,6 +12,8 @@ export interface WaitMergeableResult {
|
|
|
12
12
|
}
|
|
13
13
|
export type SubprocessTriple = readonly [number, string, string];
|
|
14
14
|
export type ProtectedCheckFn = (prNumber: number, repo: string | null, protectedIssues: readonly number[]) => SubprocessTriple;
|
|
15
|
-
export type MonitorFn = (prNumber: number, repo: string, capMinutes: number
|
|
15
|
+
export type MonitorFn = (prNumber: number, repo: string, capMinutes: number, options?: {
|
|
16
|
+
readonly projectRoot?: string;
|
|
17
|
+
}) => SubprocessTriple;
|
|
16
18
|
export type MergeFn = (prNumber: number, repo: string | null) => SubprocessTriple;
|
|
17
19
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -35,6 +35,12 @@ export declare function runProtectedCheck(prNumber: number, repo: string | null,
|
|
|
35
35
|
export interface RunMonitorOptions {
|
|
36
36
|
readonly nodeExecutable?: string;
|
|
37
37
|
readonly timeout?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Project root for plan.policy.review.minGreptileConfidence when the
|
|
40
|
+
* cascade cwd is not the monitored project (#3095 residual / #3102).
|
|
41
|
+
* Defaults to process.cwd() when omitted.
|
|
42
|
+
*/
|
|
43
|
+
readonly projectRoot?: string;
|
|
38
44
|
}
|
|
39
45
|
/** Invoke pr-monitor CLI with --json and return (returncode, stdout, stderr). */
|
|
40
46
|
export declare function runMonitor(prNumber: number, repo: string, capMinutes: number, options?: RunMonitorOptions): SubprocessTriple;
|
|
@@ -105,6 +105,7 @@ export function runMonitor(prNumber, repo, capMinutes, options = {}) {
|
|
|
105
105
|
}
|
|
106
106
|
const node = options.nodeExecutable ?? process.execPath;
|
|
107
107
|
const timeoutSec = options.timeout ?? capMinutes * 60 + 60;
|
|
108
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
108
109
|
const cmd = [
|
|
109
110
|
scriptPath,
|
|
110
111
|
String(prNumber),
|
|
@@ -112,6 +113,8 @@ export function runMonitor(prNumber, repo, capMinutes, options = {}) {
|
|
|
112
113
|
repo,
|
|
113
114
|
"--cap-minutes",
|
|
114
115
|
String(capMinutes),
|
|
116
|
+
"--project-root",
|
|
117
|
+
projectRoot,
|
|
115
118
|
"--json",
|
|
116
119
|
];
|
|
117
120
|
// Stream the monitor's per-poll heartbeat live (a buffered poll looks like a
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* cannot promise to poll and then silently forget (2026-05-11 three-strikes on
|
|
7
7
|
* #1051 / #1054).
|
|
8
8
|
*/
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* CLEAN: SHA-matched, non-errored, no P0/P1, confidence >= resolved min, CI green.
|
|
11
|
+
* Min defaults to consumer 4 (legacy > 3); dogfood/policy may raise to 5 (#3095).
|
|
12
|
+
*/
|
|
10
13
|
export declare const EXIT_CLEAN = 0;
|
|
11
14
|
/** NEW_P0_P1: blocking findings on the CURRENT (SHA-matched) review. */
|
|
12
15
|
export declare const EXIT_NEW_P0_P1 = 1;
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* cannot promise to poll and then silently forget (2026-05-11 three-strikes on
|
|
7
7
|
* #1051 / #1054).
|
|
8
8
|
*/
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* CLEAN: SHA-matched, non-errored, no P0/P1, confidence >= resolved min, CI green.
|
|
11
|
+
* Min defaults to consumer 4 (legacy > 3); dogfood/policy may raise to 5 (#3095).
|
|
12
|
+
*/
|
|
10
13
|
export const EXIT_CLEAN = 0;
|
|
11
14
|
/** NEW_P0_P1: blocking findings on the CURRENT (SHA-matched) review. */
|
|
12
15
|
export const EXIT_NEW_P0_P1 = 1;
|
|
@@ -57,7 +60,7 @@ export const WATCH_HELP = "usage: task pr:watch -- <pr_number> [options]\n" +
|
|
|
57
60
|
" --project-root PATH Chdir before probing (optional)\n" +
|
|
58
61
|
"\n" +
|
|
59
62
|
"exit codes:\n" +
|
|
60
|
-
" 0 CLEAN SHA-matched review, confidence
|
|
63
|
+
" 0 CLEAN SHA-matched review, confidence >= policy min (default 4; dogfood 5), no P0/P1, CI green\n" +
|
|
61
64
|
" 1 NEW_P0_P1 Blocking findings on the current (SHA-matched) review\n" +
|
|
62
65
|
" 2 ERRORED | STALL | TIMEOUT | CI_BLOCKED | RUNNER_CAPACITY_STALL | config / usage error\n";
|
|
63
66
|
/**
|
package/dist/pr-watch/main.js
CHANGED
|
@@ -223,6 +223,7 @@ export function runWatch(argv, options = {}) {
|
|
|
223
223
|
clockFn: options.clockFn,
|
|
224
224
|
probeFn: options.probeFn,
|
|
225
225
|
stallThreshold: options.stallThreshold,
|
|
226
|
+
projectRoot: args.projectRoot ?? process.cwd(),
|
|
226
227
|
});
|
|
227
228
|
if (args.emitJson) {
|
|
228
229
|
process.stdout.write(emitWatchJson(result));
|
package/dist/pr-watch/probe.d.ts
CHANGED
|
@@ -9,5 +9,5 @@ import type { WatchProbe } from "./types.js";
|
|
|
9
9
|
* detector (#1056 AC-2). All gh access routes through the injectable RunGhFn
|
|
10
10
|
* seam, which defaults to the UTF-8-safe execFile capture (#1366).
|
|
11
11
|
*/
|
|
12
|
-
export declare function probeOnce(prNumber: number, repoArg: string | null, runGh?: RunGhFn): WatchProbe;
|
|
12
|
+
export declare function probeOnce(prNumber: number, repoArg: string | null, runGh?: RunGhFn, projectRoot?: string | null): WatchProbe;
|
|
13
13
|
//# sourceMappingURL=probe.d.ts.map
|
package/dist/pr-watch/probe.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { detect, evaluateCleanGate, parseConfidence, parseLastReviewedShaMarkdownLink, parseLastReviewedShaNaiveInline, } from "../content-contracts/skills/greptile-detector.js";
|
|
2
|
+
import { resolveMinGreptileConfidence } from "../policy/min-greptile-confidence.js";
|
|
2
3
|
import { evaluateCiGate } from "../pr-merge-readiness/ci-gate.js";
|
|
3
4
|
import { GREPTILE_ERRORED_SENTINEL } from "../pr-merge-readiness/constants.js";
|
|
4
5
|
import { defaultRunGh, fetchCheckRunsRest, fetchGreptileBodyRest, fetchGreptileCommentBody, fetchPrHeadSha, fetchPrHeadShaRest, resolveRepo, } from "../pr-merge-readiness/gh.js";
|
|
@@ -32,9 +33,10 @@ function errorProbe(headSha, message) {
|
|
|
32
33
|
* detector (#1056 AC-2). All gh access routes through the injectable RunGhFn
|
|
33
34
|
* seam, which defaults to the UTF-8-safe execFile capture (#1366).
|
|
34
35
|
*/
|
|
35
|
-
export function probeOnce(prNumber, repoArg, runGh = defaultRunGh) {
|
|
36
|
+
export function probeOnce(prNumber, repoArg, runGh = defaultRunGh, projectRoot = null) {
|
|
36
37
|
const resolved = resolveRepo(repoArg, runGh);
|
|
37
38
|
const repo = resolved.repo;
|
|
39
|
+
const minConfidence = resolveMinGreptileConfidence(projectRoot ?? process.cwd()).min;
|
|
38
40
|
// 1. HEAD SHA -- primary `gh pr view`, then REST fallback when a repo resolved.
|
|
39
41
|
let headSha = fetchPrHeadSha(prNumber, repo, runGh);
|
|
40
42
|
if (headSha === null && repo !== null) {
|
|
@@ -88,6 +90,7 @@ export function probeOnce(prNumber, repoArg, runGh = defaultRunGh) {
|
|
|
88
90
|
ciFailures,
|
|
89
91
|
errored,
|
|
90
92
|
terminalCheckRun,
|
|
93
|
+
minConfidence,
|
|
91
94
|
});
|
|
92
95
|
return {
|
|
93
96
|
found,
|
package/dist/pr-watch/types.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export type SleepFn = (seconds: number) => void;
|
|
|
34
34
|
export interface MonotonicClock {
|
|
35
35
|
now(): number;
|
|
36
36
|
}
|
|
37
|
-
export type ProbeFn = (prNumber: number, repo: string | null, runGh: RunGhFn) => WatchProbe;
|
|
37
|
+
export type ProbeFn = (prNumber: number, repo: string | null, runGh: RunGhFn, projectRoot?: string | null) => WatchProbe;
|
|
38
38
|
export interface WatchOptions {
|
|
39
39
|
readonly maxWaitMinutes?: number;
|
|
40
40
|
readonly pollSeconds?: number;
|
|
@@ -44,6 +44,12 @@ export interface WatchOptions {
|
|
|
44
44
|
readonly sleepFn?: SleepFn;
|
|
45
45
|
readonly clockFn?: MonotonicClock;
|
|
46
46
|
readonly probeFn?: ProbeFn;
|
|
47
|
+
/**
|
|
48
|
+
* Project root for resolving plan.policy.review.minGreptileConfidence (#3095).
|
|
49
|
+
* When omitted, probeOnce uses process.cwd(). Finish-loop / pr:watch MUST pass
|
|
50
|
+
* the caller project-root so a chdir elsewhere cannot apply the wrong floor.
|
|
51
|
+
*/
|
|
52
|
+
readonly projectRoot?: string | null;
|
|
47
53
|
}
|
|
48
54
|
export interface WatchResult {
|
|
49
55
|
readonly verdict: string;
|
package/dist/pr-watch/watch.js
CHANGED
|
@@ -44,7 +44,8 @@ export function watch(prNumber, repo, options = {}) {
|
|
|
44
44
|
const runGh = options.runGh ?? defaultRunGh;
|
|
45
45
|
const clockFn = options.clockFn ?? systemMonotonicClock;
|
|
46
46
|
const sleepFn = options.sleepFn ?? defaultSleep;
|
|
47
|
-
const
|
|
47
|
+
const projectRoot = options.projectRoot ?? null;
|
|
48
|
+
const probeFn = options.probeFn ?? ((n, r, gh, root) => probeOnce(n, r, gh, root ?? projectRoot));
|
|
48
49
|
const capSeconds = Math.max(0, maxWaitMinutes * 60);
|
|
49
50
|
// Bounded loop (time is still the authority via the cap check below) so no
|
|
50
51
|
// unbounded `while (true)`; +1 covers the trailing poll after the final wait.
|
|
@@ -62,7 +63,7 @@ export function watch(prNumber, repo, options = {}) {
|
|
|
62
63
|
pollCount: poll,
|
|
63
64
|
});
|
|
64
65
|
for (let poll = 1; poll <= maxPolls; poll += 1) {
|
|
65
|
-
const probe = probeFn(prNumber, repo, runGh);
|
|
66
|
+
const probe = probeFn(prNumber, repo, runGh, projectRoot);
|
|
66
67
|
lastProbe = probe;
|
|
67
68
|
const elapsed = Math.round(clockFn.now() - startedAt);
|
|
68
69
|
process.stderr.write(`${formatWatchStatus(poll, maxPolls, probe, elapsed)}\n`);
|
|
@@ -152,9 +152,14 @@ export function rehearseGreenfieldPythonFreeSmoke(repoRoot, seams = {}, options
|
|
|
152
152
|
return [false, `greenfield smoke: expected global deft at ${deft}`];
|
|
153
153
|
}
|
|
154
154
|
const pyFree = pythonFreePathEnv(envBase);
|
|
155
|
+
const installedBin = join(npmPrefix, "bin");
|
|
156
|
+
const installedEnv = {
|
|
157
|
+
...pyFree,
|
|
158
|
+
PATH: `${installedBin}:${pyFree.PATH ?? ""}`,
|
|
159
|
+
};
|
|
155
160
|
[ok, reason] = runStep(spawn, "directive init", deft, ["init", "--yes", "--repo-root", projectDir], {
|
|
156
161
|
cwd: work,
|
|
157
|
-
env:
|
|
162
|
+
env: installedEnv,
|
|
158
163
|
timeoutMs: 120_000,
|
|
159
164
|
}, onProgress);
|
|
160
165
|
if (!ok)
|
|
@@ -173,8 +178,7 @@ export function rehearseGreenfieldPythonFreeSmoke(repoRoot, seams = {}, options
|
|
|
173
178
|
return [false, "greenfield smoke: repo-root Python run shim present after init"];
|
|
174
179
|
}
|
|
175
180
|
const checkEnv = {
|
|
176
|
-
...
|
|
177
|
-
PATH: `${join(npmPrefix, "bin")}:${pyFree.PATH ?? ""}`,
|
|
181
|
+
...installedEnv,
|
|
178
182
|
DEFT_SESSION_RITUAL_SKIP: "1",
|
|
179
183
|
};
|
|
180
184
|
onProgress?.("greenfield smoke: running consumer task deft:check (engine-invoke path)");
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owner Continuity / L4 owner gate (#3090).
|
|
3
|
+
*
|
|
4
|
+
* Exit 0 only when a fresh sticky review-owner lease exists on the PR,
|
|
5
|
+
* or the caller asserts `review_cycle: done` after Step 6.
|
|
6
|
+
* Freeform started/pending/initiated values are rejected.
|
|
7
|
+
* skipped / n/a / parent-retained are process evidence only — they do NOT
|
|
8
|
+
* satisfy this machine gate when --pr is required (lease-or-done).
|
|
9
|
+
*/
|
|
10
|
+
import { EXIT_CONFIG_ERROR, EXIT_NOT_READY, EXIT_READY } from "./constants.js";
|
|
11
|
+
import type { ReviewOwnerGithubSeams } from "./github-lease.js";
|
|
12
|
+
import { type ReviewMonitorRecord } from "./record.js";
|
|
13
|
+
/** Allowed review_cycle evidence values (prefix form for in_progress/skipped). */
|
|
14
|
+
export type ReviewCycleEvidence = "done" | "n/a" | `in_progress:${string}` | `skipped:${string}`;
|
|
15
|
+
export declare const L4_OWNER_HELP: string;
|
|
16
|
+
export declare function parseReviewCycleEvidence(raw: string | null | undefined): {
|
|
17
|
+
ok: true;
|
|
18
|
+
value: ReviewCycleEvidence | null;
|
|
19
|
+
} | {
|
|
20
|
+
ok: false;
|
|
21
|
+
reason: string;
|
|
22
|
+
};
|
|
23
|
+
/** Parse in_progress:<pr>#<ref> into parts; null if not that form. */
|
|
24
|
+
export declare function parseInProgressEvidence(value: string): {
|
|
25
|
+
pr: number;
|
|
26
|
+
ref: string;
|
|
27
|
+
} | null;
|
|
28
|
+
export interface VerifyL4OwnerArgs {
|
|
29
|
+
readonly pr: number;
|
|
30
|
+
readonly projectRoot: string;
|
|
31
|
+
readonly repo?: string | null;
|
|
32
|
+
readonly headSha?: string | null;
|
|
33
|
+
readonly reviewCycle?: string | null;
|
|
34
|
+
readonly now?: Date;
|
|
35
|
+
readonly seams?: ReviewOwnerGithubSeams;
|
|
36
|
+
}
|
|
37
|
+
export interface VerifyL4OwnerResult {
|
|
38
|
+
readonly exitCode: typeof EXIT_READY | typeof EXIT_NOT_READY | typeof EXIT_CONFIG_ERROR;
|
|
39
|
+
readonly message: string;
|
|
40
|
+
readonly monitorRecord: ReviewMonitorRecord | null;
|
|
41
|
+
readonly reviewCycle: ReviewCycleEvidence | null;
|
|
42
|
+
readonly path: "lease" | "done" | "none" | "illegal" | "config";
|
|
43
|
+
}
|
|
44
|
+
export declare function evaluateL4OwnerGate(args: VerifyL4OwnerArgs): VerifyL4OwnerResult;
|
|
45
|
+
export declare function l4OwnerResultToJson(result: VerifyL4OwnerResult): Record<string, unknown>;
|
|
46
|
+
//# sourceMappingURL=l4-owner.d.ts.map
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owner Continuity / L4 owner gate (#3090).
|
|
3
|
+
*
|
|
4
|
+
* Exit 0 only when a fresh sticky review-owner lease exists on the PR,
|
|
5
|
+
* or the caller asserts `review_cycle: done` after Step 6.
|
|
6
|
+
* Freeform started/pending/initiated values are rejected.
|
|
7
|
+
* skipped / n/a / parent-retained are process evidence only — they do NOT
|
|
8
|
+
* satisfy this machine gate when --pr is required (lease-or-done).
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, statSync } from "node:fs";
|
|
11
|
+
import { resolve } from "node:path";
|
|
12
|
+
import { resolveRepo } from "../triage/queue/repo.js";
|
|
13
|
+
import { EXIT_CONFIG_ERROR, EXIT_NOT_READY, EXIT_READY } from "./constants.js";
|
|
14
|
+
import { fetchActiveMonitorFromGithub } from "./record.js";
|
|
15
|
+
export const L4_OWNER_HELP = "usage: task verify:l4-owner -- --pr <N> [options]\n" +
|
|
16
|
+
"\n" +
|
|
17
|
+
"Owner Continuity / L4 owner gate (#3090): after drive-to:merge-ready /\n" +
|
|
18
|
+
"babysit / shepherd claims, exit 0 only when a sticky GitHub review-owner\n" +
|
|
19
|
+
"lease is fresh on the PR, or the caller asserts --review-cycle done\n" +
|
|
20
|
+
"(Step 6 fail-closed all-of on HEAD). Freeform started/pending/initiated\n" +
|
|
21
|
+
"are rejected. skipped / n/a / parent-retained do NOT satisfy this machine\n" +
|
|
22
|
+
"gate (process A/B/C still applies). Silent hold exits 1.\n" +
|
|
23
|
+
"\n" +
|
|
24
|
+
"options:\n" +
|
|
25
|
+
" -h, --help Show this help and exit 0\n" +
|
|
26
|
+
" --pr N Pull request number (required unless --help)\n" +
|
|
27
|
+
" --repo OWNER/REPO Repository (optional; inferred from origin)\n" +
|
|
28
|
+
" --head-sha SHA Expected HEAD SHA (optional freshness check)\n" +
|
|
29
|
+
" --project-root PATH Project root (default: cwd)\n" +
|
|
30
|
+
" --review-cycle VALUE done | in_progress:<pr>#<ref> | skipped:<reason> | n/a\n" +
|
|
31
|
+
" --json Emit structured JSON on stdout\n" +
|
|
32
|
+
"\n" +
|
|
33
|
+
"exit codes:\n" +
|
|
34
|
+
" 0 READY Fresh sticky lease, or --review-cycle done\n" +
|
|
35
|
+
" 1 NOT READY Silent hold / illegal evidence / lease missing\n" +
|
|
36
|
+
" 2 CONFIG Usage / path / GitHub fetch error\n";
|
|
37
|
+
const FORBIDDEN_FREEFORM = new Set(["started", "pending", "initiated", "start", "in_progress"]);
|
|
38
|
+
export function parseReviewCycleEvidence(raw) {
|
|
39
|
+
if (raw === null || raw === undefined || raw.trim() === "") {
|
|
40
|
+
return { ok: true, value: null };
|
|
41
|
+
}
|
|
42
|
+
const value = raw.trim();
|
|
43
|
+
const lower = value.toLowerCase();
|
|
44
|
+
if (FORBIDDEN_FREEFORM.has(lower)) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
reason: `illegal freeform review_cycle value '${value}' (#3090); ` +
|
|
48
|
+
"use done | in_progress:<pr>#<ref> | skipped:<reason> | n/a",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (value === "done" || value === "n/a") {
|
|
52
|
+
return { ok: true, value };
|
|
53
|
+
}
|
|
54
|
+
if (value.startsWith("in_progress:")) {
|
|
55
|
+
const rest = value.slice("in_progress:".length);
|
|
56
|
+
if (!rest.includes("#") || rest.endsWith("#") || rest.startsWith("#")) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
reason: "in_progress requires form in_progress:<pr>#<monitor_or_lease_ref> (#3090)",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const prPart = rest.slice(0, rest.indexOf("#"));
|
|
63
|
+
if (!/^\d+$/.test(prPart) || Number(prPart) <= 0) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
reason: "in_progress:<pr> must be a positive integer PR number (#3090)",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return { ok: true, value: value };
|
|
70
|
+
}
|
|
71
|
+
if (value.startsWith("skipped:")) {
|
|
72
|
+
const rest = value.slice("skipped:".length).trim();
|
|
73
|
+
if (rest.length === 0) {
|
|
74
|
+
return { ok: false, reason: "skipped requires a non-empty reason (#3090)" };
|
|
75
|
+
}
|
|
76
|
+
return { ok: true, value: value };
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
reason: `unknown review_cycle value '${value}' (#3090); ` +
|
|
81
|
+
"use done | in_progress:<pr>#<ref> | skipped:<reason> | n/a",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Parse in_progress:<pr>#<ref> into parts; null if not that form. */
|
|
85
|
+
export function parseInProgressEvidence(value) {
|
|
86
|
+
if (!value.startsWith("in_progress:")) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const rest = value.slice("in_progress:".length);
|
|
90
|
+
const hash = rest.indexOf("#");
|
|
91
|
+
if (hash <= 0) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const prPart = rest.slice(0, hash);
|
|
95
|
+
const ref = rest.slice(hash + 1);
|
|
96
|
+
if (!/^\d+$/.test(prPart) || ref.length === 0) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return { pr: Number(prPart), ref };
|
|
100
|
+
}
|
|
101
|
+
function oneLine(value) {
|
|
102
|
+
return value.replace(/\r?\n/g, " ");
|
|
103
|
+
}
|
|
104
|
+
export function evaluateL4OwnerGate(args) {
|
|
105
|
+
const projectRoot = resolve(args.projectRoot);
|
|
106
|
+
let isDir = false;
|
|
107
|
+
try {
|
|
108
|
+
isDir = existsSync(projectRoot) && statSync(projectRoot).isDirectory();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
isDir = false;
|
|
112
|
+
}
|
|
113
|
+
if (!isDir) {
|
|
114
|
+
return {
|
|
115
|
+
exitCode: EXIT_CONFIG_ERROR,
|
|
116
|
+
message: `verify_l4_owner: --project-root is not a directory: ${oneLine(projectRoot)}`,
|
|
117
|
+
monitorRecord: null,
|
|
118
|
+
reviewCycle: null,
|
|
119
|
+
path: "config",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const parsed = parseReviewCycleEvidence(args.reviewCycle);
|
|
123
|
+
if (!parsed.ok) {
|
|
124
|
+
return {
|
|
125
|
+
exitCode: EXIT_NOT_READY,
|
|
126
|
+
message: `verify_l4_owner: ${oneLine(parsed.reason)}`,
|
|
127
|
+
monitorRecord: null,
|
|
128
|
+
reviewCycle: null,
|
|
129
|
+
path: "illegal",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// Machine gate is lease-or-done only (#3090). skipped/n/a are handoff enum values
|
|
133
|
+
// but must not green-light ownership of an open PR without lease or Step 6 done.
|
|
134
|
+
if (parsed.value === "n/a" || parsed.value?.startsWith("skipped:")) {
|
|
135
|
+
return {
|
|
136
|
+
exitCode: EXIT_NOT_READY,
|
|
137
|
+
message: `verify_l4_owner: review_cycle=${oneLine(parsed.value)} does not satisfy the machine ` +
|
|
138
|
+
`gate for PR #${args.pr} (#3090). Exit 0 requires a fresh sticky lease or --review-cycle done.`,
|
|
139
|
+
monitorRecord: null,
|
|
140
|
+
reviewCycle: parsed.value,
|
|
141
|
+
path: "none",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (parsed.value === "done") {
|
|
145
|
+
return {
|
|
146
|
+
exitCode: EXIT_READY,
|
|
147
|
+
message: `verify_l4_owner: review_cycle=done asserted for PR #${args.pr} (#3090). ` +
|
|
148
|
+
"Caller MUST have satisfied Step 6 fail-closed all-of on HEAD before this claim.",
|
|
149
|
+
monitorRecord: null,
|
|
150
|
+
reviewCycle: "done",
|
|
151
|
+
path: "done",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// Validate in_progress PR binding when evidence is present (before lease fetch).
|
|
155
|
+
if (parsed.value?.startsWith("in_progress:")) {
|
|
156
|
+
const parts = parseInProgressEvidence(parsed.value);
|
|
157
|
+
if (parts === null) {
|
|
158
|
+
return {
|
|
159
|
+
exitCode: EXIT_NOT_READY,
|
|
160
|
+
message: `verify_l4_owner: malformed in_progress evidence ${oneLine(parsed.value)} (#3090).`,
|
|
161
|
+
monitorRecord: null,
|
|
162
|
+
reviewCycle: parsed.value,
|
|
163
|
+
path: "illegal",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (parts.pr !== args.pr) {
|
|
167
|
+
return {
|
|
168
|
+
exitCode: EXIT_NOT_READY,
|
|
169
|
+
message: `verify_l4_owner: review_cycle PR #${parts.pr} does not match --pr ${args.pr} (#3090). ` +
|
|
170
|
+
"Ownership evidence must bind to the target PR.",
|
|
171
|
+
monitorRecord: null,
|
|
172
|
+
reviewCycle: parsed.value,
|
|
173
|
+
path: "none",
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const repo = resolveRepo(args.repo ?? null, projectRoot);
|
|
178
|
+
if (repo === null) {
|
|
179
|
+
return {
|
|
180
|
+
exitCode: EXIT_CONFIG_ERROR,
|
|
181
|
+
message: "verify_l4_owner: could not resolve owner/repo — pass --repo OWNER/REPO or run inside a git repo with origin",
|
|
182
|
+
monitorRecord: null,
|
|
183
|
+
reviewCycle: parsed.value,
|
|
184
|
+
path: "config",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const now = args.now ?? new Date();
|
|
188
|
+
const githubMonitor = fetchActiveMonitorFromGithub(repo, args.pr, {
|
|
189
|
+
now,
|
|
190
|
+
headSha: args.headSha ?? null,
|
|
191
|
+
seams: args.seams,
|
|
192
|
+
});
|
|
193
|
+
if (githubMonitor !== null && typeof githubMonitor === "object" && "error" in githubMonitor) {
|
|
194
|
+
return {
|
|
195
|
+
exitCode: EXIT_CONFIG_ERROR,
|
|
196
|
+
message: `verify_l4_owner: ${oneLine(githubMonitor.error)}`,
|
|
197
|
+
monitorRecord: null,
|
|
198
|
+
reviewCycle: parsed.value,
|
|
199
|
+
path: "config",
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (githubMonitor !== null) {
|
|
203
|
+
const ref = parsed.value ??
|
|
204
|
+
`in_progress:${args.pr}#${githubMonitor.monitor_agent_id}`;
|
|
205
|
+
return {
|
|
206
|
+
exitCode: EXIT_READY,
|
|
207
|
+
message: `verify_l4_owner: active GitHub review-owner lease for PR #${args.pr} ` +
|
|
208
|
+
`(monitor_agent_id=${oneLine(githubMonitor.monitor_agent_id)}, owner=${oneLine(githubMonitor.owner)}) ` +
|
|
209
|
+
"— review_cycle path=lease (#3090).",
|
|
210
|
+
monitorRecord: githubMonitor,
|
|
211
|
+
reviewCycle: ref,
|
|
212
|
+
path: "lease",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
// parent-retained is process path B — machine gate cannot verify it (lease-or-done only).
|
|
216
|
+
if (parsed.value?.startsWith("in_progress:")) {
|
|
217
|
+
const parts = parseInProgressEvidence(parsed.value);
|
|
218
|
+
if (parts?.ref === "parent-retained") {
|
|
219
|
+
return {
|
|
220
|
+
exitCode: EXIT_NOT_READY,
|
|
221
|
+
message: `verify_l4_owner: parent-retained for PR #${args.pr} is process path B only (#3090). ` +
|
|
222
|
+
"Machine gate requires a sticky <!-- deft:review-owner --> lease or --review-cycle done. " +
|
|
223
|
+
"Keep parent dual-source poll/fix; do not emit L4 status:pass as terminal.",
|
|
224
|
+
monitorRecord: null,
|
|
225
|
+
reviewCycle: parsed.value,
|
|
226
|
+
path: "none",
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
exitCode: EXIT_NOT_READY,
|
|
231
|
+
message: `verify_l4_owner: review_cycle=${oneLine(parsed.value)} claims in_progress but no sticky ` +
|
|
232
|
+
`<!-- deft:review-owner --> lease found for PR #${args.pr} (#3090 / #2797).\n` +
|
|
233
|
+
" Register: deft review-monitor:register --pr <N> --monitor-agent-id <id> --platform-primitive …",
|
|
234
|
+
monitorRecord: null,
|
|
235
|
+
reviewCycle: parsed.value,
|
|
236
|
+
path: "none",
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
exitCode: EXIT_NOT_READY,
|
|
241
|
+
message: `verify_l4_owner: silent hold on PR #${args.pr} — no fresh sticky lease and no ` +
|
|
242
|
+
"review_cycle=done (#3090 Owner Continuity Gate).\n" +
|
|
243
|
+
" Same turn MUST end in A (monitor+lease), B (parent-retained + next dual-source action),\n" +
|
|
244
|
+
" or C (explicit BLOCKED/FAILED finish). Check-run SUCCESS alone is not CLEAN.",
|
|
245
|
+
monitorRecord: null,
|
|
246
|
+
reviewCycle: null,
|
|
247
|
+
path: "none",
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
export function l4OwnerResultToJson(result) {
|
|
251
|
+
return {
|
|
252
|
+
exit_code: result.exitCode,
|
|
253
|
+
message: result.message,
|
|
254
|
+
monitor_agent_id: result.monitorRecord?.monitor_agent_id ?? null,
|
|
255
|
+
monitor_owner: result.monitorRecord?.owner ?? null,
|
|
256
|
+
monitor_record: result.monitorRecord,
|
|
257
|
+
path: result.path,
|
|
258
|
+
ready: result.exitCode === EXIT_READY,
|
|
259
|
+
review_cycle: result.reviewCycle,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=l4-owner.js.map
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { type AgentHookReadinessResult } from "../verify-env/agent-hook-readiness.js";
|
|
1
2
|
export declare const ENTRYPOINT_TIMEOUT_SECONDS = 300;
|
|
2
3
|
export declare const ENTRYPOINT_TIMEOUT_EXIT_CODE = 124;
|
|
3
4
|
export type RitualEntrypointFn = (argv: readonly string[]) => number;
|
|
5
|
+
export interface DefaultRitualRunnerSeams {
|
|
6
|
+
readonly evaluateAgentHookReadiness?: (projectRoot: string) => AgentHookReadinessResult;
|
|
7
|
+
}
|
|
4
8
|
/** Run an in-process ritual entrypoint with stdout/stderr capture. */
|
|
5
9
|
export declare function callMain(mainFn: RitualEntrypointFn, argv: readonly string[], _options?: {
|
|
6
10
|
label?: string;
|
|
@@ -11,8 +15,8 @@ export declare function callMain(mainFn: RitualEntrypointFn, argv: readonly stri
|
|
|
11
15
|
};
|
|
12
16
|
/** CLI-shaped cache-fresh entrypoint (mirrors scripts/preflight_cache.py main). */
|
|
13
17
|
export declare function runCacheFreshMain(argv: readonly string[]): number;
|
|
14
|
-
/** Default gated-tier runner: in-process doctor
|
|
15
|
-
export declare function defaultRitualRunner(command: readonly string[], projectRoot: string): {
|
|
18
|
+
/** Default gated-tier runner: in-process hook readiness, doctor, and cache freshness. */
|
|
19
|
+
export declare function defaultRitualRunner(command: readonly string[], projectRoot: string, seams?: DefaultRitualRunnerSeams): {
|
|
16
20
|
code: number;
|
|
17
21
|
stdout: string;
|
|
18
22
|
stderr: string;
|