@deftai/directive 0.83.0 → 0.85.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/check.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  interface ParsedArgs {
3
3
  frameworkRoot?: string;
4
4
  projectRoot?: string;
5
+ noCache?: boolean;
5
6
  error?: string;
6
7
  }
7
8
  export declare function parseArgs(argv: string[]): ParsedArgs;
package/dist/check.js CHANGED
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * check.ts -- CLI wrapper for the context-aware `task check` orchestrator (#1854).
3
+ * check.ts -- CLI wrapper for the context-aware `task check` orchestrator (#1854, #1713).
4
4
  *
5
- * Usage: deft-ts check --framework-root <path> --project-root <path>
6
- *
7
- * Thin shim: parses args and delegates to dispatchTaskCheck in @deftai/directive-core/check.
5
+ * Usage: deft-ts check --framework-root <path> --project-root <path> [--no-cache]
8
6
  */
9
7
  import { fileURLToPath } from "node:url";
10
8
  import { dispatchTaskCheck } from "@deftai/directive-core/check";
@@ -34,6 +32,9 @@ export function parseArgs(argv) {
34
32
  else if (arg.startsWith("--project-root=")) {
35
33
  parsed.projectRoot = arg.slice("--project-root=".length);
36
34
  }
35
+ else if (arg === "--no-cache") {
36
+ parsed.noCache = true;
37
+ }
37
38
  else {
38
39
  return { ...parsed, error: `unrecognized argument: ${arg}` };
39
40
  }
@@ -50,7 +51,7 @@ export function run(argv) {
50
51
  process.stderr.write("check: --framework-root and --project-root are required\n");
51
52
  return 2;
52
53
  }
53
- return dispatchTaskCheck(args.frameworkRoot, args.projectRoot);
54
+ return dispatchTaskCheck(args.frameworkRoot, args.projectRoot, { noCache: args.noCache });
54
55
  }
55
56
  /* v8 ignore start -- entry guard */
56
57
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
@@ -68,10 +68,12 @@ export const SUBCOMMAND_ROUTES = {
68
68
  "cache:invalidate": ["cache", "invalidate"],
69
69
  "cache:fetch-all": ["cache", "fetch-all"],
70
70
  "cache:prune": ["cache", "prune"],
71
+ "cache:clear": ["cache", "clear"],
71
72
  "policy:show": ["policy", "show"],
72
73
  "policy:enforce-branches": ["policy", "enforce-branches"],
73
74
  "policy:allow-direct-commits": ["policy", "allow-direct-commits"],
74
75
  "policy:enable-value-feedback": ["policy", "enable-value-feedback"],
76
+ "policy:clear-value-feedback": ["policy", "clear-value-feedback"],
75
77
  "product-signal:status": ["product-signal", "status"],
76
78
  "product-signal:enable": ["product-signal", "enable"],
77
79
  "product-signal:consent": ["product-signal", "consent"],
@@ -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", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "lifecycle-event", "session-start", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "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", "verify-branch", "verify-encoding", "verify-forward-coverage", "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-content-manifest", "verify-skill-external-fetch-gate", "verify-contract-drift", "verify-cursor-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", "review-monitor-register", "verify-tools", "verify-wip-cap", "verify-orphan-active", "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", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "pr-watch", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "lifecycle-event", "session-start", "plan-sequence", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "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", "verify-branch", "verify-encoding", "verify-forward-coverage", "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-content-manifest", "verify-skill-external-fetch-gate", "verify-contract-drift", "verify-cursor-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-subagent-alive", "review-monitor-register", "review-monitor-release", "verify-tools", "verify-wip-cap", "verify-orphan-active", "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
- export declare const CORE_MODULE_VERBS: readonly ["scm", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "issue-sync-from-xbrief", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-finalize-cohort", "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", "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"];
15
+ export declare const CORE_MODULE_VERBS: readonly ["scm", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "issue-sync-from-xbrief", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-finalize-cohort", "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"];
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
@@ -114,7 +114,9 @@ export const CLI_MODULE_VERBS = [
114
114
  "rule-ownership-lint",
115
115
  "verify-story-ready",
116
116
  "verify-review-monitor",
117
+ "verify-subagent-alive",
117
118
  "review-monitor-register",
119
+ "review-monitor-release",
118
120
  "verify-tools",
119
121
  "verify-wip-cap",
120
122
  "verify-orphan-active",
@@ -151,6 +153,7 @@ export const CORE_MODULE_VERBS = [
151
153
  "export-spec",
152
154
  "project-render",
153
155
  "roadmap-render",
156
+ "rule-map",
154
157
  "spec-render",
155
158
  "spec-validate",
156
159
  "code-structure-validate",
@@ -188,6 +191,7 @@ export const POLICY_ACTION_ALIAS_SUBCOMMANDS = {
188
191
  "policy:enforce-branches": "enforce-branches",
189
192
  "policy:allow-direct-commits": "allow-direct-commits",
190
193
  "policy:enable-value-feedback": "enable-value-feedback",
194
+ "policy:clear-value-feedback": "clear-value-feedback",
191
195
  };
192
196
  const POLICY_ACTION_COLON_ALIASES = Object.fromEntries(Object.keys(POLICY_ACTION_ALIAS_SUBCOMMANDS).map((alias) => [alias, "policy"]));
193
197
  /** Colon aliases for plan-sequence subcommands (#2402). */
@@ -229,7 +233,10 @@ export const VERB_ALIASES = {
229
233
  "vbrief:activate": "vbrief-activate",
230
234
  "verify:story-ready": "verify-story-ready",
231
235
  "verify:review-monitor": "verify-review-monitor",
236
+ "verify:subagent-alive": "verify-subagent-alive",
237
+ "agent:monitor": "subagent-monitor",
232
238
  "review-monitor:register": "review-monitor-register",
239
+ "review-monitor:release": "review-monitor-release",
233
240
  "verify:tools": "verify-tools",
234
241
  "verify:investigation": "verify-investigation",
235
242
  "verify:judgment-gates": "verify-judgment-gates",
@@ -279,6 +286,7 @@ export const VERB_ALIASES = {
279
286
  "spec:render": "spec-render",
280
287
  "prd:render": "prd-render",
281
288
  "project:render": "project-render",
289
+ "docs:rule-map": "rule-map",
282
290
  "project:export-spec": "export-spec",
283
291
  "pr:watch": "pr-watch",
284
292
  doctor: "doctor",
@@ -2298,6 +2306,10 @@ async function loadCoreModuleHandler(verb, io) {
2298
2306
  const { runProjectRenderCli } = await import("./render-cli/project-render-cli.js");
2299
2307
  return (argv) => runProjectRenderCli(argv);
2300
2308
  }
2309
+ case "rule-map": {
2310
+ const { runRuleMapCli } = await import("./render-cli/rule-map-cli.js");
2311
+ return (argv) => runRuleMapCli(argv);
2312
+ }
2301
2313
  case "export-spec": {
2302
2314
  const { runExportSpecCli } = await import("./render-cli/export-spec-cli.js");
2303
2315
  return (argv) => runExportSpecCli(argv);
package/dist/doctor.d.ts CHANGED
@@ -1,5 +1,14 @@
1
1
  #!/usr/bin/env node
2
- /** Advisory when a consumer deposit carries git-vendored framework source (#2142 / #2347). */
3
- export declare function renderStrayPackagesAdvisoryLine(projectRoot: string): string;
2
+ export interface DepositFileSetHygieneResult {
3
+ readonly absent: readonly string[];
4
+ readonly contentRoot: string | null;
5
+ readonly skipped: boolean;
6
+ }
7
+ export interface EvaluateDepositFileSetOptions {
8
+ readonly contentRoot?: string;
9
+ }
10
+ /** Compare `.deft/core/` against `@deftai/directive-content` (#2804). */
11
+ export declare function evaluateDepositFileSetHygiene(projectRoot: string, options?: EvaluateDepositFileSetOptions): DepositFileSetHygieneResult;
12
+ export declare function renderDepositFileSetHygieneLine(projectRoot: string, result?: DepositFileSetHygieneResult): string;
4
13
  export declare function run(argv: string[]): number;
5
14
  //# sourceMappingURL=doctor.d.ts.map
package/dist/doctor.js CHANGED
@@ -2,20 +2,45 @@
2
2
  import { existsSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { resolveContentPackageRoot } from "@deftai/directive-core/dist/content-root.js";
5
6
  import { parseDoctorFlags } from "@deftai/directive-core/dist/doctor/flags.js";
6
7
  import { cmdDoctor } from "@deftai/directive-core/dist/doctor/main.js";
8
+ import { findPackageAbsentDepositPathsSync } from "@deftai/directive-core/dist/init-deposit/hygiene.js";
7
9
  import { renderPrecutoverLine } from "@deftai/directive-core/dist/vbrief-validate/precutover.js";
8
10
  import { renderStaleHeaderLine, renderXbriefMigrationLine, } from "@deftai/directive-core/xbrief-migrate";
9
- /** Advisory when a consumer deposit carries git-vendored framework source (#2142 / #2347). */
10
- export function renderStrayPackagesAdvisoryLine(projectRoot) {
11
- const packagesDir = join(projectRoot, ".deft", "core", "packages");
12
- if (!existsSync(packagesDir)) {
13
- return "Deposit hygiene: none -- .deft/core contains no stray packages/ source tree.";
11
+ /** Compare `.deft/core/` against `@deftai/directive-content` (#2804). */
12
+ export function evaluateDepositFileSetHygiene(projectRoot, options = {}) {
13
+ const deftDir = join(projectRoot, ".deft", "core");
14
+ if (!existsSync(deftDir)) {
15
+ return { absent: [], contentRoot: null, skipped: true };
14
16
  }
15
- return ("Deposit hygiene: advisory -- .deft/core/packages/ is present (git-vendored framework source, " +
16
- "not shipped by npm @deftai/directive-content). " +
17
- "Run `directive update` to auto-prune this stray tree, then commit the result (#2347). " +
18
- "Or remove it manually: `git rm -r --cached .deft/core/packages && git commit -m 'chore: remove stray framework source'`.");
17
+ const contentRoot = options.contentRoot ?? resolveContentPackageRoot(projectRoot);
18
+ if (contentRoot === null || !existsSync(contentRoot)) {
19
+ return { absent: [], contentRoot: null, skipped: true };
20
+ }
21
+ return {
22
+ absent: findPackageAbsentDepositPathsSync(deftDir, contentRoot),
23
+ contentRoot,
24
+ skipped: false,
25
+ };
26
+ }
27
+ export function renderDepositFileSetHygieneLine(projectRoot, result = evaluateDepositFileSetHygiene(projectRoot)) {
28
+ const deftDir = join(projectRoot, ".deft", "core");
29
+ if (!existsSync(deftDir)) {
30
+ return "Deposit hygiene: none -- no .deft/core deposit.";
31
+ }
32
+ if (result.skipped) {
33
+ return ("Deposit hygiene: skip -- @deftai/directive-content is not installed " +
34
+ "(cannot compare deposit file-set).");
35
+ }
36
+ if (result.absent.length === 0) {
37
+ return "Deposit hygiene: none -- .deft/core file-set matches @deftai/directive-content.";
38
+ }
39
+ const sample = result.absent.slice(0, 5).join(", ");
40
+ const suffix = result.absent.length > 5 ? ` (+${result.absent.length - 5} more)` : "";
41
+ return (`Deposit hygiene: fail -- ${result.absent.length} package-absent file(s) in .deft/core ` +
42
+ `(not shipped by @deftai/directive-content). Examples: ${sample}${suffix}. ` +
43
+ "Run `directive update` to auto-prune these stale deposit files (#2804).");
19
44
  }
20
45
  export function run(argv) {
21
46
  // #2022: surface pre-cutover (pre-v0.20 document model) migration state alongside the
@@ -23,14 +48,20 @@ export function run(argv) {
23
48
  // --json (so the machine-readable report stays valid), on --help, and when unknown flags
24
49
  // are present (so an invalid invocation still mirrors the core error path exactly).
25
50
  const flags = parseDoctorFlags(argv);
51
+ let depositHygieneExit = 0;
26
52
  if (!flags.json && !flags.help && flags.unknown.length === 0) {
27
53
  const projectRoot = flags.projectRoot ?? process.cwd();
54
+ const depositResult = evaluateDepositFileSetHygiene(projectRoot);
28
55
  process.stdout.write(`${renderPrecutoverLine(projectRoot)}\n`);
29
56
  process.stdout.write(`${renderXbriefMigrationLine(projectRoot)}\n`);
30
57
  process.stdout.write(`${renderStaleHeaderLine(projectRoot)}\n`);
31
- process.stdout.write(`${renderStrayPackagesAdvisoryLine(projectRoot)}\n`);
58
+ process.stdout.write(`${renderDepositFileSetHygieneLine(projectRoot, depositResult)}\n`);
59
+ if (flags.full && !depositResult.skipped && depositResult.absent.length > 0) {
60
+ depositHygieneExit = 1;
61
+ }
32
62
  }
33
- return cmdDoctor(argv);
63
+ const doctorExit = cmdDoctor(argv);
64
+ return Math.max(depositHygieneExit, doctorExit);
34
65
  }
35
66
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
36
67
  process.exit(run(process.argv.slice(2)));
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(argv?: string[]): number;
3
+ //# sourceMappingURL=hook-bin.d.ts.map
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from "node:url";
3
+ import { run } from "./hook-dispatch.js";
4
+ // Keep PreToolUse off the general CLI router's cold path.
5
+ export function main(argv = process.argv.slice(2)) {
6
+ return run(argv);
7
+ }
8
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
9
+ process.exit(main());
10
+ }
11
+ //# sourceMappingURL=hook-bin.js.map
@@ -2,7 +2,7 @@
2
2
  import { readFileSync } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { decideHook, hookPayloadTopLevelKeys, isHookEvent, isHookHost, projectRootFromHookPayload, renderHostDecision, } from "@deftai/directive-core/hooks";
5
+ import { decideHook, hookPayloadTopLevelKeys, isHookEvent, isHookHost, normalizeHookProjectRoot, projectRootFromHookPayload, renderHostDecision, } from "@deftai/directive-core/hooks";
6
6
  function takeValue(argv, index, flag) {
7
7
  const token = argv[index];
8
8
  const prefix = `${flag}=`;
@@ -122,9 +122,7 @@ export function run(argv, seams = {}) {
122
122
  const readStdin = seams.readStdin ?? (() => readFileSync(0, "utf8"));
123
123
  const cwd = (seams.cwd ?? process.cwd)();
124
124
  const { payload, context: payloadContext } = parsePayload(readStdin());
125
- const projectRoot = args.projectRoot
126
- ? resolve(args.projectRoot)
127
- : projectRootFromHookPayload(payload, cwd);
125
+ const projectRoot = normalizeHookProjectRoot(args.projectRoot ? resolve(args.projectRoot) : projectRootFromHookPayload(payload, cwd));
128
126
  const decision = decideHook({
129
127
  host: args.host,
130
128
  event: args.event,
@@ -0,0 +1,9 @@
1
+ import type { DispatchIo } from "../dispatch.js";
2
+ /** Flags that request usage text without executing a mutating install path (#2828). */
3
+ export declare const INIT_CLI_HELP_FLAGS: readonly ["--help", "-h", "/help", "/h"];
4
+ /** True when argv includes a help flag anywhere in the token list. */
5
+ export declare function argvWantsHelp(argv: readonly string[]): boolean;
6
+ export declare function printUpdateHelp(io: DispatchIo): void;
7
+ export declare function printInitHelp(io: DispatchIo): void;
8
+ export declare function printMigrateHelp(io: DispatchIo): void;
9
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1,42 @@
1
+ /** Flags that request usage text without executing a mutating install path (#2828). */
2
+ export const INIT_CLI_HELP_FLAGS = ["--help", "-h", "/help", "/h"];
3
+ /** True when argv includes a help flag anywhere in the token list. */
4
+ export function argvWantsHelp(argv) {
5
+ const flags = INIT_CLI_HELP_FLAGS;
6
+ return argv.some((arg) => flags.includes(arg));
7
+ }
8
+ export function printUpdateHelp(io) {
9
+ io.writeOut("Usage: directive update [options]\n" +
10
+ " deft update [options]\n\n" +
11
+ "Refresh the framework deposit in an existing Directive project and self-heal the engine.\n\n" +
12
+ "Options:\n" +
13
+ " --repo-root <path> Project root (default: current directory)\n" +
14
+ " --json Machine-readable summary on stdout\n" +
15
+ " --yes, --non-interactive Run without prompts\n" +
16
+ " --dry-run, --plan Classify and print the refresh plan without writing\n" +
17
+ " -h, --help Show this help\n");
18
+ }
19
+ export function printInitHelp(io) {
20
+ io.writeOut("Usage: directive init [options]\n" +
21
+ " deft init [options]\n\n" +
22
+ "Set up Directive in the current project (greenfield scaffold or brownfield adoption).\n\n" +
23
+ "Options:\n" +
24
+ " --repo-root <path> Project root (default: current directory)\n" +
25
+ " --json Machine-readable summary on stdout\n" +
26
+ " --yes, --non-interactive Run without prompts\n" +
27
+ " --dry-run, --plan Classify and print the dispatch plan without writing\n" +
28
+ " --headless Emit a { version, files } manifest with no side effects\n" +
29
+ " --output <path> Manifest output path for --headless (default: stdout)\n" +
30
+ " -h, --help Show this help\n");
31
+ }
32
+ export function printMigrateHelp(io) {
33
+ io.writeOut("Usage: directive migrate [options]\n" +
34
+ " deft migrate [options]\n\n" +
35
+ "Stamp a canonical-vendored .deft/core deposit as npm-managed (provenance only).\n\n" +
36
+ "Options:\n" +
37
+ " --repo-root <path> Project root (default: current directory)\n" +
38
+ " --json Machine-readable summary on stdout\n" +
39
+ " --untrack-core Un-commit .deft/core from git (destructive index mutation)\n" +
40
+ " -h, --help Show this help\n");
41
+ }
42
+ //# sourceMappingURL=help.js.map
@@ -1,5 +1,6 @@
1
1
  import { parseInitArgv, runInitDispatchCli, runInitHeadlessCli, } from "@deftai/directive-core/init-deposit";
2
2
  import { CANONICAL_INIT_ARGV, INIT_DRY_RUN_FLAGS, INIT_HEADLESS_FLAGS, INIT_OUTPUT_FLAGS, } from "./constants.js";
3
+ import { argvWantsHelp, printInitHelp } from "./help.js";
3
4
  /** True when the user argv asked for a classify-only dispatch plan (`--dry-run`/`--plan`). */
4
5
  export function isInitDryRun(argv) {
5
6
  const flags = INIT_DRY_RUN_FLAGS;
@@ -53,6 +54,10 @@ export function parseInitOutputPath(argv) {
53
54
  * `headlessSeams` injects the content-resolution seam for the headless path.
54
55
  */
55
56
  export function runInit(argv, io, seams, headlessSeams) {
57
+ if (argvWantsHelp(argv)) {
58
+ printInitHelp(io);
59
+ return Promise.resolve(0);
60
+ }
56
61
  if (isInitHeadless(argv)) {
57
62
  return runInitHeadlessCli({
58
63
  outputPath: parseInitOutputPath(argv),
@@ -1,5 +1,6 @@
1
1
  import { parseInitArgv, runMigrateCli, runUntrackCoreCli, } from "@deftai/directive-core/init-deposit";
2
2
  import { CANONICAL_MIGRATE_ARGV, MIGRATE_UNTRACK_CORE_FLAG } from "./constants.js";
3
+ import { argvWantsHelp, printMigrateHelp } from "./help.js";
3
4
  /**
4
5
  * `directive migrate` (alias `deft migrate`) -- stage-2 provenance verb (#1941):
5
6
  * stamp a canonical-vendored `.deft/core` deposit as npm-managed. Thin wrapper
@@ -19,6 +20,10 @@ function hasUntrackCoreFlag(argv) {
19
20
  return argv.some((arg) => arg === MIGRATE_UNTRACK_CORE_FLAG || arg === `/${MIGRATE_UNTRACK_CORE_FLAG.slice(2)}`);
20
21
  }
21
22
  export function runMigrate(argv, io) {
23
+ if (argvWantsHelp(argv)) {
24
+ printMigrateHelp(io);
25
+ return 0;
26
+ }
22
27
  const args = parseInitArgv(CANONICAL_MIGRATE_ARGV, argv);
23
28
  // `migrate --untrack-core` selects the destructive un-track subcommand;
24
29
  // bare `migrate` keeps the provenance-stamp behavior below.
@@ -1,11 +1,16 @@
1
1
  import { parseUpdateArgv, runRefreshDepositCli } from "@deftai/directive-core/init-deposit";
2
2
  import { CANONICAL_UPDATE_ARGV, UPDATE_DRY_RUN_FLAGS } from "./constants.js";
3
+ import { argvWantsHelp, printUpdateHelp } from "./help.js";
3
4
  /** True when the user argv asked for a classify-only dry-run (`--dry-run`/`--plan`). */
4
5
  export function isUpdateDryRun(argv) {
5
6
  const flags = UPDATE_DRY_RUN_FLAGS;
6
7
  return argv.some((arg) => flags.includes(arg));
7
8
  }
8
9
  export function runUpdate(argv, io) {
10
+ if (argvWantsHelp(argv)) {
11
+ printUpdateHelp(io);
12
+ return Promise.resolve(0);
13
+ }
9
14
  const args = parseUpdateArgv(CANONICAL_UPDATE_ARGV, argv);
10
15
  return runRefreshDepositCli({
11
16
  ...args,
package/dist/policy.d.ts CHANGED
@@ -7,7 +7,7 @@ interface ShowArgs {
7
7
  error?: string;
8
8
  }
9
9
  interface SetArgs {
10
- cmd: "show" | "enforce-branches" | "allow-direct-commits" | "enable-value-feedback" | "resolve";
10
+ cmd: "show" | "enforce-branches" | "allow-direct-commits" | "enable-value-feedback" | "clear-value-feedback" | "resolve";
11
11
  confirm: boolean;
12
12
  actor: string;
13
13
  note: string;
package/dist/policy.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import { existsSync } from "node:fs";
7
7
  import { resolve as pathResolve, relative } from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
- import { describeShadowedPlanExtension, detectShadowedPlanExtensions, disclosureLine, enableValueFeedback, FIELD_VALUE_FEEDBACK, FIELD_VALUE_FEEDBACK_CLI_ALIAS, formatValueFeedbackStatusLine, inspectAllPolicies, inspectOnePolicy, loadProjectDefinition, policyColonInvocation, projectDefinitionPath, pythonListRepr, pythonStringRepr, registeredPolicyNames, renderJson, renderText, resolvePolicy, resolveValueFeedback, setPolicy, } from "@deftai/directive-core/policy";
9
+ import { clearValueFeedback, describeShadowedPlanExtension, detectShadowedPlanExtensions, disclosureLine, enableValueFeedback, FIELD_VALUE_FEEDBACK, FIELD_VALUE_FEEDBACK_CLI_ALIAS, formatValueFeedbackStatusLine, inspectAllPolicies, inspectOnePolicy, loadProjectDefinition, policyColonInvocation, projectDefinitionPath, pythonListRepr, pythonStringRepr, registeredPolicyNames, renderJson, renderText, resolvePolicy, resolveValueFeedback, setPolicy, } from "@deftai/directive-core/policy";
10
10
  const CAPABILITY_COST_DISCLOSURE = "\u26a0 Capability-cost disclosure -- enabling direct commits to the default " +
11
11
  "branch turns OFF the deft branch-protection policy.\n" +
12
12
  " \u2022 Pre-commit + pre-push hooks will no longer block default-branch " +
@@ -114,7 +114,7 @@ export function parseShowArgs(argv) {
114
114
  /** Parse argv for the policy CLI (show + set subcommands). */
115
115
  export function parseArgs(argv) {
116
116
  if (argv.length === 0) {
117
- const usage = "usage: policy [show|enforce-branches|allow-direct-commits|enable-value-feedback|resolve] ...";
117
+ const usage = "usage: policy [show|enforce-branches|allow-direct-commits|enable-value-feedback|clear-value-feedback|resolve] ...";
118
118
  return makeSetError(usage);
119
119
  }
120
120
  const cmd = argv[0];
@@ -148,13 +148,16 @@ export function parseArgs(argv) {
148
148
  }
149
149
  if (cmd === "enforce-branches" ||
150
150
  cmd === "allow-direct-commits" ||
151
- cmd === "enable-value-feedback") {
151
+ cmd === "enable-value-feedback" ||
152
+ cmd === "clear-value-feedback") {
152
153
  let confirm = false;
153
154
  let actor = cmd === "enforce-branches"
154
155
  ? policyColonInvocation("enforce-branches")
155
156
  : cmd === "allow-direct-commits"
156
157
  ? policyColonInvocation("allow-direct-commits")
157
- : policyColonInvocation("enable-value-feedback");
158
+ : cmd === "enable-value-feedback"
159
+ ? policyColonInvocation("enable-value-feedback")
160
+ : policyColonInvocation("clear-value-feedback");
158
161
  let note = "";
159
162
  let projectRoot = ".";
160
163
  for (let i = 1; i < argv.length; i += 1) {
@@ -327,6 +330,14 @@ function runSet(args) {
327
330
  return 2;
328
331
  }
329
332
  }
333
+ function runClearValueFeedback(args) {
334
+ const result = clearValueFeedback(pathResolve(args.projectRoot), {
335
+ actor: args.actor,
336
+ note: args.note,
337
+ });
338
+ process.stdout.write(result.stdout);
339
+ return result.exitCode;
340
+ }
330
341
  /** Run the policy CLI; returns process exit code. */
331
342
  export function run(argv) {
332
343
  const args = parseArgs(argv);
@@ -351,6 +362,9 @@ export function run(argv) {
351
362
  if (args.cmd === "enable-value-feedback") {
352
363
  return runEnableValueFeedback(args);
353
364
  }
365
+ if (args.cmd === "clear-value-feedback") {
366
+ return runClearValueFeedback(args);
367
+ }
354
368
  return 2;
355
369
  }
356
370
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
@@ -0,0 +1,2 @@
1
+ export declare function runRuleMapCli(argv: readonly string[]): number;
2
+ //# sourceMappingURL=rule-map-cli.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { ruleMapMain } from "@deftai/directive-core/render";
2
+ export function runRuleMapCli(argv) {
3
+ return ruleMapMain(argv);
4
+ }
5
+ //# sourceMappingURL=rule-map-cli.js.map
@@ -6,8 +6,10 @@ interface ParsedArgs {
6
6
  platformPrimitive: PlatformPrimitive | null;
7
7
  repo: string | null;
8
8
  headSha: string | null;
9
+ owner: string | null;
9
10
  projectRoot: string;
10
11
  parentSessionId: string | null;
12
+ force: boolean;
11
13
  help: boolean;
12
14
  error?: string;
13
15
  }
@@ -10,8 +10,10 @@ export function parseRegisterArgs(argv) {
10
10
  platformPrimitive: null,
11
11
  repo: null,
12
12
  headSha: null,
13
+ owner: null,
13
14
  projectRoot: ".",
14
15
  parentSessionId: null,
16
+ force: false,
15
17
  help: false,
16
18
  };
17
19
  for (let i = 0; i < argv.length; i += 1) {
@@ -19,7 +21,10 @@ export function parseRegisterArgs(argv) {
19
21
  if (arg === "--help" || arg === "-h") {
20
22
  return { ...acc, help: true };
21
23
  }
22
- if (arg === "--pr") {
24
+ if (arg === "--force") {
25
+ acc.force = true;
26
+ }
27
+ else if (arg === "--pr") {
23
28
  const value = argv[i + 1];
24
29
  if (value === undefined) {
25
30
  return { ...acc, error: "argument --pr: expected one argument" };
@@ -78,6 +83,17 @@ export function parseRegisterArgs(argv) {
78
83
  else if (arg?.startsWith("--repo=")) {
79
84
  acc.repo = arg.slice("--repo=".length);
80
85
  }
86
+ else if (arg === "--owner") {
87
+ const value = argv[i + 1];
88
+ if (value === undefined) {
89
+ return { ...acc, error: "argument --owner: expected one argument" };
90
+ }
91
+ acc.owner = value;
92
+ i += 1;
93
+ }
94
+ else if (arg?.startsWith("--owner=")) {
95
+ acc.owner = arg.slice("--owner=".length);
96
+ }
81
97
  else if (arg === "--head-sha") {
82
98
  const value = argv[i + 1];
83
99
  if (value === undefined) {
@@ -142,23 +158,24 @@ export function run(argv) {
142
158
  process.stderr.write("review_monitor_register: --platform-primitive is required\n");
143
159
  return 2;
144
160
  }
145
- try {
146
- const { path, record } = registerReviewMonitor({
147
- pr: args.pr,
148
- repo: args.repo,
149
- headSha: args.headSha,
150
- platformPrimitive: args.platformPrimitive,
151
- monitorAgentId: args.monitorAgentId,
152
- projectRoot: resolve(args.projectRoot),
153
- parentSessionId: args.parentSessionId,
154
- });
155
- process.stdout.write(`review_monitor_register: recorded PR #${record.pr} monitor ${record.monitor_agent_id} at ${path}\n`);
156
- return 0;
161
+ const result = registerReviewMonitor({
162
+ pr: args.pr,
163
+ repo: args.repo,
164
+ headSha: args.headSha,
165
+ owner: args.owner,
166
+ platformPrimitive: args.platformPrimitive,
167
+ monitorAgentId: args.monitorAgentId,
168
+ projectRoot: resolve(args.projectRoot),
169
+ parentSessionId: args.parentSessionId,
170
+ force: args.force,
171
+ });
172
+ if (result.exitCode === 0) {
173
+ process.stdout.write(`${result.message}\n`);
157
174
  }
158
- catch (err) {
159
- process.stderr.write(`review_monitor_register: ${String(err.message ?? err)}\n`);
160
- return 2;
175
+ else {
176
+ process.stderr.write(`${result.message}\n`);
161
177
  }
178
+ return result.exitCode;
162
179
  }
163
180
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
164
181
  process.exit(run(process.argv.slice(2)));
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ interface ParsedArgs {
3
+ pr: number | null;
4
+ repo: string | null;
5
+ monitorAgentId: string | null;
6
+ owner: string | null;
7
+ projectRoot: string;
8
+ help: boolean;
9
+ error?: string;
10
+ }
11
+ export declare function parseReleaseArgs(argv: readonly string[]): ParsedArgs;
12
+ export declare function run(argv: readonly string[]): number;
13
+ export {};
14
+ //# sourceMappingURL=review-monitor-release.d.ts.map
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { RELEASE_HELP, releaseReviewMonitor } from "@deftai/directive-core/review-monitor";
5
+ export function parseReleaseArgs(argv) {
6
+ const acc = {
7
+ pr: null,
8
+ repo: null,
9
+ monitorAgentId: null,
10
+ owner: null,
11
+ projectRoot: ".",
12
+ help: false,
13
+ };
14
+ for (let i = 0; i < argv.length; i += 1) {
15
+ const arg = argv[i];
16
+ if (arg === "--help" || arg === "-h") {
17
+ return { ...acc, help: true };
18
+ }
19
+ if (arg === "--pr") {
20
+ const value = argv[i + 1];
21
+ if (value === undefined) {
22
+ return { ...acc, error: "argument --pr: expected one argument" };
23
+ }
24
+ const n = Number(value);
25
+ if (!Number.isInteger(n) || n <= 0) {
26
+ return { ...acc, error: `invalid --pr value: ${value}` };
27
+ }
28
+ acc.pr = n;
29
+ i += 1;
30
+ }
31
+ else if (arg?.startsWith("--pr=")) {
32
+ const n = Number(arg.slice("--pr=".length));
33
+ if (!Number.isInteger(n) || n <= 0) {
34
+ return { ...acc, error: `invalid --pr value: ${arg}` };
35
+ }
36
+ acc.pr = n;
37
+ }
38
+ else if (arg === "--repo") {
39
+ const value = argv[i + 1];
40
+ if (value === undefined) {
41
+ return { ...acc, error: "argument --repo: expected one argument" };
42
+ }
43
+ acc.repo = value;
44
+ i += 1;
45
+ }
46
+ else if (arg?.startsWith("--repo=")) {
47
+ acc.repo = arg.slice("--repo=".length);
48
+ }
49
+ else if (arg === "--monitor-agent-id") {
50
+ const value = argv[i + 1];
51
+ if (value === undefined) {
52
+ return { ...acc, error: "argument --monitor-agent-id: expected one argument" };
53
+ }
54
+ acc.monitorAgentId = value;
55
+ i += 1;
56
+ }
57
+ else if (arg?.startsWith("--monitor-agent-id=")) {
58
+ acc.monitorAgentId = arg.slice("--monitor-agent-id=".length);
59
+ }
60
+ else if (arg === "--owner") {
61
+ const value = argv[i + 1];
62
+ if (value === undefined) {
63
+ return { ...acc, error: "argument --owner: expected one argument" };
64
+ }
65
+ acc.owner = value;
66
+ i += 1;
67
+ }
68
+ else if (arg?.startsWith("--owner=")) {
69
+ acc.owner = arg.slice("--owner=".length);
70
+ }
71
+ else if (arg === "--project-root") {
72
+ const value = argv[i + 1];
73
+ if (value === undefined) {
74
+ return { ...acc, error: "argument --project-root: expected one argument" };
75
+ }
76
+ acc.projectRoot = value;
77
+ i += 1;
78
+ }
79
+ else if (arg?.startsWith("--project-root=")) {
80
+ acc.projectRoot = arg.slice("--project-root=".length);
81
+ }
82
+ else if (arg?.startsWith("-")) {
83
+ return { ...acc, error: `unrecognized argument: ${arg}` };
84
+ }
85
+ else {
86
+ return { ...acc, error: `unrecognized argument: ${arg}` };
87
+ }
88
+ }
89
+ return acc;
90
+ }
91
+ export function run(argv) {
92
+ const args = parseReleaseArgs(argv);
93
+ if (args.help) {
94
+ process.stdout.write(RELEASE_HELP);
95
+ return 0;
96
+ }
97
+ if (args.error !== undefined) {
98
+ process.stderr.write(`review_monitor_release: ${args.error}\n`);
99
+ return 2;
100
+ }
101
+ if (args.pr === null) {
102
+ process.stderr.write("review_monitor_release: --pr is required\n");
103
+ return 2;
104
+ }
105
+ const result = releaseReviewMonitor({
106
+ pr: args.pr,
107
+ repo: args.repo,
108
+ monitorAgentId: args.monitorAgentId,
109
+ owner: args.owner,
110
+ projectRoot: resolve(args.projectRoot),
111
+ });
112
+ if (result.exitCode === 0) {
113
+ process.stdout.write(`${result.message}\n`);
114
+ }
115
+ else {
116
+ process.stderr.write(`${result.message}\n`);
117
+ }
118
+ return result.exitCode;
119
+ }
120
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
121
+ process.exit(run(process.argv.slice(2)));
122
+ }
123
+ //# sourceMappingURL=review-monitor-release.js.map
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ export declare const SUBAGENT_ALIVE_HELP = "verify:subagent-alive \u2014 fail-closed worker liveness gate (#2824)\n\nUsage:\n task verify:subagent-alive -- [options]\n task agent:monitor -- [options] (alias: raw heartbeat sweep)\n\nOptions:\n --scratch-dir PATH Heartbeat directory (repeatable; default: .deft-scratch/subagent-status)\n --require-agent ID In-flight worker that MUST have a fresh heartbeat (repeatable)\n --threshold-minutes N Staleness threshold (default: 30)\n --json Machine-readable output\n\nExit codes:\n 0 All required agents fresh (or no required agents and sweep clean)\n 1 Missing/STALE/malformed heartbeat \u2014 prints REDISPATCH_OK for takeover\n 2 Config error (invalid args, missing scratch dir with no records)\n";
3
+ export interface VerifySubagentAliveArgs {
4
+ scratchDirs: string[];
5
+ requireAgents: string[];
6
+ thresholdMinutes: number;
7
+ emitJson: boolean;
8
+ help: boolean;
9
+ error?: string;
10
+ }
11
+ export declare function parseVerifySubagentAliveArgs(argv: readonly string[]): VerifySubagentAliveArgs;
12
+ export interface SubagentAliveVerdict {
13
+ exitCode: number;
14
+ redispatchOk: boolean;
15
+ message: string;
16
+ json?: Record<string, unknown>;
17
+ }
18
+ /** Evaluate liveness for required in-flight workers. */
19
+ export declare function evaluateSubagentAliveGate(args: VerifySubagentAliveArgs, cwd?: string): SubagentAliveVerdict;
20
+ export declare function run(argv: readonly string[]): number;
21
+ //# sourceMappingURL=verify-subagent-alive.d.ts.map
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Fail-closed worker liveness gate (#2824). Wraps subagent-monitor with
4
+ * REDISPATCH_OK on missing/STALE heartbeats for registered in-flight workers.
5
+ */
6
+ import { resolve } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { DEFAULT_THRESHOLD_MINUTES, defaultScratchDir, EXIT_EXTERNAL_ERROR, EXIT_OK, EXIT_STALE, recordOk, sweepAllOk, sweepScratchDirs, } from "@deftai/directive-core/orchestration";
9
+ export const SUBAGENT_ALIVE_HELP = `verify:subagent-alive — fail-closed worker liveness gate (#2824)
10
+
11
+ Usage:
12
+ task verify:subagent-alive -- [options]
13
+ task agent:monitor -- [options] (alias: raw heartbeat sweep)
14
+
15
+ Options:
16
+ --scratch-dir PATH Heartbeat directory (repeatable; default: .deft-scratch/subagent-status)
17
+ --require-agent ID In-flight worker that MUST have a fresh heartbeat (repeatable)
18
+ --threshold-minutes N Staleness threshold (default: 30)
19
+ --json Machine-readable output
20
+
21
+ Exit codes:
22
+ 0 All required agents fresh (or no required agents and sweep clean)
23
+ 1 Missing/STALE/malformed heartbeat — prints REDISPATCH_OK for takeover
24
+ 2 Config error (invalid args, missing scratch dir with no records)
25
+ `;
26
+ export function parseVerifySubagentAliveArgs(argv) {
27
+ const acc = {
28
+ scratchDirs: [],
29
+ requireAgents: [],
30
+ thresholdMinutes: DEFAULT_THRESHOLD_MINUTES,
31
+ emitJson: false,
32
+ help: false,
33
+ };
34
+ for (let i = 0; i < argv.length; i += 1) {
35
+ const arg = argv[i];
36
+ if (arg === "--help" || arg === "-h") {
37
+ return { ...acc, help: true };
38
+ }
39
+ if (arg === "--json") {
40
+ acc.emitJson = true;
41
+ }
42
+ else if (arg === "--scratch-dir") {
43
+ const value = argv[i + 1];
44
+ if (value === undefined) {
45
+ return { ...acc, error: "argument --scratch-dir: expected one argument" };
46
+ }
47
+ acc.scratchDirs.push(value);
48
+ i += 1;
49
+ }
50
+ else if (arg?.startsWith("--scratch-dir=")) {
51
+ acc.scratchDirs.push(arg.slice("--scratch-dir=".length));
52
+ }
53
+ else if (arg === "--threshold-minutes") {
54
+ const value = argv[i + 1];
55
+ if (value === undefined) {
56
+ return { ...acc, error: "argument --threshold-minutes: expected one argument" };
57
+ }
58
+ acc.thresholdMinutes = Number(value);
59
+ i += 1;
60
+ }
61
+ else if (arg?.startsWith("--threshold-minutes=")) {
62
+ acc.thresholdMinutes = Number(arg.slice("--threshold-minutes=".length));
63
+ }
64
+ else if (arg === "--require-agent") {
65
+ const value = argv[i + 1];
66
+ if (value === undefined) {
67
+ return { ...acc, error: "argument --require-agent: expected one argument" };
68
+ }
69
+ acc.requireAgents.push(value);
70
+ i += 1;
71
+ }
72
+ else if (arg?.startsWith("--require-agent=")) {
73
+ acc.requireAgents.push(arg.slice("--require-agent=".length));
74
+ }
75
+ else if (arg?.startsWith("-")) {
76
+ return { ...acc, error: `unrecognized argument: ${arg}` };
77
+ }
78
+ else {
79
+ return { ...acc, error: `unrecognized argument: ${arg}` };
80
+ }
81
+ }
82
+ return acc;
83
+ }
84
+ function scratchEntries(scratchDirs, cwd) {
85
+ if (scratchDirs.length > 0) {
86
+ return scratchDirs.map((p) => ({ readPath: resolve(cwd, p), label: p }));
87
+ }
88
+ const defaultDir = defaultScratchDir(cwd);
89
+ return [{ readPath: defaultDir, label: defaultDir }];
90
+ }
91
+ /** Evaluate liveness for required in-flight workers. */
92
+ export function evaluateSubagentAliveGate(args, cwd = process.cwd()) {
93
+ if (args.error !== undefined) {
94
+ return {
95
+ exitCode: EXIT_EXTERNAL_ERROR,
96
+ redispatchOk: false,
97
+ message: `verify_subagent_alive: ${args.error}`,
98
+ };
99
+ }
100
+ if (Number.isNaN(args.thresholdMinutes) || args.thresholdMinutes <= 0) {
101
+ return {
102
+ exitCode: EXIT_EXTERNAL_ERROR,
103
+ redispatchOk: false,
104
+ message: `verify_subagent_alive: --threshold-minutes must be positive, got ${args.thresholdMinutes}`,
105
+ };
106
+ }
107
+ const entries = scratchEntries(args.scratchDirs, cwd);
108
+ const sweep = sweepScratchDirs(entries, { thresholdMinutes: args.thresholdMinutes });
109
+ const configError = sweep.sweep_errors.length > 0 && sweep.records.length === 0;
110
+ const missingAgents = [];
111
+ for (const agentId of args.requireAgents) {
112
+ const rec = sweep.records.find((r) => r.agent_id === agentId);
113
+ if (rec === undefined || !recordOk(rec)) {
114
+ missingAgents.push(agentId);
115
+ }
116
+ }
117
+ const requiredUnhealthy = missingAgents.length > 0;
118
+ // When --require-agent is set, only named workers gate the verdict; unrelated
119
+ // stale records in a shared scratch dir must not trigger REDISPATCH_OK (#2824).
120
+ const sweepUnhealthy = args.requireAgents.length === 0 && !sweepAllOk(sweep);
121
+ const unhealthy = sweepUnhealthy || requiredUnhealthy;
122
+ if (args.emitJson) {
123
+ return {
124
+ exitCode: configError ? EXIT_EXTERNAL_ERROR : unhealthy ? EXIT_STALE : EXIT_OK,
125
+ redispatchOk: unhealthy && !configError,
126
+ message: "",
127
+ json: {
128
+ all_ok: !unhealthy && !configError,
129
+ redispatch_ok: unhealthy && !configError,
130
+ required_agents: [...args.requireAgents],
131
+ missing_or_stale_agents: missingAgents,
132
+ sweep: {
133
+ scratch_dirs: sweep.scratch_dirs,
134
+ threshold_minutes: sweep.threshold_minutes,
135
+ stale_count: sweep.records.filter((r) => r.is_stale).length,
136
+ malformed_count: sweep.records.filter((r) => r.failures.length > 0).length,
137
+ sweep_errors: sweep.sweep_errors,
138
+ },
139
+ },
140
+ };
141
+ }
142
+ if (configError) {
143
+ const detail = sweep.sweep_errors.join("; ");
144
+ return {
145
+ exitCode: EXIT_EXTERNAL_ERROR,
146
+ redispatchOk: false,
147
+ message: `verify_subagent_alive: config error — ${detail}`,
148
+ };
149
+ }
150
+ if (!unhealthy) {
151
+ const count = args.requireAgents.length > 0 ? args.requireAgents.length : sweep.records.length;
152
+ return {
153
+ exitCode: EXIT_OK,
154
+ redispatchOk: false,
155
+ message: `verify_subagent_alive: all ${count} monitored worker(s) alive`,
156
+ };
157
+ }
158
+ const lines = ["verify_subagent_alive: worker liveness gate FAILED"];
159
+ if (requiredUnhealthy) {
160
+ lines.push(` Missing or STALE required agent(s): ${missingAgents.join(", ")}`);
161
+ }
162
+ if (sweepUnhealthy && args.requireAgents.length === 0) {
163
+ const stale = sweep.records.filter((r) => r.is_stale).length;
164
+ const malformed = sweep.records.filter((r) => r.failures.length > 0).length;
165
+ lines.push(` Sweep: ${stale} stale, ${malformed} malformed record(s)`);
166
+ }
167
+ lines.push("");
168
+ lines.push("REDISPATCH_OK: host-reported running + missing/STALE heartbeat authorizes takeover.");
169
+ lines.push("Re-dispatch a replacement worker; do not wait on Cursor false-alive state.");
170
+ return {
171
+ exitCode: EXIT_STALE,
172
+ redispatchOk: true,
173
+ message: lines.join("\n"),
174
+ };
175
+ }
176
+ export function run(argv) {
177
+ const args = parseVerifySubagentAliveArgs(argv);
178
+ if (args.help) {
179
+ process.stdout.write(SUBAGENT_ALIVE_HELP);
180
+ return EXIT_OK;
181
+ }
182
+ const verdict = evaluateSubagentAliveGate(args);
183
+ if (args.emitJson && verdict.json !== undefined) {
184
+ process.stdout.write(`${JSON.stringify(verdict.json, null, 2)}\n`);
185
+ }
186
+ else if (verdict.message.length > 0) {
187
+ if (verdict.exitCode === EXIT_OK) {
188
+ process.stdout.write(`${verdict.message}\n`);
189
+ }
190
+ else {
191
+ process.stderr.write(`${verdict.message}\n`);
192
+ }
193
+ }
194
+ return verdict.exitCode;
195
+ }
196
+ if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
197
+ process.exit(run(process.argv.slice(2)));
198
+ }
199
+ //# sourceMappingURL=verify-subagent-alive.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive",
3
- "version": "0.83.0",
3
+ "version": "0.85.0",
4
4
  "description": "Directive CLI — npm install path for the Deft Directive framework.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,6 +9,7 @@
9
9
  "directive": "./dist/bin.js",
10
10
  "deft": "./dist/bin.js",
11
11
  "deft-ts": "./dist/bin.js",
12
+ "deft-hook": "./dist/hook-bin.js",
12
13
  "deft-verify-encoding": "./dist/verify-encoding.js"
13
14
  },
14
15
  "exports": {
@@ -31,8 +32,8 @@
31
32
  "provenance": true
32
33
  },
33
34
  "dependencies": {
34
- "@deftai/directive-core": "^0.83.0",
35
- "@deftai/directive-content": "^0.83.0"
35
+ "@deftai/directive-core": "^0.85.0",
36
+ "@deftai/directive-content": "^0.85.0"
36
37
  },
37
38
  "scripts": {
38
39
  "build": "tsc -b"