@deftai/directive-core 0.107.0 → 0.108.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/check/cached-orchestrator.js +28 -3
- package/dist/check/named-cause.js +18 -3
- package/dist/codebase/provider.js +7 -1
- package/dist/delivery-attempt/handoff.js +1 -1
- package/dist/design-critique/citation-grammar.d.ts +53 -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 +232 -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 +76 -0
- package/dist/hooks/classify/host-session-identity.js +470 -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 +7 -0
- package/dist/hooks/classify/paths.js +35 -0
- package/dist/hooks/classify/stdin.d.ts +5 -0
- package/dist/hooks/classify/stdin.js +27 -0
- package/dist/hooks/dispatcher.d.ts +52 -1
- package/dist/hooks/dispatcher.js +538 -45
- package/dist/hooks/fixtures/cases.d.ts +16 -2
- package/dist/hooks/fixtures/cases.js +175 -0
- package/dist/hooks/scope.js +3 -1
- package/dist/init-deposit/agent-hooks.d.ts +2 -1
- package/dist/init-deposit/agent-hooks.js +8 -1
- package/dist/init-deposit/hook-runtime-travel.d.ts +77 -0
- package/dist/init-deposit/hook-runtime-travel.js +269 -0
- package/dist/intake/clause-derivation.js +9 -3
- package/dist/intake/issue-ingest.js +62 -2
- package/dist/intake/platform-capabilities.d.ts +9 -2
- package/dist/intake/platform-capabilities.js +38 -9
- package/dist/orphan-active/evaluate.d.ts +25 -0
- package/dist/orphan-active/evaluate.js +193 -128
- package/dist/orphan-active/index.d.ts +1 -0
- package/dist/orphan-active/index.js +1 -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/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-protected-issues/gh.d.ts +6 -2
- package/dist/pr-protected-issues/gh.js +7 -3
- 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 +11 -0
- 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 +17 -7
- package/dist/release/cli-drift-report.d.ts +68 -0
- package/dist/release/cli-drift-report.js +189 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -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 +19 -0
- package/dist/release/types.d.ts +14 -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 +182 -1
- package/dist/review-monitor/lease-comment.d.ts +36 -0
- package/dist/review-monitor/lease-comment.js +103 -2
- package/dist/scm/call.js +12 -3
- 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 +9 -1
- package/dist/scm/gh-rest.js +103 -0
- package/dist/scm/readiness.d.ts +2 -0
- package/dist/scm/readiness.js +28 -4
- package/dist/scope/project-definition-sync.js +14 -7
- package/dist/session/git.d.ts +24 -0
- package/dist/session/git.js +138 -2
- package/dist/session/occupancy.d.ts +238 -12
- package/dist/session/occupancy.js +815 -29
- 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-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/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/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/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/project-definition-mutation-boundary.d.ts +104 -0
- package/dist/verify-source/project-definition-mutation-boundary.js +326 -0
- package/package.json +7 -3
|
@@ -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;
|
|
@@ -17,7 +17,7 @@ import { resolveAcReuse, resolveScopeIdForAcReuse, snapshotFromReuseFields, } fr
|
|
|
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) {
|
|
@@ -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
|
|
@@ -0,0 +1,189 @@
|
|
|
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 { spawnSync } from "node:child_process";
|
|
9
|
+
import { PUBLIC_NPM_REGISTRY } from "../doctor/constants.js";
|
|
10
|
+
import { checkActiveCliAgainstTarget } from "../session/active-cli.js";
|
|
11
|
+
import { RELEASE_E2E_ENV } from "./skip-ci-incident.js";
|
|
12
|
+
/** Same sentinel as release-e2e `REHEARSAL_VERSION` — do not poll npm for 0.0.1. */
|
|
13
|
+
const REHEARSAL_VERSION = "0.0.1";
|
|
14
|
+
/** Workspace packages published by npm-publish.yml (sibling propagate is not atomic). */
|
|
15
|
+
export const WORKSPACE_PACKAGES = [
|
|
16
|
+
"@deftai/directive-types",
|
|
17
|
+
"@deftai/directive-core",
|
|
18
|
+
"@deftai/directive-content",
|
|
19
|
+
"@deftai/directive",
|
|
20
|
+
];
|
|
21
|
+
/** Observed sibling lag was ~7 minutes; Phase 7 wait sits under this ceiling. */
|
|
22
|
+
export const CLI_DRIFT_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
23
|
+
export const CLI_DRIFT_POLL_INTERVAL_MS = 30_000;
|
|
24
|
+
/** Pipeline completion is a single probe — Step 13 returns before npm-publish.yml is green. */
|
|
25
|
+
export const CLI_DRIFT_PIPELINE_POLL_TIMEOUT_MS = 0;
|
|
26
|
+
export function remediationCommand(version) {
|
|
27
|
+
return `npm i -g @deftai/directive@${version} --prefer-online`;
|
|
28
|
+
}
|
|
29
|
+
export function npmViewArgs(name, version) {
|
|
30
|
+
return [
|
|
31
|
+
"view",
|
|
32
|
+
`${name}@${version}`,
|
|
33
|
+
"version",
|
|
34
|
+
"--prefer-online",
|
|
35
|
+
"--ignore-scripts",
|
|
36
|
+
`--registry=${PUBLIC_NPM_REGISTRY}`,
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
export function defaultViewWorkspacePackage(name, version) {
|
|
40
|
+
try {
|
|
41
|
+
const result = spawnSync("npm", npmViewArgs(name, version), {
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
timeout: 15_000,
|
|
44
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
45
|
+
windowsHide: true,
|
|
46
|
+
});
|
|
47
|
+
const raw = typeof result.stdout === "string" ? result.stdout : "";
|
|
48
|
+
const seen = raw.trim().split(/\r?\n/)[0]?.trim() ?? "";
|
|
49
|
+
const visible = result.status === 0 && seen === version;
|
|
50
|
+
return { name, visible, version: seen.length > 0 ? seen : null };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return { name, visible: false, version: null };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function classifyRegistryVisibility(opts) {
|
|
57
|
+
if (opts.skipped)
|
|
58
|
+
return "skipped";
|
|
59
|
+
const visibleCount = opts.probes.filter((p) => p.visible).length;
|
|
60
|
+
if (opts.probes.length > 0 && visibleCount === opts.probes.length)
|
|
61
|
+
return "all-visible";
|
|
62
|
+
if (visibleCount === 0 && opts.waitExhausted)
|
|
63
|
+
return "publish-incomplete";
|
|
64
|
+
return "still-propagating";
|
|
65
|
+
}
|
|
66
|
+
export function pollWorkspacePackages(version, opts) {
|
|
67
|
+
const now = opts.nowMs ?? Date.now;
|
|
68
|
+
const sleep = opts.sleepMs ?? (() => undefined);
|
|
69
|
+
const interval = opts.intervalMs ?? CLI_DRIFT_POLL_INTERVAL_MS;
|
|
70
|
+
const start = now();
|
|
71
|
+
let probes = WORKSPACE_PACKAGES.map((name) => opts.viewPackage(name, version));
|
|
72
|
+
if (probes.every((p) => p.visible)) {
|
|
73
|
+
return { probes, waitExhausted: false };
|
|
74
|
+
}
|
|
75
|
+
if (opts.timeoutMs <= 0) {
|
|
76
|
+
return { probes, waitExhausted: false };
|
|
77
|
+
}
|
|
78
|
+
while (now() - start < opts.timeoutMs) {
|
|
79
|
+
const remaining = opts.timeoutMs - (now() - start);
|
|
80
|
+
if (remaining <= 0)
|
|
81
|
+
break;
|
|
82
|
+
sleep(Math.min(interval, remaining));
|
|
83
|
+
probes = WORKSPACE_PACKAGES.map((name) => opts.viewPackage(name, version));
|
|
84
|
+
if (probes.every((p) => p.visible)) {
|
|
85
|
+
return { probes, waitExhausted: false };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { probes, waitExhausted: true };
|
|
89
|
+
}
|
|
90
|
+
export function shouldSkipRegistryPoll(config, env = process.env) {
|
|
91
|
+
if (config.dryRun || config.skipTag)
|
|
92
|
+
return true;
|
|
93
|
+
if (config.version === REHEARSAL_VERSION)
|
|
94
|
+
return true;
|
|
95
|
+
if (env[RELEASE_E2E_ENV])
|
|
96
|
+
return true;
|
|
97
|
+
if (env.CI === "true" || env.GITHUB_ACTIONS === "true")
|
|
98
|
+
return true;
|
|
99
|
+
// Unit tests never probe the live registry; production `task release` does not set VITEST.
|
|
100
|
+
if (env.VITEST)
|
|
101
|
+
return true;
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
function formatRegistryLine(registry, packages) {
|
|
105
|
+
if (registry === "skipped") {
|
|
106
|
+
return " registry: skipped (dry-run / skip-tag / rehearsal / CI — no publish to poll)";
|
|
107
|
+
}
|
|
108
|
+
const visible = packages.filter((p) => p.visible).map((p) => p.name);
|
|
109
|
+
const missing = packages.filter((p) => !p.visible).map((p) => p.name);
|
|
110
|
+
const counts = `visible ${visible.length}/${packages.length}`;
|
|
111
|
+
if (registry === "all-visible") {
|
|
112
|
+
return ` registry: all-visible (${counts})`;
|
|
113
|
+
}
|
|
114
|
+
if (registry === "publish-incomplete") {
|
|
115
|
+
return ` registry: publish-incomplete (${counts}; none of the four packages resolved after the wait)`;
|
|
116
|
+
}
|
|
117
|
+
const missingText = missing.length > 0 ? `; missing: ${missing.join(", ")}` : "";
|
|
118
|
+
return ` registry: still-propagating (${counts}${missingText})`;
|
|
119
|
+
}
|
|
120
|
+
export function buildCliDriftReport(releasedVersion, opts = { skipRegistryPoll: false }) {
|
|
121
|
+
const check = opts.checkActiveCli ?? ((target) => checkActiveCliAgainstTarget(target));
|
|
122
|
+
const cli = check(releasedVersion);
|
|
123
|
+
const localVersion = cli.active?.version ?? null;
|
|
124
|
+
const localPath = cli.active?.path ?? null;
|
|
125
|
+
const match = localVersion !== null && localVersion === releasedVersion && cli.ok;
|
|
126
|
+
const shadowed = !cli.ok && cli.candidates.length > 0;
|
|
127
|
+
let packages = [];
|
|
128
|
+
let waitExhausted = false;
|
|
129
|
+
if (!opts.skipRegistryPoll) {
|
|
130
|
+
const view = opts.viewPackage ?? defaultViewWorkspacePackage;
|
|
131
|
+
const polled = pollWorkspacePackages(releasedVersion, {
|
|
132
|
+
timeoutMs: opts.pollTimeoutMs ?? CLI_DRIFT_PIPELINE_POLL_TIMEOUT_MS,
|
|
133
|
+
intervalMs: opts.pollIntervalMs,
|
|
134
|
+
viewPackage: view,
|
|
135
|
+
nowMs: opts.nowMs,
|
|
136
|
+
sleepMs: opts.sleepMs,
|
|
137
|
+
});
|
|
138
|
+
packages = polled.probes;
|
|
139
|
+
waitExhausted = polled.waitExhausted;
|
|
140
|
+
}
|
|
141
|
+
const registry = classifyRegistryVisibility({
|
|
142
|
+
probes: packages,
|
|
143
|
+
waitExhausted,
|
|
144
|
+
skipped: opts.skipRegistryPoll,
|
|
145
|
+
});
|
|
146
|
+
const remediation = remediationCommand(releasedVersion);
|
|
147
|
+
const localLabel = localVersion === null
|
|
148
|
+
? "none on PATH"
|
|
149
|
+
: `${localVersion}${localPath !== null ? ` (${localPath})` : ""}`;
|
|
150
|
+
const lines = [
|
|
151
|
+
"CLI drift report (#3753):",
|
|
152
|
+
` released: ${releasedVersion}`,
|
|
153
|
+
` local global CLI: ${localLabel}`,
|
|
154
|
+
` match: ${match ? "yes" : "no"}`,
|
|
155
|
+
...(shadowed
|
|
156
|
+
? [" note: PATH-shadowed install — bare deft --version is not sufficient (#3233)"]
|
|
157
|
+
: []),
|
|
158
|
+
formatRegistryLine(registry, packages),
|
|
159
|
+
` remediation: ${remediation}`,
|
|
160
|
+
" note: report-only — this pipeline does not run npm i -g",
|
|
161
|
+
];
|
|
162
|
+
return {
|
|
163
|
+
releasedVersion,
|
|
164
|
+
localVersion,
|
|
165
|
+
localPath,
|
|
166
|
+
match,
|
|
167
|
+
shadowed,
|
|
168
|
+
registry,
|
|
169
|
+
packages,
|
|
170
|
+
remediation,
|
|
171
|
+
lines,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
export function formatCliDriftReport(report) {
|
|
175
|
+
return `${report.lines.join("\n")}\n`;
|
|
176
|
+
}
|
|
177
|
+
/** Best-effort wrapper — a report failure must never fail the cut. */
|
|
178
|
+
export function emitCliDriftReportBestEffort(releasedVersion, opts, write = (text) => {
|
|
179
|
+
process.stderr.write(text);
|
|
180
|
+
}) {
|
|
181
|
+
try {
|
|
182
|
+
write(formatCliDriftReport(buildCliDriftReport(releasedVersion, opts)));
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
186
|
+
write(`CLI drift report (#3753): skipped (${reason.replace(/\r?\n/g, " ")})\n`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=cli-drift-report.js.map
|
package/dist/release/index.d.ts
CHANGED
package/dist/release/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* v8 ignore file -- re-export barrel; covered via main.ts */
|
|
2
2
|
export * from "./auto-hatch.js";
|
|
3
3
|
export * from "./build-dist.js";
|
|
4
|
+
export * from "./cli-drift-report.js";
|
|
4
5
|
export * from "./closed-verb-gate.js";
|
|
5
6
|
export * from "./constants.js";
|
|
6
7
|
export * from "./coverage-debt-ledger.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IssueState } from "../intake/reconcile-issues.js";
|
|
2
2
|
import { type CallOptions, type CompletedProcess } from "../scm/call.js";
|
|
3
3
|
export type ScmCallFn = (source: string, verb: string, args: readonly string[] | null, options?: CallOptions) => CompletedProcess;
|
|
4
4
|
/** Max seconds to sleep before the single rate-limit retry (operator-locked cap). */
|
|
@@ -9,13 +9,15 @@ export interface RateLimitProbe {
|
|
|
9
9
|
readonly coreResetUnix: number | null;
|
|
10
10
|
readonly graphqlRemaining: number | null;
|
|
11
11
|
}
|
|
12
|
-
export interface FetchIssueStatesForReleaseOptions
|
|
12
|
+
export interface FetchIssueStatesForReleaseOptions {
|
|
13
|
+
readonly cwd?: string;
|
|
14
|
+
readonly scmCall?: ScmCallFn;
|
|
13
15
|
readonly sleep?: SleepFn;
|
|
14
16
|
readonly now?: () => number;
|
|
15
17
|
}
|
|
16
18
|
export type FetchIssueStatesForReleaseResult = {
|
|
17
19
|
readonly ok: true;
|
|
18
|
-
readonly states: Map<number,
|
|
20
|
+
readonly states: Map<number, IssueState>;
|
|
19
21
|
} | {
|
|
20
22
|
readonly ok: false;
|
|
21
23
|
readonly reason: string;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Release Step 3 issue-state fetch with capped rate-limit retry (#2577).
|
|
3
|
+
* Open-issue inventory via one paginated REST subprocess (#3752).
|
|
3
4
|
*/
|
|
4
5
|
import { detectRateLimit } from "../cache/fetch.js";
|
|
5
|
-
import {
|
|
6
|
+
import { IssueState } from "../intake/reconcile-issues.js";
|
|
6
7
|
import { call } from "../scm/call.js";
|
|
8
|
+
import { GhRestError, restIssueListOpenInventory } from "../scm/gh-rest.js";
|
|
7
9
|
/** Max seconds to sleep before the single rate-limit retry (operator-locked cap). */
|
|
8
10
|
export const MAX_RATE_LIMIT_RETRY_SLEEP_S = 120;
|
|
9
11
|
const X_RATE_LIMIT_RESET_RE = /X-RateLimit-Reset:\s*(\d+)/i;
|
|
@@ -15,6 +17,71 @@ function defaultSleep(seconds) {
|
|
|
15
17
|
const shared = new Int32Array(new SharedArrayBuffer(4));
|
|
16
18
|
Atomics.wait(shared, 0, 0, ms);
|
|
17
19
|
}
|
|
20
|
+
function scmCallToRunGhApi(scmCall, cwd) {
|
|
21
|
+
return (args, options) => {
|
|
22
|
+
const result = scmCall("github-issue", "api", args, {
|
|
23
|
+
timeout: options?.timeout ?? 120,
|
|
24
|
+
cwd,
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
returncode: result.returncode,
|
|
28
|
+
stdout: result.stdout,
|
|
29
|
+
stderr: result.stderr,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function buildStatesFromOpenInventory(issueNumbers, openInventory) {
|
|
34
|
+
const openNumbers = new Set();
|
|
35
|
+
for (const row of openInventory) {
|
|
36
|
+
const n = row.number;
|
|
37
|
+
if (typeof n === "number" && Number.isInteger(n)) {
|
|
38
|
+
openNumbers.add(n);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const states = new Map();
|
|
42
|
+
for (const n of [...issueNumbers].sort((a, b) => a - b)) {
|
|
43
|
+
states.set(n, openNumbers.has(n) ? new IssueState("OPEN") : new IssueState("NOT_FOUND"));
|
|
44
|
+
}
|
|
45
|
+
return states;
|
|
46
|
+
}
|
|
47
|
+
function fetchOpenInventoryAttempt(repo, runGhApiFn) {
|
|
48
|
+
let sawRateLimit = false;
|
|
49
|
+
let rateLimitStderr = "";
|
|
50
|
+
const trackingFn = (args, options) => {
|
|
51
|
+
const result = runGhApiFn(args, options);
|
|
52
|
+
if (result.returncode !== 0 && detectRateLimit(result.stderr)[0]) {
|
|
53
|
+
sawRateLimit = true;
|
|
54
|
+
rateLimitStderr = result.stderr;
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
return {
|
|
60
|
+
inventory: restIssueListOpenInventory(repo, { runGhApiFn: trackingFn }),
|
|
61
|
+
sawRateLimit,
|
|
62
|
+
rateLimitStderr,
|
|
63
|
+
failureReason: null,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const stderr = err instanceof GhRestError ? err.stderr : "";
|
|
68
|
+
if (stderr.length > 0 && detectRateLimit(stderr)[0]) {
|
|
69
|
+
sawRateLimit = true;
|
|
70
|
+
rateLimitStderr = stderr;
|
|
71
|
+
}
|
|
72
|
+
const reason = err instanceof GhRestError
|
|
73
|
+
? `open-issue inventory fetch failed: ${err.message}`
|
|
74
|
+
: err instanceof Error
|
|
75
|
+
? err.message
|
|
76
|
+
: String(err);
|
|
77
|
+
return {
|
|
78
|
+
inventory: null,
|
|
79
|
+
sawRateLimit,
|
|
80
|
+
rateLimitStderr,
|
|
81
|
+
failureReason: reason,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
18
85
|
function parseRateLimitProbe(stdout) {
|
|
19
86
|
try {
|
|
20
87
|
const body = JSON.parse(stdout);
|
|
@@ -101,37 +168,34 @@ export function formatRateLimitFailureDetails(probe, rateLimitRelated) {
|
|
|
101
168
|
return lines.join("\n");
|
|
102
169
|
}
|
|
103
170
|
export function fetchIssueStatesForRelease(repo, issueNumbers, options = {}) {
|
|
171
|
+
if (issueNumbers.size === 0) {
|
|
172
|
+
return { ok: true, states: new Map() };
|
|
173
|
+
}
|
|
174
|
+
process.stderr.write(`[release Step 3] checking ${issueNumbers.size} unique anchored issue(s) via open-issue inventory\n`);
|
|
104
175
|
const sleepFn = options.sleep ?? defaultSleep;
|
|
105
176
|
const nowFn = options.now ?? (() => Math.floor(Date.now() / 1000));
|
|
106
177
|
const baseScmCall = options.scmCall ?? call;
|
|
107
178
|
const cwd = options.cwd ?? undefined;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (result.returncode !== 0 && detectRateLimit(result.stderr)[0]) {
|
|
113
|
-
sawRateLimit = true;
|
|
114
|
-
lastRateLimitStderr = result.stderr;
|
|
115
|
-
}
|
|
116
|
-
return result;
|
|
179
|
+
const runGhApiFn = scmCallToRunGhApi(baseScmCall, cwd);
|
|
180
|
+
const finishSuccess = (inventory) => {
|
|
181
|
+
process.stderr.write(`[release Step 3] open-issue inventory: ${inventory.length} open issue(s)\n`);
|
|
182
|
+
return { ok: true, states: buildStatesFromOpenInventory(issueNumbers, inventory) };
|
|
117
183
|
};
|
|
118
|
-
let
|
|
119
|
-
if (
|
|
120
|
-
return
|
|
184
|
+
let attempt = fetchOpenInventoryAttempt(repo, runGhApiFn);
|
|
185
|
+
if (attempt.inventory !== null) {
|
|
186
|
+
return finishSuccess(attempt.inventory);
|
|
121
187
|
}
|
|
122
|
-
if (sawRateLimit) {
|
|
188
|
+
if (attempt.sawRateLimit) {
|
|
123
189
|
const probe = probeGithubRateLimit(baseScmCall, cwd);
|
|
124
|
-
const sleepS = computeRateLimitSleepSeconds(
|
|
190
|
+
const sleepS = computeRateLimitSleepSeconds(attempt.rateLimitStderr, probe, nowFn());
|
|
125
191
|
process.stderr.write(`[release Step 3] GitHub REST rate limit hit; sleeping ${sleepS}s before one retry\n`);
|
|
126
192
|
sleepFn(sleepS);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (states !== null) {
|
|
131
|
-
return { ok: true, states };
|
|
193
|
+
attempt = fetchOpenInventoryAttempt(repo, runGhApiFn);
|
|
194
|
+
if (attempt.inventory !== null) {
|
|
195
|
+
return finishSuccess(attempt.inventory);
|
|
132
196
|
}
|
|
133
197
|
}
|
|
134
|
-
const rateLimitRelated = sawRateLimit ||
|
|
198
|
+
const rateLimitRelated = attempt.sawRateLimit || attempt.rateLimitStderr.length > 0;
|
|
135
199
|
if (rateLimitRelated) {
|
|
136
200
|
const probe = probeGithubRateLimit(baseScmCall, cwd);
|
|
137
201
|
const details = formatRateLimitFailureDetails(probe, true);
|
|
@@ -141,6 +205,7 @@ export function fetchIssueStatesForRelease(repo, issueNumbers, options = {}) {
|
|
|
141
205
|
reason: "GitHub REST rate limit exhausted (see stderr for recovery steps)",
|
|
142
206
|
};
|
|
143
207
|
}
|
|
208
|
+
process.stderr.write(`${attempt.failureReason ?? "open-issue inventory fetch failed"}\n`);
|
|
144
209
|
return { ok: false, reason: "failed to fetch issue states from gh" };
|
|
145
210
|
}
|
|
146
211
|
//# sourceMappingURL=issue-state-fetch.js.map
|
|
@@ -43,6 +43,7 @@ export function checkVbriefLifecycleSyncNative(projectRoot, repo) {
|
|
|
43
43
|
anchorIssueNumbers.add(num);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
process.stderr.write(`[release Step 3] ${anchors.length} lifecycle anchor(s), ${anchorIssueNumbers.size} unique issue number(s) to evaluate\n`);
|
|
46
47
|
const fetchResult = fetchIssueStatesForRelease(repo, anchorIssueNumbers, {
|
|
47
48
|
cwd: projectRoot,
|
|
48
49
|
});
|
package/dist/release/pipeline.js
CHANGED
|
@@ -4,6 +4,7 @@ import { assertProjectionContained } from "../fs/projection-containment.js";
|
|
|
4
4
|
import { readCoverageTotalsFromReport } from "../vitest-runner/coverage-debt.js";
|
|
5
5
|
import { buildCoverageDebtIssueDraft, classifyStep5FailureWithFreshness, evaluateAutoHatch, formatAutoHatchBanner, parseExitCodeFromReason, reasonLooksLikeTimeout, } from "./auto-hatch.js";
|
|
6
6
|
import { prependUpgradeBanner, promoteChangelog, sectionForVersion } from "./changelog.js";
|
|
7
|
+
import { emitCliDriftReportBestEffort, shouldSkipRegistryPoll, } from "./cli-drift-report.js";
|
|
7
8
|
import { assertTagPushClosedVerb } from "./closed-verb-gate.js";
|
|
8
9
|
import { EXIT_CONFIG_ERROR, EXIT_OK, EXIT_VIOLATION, RELEASE_ARTIFACTS, RELEASE_CHECK_TIMEOUT_MINUTES, TOTAL_STEPS, VERIFY_DRAFT_INTERVAL_SECONDS, VERIFY_DRAFT_MAX_ATTEMPTS, } from "./constants.js";
|
|
9
10
|
import { createCoverageDebtIssue, probeOpenCoverageDebtLedger } from "./coverage-debt-ledger.js";
|
|
@@ -472,6 +473,24 @@ export function runPipeline(config, seams = {}) {
|
|
|
472
473
|
}
|
|
473
474
|
}
|
|
474
475
|
process.stderr.write(`Release v${version} pipeline complete (dry_run=${config.dryRun ? "True" : "False"}, skip_tag=${config.skipTag ? "True" : "False"}, skip_release=${config.skipRelease ? "True" : "False"}).\n`);
|
|
476
|
+
// #3753 — report-only. Never runs npm i -g. Never fails the cut.
|
|
477
|
+
// Single-shot registry probe (no wait): Step 13 returns before npm-publish.yml
|
|
478
|
+
// is green; Phase 7 of the release skill owns the bounded wait.
|
|
479
|
+
emitCliDriftReportBestEffort(version, {
|
|
480
|
+
skipRegistryPoll: shouldSkipRegistryPoll(config),
|
|
481
|
+
pollTimeoutMs: 0,
|
|
482
|
+
checkActiveCli: seams.checkActiveCli,
|
|
483
|
+
viewPackage: seams.viewWorkspacePackage
|
|
484
|
+
? (name, ver) => {
|
|
485
|
+
const probe = seams.viewWorkspacePackage?.(name, ver);
|
|
486
|
+
return {
|
|
487
|
+
name: name,
|
|
488
|
+
visible: probe?.visible ?? false,
|
|
489
|
+
version: probe?.version ?? null,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
: undefined,
|
|
493
|
+
});
|
|
475
494
|
return EXIT_OK;
|
|
476
495
|
}
|
|
477
496
|
//# sourceMappingURL=pipeline.js.map
|
package/dist/release/types.d.ts
CHANGED
|
@@ -89,5 +89,19 @@ export interface ReleaseSeams {
|
|
|
89
89
|
* Tests inject `{}` so a host env bypass cannot leak into fail-closed cases.
|
|
90
90
|
*/
|
|
91
91
|
readonly closedVerbEnv?: EnvMap;
|
|
92
|
+
/**
|
|
93
|
+
* #3753 — override the active-CLI probe used by the local-vs-released report.
|
|
94
|
+
* When omitted, production calls `checkActiveCliAgainstTarget`.
|
|
95
|
+
*/
|
|
96
|
+
readonly checkActiveCli?: (targetVersion: string) => import("../session/active-cli.js").ActiveCliCheckResult;
|
|
97
|
+
/**
|
|
98
|
+
* #3753 — override one `npm view <pkg>@<ver> --prefer-online` (tests).
|
|
99
|
+
* When omitted, production spawns npm. Never used to install.
|
|
100
|
+
*/
|
|
101
|
+
readonly viewWorkspacePackage?: (name: string, version: string) => {
|
|
102
|
+
readonly name: string;
|
|
103
|
+
readonly visible: boolean;
|
|
104
|
+
readonly version: string | null;
|
|
105
|
+
};
|
|
92
106
|
}
|
|
93
107
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -13,8 +13,12 @@ export declare const DEFAULT_INCLUDE_SCOPES_MODE: "off";
|
|
|
13
13
|
/** Lifecycle scope aggregation modes for rendered specs (#1566). */
|
|
14
14
|
export type IncludeScopesMode = "off" | "current" | "all";
|
|
15
15
|
export declare const LIFECYCLE_BUCKETS: ReadonlyArray<readonly [string, string]>;
|
|
16
|
+
/** Build a specification banner from the actual specification artifact path. */
|
|
17
|
+
export declare function buildSpecRenderBanner(specPath: string): string;
|
|
16
18
|
export declare const SPEC_RENDER_BANNER: string;
|
|
17
19
|
export declare const PRD_NARRATIVE_KEY_ORDER: readonly ["Overview", "ProblemStatement", "Goals", "UserStories", "Requirements", "SuccessMetrics", "Architecture"];
|
|
20
|
+
/** Build a PRD banner from the actual resolved authority path. */
|
|
21
|
+
export declare function buildPrdBanner(sourcePath: string): string;
|
|
18
22
|
export declare const PRD_BANNER: string;
|
|
19
23
|
export declare const PRD_GENERATED_SENTINEL = "AUTO-GENERATED by task prd:render";
|
|
20
24
|
/** Max completed scopes listed under ## Completed in ROADMAP.md (#2653). */
|