@deftai/directive-core 0.107.0 → 0.109.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/architecture/sor-preflight.js +2 -0
- package/dist/cache/operations.js +1 -1
- package/dist/check/cached-orchestrator.js +28 -3
- package/dist/check/gate-lists.d.ts +14 -0
- package/dist/check/gate-lists.js +26 -3
- package/dist/check/named-cause.js +18 -3
- package/dist/check/session-completed-ac.d.ts +1 -1
- package/dist/check/session-completed-ac.js +1 -1
- package/dist/codebase/provider.js +7 -1
- package/dist/consumer-check-contract/evaluate.d.ts +47 -0
- package/dist/consumer-check-contract/evaluate.js +181 -15
- package/dist/delivery-attempt/evaluate.d.ts +9 -1
- package/dist/delivery-attempt/evaluate.js +69 -0
- package/dist/delivery-attempt/handoff.js +1 -1
- package/dist/delivery-attempt/index.d.ts +1 -1
- package/dist/delivery-attempt/index.js +1 -1
- package/dist/deposit/live-procedure-exclusions.d.ts +18 -0
- package/dist/deposit/live-procedure-exclusions.js +110 -0
- package/dist/deposit/live-procedure-targets.d.ts +45 -0
- package/dist/deposit/live-procedure-targets.js +274 -0
- package/dist/deposit/python-free.d.ts +6 -0
- package/dist/deposit/python-free.js +15 -0
- package/dist/deposit/rewrite-deposit-links.d.ts +42 -0
- package/dist/deposit/rewrite-deposit-links.js +148 -0
- package/dist/deposit/run-stage-content-pack.d.ts +2 -0
- package/dist/deposit/run-stage-content-pack.js +3 -0
- package/dist/deposit/stage-content-pack.d.ts +17 -0
- package/dist/deposit/stage-content-pack.js +91 -0
- package/dist/design-critique/citation-grammar.d.ts +60 -0
- package/dist/design-critique/citation-grammar.js +303 -0
- package/dist/design-critique/completed-arc-record.d.ts +62 -0
- package/dist/design-critique/completed-arc-record.js +277 -0
- package/dist/freshness/bind.d.ts +32 -3
- package/dist/freshness/bind.js +58 -12
- package/dist/hooks/classify/host-session-identity.d.ts +89 -0
- package/dist/hooks/classify/host-session-identity.js +467 -0
- package/dist/hooks/classify/index.d.ts +3 -2
- package/dist/hooks/classify/index.js +3 -2
- package/dist/hooks/classify/paths.d.ts +9 -0
- package/dist/hooks/classify/paths.js +39 -0
- package/dist/hooks/classify/stdin.d.ts +5 -0
- package/dist/hooks/classify/stdin.js +94 -1
- package/dist/hooks/dest-form.d.ts +20 -1
- package/dist/hooks/dest-form.js +158 -21
- package/dist/hooks/dispatcher.d.ts +58 -3
- package/dist/hooks/dispatcher.js +762 -73
- package/dist/hooks/fixtures/cases.d.ts +22 -2
- package/dist/hooks/fixtures/cases.js +228 -0
- package/dist/hooks/git-destructive-log.d.ts +32 -0
- package/dist/hooks/git-destructive-log.js +46 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/scope.js +3 -1
- package/dist/hooks/shell-write-targets.d.ts +10 -0
- package/dist/hooks/shell-write-targets.js +274 -0
- package/dist/hooks/tools.d.ts +20 -2
- package/dist/hooks/tools.js +30 -1
- package/dist/init-deposit/agent-hooks.d.ts +2 -1
- package/dist/init-deposit/agent-hooks.js +8 -1
- package/dist/init-deposit/gitignore.d.ts +7 -0
- package/dist/init-deposit/gitignore.js +24 -0
- package/dist/init-deposit/hook-runtime-travel.d.ts +77 -0
- package/dist/init-deposit/hook-runtime-travel.js +269 -0
- package/dist/init-deposit/init-deposit.js +3 -0
- package/dist/init-deposit/refresh.js +7 -0
- package/dist/init-deposit/runtime-writers.d.ts +14 -0
- package/dist/init-deposit/runtime-writers.js +33 -0
- package/dist/intake/clause-derivation.js +9 -3
- package/dist/intake/issue-ingest.d.ts +6 -1
- package/dist/intake/issue-ingest.js +83 -4
- package/dist/intake/platform-capabilities.d.ts +9 -2
- package/dist/intake/platform-capabilities.js +38 -9
- package/dist/intake/reconcile-issues.js +13 -13
- package/dist/lifecycle/brief-envelope.d.ts +25 -0
- package/dist/lifecycle/brief-envelope.js +42 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/literal-acceptance/evaluate.js +14 -5
- package/dist/literal-acceptance/index.d.ts +1 -1
- package/dist/literal-acceptance/index.js +1 -1
- package/dist/literal-acceptance/run.d.ts +2 -0
- package/dist/literal-acceptance/run.js +19 -1
- package/dist/orphan-active/candidate-scope.d.ts +53 -0
- package/dist/orphan-active/candidate-scope.js +157 -0
- package/dist/orphan-active/evaluate.d.ts +52 -0
- package/dist/orphan-active/evaluate.js +250 -128
- package/dist/orphan-active/index.d.ts +2 -0
- package/dist/orphan-active/index.js +2 -0
- package/dist/orphan-active/issue-state.d.ts +121 -0
- package/dist/orphan-active/issue-state.js +278 -0
- package/dist/platform/cursor-managed-runtime.d.ts +95 -0
- package/dist/platform/cursor-managed-runtime.js +241 -0
- package/dist/platform/index.d.ts +1 -0
- package/dist/platform/index.js +1 -0
- package/dist/platform/platform-capabilities.d.ts +23 -1
- package/dist/platform/platform-capabilities.js +55 -15
- package/dist/policy/ceremony-dial.js +5 -9
- package/dist/policy/host-hooks.js +4 -9
- package/dist/policy/merge-approval-head.js +7 -6
- package/dist/policy/org-force-on-migration.js +5 -10
- package/dist/policy/plan-extensions.d.ts +14 -2
- package/dist/policy/plan-extensions.js +24 -3
- package/dist/policy/product-signal.js +5 -10
- package/dist/policy/require-human-merge.js +5 -9
- package/dist/policy/resolve.js +77 -16
- package/dist/policy/value-feedback.js +9 -18
- package/dist/pr-closeout-attestable/evaluate.d.ts +80 -0
- package/dist/pr-closeout-attestable/evaluate.js +306 -0
- package/dist/pr-closeout-attestable/index.d.ts +2 -0
- package/dist/pr-closeout-attestable/index.js +2 -0
- package/dist/pr-closing-keywords/gh.js +32 -9
- package/dist/pr-closing-keywords/main.d.ts +1 -0
- package/dist/pr-closing-keywords/main.js +68 -3
- package/dist/pr-closing-keywords/types.d.ts +2 -0
- package/dist/pr-merge-readiness/gh.js +32 -9
- package/dist/pr-protected-issues/gh.d.ts +6 -2
- package/dist/pr-protected-issues/gh.js +42 -11
- package/dist/pr-wait-mergeable/cascade.d.ts +9 -1
- package/dist/pr-wait-mergeable/cascade.js +21 -1
- package/dist/pr-wait-mergeable/types.d.ts +2 -0
- package/dist/pr-wait-mergeable/wrappers.d.ts +6 -0
- package/dist/pr-wait-mergeable/wrappers.js +14 -3
- package/dist/preflight/evaluate.d.ts +15 -0
- package/dist/preflight/evaluate.js +29 -3
- package/dist/product-first-done-gate/acceptance-resolver.d.ts +14 -2
- package/dist/product-first-done-gate/acceptance-resolver.js +13 -2
- package/dist/product-first-done-gate/evaluate.js +23 -9
- package/dist/product-first-done-gate/types.js +2 -0
- package/dist/release/cli-drift-report.d.ts +68 -0
- package/dist/release/cli-drift-report.js +189 -0
- package/dist/release/consumer-hard-stops.d.ts +48 -0
- package/dist/release/consumer-hard-stops.js +140 -0
- package/dist/release/consumer-readiness-disclosure.d.ts +18 -0
- package/dist/release/consumer-readiness-disclosure.js +51 -0
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.js +3 -0
- package/dist/release/issue-state-fetch.d.ts +5 -3
- package/dist/release/issue-state-fetch.js +86 -21
- package/dist/release/native-steps.js +1 -0
- package/dist/release/pipeline.js +74 -0
- package/dist/release/run-consumer-readiness.d.ts +15 -0
- package/dist/release/run-consumer-readiness.js +24 -0
- package/dist/release/types.d.ts +20 -0
- package/dist/render/constants.d.ts +4 -0
- package/dist/render/constants.js +11 -8
- package/dist/render/export-spec.js +31 -5
- package/dist/render/index.d.ts +1 -1
- package/dist/render/index.js +1 -1
- package/dist/render/prd-render.d.ts +4 -1
- package/dist/render/prd-render.js +82 -23
- package/dist/render/project-render.js +14 -7
- package/dist/render/scope-outlook.d.ts +2 -0
- package/dist/render/scope-outlook.js +3 -0
- package/dist/render/spec-render.js +2 -2
- package/dist/resolution/package-manager.d.ts +33 -4
- package/dist/resolution/package-manager.js +210 -9
- package/dist/review-monitor/constants.d.ts +7 -0
- package/dist/review-monitor/constants.js +7 -0
- package/dist/review-monitor/github-lease.d.ts +98 -1
- package/dist/review-monitor/github-lease.js +186 -4
- package/dist/review-monitor/lease-comment.d.ts +36 -0
- package/dist/review-monitor/lease-comment.js +103 -2
- package/dist/run-summary/types.d.ts +2 -2
- package/dist/scm/build-command.d.ts +2 -2
- package/dist/scm/build-command.js +2 -2
- package/dist/scm/call-shape.d.ts +25 -0
- package/dist/scm/call-shape.js +59 -0
- package/dist/scm/call.d.ts +7 -4
- package/dist/scm/call.js +48 -9
- package/dist/scm/design-critique-chip.d.ts +1 -0
- package/dist/scm/design-critique-chip.js +22 -6
- package/dist/scm/gh-rest.d.ts +34 -13
- package/dist/scm/gh-rest.js +168 -15
- package/dist/scm/index.d.ts +2 -0
- package/dist/scm/index.js +2 -0
- package/dist/scm/readiness.d.ts +2 -0
- package/dist/scm/readiness.js +28 -4
- package/dist/scm/spawn-status.d.ts +33 -0
- package/dist/scm/spawn-status.js +53 -0
- package/dist/scope/acceptance-evidence.d.ts +1 -1
- package/dist/scope/project-definition-sync.js +14 -7
- package/dist/scope/transition.js +4 -14
- package/dist/session/ac-pass-banking.d.ts +2 -2
- package/dist/session/ac-pass-banking.js +2 -2
- package/dist/session/git.d.ts +24 -0
- package/dist/session/git.js +138 -2
- package/dist/session/host-session-owner.d.ts +53 -0
- package/dist/session/host-session-owner.js +89 -0
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.js +1 -0
- package/dist/session/occupancy.d.ts +259 -13
- package/dist/session/occupancy.js +877 -33
- package/dist/session/ritual-sentinel.d.ts +5 -0
- package/dist/session/ritual-sentinel.js +5 -0
- package/dist/session/session-ready.d.ts +5 -1
- package/dist/session/session-ready.js +98 -8
- package/dist/session/session-start.d.ts +5 -1
- package/dist/session/session-start.js +32 -17
- package/dist/session/toolchain-preflight.d.ts +13 -3
- package/dist/session/toolchain-preflight.js +93 -18
- package/dist/session/verify-ac-session-cache.d.ts +2 -2
- package/dist/session/verify-ac-session-cache.js +2 -2
- package/dist/session/verify-session-ritual.d.ts +11 -0
- package/dist/session/verify-session-ritual.js +60 -15
- package/dist/slice/constants.d.ts +1 -1
- package/dist/spec-authority/constants.d.ts +10 -2
- package/dist/spec-authority/constants.js +53 -8
- package/dist/spec-authority/resolver.d.ts +3 -0
- package/dist/spec-authority/resolver.js +55 -7
- package/dist/subprocess/max-buffer.d.ts +14 -0
- package/dist/subprocess/max-buffer.js +15 -0
- package/dist/swarm/complete-cohort.d.ts +2 -0
- package/dist/swarm/complete-cohort.js +21 -13
- package/dist/swarm/index.d.ts +1 -0
- package/dist/swarm/index.js +1 -0
- package/dist/swarm/launch-cli.js +53 -33
- package/dist/swarm/launch.d.ts +8 -0
- package/dist/swarm/launch.js +63 -43
- package/dist/swarm/pre-dispatch-cli.js +2 -1
- package/dist/swarm/pre-dispatch.js +10 -1
- package/dist/swarm/subagent-status-dir.d.ts +27 -0
- package/dist/swarm/subagent-status-dir.js +42 -0
- package/dist/swarm/worktrees.d.ts +17 -3
- package/dist/swarm/worktrees.js +48 -4
- package/dist/triage/evaluate/worktrees.js +153 -6
- package/dist/triage/scope/mutations-core.d.ts +2 -6
- package/dist/triage/scope/mutations-core.js +23 -55
- package/dist/triage/scope-drift/add-ignore.js +5 -39
- package/dist/triage/subscribe/index.d.ts +2 -6
- package/dist/triage/subscribe/index.js +15 -65
- package/dist/triage/welcome/writers.js +15 -74
- package/dist/umbrella-current-shape/index.d.ts +51 -3
- package/dist/umbrella-current-shape/index.js +106 -18
- package/dist/validate-content/deposit-required.d.ts +39 -0
- package/dist/validate-content/deposit-required.js +147 -0
- package/dist/validate-content/index.d.ts +1 -0
- package/dist/validate-content/index.js +1 -0
- package/dist/validate-content/validate-links.d.ts +2 -3
- package/dist/validate-content/validate-links.js +29 -2
- package/dist/vbrief-activate/activate.d.ts +7 -2
- package/dist/vbrief-activate/activate.js +26 -13
- package/dist/vbrief-build/index.d.ts +2 -1
- package/dist/vbrief-build/index.js +2 -1
- package/dist/vbrief-build/parity-scenarios.js +5 -5
- package/dist/vbrief-build/project-definition-io.d.ts +63 -3
- package/dist/vbrief-build/project-definition-io.js +357 -31
- package/dist/vbrief-build/project-definition-mutation.d.ts +32 -0
- package/dist/vbrief-build/project-definition-mutation.js +43 -0
- package/dist/vbrief-validate/conformance.d.ts +1 -0
- package/dist/vbrief-validate/conformance.js +85 -8
- package/dist/vbrief-validate/main.js +2 -0
- package/dist/vbrief-validate/precutover.js +5 -10
- package/dist/verify-ac/clauses.d.ts +62 -2
- package/dist/verify-ac/clauses.js +183 -111
- package/dist/verify-ac/evaluate.d.ts +9 -0
- package/dist/verify-ac/evaluate.js +32 -9
- package/dist/verify-ac/index.d.ts +1 -1
- package/dist/verify-ac/index.js +1 -1
- package/dist/verify-env/node-runtime.d.ts +8 -4
- package/dist/verify-env/node-runtime.js +9 -6
- package/dist/verify-env/toolchain-check.d.ts +35 -3
- package/dist/verify-env/toolchain-check.js +155 -36
- package/dist/verify-source/deposit-closure.d.ts +23 -0
- package/dist/verify-source/deposit-closure.js +162 -0
- package/dist/verify-source/index.d.ts +2 -0
- package/dist/verify-source/index.js +2 -0
- package/dist/verify-source/project-definition-mutation-boundary.d.ts +104 -0
- package/dist/verify-source/project-definition-mutation-boundary.js +326 -0
- package/dist/verify-source/semantic-single-source.d.ts +36 -0
- package/dist/verify-source/semantic-single-source.js +349 -0
- package/package.json +7 -3
|
@@ -1,24 +1,55 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { defaultWhich } from "../scm/binary.js";
|
|
3
|
+
import { classifyScmArgv, resolveBinaryForArgv } from "../scm/call-shape.js";
|
|
4
|
+
import { ghxSpawnFallbackBinary } from "../scm/spawn-status.js";
|
|
3
5
|
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
4
6
|
import { GH_TIMEOUT_S } from "./constants.js";
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* UTF-8-safe gh capture via execFile (no shell) — mirrors _safe_subprocess.run_text (#1366).
|
|
9
|
+
* `binaryOverride` lets a caller pin the SCM binary (e.g. plain `gh` instead of
|
|
10
|
+
* the `ghx` cached proxy) when its guarantee depends on an uncached read (#3767).
|
|
11
|
+
*/
|
|
12
|
+
export function defaultRunGh(cmd, binaryOverride) {
|
|
7
13
|
if (cmd.length === 0 || cmd[0] !== "gh") {
|
|
8
14
|
return { returncode: -1, stdout: "", stderr: "expected gh as first argv element" };
|
|
9
15
|
}
|
|
10
|
-
const binary = resolveBinary();
|
|
11
16
|
const args = cmd.slice(1);
|
|
17
|
+
const binary = binaryOverride ?? resolveBinaryForArgv(args[0] ?? "", args.slice(1));
|
|
18
|
+
const execOpts = {
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
timeout: GH_TIMEOUT_S * 1000,
|
|
21
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
22
|
+
maxBuffer: SUBPROCESS_MAX_BUFFER,
|
|
23
|
+
};
|
|
24
|
+
const runOnce = (bin) => execFileSync(bin, args, execOpts);
|
|
12
25
|
try {
|
|
13
|
-
const stdout =
|
|
14
|
-
encoding: "utf8",
|
|
15
|
-
timeout: GH_TIMEOUT_S * 1000,
|
|
16
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
17
|
-
maxBuffer: SUBPROCESS_MAX_BUFFER,
|
|
18
|
-
});
|
|
26
|
+
const stdout = runOnce(binary);
|
|
19
27
|
return { returncode: 0, stdout: typeof stdout === "string" ? stdout : "", stderr: "" };
|
|
20
28
|
}
|
|
21
|
-
catch (
|
|
29
|
+
catch (caught) {
|
|
30
|
+
let err = caught;
|
|
31
|
+
const first = err;
|
|
32
|
+
const retry = binaryOverride === undefined
|
|
33
|
+
? ghxSpawnFallbackBinary(classifyScmArgv(args[0] ?? "", args.slice(1)), binary, defaultWhich, {
|
|
34
|
+
status: typeof first.status === "number" ? first.status : null,
|
|
35
|
+
error: first.code === "ENOENT" ||
|
|
36
|
+
first.code === "ETIMEDOUT" ||
|
|
37
|
+
typeof first.status !== "number"
|
|
38
|
+
? { code: first.code, message: first.message }
|
|
39
|
+
: undefined,
|
|
40
|
+
stdout: typeof first.stdout === "string" ? first.stdout : "",
|
|
41
|
+
stderr: typeof first.stderr === "string" ? first.stderr : "",
|
|
42
|
+
})
|
|
43
|
+
: null;
|
|
44
|
+
if (retry !== null) {
|
|
45
|
+
try {
|
|
46
|
+
const stdout = runOnce(retry);
|
|
47
|
+
return { returncode: 0, stdout: typeof stdout === "string" ? stdout : "", stderr: "" };
|
|
48
|
+
}
|
|
49
|
+
catch (retryErr) {
|
|
50
|
+
err = retryErr;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
22
53
|
const e = err;
|
|
23
54
|
if (e.code === "ENOENT") {
|
|
24
55
|
return { returncode: -1, stdout: "", stderr: "gh CLI not found. Install GitHub CLI." };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type EnforceMergeApprovalHeadInput, type MergeApprovalHeadResult } from "../policy/merge-approval-head.js";
|
|
2
2
|
import { type AgentMergeEvaluateResult } from "../policy/require-human-merge.js";
|
|
3
3
|
import { type SemanticGreenFn } from "./semantic-green.js";
|
|
4
|
-
import type { MergeFn, MonitorFn, ProtectedCheckFn, WaitMergeableResult } from "./types.js";
|
|
4
|
+
import type { CloseoutAttestableFn, MergeFn, MonitorFn, ProtectedCheckFn, WaitMergeableResult } from "./types.js";
|
|
5
5
|
/** Post-merge umbrella checklist + current-shape refresh (#1649). */
|
|
6
6
|
export type UmbrellaReconcileFn = (projectRoot: string, repo: string) => void;
|
|
7
7
|
export interface WaitMergeableOptions {
|
|
@@ -32,6 +32,14 @@ export interface WaitMergeableOptions {
|
|
|
32
32
|
readonly skipMergeApprovalHeadGate?: boolean;
|
|
33
33
|
/** Inject head-bound approval enforcer (unit tests). */
|
|
34
34
|
readonly mergeApprovalHeadFn?: (input: EnforceMergeApprovalHeadInput) => MergeApprovalHeadResult;
|
|
35
|
+
/**
|
|
36
|
+
* When true, skip the merge-time closeout attestability gate (#3781).
|
|
37
|
+
* Default: same as skipHumanMergeGate, matching the head-gate convention —
|
|
38
|
+
* test harnesses that skip human-merge also skip this unless they opt in.
|
|
39
|
+
*/
|
|
40
|
+
readonly skipCloseoutAttestableGate?: boolean;
|
|
41
|
+
/** Inject the closeout attestability gate (unit tests). */
|
|
42
|
+
readonly closeoutAttestableFn?: CloseoutAttestableFn;
|
|
35
43
|
/** Inject PR HEAD fetch (unit tests; defaults to REST `pulls/<N>`). */
|
|
36
44
|
readonly fetchPrHeadShaFn?: (prNumber: number, repo: string | null) => string | null;
|
|
37
45
|
/**
|
|
@@ -6,7 +6,7 @@ import { classifyMonitorOutcome, parseMonitorPayload } from "./classify.js";
|
|
|
6
6
|
import { EXIT_CONFIG_ERROR, EXIT_MERGED, EXIT_TIMEOUT_OR_ESCALATION } from "./constants.js";
|
|
7
7
|
import { makeResult } from "./result.js";
|
|
8
8
|
import { evaluateSemanticGreen } from "./semantic-green.js";
|
|
9
|
-
import { runGhMerge, runMonitor, runProtectedCheck } from "./wrappers.js";
|
|
9
|
+
import { runCloseoutAttestableCheck, runGhMerge, runMonitor, runProtectedCheck, } from "./wrappers.js";
|
|
10
10
|
/** Node module-not-found / missing script — not a protected-issue overlap (#2667). */
|
|
11
11
|
function isProtectedCheckConfigFailure(stderr) {
|
|
12
12
|
const tail = stderr.trim();
|
|
@@ -228,6 +228,26 @@ export function waitMergeableAndMerge(prNumber, repo, options) {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
+
// #3781: last gate before the merge call. A PR may leave a brief unattested; it
|
|
232
|
+
// may not merge one whose issue it closes in the same act. Keyed on the PR's
|
|
233
|
+
// closing references, so it fires even when the brief is not in the branch diff.
|
|
234
|
+
const skipCloseoutGate = options.skipCloseoutAttestableGate === true ||
|
|
235
|
+
(options.skipCloseoutAttestableGate === undefined && options.skipHumanMergeGate === true);
|
|
236
|
+
if (!skipCloseoutGate) {
|
|
237
|
+
const closeoutFn = options.closeoutAttestableFn ?? runCloseoutAttestableCheck;
|
|
238
|
+
const [coRc, , coStderr] = closeoutFn(prNumber, repo, projectRoot);
|
|
239
|
+
if (coRc !== 0) {
|
|
240
|
+
return makeResult({
|
|
241
|
+
prNumber,
|
|
242
|
+
repo,
|
|
243
|
+
outcome: coRc === 1 ? "closeout-unattested" : "config-error",
|
|
244
|
+
exitCode: coRc === 1 ? EXIT_TIMEOUT_OR_ESCALATION : EXIT_CONFIG_ERROR,
|
|
245
|
+
monitorResult: monitorPayload,
|
|
246
|
+
protectedCheck: protectedCheckPayload,
|
|
247
|
+
error: coStderr.trim(),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
231
251
|
const [mergeRc, mergeStdout, mergeStderr] = mergeFn(prNumber, repo, {
|
|
232
252
|
matchHeadCommit,
|
|
233
253
|
});
|
|
@@ -18,4 +18,6 @@ export type MonitorFn = (prNumber: number, repo: string, capMinutes: number, opt
|
|
|
18
18
|
export type MergeFn = (prNumber: number, repo: string | null, options?: {
|
|
19
19
|
readonly matchHeadCommit?: string | null;
|
|
20
20
|
}) => SubprocessTriple;
|
|
21
|
+
/** Merge-time closeout attestability gate (#3781): 0 attestable / 1 unattested / 2 lookup. */
|
|
22
|
+
export type CloseoutAttestableFn = (prNumber: number, repo: string | null, projectRoot: string) => SubprocessTriple;
|
|
21
23
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -32,6 +32,12 @@ export interface RunProtectedCheckOptions {
|
|
|
32
32
|
}
|
|
33
33
|
/** Invoke pr-protected-issues CLI and return (returncode, stdout, stderr). */
|
|
34
34
|
export declare function runProtectedCheck(prNumber: number, repo: string | null, protectedIssues: readonly number[], options?: RunProtectedCheckOptions): SubprocessTriple;
|
|
35
|
+
/**
|
|
36
|
+
* Merge-time closeout attestability gate (#3781). In-process: the evaluator lives
|
|
37
|
+
* in this package, and a subprocess hop would only add a script-path failure mode
|
|
38
|
+
* to a gate that must fail closed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runCloseoutAttestableCheck(prNumber: number, repo: string | null, projectRoot: string): SubprocessTriple;
|
|
35
41
|
export interface RunMonitorOptions {
|
|
36
42
|
readonly nodeExecutable?: string;
|
|
37
43
|
readonly timeout?: number;
|
|
@@ -3,7 +3,8 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
6
|
+
import { evaluate as evaluateCloseoutAttestable } from "../pr-closeout-attestable/evaluate.js";
|
|
7
|
+
import { resolveBinaryForArgv } from "../scm/call-shape.js";
|
|
7
8
|
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
8
9
|
/** UTF-8-safe subprocess capture via spawnSync (no shell) — mirrors #1366. */
|
|
9
10
|
export function captureExec(executable, args, timeoutMs, options = {}) {
|
|
@@ -97,6 +98,16 @@ export function runProtectedCheck(prNumber, repo, protectedIssues, options = {})
|
|
|
97
98
|
});
|
|
98
99
|
return [result.returncode, result.stdout, result.stderr];
|
|
99
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Merge-time closeout attestability gate (#3781). In-process: the evaluator lives
|
|
103
|
+
* in this package, and a subprocess hop would only add a script-path failure mode
|
|
104
|
+
* to a gate that must fail closed.
|
|
105
|
+
*/
|
|
106
|
+
export function runCloseoutAttestableCheck(prNumber, repo, projectRoot) {
|
|
107
|
+
const result = evaluateCloseoutAttestable(projectRoot, prNumber, { repo });
|
|
108
|
+
const text = result.message.length > 0 ? `${result.message}\n` : "";
|
|
109
|
+
return result.code === 0 ? [0, text, ""] : [result.code, "", text];
|
|
110
|
+
}
|
|
100
111
|
/** Invoke pr-monitor CLI with --json and return (returncode, stdout, stderr). */
|
|
101
112
|
export function runMonitor(prNumber, repo, capMinutes, options = {}) {
|
|
102
113
|
const scriptPath = cliScriptPath("pr-monitor");
|
|
@@ -129,14 +140,14 @@ export function runMonitor(prNumber, repo, capMinutes, options = {}) {
|
|
|
129
140
|
/** Invoke ``gh pr merge --squash --delete-branch --admin`` [``--match-head-commit``]. */
|
|
130
141
|
export function runGhMerge(prNumber, repo, options = {}) {
|
|
131
142
|
const timeoutSec = options.timeout ?? 120;
|
|
143
|
+
const args = ["pr", "merge", String(prNumber), "--squash", "--delete-branch", "--admin"];
|
|
132
144
|
let binary;
|
|
133
145
|
try {
|
|
134
|
-
binary =
|
|
146
|
+
binary = resolveBinaryForArgv("pr", args.slice(1));
|
|
135
147
|
}
|
|
136
148
|
catch {
|
|
137
149
|
return [-1, "", "gh CLI not found. Install GitHub CLI."];
|
|
138
150
|
}
|
|
139
|
-
const args = ["pr", "merge", String(prNumber), "--squash", "--delete-branch", "--admin"];
|
|
140
151
|
if (repo) {
|
|
141
152
|
args.push("--repo", repo);
|
|
142
153
|
}
|
|
@@ -6,6 +6,19 @@ export declare const ACTIVE_FOLDER = "active";
|
|
|
6
6
|
export declare const ELIGIBLE_STATUS = "running";
|
|
7
7
|
/** Actionable redirect appended to every reject path (#810 / #2449). */
|
|
8
8
|
export declare const ACTIVATE_HINT = "Run `task scope:activate -- {path}` (or legacy `task vbrief:activate -- {path}`) before spawning an implementation agent.";
|
|
9
|
+
/**
|
|
10
|
+
* Recovery for the origin-freshness reject (#3828).
|
|
11
|
+
*
|
|
12
|
+
* Freshness is only reached after the active/ + running checks pass, so
|
|
13
|
+
* `ACTIVATE_HINT` names a transition that cannot apply here: `activate` accepts
|
|
14
|
+
* `pending/` alone and fails with `Invalid transition: 'activate' requires file
|
|
15
|
+
* in pending/`. `block` -> `unblock` is in place (`targetFolder: null`), requires
|
|
16
|
+
* and restores `running`, and stamps `plan.updated` plus `xBRIEFInfo.updated`,
|
|
17
|
+
* the field this reject compares. It is interim: the pair also records a
|
|
18
|
+
* `blocked` -> `running` transition for a brief that was never blocked, a
|
|
19
|
+
* tradeoff accepted knowingly. #3857 owns the dedicated acknowledge verb.
|
|
20
|
+
*/
|
|
21
|
+
export declare const ORIGIN_FRESHNESS_HINT: string;
|
|
9
22
|
/** Lifecycle folder names eligible for implementation (#810). */
|
|
10
23
|
export declare const ELIGIBLE_LIFECYCLE_DIRS: readonly ["xbrief/active", "vbrief/active"];
|
|
11
24
|
export declare const PREFLIGHT_USAGE_HINT = "Expected: `task xbrief:preflight -- xbrief/active/<story>.xbrief.json` (legacy: `task vbrief:preflight -- <path>`).";
|
|
@@ -32,6 +45,8 @@ export interface EvaluateOptions {
|
|
|
32
45
|
}
|
|
33
46
|
/** Substitute `{path}` without `$`-pattern expansion in user paths (#1721). */
|
|
34
47
|
export declare function formatActivateHint(path: string): string;
|
|
48
|
+
/** Substitute every `{path}` without `$`-pattern expansion in user paths (#1721). */
|
|
49
|
+
export declare function formatOriginFreshnessHint(path: string): string;
|
|
35
50
|
/**
|
|
36
51
|
* Pure evaluator — returns `{ exitCode, message }`. Never throws; every error
|
|
37
52
|
* path collapses to exit 1 with an actionable message. Faithful to
|
|
@@ -11,6 +11,26 @@ export const ACTIVE_FOLDER = "active";
|
|
|
11
11
|
export const ELIGIBLE_STATUS = "running";
|
|
12
12
|
/** Actionable redirect appended to every reject path (#810 / #2449). */
|
|
13
13
|
export const ACTIVATE_HINT = "Run `task scope:activate -- {path}` (or legacy `task vbrief:activate -- {path}`) before spawning an implementation agent.";
|
|
14
|
+
/**
|
|
15
|
+
* Recovery for the origin-freshness reject (#3828).
|
|
16
|
+
*
|
|
17
|
+
* Freshness is only reached after the active/ + running checks pass, so
|
|
18
|
+
* `ACTIVATE_HINT` names a transition that cannot apply here: `activate` accepts
|
|
19
|
+
* `pending/` alone and fails with `Invalid transition: 'activate' requires file
|
|
20
|
+
* in pending/`. `block` -> `unblock` is in place (`targetFolder: null`), requires
|
|
21
|
+
* and restores `running`, and stamps `plan.updated` plus `xBRIEFInfo.updated`,
|
|
22
|
+
* the field this reject compares. It is interim: the pair also records a
|
|
23
|
+
* `blocked` -> `running` transition for a brief that was never blocked, a
|
|
24
|
+
* tradeoff accepted knowingly. #3857 owns the dedicated acknowledge verb.
|
|
25
|
+
*/
|
|
26
|
+
export const ORIGIN_FRESHNESS_HINT = "Recovery: this xBRIEF is already in active/ at status running. " +
|
|
27
|
+
"Once you have re-read the origin delta, stamp xBRIEFInfo.updated in place with " +
|
|
28
|
+
"`task scope:block -- {path}` then `task scope:unblock -- {path}`. " +
|
|
29
|
+
"That pair is interim: it records a blocked -> running transition for a brief " +
|
|
30
|
+
"that was never blocked, and #3857 owns the verb that records the " +
|
|
31
|
+
"acknowledgement honestly. If the origin could not be fetched or compared, " +
|
|
32
|
+
"restore `gh` REST access to the origin repository first -- a stamp does not " +
|
|
33
|
+
"clear that.";
|
|
14
34
|
/** Lifecycle folder names eligible for implementation (#810). */
|
|
15
35
|
export const ELIGIBLE_LIFECYCLE_DIRS = ["xbrief/active", "vbrief/active"];
|
|
16
36
|
export const PREFLIGHT_USAGE_HINT = "Expected: `task xbrief:preflight -- xbrief/active/<story>.xbrief.json` (legacy: `task vbrief:preflight -- <path>`).";
|
|
@@ -18,8 +38,12 @@ export const PREFLIGHT_USAGE_HINT = "Expected: `task xbrief:preflight -- xbrief/
|
|
|
18
38
|
export function formatActivateHint(path) {
|
|
19
39
|
return ACTIVATE_HINT.replace("{path}", () => path);
|
|
20
40
|
}
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
/** Substitute every `{path}` without `$`-pattern expansion in user paths (#1721). */
|
|
42
|
+
export function formatOriginFreshnessHint(path) {
|
|
43
|
+
return ORIGIN_FRESHNESS_HINT.split("{path}").join(path);
|
|
44
|
+
}
|
|
45
|
+
function buildReject(path, reason, hint) {
|
|
46
|
+
return `${reason}\n ${PREFLIGHT_USAGE_HINT}\n ${hint ?? formatActivateHint(path)}`;
|
|
23
47
|
}
|
|
24
48
|
/** Map Node `JSON.parse` errors to CPython `json.JSONDecodeError.msg` for parity (#1721). */
|
|
25
49
|
function nodeJsonErrorToPythonMsg(nodeMessage) {
|
|
@@ -167,7 +191,9 @@ export function evaluate(vbriefPath, options = {}) {
|
|
|
167
191
|
return {
|
|
168
192
|
exitCode: 1,
|
|
169
193
|
parentLineage: lineage,
|
|
170
|
-
|
|
194
|
+
// #3828: the brief is active + running by this point, so the activate
|
|
195
|
+
// hint would name a transition that hard-errors from the printed state.
|
|
196
|
+
message: buildReject(path, originFreshness.message, formatOriginFreshnessHint(path)),
|
|
171
197
|
};
|
|
172
198
|
}
|
|
173
199
|
// #3425: fail closed when an applicable project invariant has no disposition.
|
|
@@ -93,18 +93,30 @@ export declare function resolveAcceptanceVerdict(reading: AcceptanceReading): Ac
|
|
|
93
93
|
/** One line naming the predicate and the value it read (#3497). */
|
|
94
94
|
export declare function formatAcceptanceVerdict(verdictResult: AcceptanceVerdict): string;
|
|
95
95
|
/**
|
|
96
|
-
* Clause-walk composition (#3323 / #3497).
|
|
96
|
+
* Clause-walk composition (#3323 / #3497 / #3826).
|
|
97
97
|
*
|
|
98
98
|
* A clause the shipped artifact contradicts (`failed`) always blocks. A clause the
|
|
99
99
|
* static walk cannot decide (`unverifiable`) is evidence of nothing — it blocks only
|
|
100
100
|
* when nothing else verified the product. A green executable acceptance run IS that
|
|
101
101
|
* something: the product-first oracle already ran. Before #3497 an all-unverifiable
|
|
102
102
|
* clause set refused an artifact whose stated command had just exited 0.
|
|
103
|
+
*
|
|
104
|
+
* #3826 excused a set the walk has no oracle for at all: a clause with no bound
|
|
105
|
+
* artifact path can only ever come back `unverifiable`, so demanding a positive
|
|
106
|
+
* `verified` from a set of them cannot be satisfied by doing the work correctly.
|
|
107
|
+
* Where the walk has no oracle, `failed === 0` is the strongest verdict available
|
|
108
|
+
* and `evaluateAcceptanceEvidenceGate` adjudicates those criteria at `scope:complete`.
|
|
109
|
+
*
|
|
110
|
+
* #3835 makes that excusal per clause. As a *set* predicate, `verified > 0` was
|
|
111
|
+
* re-armed for every clause by any single bound one, so one verified binding
|
|
112
|
+
* covered siblings that had their own oracle and did not meet it.
|
|
113
|
+
* `adjudicableUnverified` counts exactly those siblings.
|
|
103
114
|
*/
|
|
104
115
|
export declare function clauseWalkBlocks(input: {
|
|
105
116
|
readonly failed: number;
|
|
106
|
-
readonly verified: number;
|
|
107
117
|
readonly walked: number;
|
|
118
|
+
/** Clauses the walk had an oracle for and that did not come back `verified`. */
|
|
119
|
+
readonly adjudicableUnverified: number;
|
|
108
120
|
readonly hasGreenExecutableRun: boolean;
|
|
109
121
|
}): boolean;
|
|
110
122
|
/** Which consumer is reading acceptance. Selects one shared option profile (#3497). */
|
|
@@ -106,19 +106,30 @@ export function formatAcceptanceVerdict(verdictResult) {
|
|
|
106
106
|
return `${lead}\n remedy: ${verdictResult.remedy}`;
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
|
-
* Clause-walk composition (#3323 / #3497).
|
|
109
|
+
* Clause-walk composition (#3323 / #3497 / #3826).
|
|
110
110
|
*
|
|
111
111
|
* A clause the shipped artifact contradicts (`failed`) always blocks. A clause the
|
|
112
112
|
* static walk cannot decide (`unverifiable`) is evidence of nothing — it blocks only
|
|
113
113
|
* when nothing else verified the product. A green executable acceptance run IS that
|
|
114
114
|
* something: the product-first oracle already ran. Before #3497 an all-unverifiable
|
|
115
115
|
* clause set refused an artifact whose stated command had just exited 0.
|
|
116
|
+
*
|
|
117
|
+
* #3826 excused a set the walk has no oracle for at all: a clause with no bound
|
|
118
|
+
* artifact path can only ever come back `unverifiable`, so demanding a positive
|
|
119
|
+
* `verified` from a set of them cannot be satisfied by doing the work correctly.
|
|
120
|
+
* Where the walk has no oracle, `failed === 0` is the strongest verdict available
|
|
121
|
+
* and `evaluateAcceptanceEvidenceGate` adjudicates those criteria at `scope:complete`.
|
|
122
|
+
*
|
|
123
|
+
* #3835 makes that excusal per clause. As a *set* predicate, `verified > 0` was
|
|
124
|
+
* re-armed for every clause by any single bound one, so one verified binding
|
|
125
|
+
* covered siblings that had their own oracle and did not meet it.
|
|
126
|
+
* `adjudicableUnverified` counts exactly those siblings.
|
|
116
127
|
*/
|
|
117
128
|
export function clauseWalkBlocks(input) {
|
|
118
129
|
if (input.failed > 0) {
|
|
119
130
|
return true;
|
|
120
131
|
}
|
|
121
|
-
if (input.walked === 0 || input.
|
|
132
|
+
if (input.walked === 0 || input.adjudicableUnverified === 0) {
|
|
122
133
|
return false;
|
|
123
134
|
}
|
|
124
135
|
return !input.hasGreenExecutableRun;
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
import { existsSync, readFileSync } from "node:fs";
|
|
11
11
|
import { basename, isAbsolute, relative, resolve } from "node:path";
|
|
12
12
|
import { emitAcceptanceStampFromPlan, MISSING_AMBIGUITY_ATTESTATION_CAUSE, stampedAmbiguityAttestationError, } from "../intake/clause-derivation.js";
|
|
13
|
-
import { appendLiteralAcceptanceAdvisory, evaluateLiteralAcceptanceFromPlan, isExecutableLiteralSource, isInlineProseMention, isNoopRefusalReason, readNotAcceptanceCommands, readStoredLiteralAcceptanceCommands, runLiteralAcceptanceCommands, stripLiteralAcceptanceAdvisory, } from "../literal-acceptance/index.js";
|
|
13
|
+
import { appendLiteralAcceptanceAdvisory, evaluateLiteralAcceptanceFromPlan, isExecutableLiteralSource, isInlineProseMention, isNoopRefusalReason, isSafetyRefusalRun, readNotAcceptanceCommands, readStoredLiteralAcceptanceCommands, runLiteralAcceptanceCommands, stripLiteralAcceptanceAdvisory, } from "../literal-acceptance/index.js";
|
|
14
14
|
import { ENV_RUN_SUMMARY_PATH, RunSummaryEmitter, } from "../run-summary/index.js";
|
|
15
15
|
import { maybeBankOnAcPass } from "../session/ac-pass-banking.js";
|
|
16
16
|
import { resolveAcReuse, resolveScopeIdForAcReuse, snapshotFromReuseFields, } from "../session/ac-pass-reuse.js";
|
|
17
17
|
import { gitHead } from "../session/git.js";
|
|
18
18
|
import { hashProductState } from "../session/product-state-hash.js";
|
|
19
19
|
import { resolveVerifyAcSessionId, writeVerifyAcSessionCache, } from "../session/verify-ac-session-cache.js";
|
|
20
|
-
import { formatClauseWalkMessage, walkAcceptanceClauses, } from "../verify-ac/clauses.js";
|
|
20
|
+
import { countUnverifiedAdjudicableClauses, formatClauseWalkMessage, readDeclaredArtifactScope, walkAcceptanceClauses, } from "../verify-ac/clauses.js";
|
|
21
21
|
import { emitVerifyAcAttempts, evaluateProductOracleIntegrity, mergeOracleVerdict, } from "../verify-ac/evaluate.js";
|
|
22
22
|
import { readPlanAcceptance, validatePlanAcceptance } from "./acceptance.js";
|
|
23
23
|
import { clauseWalkBlocks, formatAcceptanceVerdict, resolveAcceptanceVerdict, } from "./acceptance-resolver.js";
|
|
@@ -475,21 +475,24 @@ export function emitVerifyAcTerminalOutcome(input) {
|
|
|
475
475
|
resolvedCommandCount: 0,
|
|
476
476
|
}, { projectRoot: input.projectRoot, env: input.env }, resolve(input.projectRoot));
|
|
477
477
|
}
|
|
478
|
-
function applyClauseWalk(result, options) {
|
|
478
|
+
function applyClauseWalk(result, options, plan) {
|
|
479
479
|
const clauses = result.acceptance.clauses ?? [];
|
|
480
480
|
if (clauses.length === 0 || result.resolution === "config" || result.resolution === "skipped") {
|
|
481
481
|
return result;
|
|
482
482
|
}
|
|
483
483
|
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
484
|
-
|
|
484
|
+
// #3835: the walk reads files, so it reads only what this brief declared.
|
|
485
|
+
const report = walkAcceptanceClauses(clauses, projectRoot, {
|
|
486
|
+
declaredScope: readDeclaredArtifactScope(plan),
|
|
487
|
+
});
|
|
485
488
|
const message = options.quiet ? result.message : formatClauseWalkMessage(report, result.message);
|
|
486
489
|
// #3497: a clause the static walk cannot decide is evidence of nothing. It blocks
|
|
487
490
|
// only when nothing else verified the product; a green executable acceptance run
|
|
488
491
|
// already is the product-first oracle. Failed clauses still block unconditionally.
|
|
489
492
|
const blocked = clauseWalkBlocks({
|
|
490
493
|
failed: report.failed.length,
|
|
491
|
-
verified: report.verified.length,
|
|
492
494
|
walked: report.clauses.length,
|
|
495
|
+
adjudicableUnverified: countUnverifiedAdjudicableClauses(report.clauses),
|
|
493
496
|
hasGreenExecutableRun: result.ok && result.runs.length > 0 && result.runs.every((run) => run.ok),
|
|
494
497
|
});
|
|
495
498
|
const ok = result.ok && !blocked;
|
|
@@ -498,8 +501,10 @@ function applyClauseWalk(result, options) {
|
|
|
498
501
|
ok,
|
|
499
502
|
code: ok ? result.code : result.code === 2 ? 2 : 1,
|
|
500
503
|
message,
|
|
504
|
+
// #3835: only a clause that actually verified may relabel an empty pass as
|
|
505
|
+
// verified. A walk that verified nothing has not verified anything.
|
|
501
506
|
resolution: ok
|
|
502
|
-
? result.resolution === "empty-pass"
|
|
507
|
+
? result.resolution === "empty-pass" && report.verified.length > 0
|
|
503
508
|
? "verified-pass"
|
|
504
509
|
: result.resolution
|
|
505
510
|
: "fail",
|
|
@@ -549,8 +554,13 @@ function labelVerdict(result) {
|
|
|
549
554
|
}
|
|
550
555
|
function applyOracle(result, options, plan = {}) {
|
|
551
556
|
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
552
|
-
const walked = applyClauseWalk(applyRejectedNoop(result), options);
|
|
553
|
-
|
|
557
|
+
const walked = applyClauseWalk(applyRejectedNoop(result), options, plan);
|
|
558
|
+
// #3835: the clause walk may stand in for the empty floor only when it actually
|
|
559
|
+
// verified something. A walk that verified nothing is not positive evidence, so
|
|
560
|
+
// an otherwise-empty acceptance still answers to the project floor rather than
|
|
561
|
+
// passing on the strength of a clause set nothing adjudicated.
|
|
562
|
+
const walkVerified = (walked.clauseOutcomes ?? []).some((row) => row.outcome === "verified");
|
|
563
|
+
const gated = walked.clauseWalked === true && walkVerified ? walked : applyEmptyFloorPolicy(walked, options);
|
|
554
564
|
// Emit/read disk only when the caller supplied env (CLI passes process.env).
|
|
555
565
|
// Tests stay isolated unless they opt in with env or runSummaryText.
|
|
556
566
|
if (options.env !== undefined) {
|
|
@@ -624,6 +634,10 @@ function annotate(result, acceptance, quiet) {
|
|
|
624
634
|
message = "";
|
|
625
635
|
}
|
|
626
636
|
const commandCount = Math.max(result.commands.length, acceptance.commands.length);
|
|
637
|
+
const executedRuns = result.runs.filter((run) => !isSafetyRefusalRun(run));
|
|
638
|
+
const refusedRuns = result.runs.filter(isSafetyRefusalRun);
|
|
639
|
+
const hasRefusal = refusedRuns.length > 0 || (result.rejected?.length ?? 0) > 0;
|
|
640
|
+
const servedFrom = executedRuns.length > 0 ? "executed" : hasRefusal ? "refused" : "executed";
|
|
627
641
|
return {
|
|
628
642
|
...result,
|
|
629
643
|
message,
|
|
@@ -638,7 +652,7 @@ function annotate(result, acceptance, quiet) {
|
|
|
638
652
|
rejectedCount: result.rejected?.length ?? 0,
|
|
639
653
|
}),
|
|
640
654
|
resolvedCommandCount: result.runs.length > 0 ? result.runs.length : commandCount,
|
|
641
|
-
servedFrom
|
|
655
|
+
servedFrom,
|
|
642
656
|
};
|
|
643
657
|
}
|
|
644
658
|
/**
|
|
@@ -26,7 +26,9 @@ export const HYGIENE_GATE_ID_PREFIXES = [
|
|
|
26
26
|
"verify:rule-ownership",
|
|
27
27
|
"verify:biome-config",
|
|
28
28
|
"verify:content-manifest",
|
|
29
|
+
"verify:deposit-closure",
|
|
29
30
|
"verify:skill-external-fetch-gate",
|
|
31
|
+
"verify:semantic-single-source",
|
|
30
32
|
"verify:cursor-tier1",
|
|
31
33
|
"verify:openclaw-tier1",
|
|
32
34
|
"verify:go-freeze",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-vs-released CLI drift report after a cut (#3753).
|
|
3
|
+
*
|
|
4
|
+
* Report-only: never runs `npm i -g`. Never fails the release. Polls all four
|
|
5
|
+
* workspace packages with `--prefer-online` so a lag-poisoned npm cache cannot
|
|
6
|
+
* masquerade as a missing publish.
|
|
7
|
+
*/
|
|
8
|
+
import { type ActiveCliCheckResult } from "../session/active-cli.js";
|
|
9
|
+
import type { ReleaseConfig } from "./types.js";
|
|
10
|
+
/** Workspace packages published by npm-publish.yml (sibling propagate is not atomic). */
|
|
11
|
+
export declare const WORKSPACE_PACKAGES: readonly ["@deftai/directive-types", "@deftai/directive-core", "@deftai/directive-content", "@deftai/directive"];
|
|
12
|
+
export type WorkspacePackageName = (typeof WORKSPACE_PACKAGES)[number];
|
|
13
|
+
/** Observed sibling lag was ~7 minutes; Phase 7 wait sits under this ceiling. */
|
|
14
|
+
export declare const CLI_DRIFT_POLL_TIMEOUT_MS: number;
|
|
15
|
+
export declare const CLI_DRIFT_POLL_INTERVAL_MS = 30000;
|
|
16
|
+
/** Pipeline completion is a single probe — Step 13 returns before npm-publish.yml is green. */
|
|
17
|
+
export declare const CLI_DRIFT_PIPELINE_POLL_TIMEOUT_MS = 0;
|
|
18
|
+
export type RegistryVisibility = "all-visible" | "still-propagating" | "publish-incomplete" | "skipped";
|
|
19
|
+
export interface WorkspacePackageProbe {
|
|
20
|
+
readonly name: WorkspacePackageName;
|
|
21
|
+
readonly visible: boolean;
|
|
22
|
+
readonly version: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface CliDriftReport {
|
|
25
|
+
readonly releasedVersion: string;
|
|
26
|
+
readonly localVersion: string | null;
|
|
27
|
+
readonly localPath: string | null;
|
|
28
|
+
readonly match: boolean;
|
|
29
|
+
readonly shadowed: boolean;
|
|
30
|
+
readonly registry: RegistryVisibility;
|
|
31
|
+
readonly packages: readonly WorkspacePackageProbe[];
|
|
32
|
+
readonly remediation: string;
|
|
33
|
+
readonly lines: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
export interface CliDriftReportSeams {
|
|
36
|
+
readonly checkActiveCli?: (targetVersion: string) => ActiveCliCheckResult;
|
|
37
|
+
readonly viewPackage?: (name: WorkspacePackageName, version: string) => WorkspacePackageProbe;
|
|
38
|
+
readonly nowMs?: () => number;
|
|
39
|
+
readonly sleepMs?: (ms: number) => void;
|
|
40
|
+
}
|
|
41
|
+
export declare function remediationCommand(version: string): string;
|
|
42
|
+
export declare function npmViewArgs(name: WorkspacePackageName, version: string): string[];
|
|
43
|
+
export declare function defaultViewWorkspacePackage(name: WorkspacePackageName, version: string): WorkspacePackageProbe;
|
|
44
|
+
export declare function classifyRegistryVisibility(opts: {
|
|
45
|
+
readonly probes: readonly WorkspacePackageProbe[];
|
|
46
|
+
readonly waitExhausted: boolean;
|
|
47
|
+
readonly skipped: boolean;
|
|
48
|
+
}): RegistryVisibility;
|
|
49
|
+
export declare function pollWorkspacePackages(version: string, opts: {
|
|
50
|
+
readonly timeoutMs: number;
|
|
51
|
+
readonly intervalMs?: number;
|
|
52
|
+
readonly viewPackage: (name: WorkspacePackageName, version: string) => WorkspacePackageProbe;
|
|
53
|
+
readonly nowMs?: () => number;
|
|
54
|
+
readonly sleepMs?: (ms: number) => void;
|
|
55
|
+
}): {
|
|
56
|
+
readonly probes: readonly WorkspacePackageProbe[];
|
|
57
|
+
readonly waitExhausted: boolean;
|
|
58
|
+
};
|
|
59
|
+
export declare function shouldSkipRegistryPoll(config: Pick<ReleaseConfig, "dryRun" | "skipTag" | "version">, env?: NodeJS.ProcessEnv): boolean;
|
|
60
|
+
export declare function buildCliDriftReport(releasedVersion: string, opts?: {
|
|
61
|
+
readonly skipRegistryPoll: boolean;
|
|
62
|
+
readonly pollTimeoutMs?: number;
|
|
63
|
+
readonly pollIntervalMs?: number;
|
|
64
|
+
} & CliDriftReportSeams): CliDriftReport;
|
|
65
|
+
export declare function formatCliDriftReport(report: CliDriftReport): string;
|
|
66
|
+
/** Best-effort wrapper — a report failure must never fail the cut. */
|
|
67
|
+
export declare function emitCliDriftReportBestEffort(releasedVersion: string, opts: Parameters<typeof buildCliDriftReport>[1], write?: (text: string) => void): void;
|
|
68
|
+
//# sourceMappingURL=cli-drift-report.d.ts.map
|