@deftai/directive 0.119.9 → 0.119.11
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/dispatch.d.ts +2 -2
- package/dist/dispatch.js +13 -0
- package/dist/session-start.d.ts +2 -0
- package/dist/session-start.js +17 -0
- package/dist/verify-ac.js +103 -1
- package/dist/verify-completed-write-guard.js +12 -0
- package/dist/verify-durable-effect-acquisition.d.ts +13 -0
- package/dist/verify-durable-effect-acquisition.js +70 -0
- package/dist/verify-operator-scope-limit.d.ts +17 -0
- package/dist/verify-operator-scope-limit.js +285 -0
- package/dist/verify-presentation-ceiling.d.ts +11 -0
- package/dist/verify-presentation-ceiling.js +71 -0
- package/dist/verify-presentation-coverage.d.ts +14 -0
- package/dist/verify-presentation-coverage.js +90 -0
- package/dist/verify-review-monitor.js +23 -12
- package/dist/verify-scope-provenance.js +5 -1
- package/dist/windows-bin-ps1.js +2 -0
- package/package.json +3 -3
package/dist/dispatch.d.ts
CHANGED
|
@@ -10,9 +10,9 @@ export interface DispatchIo {
|
|
|
10
10
|
writeErr: (text: string) => void;
|
|
11
11
|
}
|
|
12
12
|
/** CLI modules in packages/cli/src (excluding parity harnesses and bin/index). */
|
|
13
|
-
export declare const CLI_MODULE_VERBS: readonly ["agents-refresh", "cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "install-upgrade", "install-uninstall", "migrate-preflight", "migrate-xbrief", "migrate-category-b", "framework-check-updates", "hook-dispatch", "umbrella-current-shape", "changelog-check", "change-init", "commit-lint", "coverage-hotspots", "policy", "authz", "escalation-cli", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "pr-finish-loop", "directive-finish-loop", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "release-wait-npm", "scope-lifecycle", "scope-record-approved-scope", "scope-record-observable-scope", "scope-record-intent-constraint", "scm-sync-default", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "occupancy-steal", "occupancy-release", "occupancy-heartbeat", "occupancy-grant", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-strip-withdrawn", "triage-evaluate", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "xbrief-create", "xbrief-verify", "xbrief-adopt-stored-plan-id", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "verify-class-checks", "verify-scope-provenance", "verify-consumer-check-contract", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-biome-config", "verify-bridge-drift", "verify-capacity", "verify-contained-writes", "verify-telemetry-coverage", "verify-content-manifest", "verify-deposit-closure", "verify-consumer-hard-stops", "verify-closing-keywords", "verify-skill-external-fetch-gate", "verify-semantic-single-source", "verify-contract-drift", "verify-cursor-tier1", "verify-openclaw-tier1", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-plan-sequence", "verify-stubs", "verify-xbrief-drift", "verify-spec-prd-fresh", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "verify-subagent-steer", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "verify-pr-closeout-attestable", "verify-lifecycle-visible", "verify-completed-tracked", "verify-completed-write-guard", "verify-literal-ac", "verify-ac", "verify-agents-md-budget", "verify-agents-md-advisory", "verify-eval-health-relocation", "verify-eval-triggers-relocation", "verify-evaluator-surface", "verify-observable-scope", "verify-intent-constraint", "verify-consumer-test-lane", "eval-health", "eval-run", "eval-report", "eval-triggers"];
|
|
13
|
+
export declare const CLI_MODULE_VERBS: readonly ["agents-refresh", "cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "install-upgrade", "install-uninstall", "migrate-preflight", "migrate-xbrief", "migrate-category-b", "framework-check-updates", "hook-dispatch", "umbrella-current-shape", "changelog-check", "change-init", "commit-lint", "coverage-hotspots", "policy", "authz", "escalation-cli", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "pr-finish-loop", "directive-finish-loop", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "release-wait-npm", "scope-lifecycle", "scope-record-approved-scope", "scope-record-observable-scope", "scope-record-intent-constraint", "scm-sync-default", "lifecycle-event", "lifecycle-stats", "session-start", "session-ready", "occupancy-steal", "occupancy-release", "occupancy-heartbeat", "occupancy-grant", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-strip-withdrawn", "triage-evaluate", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "xbrief-create", "xbrief-verify", "xbrief-adopt-stored-plan-id", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "verify-class-checks", "verify-presentation-coverage", "verify-scope-provenance", "verify-consumer-check-contract", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-biome-config", "verify-bridge-drift", "verify-capacity", "verify-contained-writes", "verify-telemetry-coverage", "verify-content-manifest", "verify-deposit-closure", "verify-consumer-hard-stops", "verify-closing-keywords", "verify-skill-external-fetch-gate", "verify-semantic-single-source", "verify-contract-drift", "verify-cursor-tier1", "verify-openclaw-tier1", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-plan-sequence", "verify-stubs", "verify-xbrief-drift", "verify-spec-prd-fresh", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "verify-subagent-steer", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "verify-pr-closeout-attestable", "verify-lifecycle-visible", "verify-completed-tracked", "verify-completed-write-guard", "verify-literal-ac", "verify-ac", "verify-agents-md-budget", "verify-agents-md-advisory", "verify-eval-health-relocation", "verify-eval-triggers-relocation", "verify-evaluator-surface", "verify-observable-scope", "verify-operator-scope-limit", "verify-presentation-ceiling", "verify-intent-constraint", "verify-durable-effect-acquisition", "verify-consumer-test-lane", "eval-health", "eval-run", "eval-report", "eval-triggers"];
|
|
14
14
|
/** Core-only CLI entrypoints without a packages/cli wrapper. */
|
|
15
|
-
export declare const CORE_MODULE_VERBS: readonly ["scm", "scm-readiness", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "issue-sync-from-xbrief", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-finalize-cohort", "swarm-pre-dispatch", "swarm-readiness", "swarm-routing-verify", "swarm-routing-set", "swarm-verify-review-clean", "swarm-worktrees", "framework-commands", "pack-render", "packs-slice", "prd-render", "export-spec", "project-render", "project-write-narratives", "roadmap-render", "rule-map", "spec-render", "spec-validate", "code-structure-validate", "pack-migrate-skills", "pack-migrate-rules", "pack-migrate-strategies", "pack-migrate-patterns", "pack-migrate-swarm-spec", "policy-set", "setup-ghx", "scope-undo", "scope-demote", "scope-decompose", "changelog-resolve-unreleased", "architecture-preflight-sor", "feedback-file", "value-readback", "product-signal", "freshness-report", "decision-write", "decision-list", "docs-impact"];
|
|
15
|
+
export declare const CORE_MODULE_VERBS: readonly ["scm", "scm-readiness", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "issue-sync-from-xbrief", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-finalize-cohort", "swarm-finalize-owed", "swarm-pre-dispatch", "swarm-readiness", "swarm-routing-verify", "swarm-routing-set", "swarm-verify-review-clean", "swarm-worktrees", "framework-commands", "pack-render", "packs-slice", "prd-render", "export-spec", "project-render", "project-write-narratives", "roadmap-render", "rule-map", "spec-render", "spec-validate", "code-structure-validate", "pack-migrate-skills", "pack-migrate-rules", "pack-migrate-strategies", "pack-migrate-patterns", "pack-migrate-swarm-spec", "policy-set", "setup-ghx", "scope-undo", "scope-demote", "scope-decompose", "changelog-resolve-unreleased", "architecture-preflight-sor", "feedback-file", "value-readback", "product-signal", "freshness-report", "decision-write", "decision-list", "docs-impact"];
|
|
16
16
|
/** Colon aliases for triage-actions (mirrors cli-router SUBCOMMAND_ROUTES). */
|
|
17
17
|
export declare const TRIAGE_ACTION_ALIAS_SUBCOMMANDS: Readonly<Record<string, string>>;
|
|
18
18
|
/** Colon aliases for policy subcommands (mirrors cli-router SUBCOMMAND_ROUTES). */
|
package/dist/dispatch.js
CHANGED
|
@@ -117,6 +117,7 @@ export const CLI_MODULE_VERBS = [
|
|
|
117
117
|
"verify-forward-coverage",
|
|
118
118
|
"verify-test-boundary",
|
|
119
119
|
"verify-class-checks",
|
|
120
|
+
"verify-presentation-coverage",
|
|
120
121
|
"verify-scope-provenance",
|
|
121
122
|
"verify-consumer-check-contract",
|
|
122
123
|
"verify-hooks-installed",
|
|
@@ -169,7 +170,10 @@ export const CLI_MODULE_VERBS = [
|
|
|
169
170
|
"verify-eval-triggers-relocation",
|
|
170
171
|
"verify-evaluator-surface",
|
|
171
172
|
"verify-observable-scope",
|
|
173
|
+
"verify-operator-scope-limit",
|
|
174
|
+
"verify-presentation-ceiling",
|
|
172
175
|
"verify-intent-constraint",
|
|
176
|
+
"verify-durable-effect-acquisition",
|
|
173
177
|
"verify-consumer-test-lane",
|
|
174
178
|
"eval-health",
|
|
175
179
|
"eval-run",
|
|
@@ -189,6 +193,7 @@ export const CORE_MODULE_VERBS = [
|
|
|
189
193
|
"swarm-launch",
|
|
190
194
|
"swarm-complete-cohort",
|
|
191
195
|
"swarm-finalize-cohort",
|
|
196
|
+
"swarm-finalize-owed",
|
|
192
197
|
"swarm-pre-dispatch",
|
|
193
198
|
"swarm-readiness",
|
|
194
199
|
"swarm-routing-verify",
|
|
@@ -304,6 +309,8 @@ export const VERB_ALIASES = {
|
|
|
304
309
|
"verify:forward-coverage": "verify-forward-coverage",
|
|
305
310
|
"verify:test-boundary": "verify-test-boundary",
|
|
306
311
|
"verify:class-checks": "verify-class-checks",
|
|
312
|
+
"verify:presentation-ceiling": "verify-presentation-ceiling",
|
|
313
|
+
"verify:presentation-coverage": "verify-presentation-coverage",
|
|
307
314
|
"verify:scope-provenance": "verify-scope-provenance",
|
|
308
315
|
"scope:record-approved-scope": "scope-record-approved-scope",
|
|
309
316
|
"scope:record-observable-scope": "scope-record-observable-scope",
|
|
@@ -328,7 +335,9 @@ export const VERB_ALIASES = {
|
|
|
328
335
|
"verify:eval-triggers-relocation": "verify-eval-triggers-relocation",
|
|
329
336
|
"verify:evaluator-surface": "verify-evaluator-surface",
|
|
330
337
|
"verify:observable-scope": "verify-observable-scope",
|
|
338
|
+
"verify:operator-scope-limit": "verify-operator-scope-limit",
|
|
331
339
|
"verify:intent-constraint": "verify-intent-constraint",
|
|
340
|
+
"verify:durable-effect-acquisition": "verify-durable-effect-acquisition",
|
|
332
341
|
"verify:consumer-test-lane": "verify-consumer-test-lane",
|
|
333
342
|
"verify:hooks-installed": "verify-hooks-installed",
|
|
334
343
|
"verify:no-task-runtime": "verify-no-task-runtime",
|
|
@@ -2455,6 +2464,10 @@ async function loadCoreModuleHandler(verb, io) {
|
|
|
2455
2464
|
const { finalizeCohortMain } = await import("@deftai/directive-core/dist/swarm/finalize-cohort-cli.js");
|
|
2456
2465
|
return finalizeCohortMain;
|
|
2457
2466
|
}
|
|
2467
|
+
case "swarm-finalize-owed": {
|
|
2468
|
+
const { finalizeOwedMain } = await import("@deftai/directive-core/dist/swarm/finalize-owed-cli.js");
|
|
2469
|
+
return finalizeOwedMain;
|
|
2470
|
+
}
|
|
2458
2471
|
case "swarm-pre-dispatch": {
|
|
2459
2472
|
const { preDispatchMain } = await import("@deftai/directive-core/dist/swarm/pre-dispatch-cli.js");
|
|
2460
2473
|
return preDispatchMain;
|
package/dist/session-start.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { type PrimaryClaimException, type SessionCeremonyTier, type SessionPostu
|
|
|
4
4
|
export interface ParsedSessionStartArgs {
|
|
5
5
|
projectRoot: string;
|
|
6
6
|
deferValues: string[];
|
|
7
|
+
/** #4919: defer finalize-owed session gate with a recorded reason. */
|
|
8
|
+
deferOwedReason: string | null;
|
|
7
9
|
emitJson: boolean;
|
|
8
10
|
noHistory: boolean;
|
|
9
11
|
readOnly: boolean;
|
package/dist/session-start.js
CHANGED
|
@@ -30,6 +30,7 @@ export function parseArgs(argv) {
|
|
|
30
30
|
const parsed = {
|
|
31
31
|
projectRoot: ".",
|
|
32
32
|
deferValues: [],
|
|
33
|
+
deferOwedReason: null,
|
|
33
34
|
emitJson: false,
|
|
34
35
|
noHistory: false,
|
|
35
36
|
readOnly: false,
|
|
@@ -124,6 +125,21 @@ export function parseArgs(argv) {
|
|
|
124
125
|
}
|
|
125
126
|
parsed.deferValues.push(value);
|
|
126
127
|
}
|
|
128
|
+
else if (arg === "--defer-owed") {
|
|
129
|
+
const value = argv[i + 1];
|
|
130
|
+
if (value === undefined || value.startsWith("--")) {
|
|
131
|
+
return { ...parsed, error: "argument --defer-owed: expected one argument" };
|
|
132
|
+
}
|
|
133
|
+
parsed.deferOwedReason = value;
|
|
134
|
+
i += 1;
|
|
135
|
+
}
|
|
136
|
+
else if (arg?.startsWith("--defer-owed=")) {
|
|
137
|
+
const value = arg.slice("--defer-owed=".length);
|
|
138
|
+
if (value.length === 0 || value.startsWith("--")) {
|
|
139
|
+
return { ...parsed, error: "argument --defer-owed: expected one argument" };
|
|
140
|
+
}
|
|
141
|
+
parsed.deferOwedReason = value;
|
|
142
|
+
}
|
|
127
143
|
else if (arg === "--task-size" || arg === "--ceremony-task-size") {
|
|
128
144
|
const value = argv[i + 1];
|
|
129
145
|
if (value === undefined) {
|
|
@@ -487,6 +503,7 @@ export function run(argv) {
|
|
|
487
503
|
occupant: args.occupant ?? undefined,
|
|
488
504
|
primaryClaimException: args.primaryClaimException ?? undefined,
|
|
489
505
|
sessionId: args.sessionId ?? undefined,
|
|
506
|
+
deferOwedReason: args.deferOwedReason,
|
|
490
507
|
...(args.ceremonyDepthOverride !== null
|
|
491
508
|
? {
|
|
492
509
|
ceremonyDial: selectCeremonyDepth({
|
package/dist/verify-ac.js
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
* Primary name for the product-first done-gate; verify:literal-ac remains
|
|
7
7
|
* the #3267 mechanism alias.
|
|
8
8
|
*/
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
9
10
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
10
11
|
import { join, resolve } from "node:path";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
13
|
import { resolveSessionCompletedVerifyAcTarget } from "@deftai/directive-core/check";
|
|
13
14
|
import { formatRejectedLedger, resolveLiteralAcceptanceDetailed, } from "@deftai/directive-core/literal-acceptance";
|
|
14
|
-
import { emitVerifyAcTerminalOutcome, evaluateVerifyAcFromPath, readPlanAcceptance, resolveAcceptanceGateProfile, } from "@deftai/directive-core/product-first-done-gate";
|
|
15
|
+
import { emitVerifyAcTerminalOutcome, evaluateVerifyAcFromPath, readAdmittedSourceDigest, readAdmittedSourceSentences, readPlanAcceptance, resolveAcceptanceGateProfile, } from "@deftai/directive-core/product-first-done-gate";
|
|
15
16
|
/** Parse verify:ac CLI args. */
|
|
16
17
|
export function parseArgs(argv) {
|
|
17
18
|
const parsed = {
|
|
@@ -111,6 +112,84 @@ export function clampVerifyAcExit(ok, code) {
|
|
|
111
112
|
return 2;
|
|
112
113
|
return 1;
|
|
113
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Spec-path briefs persist the refused GitHub body under plan.metadata.issueBody
|
|
117
|
+
* (#4524 / #5055), including empty string when the origin body was empty. Live
|
|
118
|
+
* recovery must use the Bound-remedy harvest (Overview), not body-normative REST.
|
|
119
|
+
*/
|
|
120
|
+
function planHasSpecPathRefusedBody(plan) {
|
|
121
|
+
const meta = asRecord(plan.metadata);
|
|
122
|
+
if (meta === null) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return Object.hasOwn(meta, "issueBody") && typeof meta.issueBody === "string";
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Spec-path admitted source = Overview harvest remainder (#5055).
|
|
129
|
+
* Fail closed when Overview is empty — do not fall through to the refused body.
|
|
130
|
+
*/
|
|
131
|
+
function fetchSpecPathHarvest(plan) {
|
|
132
|
+
const narratives = asRecord(plan.narratives);
|
|
133
|
+
const overview = narratives?.Overview;
|
|
134
|
+
if (typeof overview === "string" && overview.trim().length > 0) {
|
|
135
|
+
return { ok: true, text: overview };
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
reason: "Spec-path Bound-remedy harvest unavailable (Overview empty); refuse offline / restore from git",
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Live REST body for the origin issue (body-normative admitted source, #5055).
|
|
144
|
+
* Fail closed on forge outage — do not skip.
|
|
145
|
+
*/
|
|
146
|
+
function fetchOriginIssueBody(plan) {
|
|
147
|
+
const refs = Array.isArray(plan.references) ? plan.references : [];
|
|
148
|
+
let issueUrl = null;
|
|
149
|
+
for (const entry of refs) {
|
|
150
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const row = entry;
|
|
154
|
+
if (row.type === "x-xbrief/github-issue" && typeof row.uri === "string") {
|
|
155
|
+
issueUrl = row.uri;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (issueUrl === null) {
|
|
160
|
+
return { ok: false, reason: "no github-issue reference on the brief for live REST" };
|
|
161
|
+
}
|
|
162
|
+
const match = issueUrl.match(/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/i);
|
|
163
|
+
if (match === null) {
|
|
164
|
+
return { ok: false, reason: `unparseable github-issue uri: ${issueUrl}` };
|
|
165
|
+
}
|
|
166
|
+
const owner = match[1] ?? "";
|
|
167
|
+
const repo = match[2] ?? "";
|
|
168
|
+
const number = match[3] ?? "";
|
|
169
|
+
const apiPath = `repos/${owner}/${repo}/issues/${number}`;
|
|
170
|
+
const proc = spawnSync("gh", ["api", apiPath, "--jq", ".body"], {
|
|
171
|
+
encoding: "utf8",
|
|
172
|
+
env: process.env,
|
|
173
|
+
});
|
|
174
|
+
if (proc.error) {
|
|
175
|
+
return { ok: false, reason: `forge outage: ${proc.error.message}` };
|
|
176
|
+
}
|
|
177
|
+
if (proc.status !== 0) {
|
|
178
|
+
const detail = `${proc.stderr ?? ""}${proc.stdout ?? ""}`.trim() || `gh api exited ${String(proc.status)}`;
|
|
179
|
+
return { ok: false, reason: `forge outage: ${detail}` };
|
|
180
|
+
}
|
|
181
|
+
return { ok: true, text: typeof proc.stdout === "string" ? proc.stdout : "" };
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Live admitted-source text for digest compare / missing-pin recovery (#5055).
|
|
185
|
+
* Spec-path → Bound-remedy harvest; body-normative → origin issue body.
|
|
186
|
+
*/
|
|
187
|
+
function fetchAdmittedSourceForPlan(plan) {
|
|
188
|
+
if (planHasSpecPathRefusedBody(plan)) {
|
|
189
|
+
return fetchSpecPathHarvest(plan);
|
|
190
|
+
}
|
|
191
|
+
return fetchOriginIssueBody(plan);
|
|
192
|
+
}
|
|
114
193
|
/** Evaluate one or many xBRIEF paths; return worst non-zero code (fail closed). */
|
|
115
194
|
function evaluatePaths(paths, options) {
|
|
116
195
|
let worst = 0;
|
|
@@ -121,6 +200,28 @@ function evaluatePaths(paths, options) {
|
|
|
121
200
|
if (!options.quiet && paths.length > 1) {
|
|
122
201
|
process.stdout.write(`verify:ac — evaluating ${path}\n`);
|
|
123
202
|
}
|
|
203
|
+
let fetchAdmittedSourceText;
|
|
204
|
+
try {
|
|
205
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
206
|
+
const root = asRecord(raw);
|
|
207
|
+
const plan = asRecord(root?.plan);
|
|
208
|
+
// Arm live admitted-source fetch when a pin is present (digest compare), a
|
|
209
|
+
// digest remains after pin delete (honor recorded digest), or Spec-path
|
|
210
|
+
// refused-body metadata marks harvest recovery (#5055). Spec-path callbacks
|
|
211
|
+
// return the Bound-remedy harvest, not the refused raw issue body. Body-
|
|
212
|
+
// normative both-deleted recovery prefers git HEAD / merge-base so
|
|
213
|
+
// pre-#5055 briefs without a pin are not suddenly floored by live REST.
|
|
214
|
+
if (plan !== null) {
|
|
215
|
+
const pin = readAdmittedSourceSentences(plan.acceptance);
|
|
216
|
+
const digest = readAdmittedSourceDigest(plan.acceptance);
|
|
217
|
+
if (pin !== null || digest !== null || planHasSpecPathRefusedBody(plan)) {
|
|
218
|
+
fetchAdmittedSourceText = () => fetchAdmittedSourceForPlan(plan);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Path evaluation still runs; unreadable brief is handled inside evaluateVerifyAcFromPath.
|
|
224
|
+
}
|
|
124
225
|
const result = evaluateVerifyAcFromPath(path, {
|
|
125
226
|
projectRoot: options.projectRoot,
|
|
126
227
|
quiet: options.quiet,
|
|
@@ -129,6 +230,7 @@ function evaluatePaths(paths, options) {
|
|
|
129
230
|
captureFromNarratives: profile.captureFromNarratives,
|
|
130
231
|
reuseMode: profile.reuseMode,
|
|
131
232
|
env: process.env,
|
|
233
|
+
...(fetchAdmittedSourceText !== undefined ? { fetchAdmittedSourceText } : {}),
|
|
132
234
|
});
|
|
133
235
|
if (result.message.length > 0) {
|
|
134
236
|
if (result.ok) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
2
3
|
/**
|
|
3
4
|
* CLI for verify:completed-write-guard (#3679).
|
|
4
5
|
*/
|
|
@@ -55,6 +56,17 @@ export function run(argv) {
|
|
|
55
56
|
const projectRoot = resolve(args.projectRoot);
|
|
56
57
|
const result = evaluateCompletedWriteGuard(projectRoot, {
|
|
57
58
|
...(args.baseRef.length > 0 ? { baseRef: args.baseRef } : {}),
|
|
59
|
+
runGh: (command) => {
|
|
60
|
+
const proc = spawnSync(command[0] ?? "gh", command.slice(1), {
|
|
61
|
+
cwd: projectRoot,
|
|
62
|
+
encoding: "utf8",
|
|
63
|
+
timeout: 15_000,
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
returncode: proc.status ?? 1,
|
|
67
|
+
stdout: proc.stdout ?? "",
|
|
68
|
+
};
|
|
69
|
+
},
|
|
58
70
|
});
|
|
59
71
|
if (result.message.length > 0 && !args.quiet) {
|
|
60
72
|
if (result.code === 0) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
originRef?: string;
|
|
5
|
+
quiet: boolean;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Parse verify-durable-effect-acquisition CLI args. */
|
|
9
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
10
|
+
/** Run the gate and return the process exit code. */
|
|
11
|
+
export declare function run(argv: string[]): number;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=verify-durable-effect-acquisition.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { evaluateDurableEffectAcquisition } from "@deftai/directive-core/durable-effect-acquisition";
|
|
5
|
+
/** Parse verify-durable-effect-acquisition CLI args. */
|
|
6
|
+
export function parseArgs(argv) {
|
|
7
|
+
const parsed = { projectRoot: ".", quiet: false };
|
|
8
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
9
|
+
const arg = argv[i];
|
|
10
|
+
if (arg === "--quiet") {
|
|
11
|
+
parsed.quiet = true;
|
|
12
|
+
}
|
|
13
|
+
else if (arg === "--project-root") {
|
|
14
|
+
const value = argv[i + 1];
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
17
|
+
}
|
|
18
|
+
parsed.projectRoot = value;
|
|
19
|
+
i += 1;
|
|
20
|
+
}
|
|
21
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
22
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
23
|
+
}
|
|
24
|
+
else if (arg === "--origin-ref") {
|
|
25
|
+
const value = argv[i + 1];
|
|
26
|
+
if (value === undefined) {
|
|
27
|
+
return { ...parsed, error: "argument --origin-ref: expected one argument" };
|
|
28
|
+
}
|
|
29
|
+
parsed.originRef = value;
|
|
30
|
+
i += 1;
|
|
31
|
+
}
|
|
32
|
+
else if (arg?.startsWith("--origin-ref=")) {
|
|
33
|
+
parsed.originRef = arg.slice("--origin-ref=".length);
|
|
34
|
+
}
|
|
35
|
+
else if (arg === "--base-ref") {
|
|
36
|
+
return {
|
|
37
|
+
...parsed,
|
|
38
|
+
error: "unrecognized argument: --base-ref (baseline is the computed merge base; use --origin-ref to name the origin default)",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
/** Run the gate and return the process exit code. */
|
|
48
|
+
export function run(argv) {
|
|
49
|
+
const args = parseArgs(argv);
|
|
50
|
+
if (args.error !== undefined) {
|
|
51
|
+
process.stderr.write(`verify_durable_effect_acquisition: ${args.error}\n`);
|
|
52
|
+
return 2;
|
|
53
|
+
}
|
|
54
|
+
const result = evaluateDurableEffectAcquisition({
|
|
55
|
+
projectRoot: resolve(args.projectRoot),
|
|
56
|
+
originRef: args.originRef,
|
|
57
|
+
quiet: args.quiet,
|
|
58
|
+
});
|
|
59
|
+
if (result.message.length > 0) {
|
|
60
|
+
if (result.stream === "stdout")
|
|
61
|
+
process.stdout.write(`${result.message}\n`);
|
|
62
|
+
else if (result.stream === "stderr")
|
|
63
|
+
process.stderr.write(`${result.message}\n`);
|
|
64
|
+
}
|
|
65
|
+
return result.code;
|
|
66
|
+
}
|
|
67
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
68
|
+
process.exit(run(process.argv.slice(2)));
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=verify-durable-effect-acquisition.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
promptFile?: string;
|
|
4
|
+
prompt?: string;
|
|
5
|
+
surfacesFile?: string;
|
|
6
|
+
briefOut?: string;
|
|
7
|
+
artifactOut?: string;
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
quiet: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Parse verify-operator-scope-limit CLI args. */
|
|
13
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
14
|
+
/** Run the gate and return the process exit code (0 clean/warn, 2 config). */
|
|
15
|
+
export declare function run(argv: string[]): number;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=verify-operator-scope-limit.d.ts.map
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Warn-first operator scope-limit check (#4545).
|
|
4
|
+
*
|
|
5
|
+
* Seeds a hard ceiling from an operator prompt (closed lexicon) and lists
|
|
6
|
+
* shipped surfaces not traceable to a recorded requirement line. Warn-first:
|
|
7
|
+
* untraceable surfaces print WARN and exit 0; config errors exit 2.
|
|
8
|
+
*
|
|
9
|
+
* Default path always persists a durable ceiling artifact (or merges into
|
|
10
|
+
* --brief-out). Without --surfaces-file, runs a default app/actions inventory;
|
|
11
|
+
* empty inventory warns that surfaces were not checked (does not silent-skip).
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { dirname, resolve } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { applyCeilingToBrief, evaluateUntraceableSurfaces, inventoryDefaultSurfaces, OPERATOR_SCOPE_CEILING_ARTIFACT_REL, SURFACES_NOT_CHECKED_REMEDIATION, seedOperatorScopeCeiling, UNTRACEABLE_SURFACE_REMEDIATION, } from "@deftai/directive-core/operator-scope-limit";
|
|
17
|
+
/** Parse verify-operator-scope-limit CLI args. */
|
|
18
|
+
export function parseArgs(argv) {
|
|
19
|
+
const parsed = { quiet: false, projectRoot: "." };
|
|
20
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
21
|
+
const arg = argv[i];
|
|
22
|
+
if (arg === "--quiet") {
|
|
23
|
+
parsed.quiet = true;
|
|
24
|
+
}
|
|
25
|
+
else if (arg === "--prompt-file") {
|
|
26
|
+
const value = argv[i + 1];
|
|
27
|
+
if (value === undefined) {
|
|
28
|
+
return { ...parsed, error: "argument --prompt-file: expected one argument" };
|
|
29
|
+
}
|
|
30
|
+
parsed.promptFile = value;
|
|
31
|
+
i += 1;
|
|
32
|
+
}
|
|
33
|
+
else if (arg?.startsWith("--prompt-file=")) {
|
|
34
|
+
parsed.promptFile = arg.slice("--prompt-file=".length);
|
|
35
|
+
}
|
|
36
|
+
else if (arg === "--prompt") {
|
|
37
|
+
const value = argv[i + 1];
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
return { ...parsed, error: "argument --prompt: expected one argument" };
|
|
40
|
+
}
|
|
41
|
+
parsed.prompt = value;
|
|
42
|
+
i += 1;
|
|
43
|
+
}
|
|
44
|
+
else if (arg?.startsWith("--prompt=")) {
|
|
45
|
+
parsed.prompt = arg.slice("--prompt=".length);
|
|
46
|
+
}
|
|
47
|
+
else if (arg === "--surfaces-file") {
|
|
48
|
+
const value = argv[i + 1];
|
|
49
|
+
if (value === undefined) {
|
|
50
|
+
return { ...parsed, error: "argument --surfaces-file: expected one argument" };
|
|
51
|
+
}
|
|
52
|
+
parsed.surfacesFile = value;
|
|
53
|
+
i += 1;
|
|
54
|
+
}
|
|
55
|
+
else if (arg?.startsWith("--surfaces-file=")) {
|
|
56
|
+
parsed.surfacesFile = arg.slice("--surfaces-file=".length);
|
|
57
|
+
}
|
|
58
|
+
else if (arg === "--brief-out") {
|
|
59
|
+
const value = argv[i + 1];
|
|
60
|
+
if (value === undefined) {
|
|
61
|
+
return { ...parsed, error: "argument --brief-out: expected one argument" };
|
|
62
|
+
}
|
|
63
|
+
parsed.briefOut = value;
|
|
64
|
+
i += 1;
|
|
65
|
+
}
|
|
66
|
+
else if (arg?.startsWith("--brief-out=")) {
|
|
67
|
+
parsed.briefOut = arg.slice("--brief-out=".length);
|
|
68
|
+
}
|
|
69
|
+
else if (arg === "--artifact-out") {
|
|
70
|
+
const value = argv[i + 1];
|
|
71
|
+
if (value === undefined) {
|
|
72
|
+
return { ...parsed, error: "argument --artifact-out: expected one argument" };
|
|
73
|
+
}
|
|
74
|
+
parsed.artifactOut = value;
|
|
75
|
+
i += 1;
|
|
76
|
+
}
|
|
77
|
+
else if (arg?.startsWith("--artifact-out=")) {
|
|
78
|
+
parsed.artifactOut = arg.slice("--artifact-out=".length);
|
|
79
|
+
}
|
|
80
|
+
else if (arg === "--project-root") {
|
|
81
|
+
const value = argv[i + 1];
|
|
82
|
+
if (value === undefined) {
|
|
83
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
84
|
+
}
|
|
85
|
+
parsed.projectRoot = value;
|
|
86
|
+
i += 1;
|
|
87
|
+
}
|
|
88
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
89
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return parsed;
|
|
96
|
+
}
|
|
97
|
+
function loadPrompt(args) {
|
|
98
|
+
if (typeof args.prompt === "string") {
|
|
99
|
+
return { ok: true, prompt: args.prompt };
|
|
100
|
+
}
|
|
101
|
+
if (typeof args.promptFile === "string" && args.promptFile.length > 0) {
|
|
102
|
+
try {
|
|
103
|
+
return { ok: true, prompt: readFileSync(resolve(args.promptFile), "utf8") };
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
detail: `failed to read --prompt-file: ${err instanceof Error ? err.message : String(err)}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
detail: "required: --prompt <text> or --prompt-file <path>",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function loadSurfacesFile(surfacesFile) {
|
|
118
|
+
try {
|
|
119
|
+
const raw = readFileSync(resolve(surfacesFile), "utf8");
|
|
120
|
+
const parsed = JSON.parse(raw);
|
|
121
|
+
if (!Array.isArray(parsed)) {
|
|
122
|
+
return { ok: false, detail: "--surfaces-file must be a JSON array" };
|
|
123
|
+
}
|
|
124
|
+
const surfaces = [];
|
|
125
|
+
for (const entry of parsed) {
|
|
126
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
127
|
+
return { ok: false, detail: "--surfaces-file entries must be objects" };
|
|
128
|
+
}
|
|
129
|
+
const obj = entry;
|
|
130
|
+
if ((obj.kind !== "server-action" && obj.kind !== "route" && obj.kind !== "page") ||
|
|
131
|
+
typeof obj.id !== "string" ||
|
|
132
|
+
obj.id.trim().length === 0) {
|
|
133
|
+
return {
|
|
134
|
+
ok: false,
|
|
135
|
+
detail: "--surfaces-file entries need kind (server-action|route|page) and id",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
surfaces.push({
|
|
139
|
+
kind: obj.kind,
|
|
140
|
+
id: obj.id,
|
|
141
|
+
path: typeof obj.path === "string" ? obj.path : undefined,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return { ok: true, surfaces };
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return {
|
|
148
|
+
ok: false,
|
|
149
|
+
detail: `failed to read --surfaces-file: ${err instanceof Error ? err.message : String(err)}`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function writeJsonFile(path, value) {
|
|
154
|
+
try {
|
|
155
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
156
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
157
|
+
return { ok: true };
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
return {
|
|
161
|
+
ok: false,
|
|
162
|
+
detail: `failed to write ${path}: ${err instanceof Error ? err.message : String(err)}`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function loadExistingBrief(path) {
|
|
167
|
+
if (!existsSync(path))
|
|
168
|
+
return null;
|
|
169
|
+
try {
|
|
170
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
171
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
172
|
+
return null;
|
|
173
|
+
return raw;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/** Persist ceiling: explicit outs, else default durable artifact under project root. */
|
|
180
|
+
function persistCeiling(input) {
|
|
181
|
+
const { projectRoot, ceiling, artifactOut, briefOut } = input;
|
|
182
|
+
let durablePath = null;
|
|
183
|
+
if (typeof artifactOut === "string" && artifactOut.length > 0) {
|
|
184
|
+
const path = resolve(artifactOut);
|
|
185
|
+
const wrote = writeJsonFile(path, ceiling);
|
|
186
|
+
if (!wrote.ok)
|
|
187
|
+
return wrote;
|
|
188
|
+
durablePath = path;
|
|
189
|
+
}
|
|
190
|
+
if (typeof briefOut === "string" && briefOut.length > 0) {
|
|
191
|
+
const path = resolve(briefOut);
|
|
192
|
+
const existing = loadExistingBrief(path);
|
|
193
|
+
const base = existing ??
|
|
194
|
+
{
|
|
195
|
+
xBRIEFInfo: { version: "0.8" },
|
|
196
|
+
plan: { status: "draft", metadata: {} },
|
|
197
|
+
};
|
|
198
|
+
// Merge/add ceiling onto existing proposed/active brief — never replace scope.
|
|
199
|
+
const merged = applyCeilingToBrief(base, ceiling);
|
|
200
|
+
const wrote = writeJsonFile(path, merged);
|
|
201
|
+
if (!wrote.ok)
|
|
202
|
+
return wrote;
|
|
203
|
+
durablePath = path;
|
|
204
|
+
}
|
|
205
|
+
if (durablePath === null) {
|
|
206
|
+
const path = resolve(projectRoot, OPERATOR_SCOPE_CEILING_ARTIFACT_REL);
|
|
207
|
+
const wrote = writeJsonFile(path, ceiling);
|
|
208
|
+
if (!wrote.ok)
|
|
209
|
+
return wrote;
|
|
210
|
+
durablePath = path;
|
|
211
|
+
}
|
|
212
|
+
return { ok: true, durablePath };
|
|
213
|
+
}
|
|
214
|
+
/** Run the gate and return the process exit code (0 clean/warn, 2 config). */
|
|
215
|
+
export function run(argv) {
|
|
216
|
+
const args = parseArgs(argv);
|
|
217
|
+
if (args.error !== undefined) {
|
|
218
|
+
process.stderr.write(`verify_operator_scope_limit: ${args.error}\n`);
|
|
219
|
+
return 2;
|
|
220
|
+
}
|
|
221
|
+
const projectRoot = resolve(args.projectRoot);
|
|
222
|
+
const promptLoad = loadPrompt(args);
|
|
223
|
+
if (!promptLoad.ok) {
|
|
224
|
+
process.stderr.write(`verify_operator_scope_limit: ${promptLoad.detail}\n`);
|
|
225
|
+
return 2;
|
|
226
|
+
}
|
|
227
|
+
const seeded = seedOperatorScopeCeiling(promptLoad.prompt, null);
|
|
228
|
+
if (!seeded.ok) {
|
|
229
|
+
process.stderr.write(`verify_operator_scope_limit: ${seeded.detail}\n`);
|
|
230
|
+
// No phrase is a returned miss — still exit 2 so callers know ceiling was not recorded.
|
|
231
|
+
return 2;
|
|
232
|
+
}
|
|
233
|
+
const persisted = persistCeiling({
|
|
234
|
+
projectRoot,
|
|
235
|
+
ceiling: seeded.ceiling,
|
|
236
|
+
artifactOut: args.artifactOut,
|
|
237
|
+
briefOut: args.briefOut,
|
|
238
|
+
});
|
|
239
|
+
if (!persisted.ok) {
|
|
240
|
+
process.stderr.write(`verify_operator_scope_limit: ${persisted.detail}\n`);
|
|
241
|
+
return 2;
|
|
242
|
+
}
|
|
243
|
+
let surfaces = [];
|
|
244
|
+
let surfacesSource = "default-inventory";
|
|
245
|
+
if (typeof args.surfacesFile === "string" && args.surfacesFile.length > 0) {
|
|
246
|
+
const surfacesLoad = loadSurfacesFile(args.surfacesFile);
|
|
247
|
+
if (!surfacesLoad.ok) {
|
|
248
|
+
process.stderr.write(`verify_operator_scope_limit: ${surfacesLoad.detail}\n`);
|
|
249
|
+
return 2;
|
|
250
|
+
}
|
|
251
|
+
surfaces = surfacesLoad.surfaces;
|
|
252
|
+
surfacesSource = "surfaces-file";
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
surfaces = inventoryDefaultSurfaces(projectRoot);
|
|
256
|
+
surfacesSource = "default-inventory";
|
|
257
|
+
}
|
|
258
|
+
if (surfaces.length === 0) {
|
|
259
|
+
if (!args.quiet) {
|
|
260
|
+
process.stdout.write(`operator-scope-limit WARN: surfaces were not checked ` +
|
|
261
|
+
`(source=${surfacesSource}; durable=${persisted.durablePath}; ` +
|
|
262
|
+
`phrase=${JSON.stringify(seeded.ceiling.matchedPhrase)}; ` +
|
|
263
|
+
`requirements=${seeded.ceiling.requirementLines.length}). ` +
|
|
264
|
+
`Remediation: ${SURFACES_NOT_CHECKED_REMEDIATION}\n`);
|
|
265
|
+
}
|
|
266
|
+
// Warn-first: missing inventory does not fail the process.
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
const result = evaluateUntraceableSurfaces({
|
|
270
|
+
requirementLines: seeded.ceiling.requirementLines,
|
|
271
|
+
surfaces,
|
|
272
|
+
});
|
|
273
|
+
if (!args.quiet) {
|
|
274
|
+
process.stdout.write(`${result.message} (durable=${persisted.durablePath}; source=${surfacesSource})\n`);
|
|
275
|
+
if (result.severity === "warn") {
|
|
276
|
+
process.stdout.write(`Remediation: ${UNTRACEABLE_SURFACE_REMEDIATION}\n`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Warn-first: untraceable surfaces do not fail the process.
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
283
|
+
process.exit(run(process.argv.slice(2)));
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=verify-operator-scope-limit.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
baseRef: string | null;
|
|
5
|
+
quiet: boolean;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
9
|
+
export declare function run(argv: string[]): number;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=verify-presentation-ceiling.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for verify:presentation-ceiling (#5056).
|
|
4
|
+
*/
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { presentationCeiling } from "@deftai/directive-core";
|
|
7
|
+
import { isDirectEntrypoint } from "./entrypoint.js";
|
|
8
|
+
export function parseArgs(argv) {
|
|
9
|
+
const parsed = {
|
|
10
|
+
projectRoot: ".",
|
|
11
|
+
baseRef: null,
|
|
12
|
+
quiet: false,
|
|
13
|
+
};
|
|
14
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
15
|
+
const arg = argv[i];
|
|
16
|
+
if (arg === "--quiet") {
|
|
17
|
+
parsed.quiet = true;
|
|
18
|
+
}
|
|
19
|
+
else if (arg === "--project-root") {
|
|
20
|
+
const value = argv[i + 1];
|
|
21
|
+
if (value === undefined) {
|
|
22
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
23
|
+
}
|
|
24
|
+
parsed.projectRoot = value;
|
|
25
|
+
i += 1;
|
|
26
|
+
}
|
|
27
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
28
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
29
|
+
}
|
|
30
|
+
else if (arg === "--base-ref") {
|
|
31
|
+
const value = argv[i + 1];
|
|
32
|
+
if (value === undefined) {
|
|
33
|
+
return { ...parsed, error: "argument --base-ref: expected one argument" };
|
|
34
|
+
}
|
|
35
|
+
parsed.baseRef = value;
|
|
36
|
+
i += 1;
|
|
37
|
+
}
|
|
38
|
+
else if (arg?.startsWith("--base-ref=")) {
|
|
39
|
+
parsed.baseRef = arg.slice("--base-ref=".length);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
export function run(argv) {
|
|
48
|
+
const args = parseArgs(argv);
|
|
49
|
+
if (args.error !== undefined) {
|
|
50
|
+
process.stderr.write(`verify_presentation_ceiling: ${args.error}\n`);
|
|
51
|
+
return 2;
|
|
52
|
+
}
|
|
53
|
+
const projectRoot = resolve(args.projectRoot);
|
|
54
|
+
const result = presentationCeiling.evaluatePresentationCeiling(projectRoot, {
|
|
55
|
+
baseRef: args.baseRef,
|
|
56
|
+
quiet: args.quiet,
|
|
57
|
+
});
|
|
58
|
+
if (result.exitCode === 0) {
|
|
59
|
+
if (!args.quiet) {
|
|
60
|
+
process.stdout.write(`${result.message}\n`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
process.stderr.write(`${result.message}\n`);
|
|
65
|
+
}
|
|
66
|
+
return result.exitCode;
|
|
67
|
+
}
|
|
68
|
+
if (isDirectEntrypoint(import.meta.url)) {
|
|
69
|
+
process.exit(run(process.argv.slice(2)));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=verify-presentation-ceiling.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
originRef?: string;
|
|
5
|
+
staged: boolean;
|
|
6
|
+
quiet: boolean;
|
|
7
|
+
json: boolean;
|
|
8
|
+
planId?: string;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
12
|
+
export declare function run(argv: string[]): number;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=verify-presentation-coverage.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for verify:presentation-coverage (#5079).
|
|
4
|
+
*/
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { presentationCoverage } from "@deftai/directive-core";
|
|
7
|
+
import { isDirectEntrypoint } from "./entrypoint.js";
|
|
8
|
+
export function parseArgs(argv) {
|
|
9
|
+
const parsed = { projectRoot: ".", staged: false, quiet: false, json: false };
|
|
10
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
11
|
+
const arg = argv[i];
|
|
12
|
+
if (arg === "--json") {
|
|
13
|
+
parsed.json = true;
|
|
14
|
+
}
|
|
15
|
+
else if (arg === "--plan-id") {
|
|
16
|
+
const value = argv[i + 1];
|
|
17
|
+
if (value === undefined || value.startsWith("--"))
|
|
18
|
+
return { ...parsed, error: "argument --plan-id: expected one argument" };
|
|
19
|
+
parsed.planId = value;
|
|
20
|
+
i += 1;
|
|
21
|
+
}
|
|
22
|
+
else if (arg === "--quiet") {
|
|
23
|
+
parsed.quiet = true;
|
|
24
|
+
}
|
|
25
|
+
else if (arg === "--staged") {
|
|
26
|
+
parsed.staged = true;
|
|
27
|
+
}
|
|
28
|
+
else if (arg === "--project-root") {
|
|
29
|
+
const value = argv[i + 1];
|
|
30
|
+
if (value === undefined || value.startsWith("--")) {
|
|
31
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
32
|
+
}
|
|
33
|
+
parsed.projectRoot = value;
|
|
34
|
+
i += 1;
|
|
35
|
+
}
|
|
36
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
37
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
38
|
+
}
|
|
39
|
+
else if (arg === "--origin-ref") {
|
|
40
|
+
const value = argv[i + 1];
|
|
41
|
+
if (value === undefined || value.startsWith("--")) {
|
|
42
|
+
return { ...parsed, error: "argument --origin-ref: expected one argument" };
|
|
43
|
+
}
|
|
44
|
+
parsed.originRef = value;
|
|
45
|
+
i += 1;
|
|
46
|
+
}
|
|
47
|
+
else if (arg?.startsWith("--origin-ref=")) {
|
|
48
|
+
parsed.originRef = arg.slice("--origin-ref=".length);
|
|
49
|
+
}
|
|
50
|
+
else if (arg === "--base-ref") {
|
|
51
|
+
return {
|
|
52
|
+
...parsed,
|
|
53
|
+
error: "unrecognized argument: --base-ref (baseline is the computed merge base; use --origin-ref to name the origin default)",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return parsed;
|
|
61
|
+
}
|
|
62
|
+
export function run(argv) {
|
|
63
|
+
const args = parseArgs(argv);
|
|
64
|
+
if (args.error !== undefined) {
|
|
65
|
+
process.stderr.write(`verify_presentation_coverage: ${args.error}\n`);
|
|
66
|
+
return 2;
|
|
67
|
+
}
|
|
68
|
+
const result = presentationCoverage.evaluatePresentationCoverage({
|
|
69
|
+
projectRoot: resolve(args.projectRoot),
|
|
70
|
+
originRef: args.originRef,
|
|
71
|
+
staged: args.staged,
|
|
72
|
+
quiet: args.quiet,
|
|
73
|
+
planId: args.planId,
|
|
74
|
+
});
|
|
75
|
+
if (args.json) {
|
|
76
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
77
|
+
return result.code;
|
|
78
|
+
}
|
|
79
|
+
if (!args.quiet && result.message.length > 0) {
|
|
80
|
+
if (result.stream === "stdout")
|
|
81
|
+
process.stdout.write(`${result.message}\n`);
|
|
82
|
+
else if (result.stream === "stderr")
|
|
83
|
+
process.stderr.write(`${result.message}\n`);
|
|
84
|
+
}
|
|
85
|
+
return result.code;
|
|
86
|
+
}
|
|
87
|
+
if (isDirectEntrypoint(import.meta.url)) {
|
|
88
|
+
process.exit(run(process.argv.slice(2)));
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=verify-presentation-coverage.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { evaluateMergePathArm, } from "@deftai/directive-core/dist/pr-watch/main.js";
|
|
4
|
+
import { bindLivePhaseCorrectWait, evaluateMergePathArm, } from "@deftai/directive-core/dist/pr-watch/main.js";
|
|
5
5
|
import { EXIT_CONFIG_ERROR, EXIT_NOT_READY, evaluateReviewMonitorGate, isTier1, REVIEW_MONITOR_HELP, verifyResultToJson, } from "@deftai/directive-core/review-monitor";
|
|
6
6
|
const CALL_SITES = new Set([
|
|
7
7
|
"solo",
|
|
@@ -134,13 +134,15 @@ export function run(argv) {
|
|
|
134
134
|
const args = parseVerifyReviewMonitorArgs(argv);
|
|
135
135
|
if (args.help) {
|
|
136
136
|
process.stdout.write(REVIEW_MONITOR_HELP);
|
|
137
|
-
process.stdout.write("\n#4882 merge-path arm observer (optional):\n" +
|
|
137
|
+
process.stdout.write("\n#4882 / #5020 merge-path arm observer (optional):\n" +
|
|
138
138
|
" --merge-path-arm Fail closed when neither live wait nor explicit finish\n" +
|
|
139
|
-
" --live-wait
|
|
140
|
-
" (Tier 1:
|
|
139
|
+
" --live-wait Require still-running wait evidence for this PR\n" +
|
|
140
|
+
" (Tier 1: lease + active polling heartbeat with pid liveness;\n" +
|
|
141
|
+
" lease+flag alone is not armed — #5020)\n" +
|
|
141
142
|
" --explicit-finish Attest option-C BLOCKED/FAILED finish for this PR\n" +
|
|
142
143
|
" --sticky-lease Attest a fresh sticky lease (not sufficient alone)\n" +
|
|
143
|
-
" Prefer Approach 1 / native pr:watch
|
|
144
|
+
" Prefer Approach 1 / native pr:watch or post-CLEAN pr:wait-mergeable-and-merge;\n" +
|
|
145
|
+
" homemade line-parsed --json is not an arm.\n");
|
|
144
146
|
return 0;
|
|
145
147
|
}
|
|
146
148
|
if (args.error !== undefined) {
|
|
@@ -167,21 +169,29 @@ export function run(argv) {
|
|
|
167
169
|
});
|
|
168
170
|
let arm = null;
|
|
169
171
|
if (args.mergePathArm) {
|
|
170
|
-
// Bind --live-wait to
|
|
171
|
-
// Bare flags must not arm when Tier 1 requires a lease and none is present.
|
|
172
|
+
// Bind --live-wait to lease (#5018) + process-liveness heartbeat (#5020) on Tier 1.
|
|
172
173
|
const leaseEvidence = result.monitorRecord !== null;
|
|
173
|
-
const
|
|
174
|
+
const liveBind = bindLivePhaseCorrectWait({
|
|
175
|
+
liveWaitFlag: args.liveWait,
|
|
176
|
+
tierIs1: isTier1(result.tier),
|
|
177
|
+
leaseEvidence,
|
|
178
|
+
heartbeatActive: result.heartbeatActive,
|
|
179
|
+
pr: args.pr,
|
|
180
|
+
});
|
|
174
181
|
arm = evaluateMergePathArm({
|
|
175
|
-
livePhaseCorrectWait:
|
|
182
|
+
livePhaseCorrectWait: liveBind.livePhaseCorrectWait,
|
|
176
183
|
explicitFinish: args.explicitFinish,
|
|
177
184
|
stickyLeaseActive: args.stickyLease || leaseEvidence,
|
|
178
185
|
});
|
|
179
|
-
if (args.liveWait &&
|
|
186
|
+
if (args.liveWait &&
|
|
187
|
+
!liveBind.livePhaseCorrectWait &&
|
|
188
|
+
!args.explicitFinish &&
|
|
189
|
+
!arm.armed &&
|
|
190
|
+
liveBind.message !== null) {
|
|
180
191
|
arm = {
|
|
181
192
|
armed: false,
|
|
182
193
|
reason: "unarmed_stand_down",
|
|
183
|
-
message:
|
|
184
|
-
`for PR #${args.pr} (Tier 1); sticky lease alone is not a live arm (#4882)`,
|
|
194
|
+
message: liveBind.message,
|
|
185
195
|
};
|
|
186
196
|
}
|
|
187
197
|
}
|
|
@@ -196,6 +206,7 @@ export function run(argv) {
|
|
|
196
206
|
explicit_finish: args.explicitFinish,
|
|
197
207
|
sticky_lease: args.stickyLease,
|
|
198
208
|
lease_evidence: result.monitorRecord !== null,
|
|
209
|
+
heartbeat_active: result.heartbeatActive,
|
|
199
210
|
};
|
|
200
211
|
// Combined gate+arm: unarmed fails closed even when the monitor gate is ready.
|
|
201
212
|
if (!arm.armed && result.exitCode !== EXIT_CONFIG_ERROR) {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* CLI for verify:scope-provenance (#3145).
|
|
3
|
+
* CLI for verify:scope-provenance (#3145 / #4956 / #4774).
|
|
4
|
+
*
|
|
5
|
+
* Membership against the declared allowlist (mint / brief file_scope) is
|
|
6
|
+
* evaluated inside evaluateScopeProvenance; this CLI only forwards
|
|
7
|
+
* --base-ref / --enforce.
|
|
4
8
|
*/
|
|
5
9
|
import { resolve } from "node:path";
|
|
6
10
|
import { scopeProvenance } from "@deftai/directive-core";
|
package/dist/windows-bin-ps1.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* A .ps1 is removed only when its sibling .cmd records a target inside this
|
|
7
7
|
* install, so an ambient PNPM_HOME from another install is left alone.
|
|
8
8
|
* It does not change npx.ps1, npm.ps1, or the operator's execution policy.
|
|
9
|
+
* Codex deposits bare deft-hook (#4659); this postinstall is what makes Restricted
|
|
10
|
+
* Get-Command select deft-hook.cmd without ExecutionPolicy Bypass.
|
|
9
11
|
*/
|
|
10
12
|
import { existsSync, readFileSync, realpathSync, unlinkSync } from "node:fs";
|
|
11
13
|
import { basename, dirname, join, win32 } from "node:path";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive",
|
|
3
|
-
"version": "0.119.
|
|
3
|
+
"version": "0.119.11",
|
|
4
4
|
"description": "Directive CLI — npm install path for the Deft Directive framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://deftai.github.io/directive/",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"provenance": true
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@deftai/directive-core": "^0.119.
|
|
39
|
-
"@deftai/directive-content": "^0.119.
|
|
38
|
+
"@deftai/directive-core": "^0.119.11",
|
|
39
|
+
"@deftai/directive-content": "^0.119.11"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -b",
|