@deftai/directive 0.108.0 → 0.109.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ 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", "scope-lifecycle", "scope-record-approved-scope", "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-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", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "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-skill-external-fetch-gate", "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", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "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", "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", "scope-lifecycle", "scope-record-approved-scope", "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-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", "verify-branch", "verify-encoding", "verify-forward-coverage", "verify-test-boundary", "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", "rule-ownership-lint", "verify-story-ready", "verify-review-monitor", "verify-l4-owner", "verify-subagent-alive", "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", "eval-health", "eval-run", "eval-report", "eval-triggers"];
14
14
  /** Core-only CLI entrypoints without a packages/cli wrapper. */
15
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", "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"];
16
16
  /** Colon aliases for triage-actions (mirrors cli-router SUBCOMMAND_ROUTES). */
package/dist/dispatch.js CHANGED
@@ -123,7 +123,11 @@ export const CLI_MODULE_VERBS = [
123
123
  "verify-contained-writes",
124
124
  "verify-telemetry-coverage",
125
125
  "verify-content-manifest",
126
+ "verify-deposit-closure",
127
+ "verify-consumer-hard-stops",
128
+ "verify-closing-keywords",
126
129
  "verify-skill-external-fetch-gate",
130
+ "verify-semantic-single-source",
127
131
  "verify-contract-drift",
128
132
  "verify-cursor-tier1",
129
133
  "verify-openclaw-tier1",
@@ -333,7 +337,11 @@ export const VERB_ALIASES = {
333
337
  "verify:contained-writes": "verify-contained-writes",
334
338
  "verify:telemetry-coverage": "verify-telemetry-coverage",
335
339
  "verify:content-manifest": "verify-content-manifest",
340
+ "verify:deposit-closure": "verify-deposit-closure",
341
+ "verify:consumer-hard-stops": "verify-consumer-hard-stops",
342
+ "verify:closing-keywords": "verify-closing-keywords",
336
343
  "verify:skill-external-fetch-gate": "verify-skill-external-fetch-gate",
344
+ "verify:semantic-single-source": "verify-semantic-single-source",
337
345
  "verify:contract-drift": "verify-contract-drift",
338
346
  "verify:cursor-tier1": "verify-cursor-tier1",
339
347
  "verify:openclaw-tier1": "verify-openclaw-tier1",
@@ -413,7 +421,11 @@ const SUBDIR_CLI_STEMS = {
413
421
  "verify-contained-writes": "verify-source-cli/verify-contained-writes",
414
422
  "verify-telemetry-coverage": "verify-source-cli/verify-telemetry-coverage",
415
423
  "verify-content-manifest": "verify-source-cli/verify-content-manifest",
424
+ "verify-deposit-closure": "verify-source-cli/verify-deposit-closure",
425
+ "verify-consumer-hard-stops": "verify-source-cli/verify-consumer-hard-stops",
426
+ "verify-closing-keywords": "verify-source-cli/verify-closing-keywords",
416
427
  "verify-skill-external-fetch-gate": "verify-source-cli/verify-skill-external-fetch-gate",
428
+ "verify-semantic-single-source": "verify-source-cli/verify-semantic-single-source",
417
429
  "verify-contract-drift": "verify-source-cli/verify-contract-drift",
418
430
  "verify-cursor-tier1": "verify-source-cli/verify-cursor-tier1",
419
431
  "verify-openclaw-tier1": "verify-source-cli/verify-openclaw-tier1",
package/dist/doctor.js CHANGED
@@ -6,6 +6,7 @@ import { resolveContentPackageRoot } from "@deftai/directive-core/dist/content-r
6
6
  import { parseDoctorFlags } from "@deftai/directive-core/dist/doctor/flags.js";
7
7
  import { cmdDoctor } from "@deftai/directive-core/dist/doctor/main.js";
8
8
  import { findPackageAbsentDepositPathsSync } from "@deftai/directive-core/dist/init-deposit/hygiene.js";
9
+ import { evaluateInstalledDepositClosure, renderDeclaredDepositClosureLine, } from "@deftai/directive-core/dist/validate-content/deposit-required.js";
9
10
  import { renderPrecutoverLine } from "@deftai/directive-core/dist/vbrief-validate/precutover.js";
10
11
  import { renderStaleHeaderLine, renderXbriefMigrationLine, } from "@deftai/directive-core/xbrief-migrate";
11
12
  /** Compare `.deft/core/` against `@deftai/directive-content` (#2804). */
@@ -56,9 +57,14 @@ export function run(argv) {
56
57
  process.stdout.write(`${renderXbriefMigrationLine(projectRoot)}\n`);
57
58
  process.stdout.write(`${renderStaleHeaderLine(projectRoot)}\n`);
58
59
  process.stdout.write(`${renderDepositFileSetHygieneLine(projectRoot, depositResult)}\n`);
60
+ const closure = evaluateInstalledDepositClosure(projectRoot);
61
+ process.stdout.write(`${renderDeclaredDepositClosureLine(closure)}\n`);
59
62
  if (flags.full && !depositResult.skipped && depositResult.absent.length > 0) {
60
63
  depositHygieneExit = 1;
61
64
  }
65
+ if (flags.full && !closure.skipped && (closure.missing.length > 0 || closure.error !== null)) {
66
+ depositHygieneExit = 1;
67
+ }
62
68
  }
63
69
  const doctorExit = cmdDoctor(argv);
64
70
  return Math.max(depositHygieneExit, doctorExit);
@@ -5,6 +5,8 @@ interface ParsedArgs {
5
5
  issue: number | null;
6
6
  quiet: boolean;
7
7
  skipGh: boolean;
8
+ changedOnly: boolean;
9
+ baseRef: string | null;
8
10
  error?: string;
9
11
  }
10
12
  /** Parse verify-orphan-active CLI args. */
@@ -18,6 +18,8 @@ export function parseArgs(argv) {
18
18
  issue: null,
19
19
  quiet: false,
20
20
  skipGh: false,
21
+ changedOnly: false,
22
+ baseRef: null,
21
23
  };
22
24
  for (let i = 0; i < argv.length; i += 1) {
23
25
  const arg = argv[i];
@@ -27,6 +29,20 @@ export function parseArgs(argv) {
27
29
  else if (arg === "--skip-gh") {
28
30
  parsed.skipGh = true;
29
31
  }
32
+ else if (arg === "--changed-only") {
33
+ parsed.changedOnly = true;
34
+ }
35
+ else if (arg === "--base-ref") {
36
+ const value = argv[i + 1];
37
+ if (value === undefined) {
38
+ return { ...parsed, error: "argument --base-ref: expected one argument" };
39
+ }
40
+ parsed.baseRef = value;
41
+ i += 1;
42
+ }
43
+ else if (arg?.startsWith("--base-ref=")) {
44
+ parsed.baseRef = arg.slice("--base-ref=".length);
45
+ }
30
46
  else if (arg === "--project-root") {
31
47
  const value = argv[i + 1];
32
48
  if (value === undefined) {
@@ -73,6 +89,18 @@ export function parseArgs(argv) {
73
89
  return { ...parsed, error: `unrecognized argument: ${arg}` };
74
90
  }
75
91
  }
92
+ // The two scopes answer different questions; silently preferring one would
93
+ // hide which residue the run actually covered (#3893).
94
+ if (parsed.changedOnly && parsed.issue !== null) {
95
+ return {
96
+ ...parsed,
97
+ error: "--changed-only and --issue are mutually exclusive: --issue is the after-merge " +
98
+ "one-origin scan, --changed-only is the merge-gate candidate scan",
99
+ };
100
+ }
101
+ if (parsed.baseRef !== null && !parsed.changedOnly) {
102
+ return { ...parsed, error: "--base-ref requires --changed-only" };
103
+ }
76
104
  return parsed;
77
105
  }
78
106
  /** Run the gate and return the process exit code. */
@@ -88,6 +116,8 @@ export function run(argv) {
88
116
  repo: args.repo,
89
117
  skipGh: args.skipGh,
90
118
  issue: args.issue,
119
+ changedOnly: args.changedOnly,
120
+ baseRef: args.baseRef,
91
121
  });
92
122
  if (result.message.length > 0) {
93
123
  if (result.stream === "stdout") {
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ export type RunGitFn = (args: readonly string[]) => {
3
+ readonly returncode: number;
4
+ readonly stdout: string;
5
+ readonly stderr: string;
6
+ };
7
+ export type RangeResolution = {
8
+ readonly kind: "pr";
9
+ readonly pr: string;
10
+ } | {
11
+ readonly kind: "range";
12
+ readonly range: string;
13
+ } | {
14
+ readonly kind: "missing-base";
15
+ readonly reason: string;
16
+ } | {
17
+ readonly kind: "stale-base";
18
+ readonly reason: string;
19
+ };
20
+ export declare function defaultRunGit(args: readonly string[]): {
21
+ returncode: number;
22
+ stdout: string;
23
+ stderr: string;
24
+ };
25
+ /**
26
+ * Resolve the candidate commit range against a merge-base, not a hardcoded
27
+ * origin/master two-dot range (#3969 Greptile leftover).
28
+ */
29
+ export declare function resolveClosingKeywordsSource(env: NodeJS.ProcessEnv, runGit?: RunGitFn): RangeResolution;
30
+ export declare function buildClosingKeywordsCheckArgv(env: NodeJS.ProcessEnv, extra?: readonly string[], runGit?: RunGitFn): {
31
+ argv: string[];
32
+ error?: string;
33
+ };
34
+ export declare function run(argv: string[], env?: NodeJS.ProcessEnv, invoke?: (args: readonly string[]) => number, runGit?: RunGitFn): number;
35
+ //# sourceMappingURL=verify-closing-keywords.d.ts.map
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync } from "node:child_process";
3
+ import { fileURLToPath } from "node:url";
4
+ import { cmdPrCheckClosingKeywords } from "@deftai/directive-core/dist/pr-closing-keywords/main.js";
5
+ const BASE_CANDIDATES = ["origin/master", "origin/main"];
6
+ export function defaultRunGit(args) {
7
+ try {
8
+ const stdout = execFileSync("git", [...args], {
9
+ encoding: "utf8",
10
+ timeout: 30_000,
11
+ stdio: ["ignore", "pipe", "pipe"],
12
+ });
13
+ return { returncode: 0, stdout: typeof stdout === "string" ? stdout : "", stderr: "" };
14
+ }
15
+ catch (err) {
16
+ const e = err;
17
+ return {
18
+ returncode: typeof e.status === "number" ? e.status : 1,
19
+ stdout: typeof e.stdout === "string" ? e.stdout : "",
20
+ stderr: typeof e.stderr === "string" ? e.stderr : String(e.message ?? ""),
21
+ };
22
+ }
23
+ }
24
+ function firstLine(text) {
25
+ return text.trim().split(/\r?\n/)[0] ?? "";
26
+ }
27
+ function shaOf(result) {
28
+ if (result.returncode !== 0)
29
+ return null;
30
+ const sha = firstLine(result.stdout);
31
+ return /^[0-9a-f]{7,40}$/i.test(sha) ? sha : null;
32
+ }
33
+ function localDefaultFor(originRef) {
34
+ if (originRef.endsWith("/master") || originRef === "master")
35
+ return "master";
36
+ if (originRef.endsWith("/main") || originRef === "main")
37
+ return "main";
38
+ const slash = originRef.lastIndexOf("/");
39
+ return slash >= 0 ? originRef.slice(slash + 1) : null;
40
+ }
41
+ /** Remote-tracking ref name for `git fetch origin <name> --`. */
42
+ function originFetchArg(originRef) {
43
+ if (!originRef.startsWith("origin/"))
44
+ return null;
45
+ const name = originRef.slice("origin/".length);
46
+ return name.length > 0 ? name : null;
47
+ }
48
+ /**
49
+ * Detect the locally observable stale-range enlargement without fetching:
50
+ * origin/<default> lags a descendant local default, and HEAD's merge-base
51
+ * against that local default is not the origin merge-base. Then
52
+ * origin/master..HEAD would include already-merged local-default commits.
53
+ */
54
+ function staleRelativeToLocalDefault(originRef, originMergeBase, runGit) {
55
+ const localDefault = localDefaultFor(originRef);
56
+ if (localDefault === null)
57
+ return null;
58
+ const ahead = runGit(["merge-base", "--is-ancestor", originRef, localDefault]);
59
+ if (ahead.returncode !== 0)
60
+ return null;
61
+ const localMb = shaOf(runGit(["merge-base", localDefault, "HEAD"]));
62
+ if (localMb === null || localMb === originMergeBase)
63
+ return null;
64
+ return {
65
+ kind: "stale-base",
66
+ reason: originRef +
67
+ " lags local " +
68
+ localDefault +
69
+ " relative to HEAD, so the scan range would include already-merged commits. Recovery: git fetch origin " +
70
+ localDefault +
71
+ ".",
72
+ };
73
+ }
74
+ /**
75
+ * Resolve the candidate commit range against a merge-base, not a hardcoded
76
+ * origin/master two-dot range (#3969 Greptile leftover).
77
+ */
78
+ export function resolveClosingKeywordsSource(env, runGit = defaultRunGit) {
79
+ const raw = env.GITHUB_PR_NUMBER ?? env.PR_NUMBER;
80
+ const pr = raw?.trim() ?? "";
81
+ if (/^\d+$/.test(pr)) {
82
+ return { kind: "pr", pr };
83
+ }
84
+ const bases = [
85
+ env.GITHUB_BASE_REF?.trim() ? `origin/${env.GITHUB_BASE_REF.trim()}` : null,
86
+ ...BASE_CANDIDATES,
87
+ ].filter((base) => base !== null && base.length > 0);
88
+ const seen = new Set();
89
+ for (const base of bases) {
90
+ if (seen.has(base))
91
+ continue;
92
+ seen.add(base);
93
+ const fetchArg = originFetchArg(base);
94
+ let fetched = false;
95
+ if (fetchArg !== null) {
96
+ // Scoped to this wrapper, not the whole check graph. CI uses --pr
97
+ // and never reaches this path.
98
+ fetched = runGit(["fetch", "origin", fetchArg, "--"]).returncode === 0;
99
+ }
100
+ const sha = shaOf(runGit(["merge-base", base, "HEAD"]));
101
+ if (sha === null)
102
+ continue;
103
+ if (!fetched) {
104
+ const stale = staleRelativeToLocalDefault(base, sha, runGit);
105
+ if (stale !== null)
106
+ return stale;
107
+ // Fetch failed and local evidence cannot prove freshness: do not
108
+ // scan a possibly stale origin merge-base.
109
+ continue;
110
+ }
111
+ return { kind: "range", range: `${sha}..HEAD` };
112
+ }
113
+ return {
114
+ kind: "missing-base",
115
+ reason: "no merge-base against origin/master or origin/main. Recovery: git fetch origin master.",
116
+ };
117
+ }
118
+ export function buildClosingKeywordsCheckArgv(env, extra = [], runGit = defaultRunGit) {
119
+ const source = resolveClosingKeywordsSource(env, runGit);
120
+ if (source.kind === "pr") {
121
+ return { argv: ["--mode", "fp", "--pr", source.pr, ...extra] };
122
+ }
123
+ if (source.kind === "missing-base" || source.kind === "stale-base") {
124
+ return { argv: [], error: source.reason };
125
+ }
126
+ return { argv: ["--mode", "fp", "--from-git-range", source.range, ...extra] };
127
+ }
128
+ export function run(argv, env = process.env, invoke = cmdPrCheckClosingKeywords, runGit = defaultRunGit) {
129
+ const built = buildClosingKeywordsCheckArgv(env, argv, runGit);
130
+ if (built.error !== undefined) {
131
+ process.stderr.write("verify:closing-keywords: fail -- " + built.error + "\n");
132
+ return 2;
133
+ }
134
+ return invoke(built.argv);
135
+ }
136
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
137
+ process.exit(run(process.argv.slice(2)));
138
+ }
139
+ //# sourceMappingURL=verify-closing-keywords.js.map
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ interface ParsedArgs {
3
+ repo: string;
4
+ projectRoot: string;
5
+ changelog: string | null;
6
+ error?: string;
7
+ }
8
+ export interface HardStopCliSeams {
9
+ readonly inventory?: readonly Record<string, unknown>[];
10
+ readonly changelogText?: string;
11
+ }
12
+ /** Parse verify-consumer-hard-stops CLI args (#3900 / #3713). */
13
+ export declare function parseArgs(argv: string[]): ParsedArgs;
14
+ export declare function run(argv: string[], seams?: HardStopCliSeams): number;
15
+ export {};
16
+ //# sourceMappingURL=verify-consumer-hard-stops.d.ts.map
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { evaluateConsumerHardStopCensus, issueFromInventoryRow, parseClosesSet, } from "@deftai/directive-core/release";
6
+ import { restIssueListOpenInventory } from "@deftai/directive-core/scm";
7
+ /** Parse verify-consumer-hard-stops CLI args (#3900 / #3713). */
8
+ export function parseArgs(argv) {
9
+ const parsed = { repo: "deftai/directive", projectRoot: ".", changelog: null };
10
+ for (let i = 0; i < argv.length; i += 1) {
11
+ const arg = argv[i];
12
+ if (arg === "--repo") {
13
+ const value = argv[i + 1];
14
+ if (value === undefined)
15
+ return { ...parsed, error: "argument --repo: expected one argument" };
16
+ parsed.repo = value;
17
+ i += 1;
18
+ }
19
+ else if (arg?.startsWith("--repo=")) {
20
+ parsed.repo = arg.slice("--repo=".length);
21
+ }
22
+ else if (arg === "--project-root") {
23
+ const value = argv[i + 1];
24
+ if (value === undefined)
25
+ return { ...parsed, error: "argument --project-root: expected one argument" };
26
+ parsed.projectRoot = value;
27
+ i += 1;
28
+ }
29
+ else if (arg?.startsWith("--project-root=")) {
30
+ parsed.projectRoot = arg.slice("--project-root=".length);
31
+ }
32
+ else if (arg === "--changelog") {
33
+ const value = argv[i + 1];
34
+ if (value === undefined)
35
+ return { ...parsed, error: "argument --changelog: expected one argument" };
36
+ parsed.changelog = value;
37
+ i += 1;
38
+ }
39
+ else if (arg?.startsWith("--changelog=")) {
40
+ parsed.changelog = arg.slice("--changelog=".length);
41
+ }
42
+ else {
43
+ return { ...parsed, error: "unrecognized argument: " + String(arg) };
44
+ }
45
+ }
46
+ return parsed;
47
+ }
48
+ export function run(argv, seams = {}) {
49
+ const args = parseArgs(argv);
50
+ if (args.error !== undefined) {
51
+ process.stderr.write("verify_consumer_hard_stops: " + args.error + "\n");
52
+ return 2;
53
+ }
54
+ const root = resolve(args.projectRoot);
55
+ let changelogText = seams.changelogText;
56
+ if (changelogText === undefined) {
57
+ const changelogPath = resolve(root, args.changelog ?? "CHANGELOG.md");
58
+ try {
59
+ changelogText = readFileSync(changelogPath, "utf8");
60
+ }
61
+ catch (err) {
62
+ const reason = err instanceof Error ? err.message : String(err);
63
+ process.stderr.write("verify_consumer_hard_stops: could not read CHANGELOG (" + reason + ")\n");
64
+ return 2;
65
+ }
66
+ }
67
+ let rows;
68
+ try {
69
+ rows = seams.inventory ?? restIssueListOpenInventory(args.repo);
70
+ }
71
+ catch (err) {
72
+ const reason = err instanceof Error ? err.message : String(err);
73
+ process.stderr.write("verify_consumer_hard_stops: fail -- could not list open issues. Recovery: check gh auth and REST quota. " +
74
+ reason +
75
+ "\n");
76
+ return 2;
77
+ }
78
+ const issues = [];
79
+ for (const row of rows) {
80
+ const issue = issueFromInventoryRow(row);
81
+ if (issue !== null)
82
+ issues.push(issue);
83
+ }
84
+ const result = evaluateConsumerHardStopCensus({
85
+ issues,
86
+ closesSet: parseClosesSet(changelogText),
87
+ });
88
+ if (result.stream === "stdout") {
89
+ process.stdout.write(result.message + "\n");
90
+ }
91
+ else {
92
+ process.stderr.write(result.message + "\n");
93
+ }
94
+ return result.code;
95
+ }
96
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
97
+ process.exit(run(process.argv.slice(2)));
98
+ }
99
+ //# sourceMappingURL=verify-consumer-hard-stops.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ interface ParsedArgs {
3
+ projectRoot: string;
4
+ packRootExplicit: boolean;
5
+ error?: string;
6
+ }
7
+ /** Parse verify-deposit-closure CLI args (#3900 / #3601 C1). */
8
+ export declare function parseArgs(argv: string[]): ParsedArgs;
9
+ /** Run the gate and return the process exit code. */
10
+ export declare function run(argv: string[]): number;
11
+ export {};
12
+ //# sourceMappingURL=verify-deposit-closure.d.ts.map
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { evaluateDepositClosureAtRoot } from "@deftai/directive-core/verify-source";
5
+ /** Parse verify-deposit-closure CLI args (#3900 / #3601 C1). */
6
+ export function parseArgs(argv) {
7
+ const parsed = { projectRoot: ".", packRootExplicit: false };
8
+ for (let i = 0; i < argv.length; i += 1) {
9
+ const arg = argv[i];
10
+ if (arg === "--project-root" || arg === "--pack-root") {
11
+ const value = argv[i + 1];
12
+ if (value === undefined) {
13
+ return { ...parsed, error: "argument " + arg + ": expected one argument" };
14
+ }
15
+ parsed.projectRoot = value;
16
+ parsed.packRootExplicit = arg === "--pack-root";
17
+ i += 1;
18
+ }
19
+ else if (arg?.startsWith("--project-root=")) {
20
+ parsed.projectRoot = arg.slice("--project-root=".length);
21
+ }
22
+ else if (arg?.startsWith("--pack-root=")) {
23
+ parsed.projectRoot = arg.slice("--pack-root=".length);
24
+ parsed.packRootExplicit = true;
25
+ }
26
+ else {
27
+ return { ...parsed, error: "unrecognized argument: " + String(arg) };
28
+ }
29
+ }
30
+ return parsed;
31
+ }
32
+ /** Run the gate and return the process exit code. */
33
+ export function run(argv) {
34
+ const args = parseArgs(argv);
35
+ if (args.error !== undefined) {
36
+ process.stderr.write("verify_deposit_closure: " + args.error + "\n");
37
+ return 2;
38
+ }
39
+ const root = resolve(args.projectRoot);
40
+ const result = evaluateDepositClosureAtRoot(root, args.packRootExplicit);
41
+ if (result.stream === "stdout") {
42
+ process.stdout.write(result.message + "\n");
43
+ }
44
+ else {
45
+ process.stderr.write(result.message + "\n");
46
+ }
47
+ return result.code;
48
+ }
49
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
50
+ process.exit(run(process.argv.slice(2)));
51
+ }
52
+ //# sourceMappingURL=verify-deposit-closure.js.map
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ interface ParsedArgs {
3
+ projectRoot: string;
4
+ error?: string;
5
+ }
6
+ /** Parse verify-semantic-single-source CLI args (#3600 / #3899 C2). */
7
+ export declare function parseArgs(argv: string[]): ParsedArgs;
8
+ /** Run the C2 gate and return the process exit code. */
9
+ export declare function run(argv: string[]): number;
10
+ export {};
11
+ //# sourceMappingURL=verify-semantic-single-source.d.ts.map
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { evaluateSemanticSingleSource } from "@deftai/directive-core/verify-source";
5
+ /** Parse verify-semantic-single-source CLI args (#3600 / #3899 C2). */
6
+ export function parseArgs(argv) {
7
+ const parsed = { projectRoot: "." };
8
+ for (let i = 0; i < argv.length; i += 1) {
9
+ const arg = argv[i];
10
+ if (arg === "--project-root" || arg === "--pack-root") {
11
+ const value = argv[i + 1];
12
+ if (value === undefined) {
13
+ return { ...parsed, error: `argument ${arg}: expected one argument` };
14
+ }
15
+ parsed.projectRoot = value;
16
+ i += 1;
17
+ }
18
+ else if (arg?.startsWith("--project-root=")) {
19
+ parsed.projectRoot = arg.slice("--project-root=".length);
20
+ }
21
+ else if (arg?.startsWith("--pack-root=")) {
22
+ parsed.projectRoot = arg.slice("--pack-root=".length);
23
+ }
24
+ else {
25
+ return { ...parsed, error: `unrecognized argument: ${arg}` };
26
+ }
27
+ }
28
+ return parsed;
29
+ }
30
+ /** Run the C2 gate and return the process exit code. */
31
+ export function run(argv) {
32
+ const args = parseArgs(argv);
33
+ if (args.error !== undefined) {
34
+ process.stderr.write(`verify_semantic_single_source: ${args.error}\n`);
35
+ return 2;
36
+ }
37
+ const result = evaluateSemanticSingleSource(resolve(args.projectRoot));
38
+ if (result.stream === "stdout") {
39
+ process.stdout.write(`${result.message}\n`);
40
+ }
41
+ else {
42
+ process.stderr.write(`${result.message}\n`);
43
+ }
44
+ return result.code;
45
+ }
46
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
47
+ process.exit(run(process.argv.slice(2)));
48
+ }
49
+ //# sourceMappingURL=verify-semantic-single-source.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive",
3
- "version": "0.108.0",
3
+ "version": "0.109.1",
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/",
@@ -34,8 +34,8 @@
34
34
  "provenance": true
35
35
  },
36
36
  "dependencies": {
37
- "@deftai/directive-core": "^0.108.0",
38
- "@deftai/directive-content": "^0.108.0"
37
+ "@deftai/directive-core": "^0.109.1",
38
+ "@deftai/directive-content": "^0.109.1"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsc -b"