@deftai/directive-runtime 0.129.1 → 0.129.3
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/.githooks/_directive-run.sh +9 -12
- package/.githooks/pre-push +1 -5
- package/dist/doctor-diagnose.js +6 -3
- package/dist/pre-pr-run.js +9 -2
- package/dist/setup-wiring.js +64 -41
- package/package.json +1 -1
- package/tasks/engine-invoke.cjs +37 -2
- package/tasks/engine-invoke.test.cjs +14 -0
- package/tasks/engine.yml +5 -0
- package/vendor/directive-content/.githooks/_directive-run.sh +9 -12
- package/vendor/directive-content/.githooks/pre-push +1 -5
- package/vendor/directive-content/tasks/engine-invoke.cjs +37 -2
- package/vendor/directive-content/tasks/engine-invoke.test.cjs +14 -0
- package/vendor/directive-content/tasks/engine.yml +5 -0
- package/vendor/directive-core/dist/.tsbuildinfo +1 -1
- package/vendor/directive-core/dist/class-checks/evaluate.d.ts.map +1 -1
- package/vendor/directive-core/dist/class-checks/evaluate.js +21 -4
- package/vendor/directive-core/dist/class-checks/evaluate.js.map +1 -1
- package/vendor/directive-core/dist/coverage-applicability/evaluate.d.ts.map +1 -1
- package/vendor/directive-core/dist/coverage-applicability/evaluate.js +134 -6
- package/vendor/directive-core/dist/coverage-applicability/evaluate.js.map +1 -1
- package/vendor/directive-core/dist/coverage-hotspots/evaluate.d.ts +2 -0
- package/vendor/directive-core/dist/coverage-hotspots/evaluate.d.ts.map +1 -1
- package/vendor/directive-core/dist/coverage-hotspots/evaluate.js +19 -6
- package/vendor/directive-core/dist/coverage-hotspots/evaluate.js.map +1 -1
- package/vendor/directive-core/dist/fs/contained-write.d.ts +12 -0
- package/vendor/directive-core/dist/fs/contained-write.d.ts.map +1 -1
- package/vendor/directive-core/dist/fs/contained-write.js +35 -1
- package/vendor/directive-core/dist/fs/contained-write.js.map +1 -1
- package/vendor/directive-core/dist/init-deposit/agent-hooks.d.ts +1 -0
- package/vendor/directive-core/dist/init-deposit/agent-hooks.d.ts.map +1 -1
- package/vendor/directive-core/dist/init-deposit/agent-hooks.js +75 -72
- package/vendor/directive-core/dist/init-deposit/agent-hooks.js.map +1 -1
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts +26 -0
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts.map +1 -0
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.js +158 -0
- package/vendor/directive-core/dist/init-deposit/host-hook-outer.js.map +1 -0
- package/vendor/directive-core/dist/init-deposit/hygiene.d.ts.map +1 -1
- package/vendor/directive-core/dist/init-deposit/hygiene.js +29 -1
- package/vendor/directive-core/dist/init-deposit/hygiene.js.map +1 -1
- package/vendor/directive-core/dist/install-health/wiring.d.ts.map +1 -1
- package/vendor/directive-core/dist/install-health/wiring.js +30 -1
- package/vendor/directive-core/dist/install-health/wiring.js.map +1 -1
- package/vendor/directive-core/dist/pr-closing-keywords/gh.d.ts.map +1 -1
- package/vendor/directive-core/dist/pr-closing-keywords/gh.js +3 -0
- package/vendor/directive-core/dist/pr-closing-keywords/gh.js.map +1 -1
- package/vendor/directive-core/dist/pr-merge-readiness/gh.d.ts.map +1 -1
- package/vendor/directive-core/dist/pr-merge-readiness/gh.js +3 -0
- package/vendor/directive-core/dist/pr-merge-readiness/gh.js.map +1 -1
- package/vendor/directive-core/dist/pr-protected-issues/gh.d.ts.map +1 -1
- package/vendor/directive-core/dist/pr-protected-issues/gh.js +3 -0
- package/vendor/directive-core/dist/pr-protected-issues/gh.js.map +1 -1
- package/vendor/directive-core/dist/pre-pr-controller/controller.d.ts +1 -1
- package/vendor/directive-core/dist/pre-pr-controller/controller.d.ts.map +1 -1
- package/vendor/directive-core/dist/pre-pr-controller/controller.js +43 -15
- package/vendor/directive-core/dist/pre-pr-controller/controller.js.map +1 -1
- package/vendor/directive-core/dist/pre-pr-controller/coverage-report.d.ts +22 -0
- package/vendor/directive-core/dist/pre-pr-controller/coverage-report.d.ts.map +1 -0
- package/vendor/directive-core/dist/pre-pr-controller/coverage-report.js +48 -0
- package/vendor/directive-core/dist/pre-pr-controller/coverage-report.js.map +1 -0
- package/vendor/directive-core/dist/pre-pr-controller/types.d.ts +7 -0
- package/vendor/directive-core/dist/pre-pr-controller/types.d.ts.map +1 -1
- package/vendor/directive-core/dist/pre-pr-controller/types.js.map +1 -1
- package/vendor/directive-core/dist/scm/call.d.ts.map +1 -1
- package/vendor/directive-core/dist/scm/call.js +5 -1
- package/vendor/directive-core/dist/scm/call.js.map +1 -1
- package/vendor/directive-core/dist/scm/gh-rest.d.ts.map +1 -1
- package/vendor/directive-core/dist/scm/gh-rest.js +3 -1
- package/vendor/directive-core/dist/scm/gh-rest.js.map +1 -1
- package/vendor/directive-core/dist/subprocess/plain-gh-env.d.ts +2 -0
- package/vendor/directive-core/dist/subprocess/plain-gh-env.d.ts.map +1 -0
- package/vendor/directive-core/dist/subprocess/plain-gh-env.js +25 -0
- package/vendor/directive-core/dist/subprocess/plain-gh-env.js.map +1 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
|
-
# Package-relative Directive git-hook helper (AC9.9).
|
|
2
|
+
# Package-relative Directive git-hook helper (AC9.9 / AC9.12 / #5994).
|
|
3
3
|
# Sourced by pre-commit/pre-push; defines run_directive.
|
|
4
|
+
# F1 order: disable → missing pin (project PM) → pin bin.js.
|
|
4
5
|
if [ -z "${REPO_ROOT:-}" ]; then
|
|
5
6
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
6
7
|
fi
|
|
@@ -8,23 +9,19 @@ if [ -z "$REPO_ROOT" ]; then
|
|
|
8
9
|
echo "directive hooks: unable to resolve repo root." >&2
|
|
9
10
|
exit 1
|
|
10
11
|
fi
|
|
11
|
-
RUNTIME_BIN="$REPO_ROOT/node_modules/@deftai/directive-runtime/dist/bin.js"
|
|
12
|
-
if [ ! -f "$RUNTIME_BIN" ]; then
|
|
13
|
-
echo "directive hooks: missing $RUNTIME_BIN" >&2
|
|
14
|
-
echo "Recovery: npm i -g @deftai/directive, then directive install --repair" >&2
|
|
15
|
-
exit 1
|
|
16
|
-
fi
|
|
17
12
|
run_directive() {
|
|
18
|
-
# #3039 / #5543
|
|
19
|
-
# not a symlink, and not tracked by git (tracked flag must not disable clones).
|
|
13
|
+
# #3039 / #5543 / #5994 F1: disable BEFORE requiring pin bin.js; quiet skip.
|
|
20
14
|
_kill="$REPO_ROOT/.deft-directive-disable"
|
|
21
15
|
if [ -f "$_kill" ] && [ ! -L "$_kill" ]; then
|
|
22
16
|
if ! git -C "$REPO_ROOT" ls-files --error-unmatch -- .deft-directive-disable >/dev/null 2>&1; then
|
|
23
|
-
echo "Directive is DISABLED for this project via root .deft-directive-disable (test/local kill-switch)." >&2
|
|
24
|
-
echo "Git hooks skipping Directive CLI spawn (#5543 / #3039). Deposit may remain." >&2
|
|
25
|
-
echo "Recovery: rm .deft-directive-disable && start a new agent session." >&2
|
|
26
17
|
return 0
|
|
27
18
|
fi
|
|
28
19
|
fi
|
|
20
|
+
RUNTIME_BIN="$REPO_ROOT/node_modules/@deftai/directive-runtime/dist/bin.js"
|
|
21
|
+
if [ ! -f "$RUNTIME_BIN" ]; then
|
|
22
|
+
echo "directive hooks: missing $RUNTIME_BIN" >&2
|
|
23
|
+
echo "Directive hooks: missing node_modules/@deftai/directive-runtime. Run npm install or pnpm install (or yarn) in this project." >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
29
26
|
node "$RUNTIME_BIN" "$@"
|
|
30
27
|
}
|
package/.githooks/pre-push
CHANGED
|
@@ -5,8 +5,4 @@ REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 1
|
|
|
5
5
|
. "$REPO_ROOT/.githooks/_directive-run.sh"
|
|
6
6
|
run_directive verify:branch --project-root "$REPO_ROOT" || exit $?
|
|
7
7
|
# Enrolled bound pre-PR arm: sole-stdin (do not redirect shared run_directive to /dev/null)
|
|
8
|
-
|
|
9
|
-
_pre_pr_help="$(run_directive pre-pr:run --help </dev/null 2>&1)" || exit $?
|
|
10
|
-
case "$_pre_pr_help" in
|
|
11
|
-
*--push-admit*) run_directive pre-pr:run --push-admit --project-root "$REPO_ROOT" || exit $? ;;
|
|
12
|
-
esac
|
|
8
|
+
run_directive pre-pr:run --push-admit --project-root "$REPO_ROOT" || exit $?
|
package/dist/doctor-diagnose.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
+
import { isHostHookOuterCommand } from "../vendor/directive-core/dist/init-deposit/host-hook-outer.js";
|
|
9
10
|
import { checkFullInSync, DEFT_DOCTOR_HOOK_DIAGNOSTIC, INSTALLATION_RECOVERY_GUIDANCE, RUNTIME_PACKAGE_PATH_PREFIX, } from "../vendor/directive-core/dist/install-health/index.js";
|
|
10
11
|
import { readProjectDataStatus } from "./data-status.js";
|
|
11
12
|
export { DEFT_DOCTOR_HOOK_DIAGNOSTIC };
|
|
@@ -48,7 +49,7 @@ function schemaSurface(dataStatus) {
|
|
|
48
49
|
return { ok: false, detail: "project data schema diagnosis failed" };
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
51
|
-
* Cheap read-only check that committed hook/skill wiring uses package-relative form.
|
|
52
|
+
* Cheap read-only check that committed hook/skill wiring uses host `.mjs` outer or package-relative form.
|
|
52
53
|
* Does not spawn hooks; structural only (AC12.3 hook command form / skill pointers).
|
|
53
54
|
*/
|
|
54
55
|
function inspectHookAndSkillForm(projectRoot) {
|
|
@@ -70,11 +71,13 @@ function inspectHookAndSkillForm(projectRoot) {
|
|
|
70
71
|
sawHook = true;
|
|
71
72
|
try {
|
|
72
73
|
const text = readFileSync(abs, "utf8");
|
|
74
|
+
// #5994 / AC9.1: v261027 host `.mjs` outer is the registered form; pin hook-bin is spawned inside.
|
|
75
|
+
const hasOuter = isHostHookOuterCommand(text);
|
|
73
76
|
const hasPkg = text.includes(prefix) && text.includes("hook-bin");
|
|
74
77
|
const hasLegacy = text.includes(".deft/core/") || /(^|[\s"`'])deft-hook([\s"`']|$)/.test(text);
|
|
75
|
-
if (hasLegacy || !hasPkg) {
|
|
78
|
+
if (hasLegacy || !(hasOuter || hasPkg)) {
|
|
76
79
|
hookOk = false;
|
|
77
|
-
hookDetail = `${rel} does not use package-relative hook-bin form`;
|
|
80
|
+
hookDetail = `${rel} does not use host .mjs outer or package-relative hook-bin form`;
|
|
78
81
|
break;
|
|
79
82
|
}
|
|
80
83
|
}
|
package/dist/pre-pr-run.js
CHANGED
|
@@ -422,13 +422,15 @@ export function run(argv) {
|
|
|
422
422
|
return 2;
|
|
423
423
|
}
|
|
424
424
|
const spec = phaseSpec(phase);
|
|
425
|
+
// Same root rule as push-admit: one report path for observe and satisfy.
|
|
426
|
+
const projectRoot = args.projectRoot?.trim() || process.cwd();
|
|
425
427
|
const d = observeCommandPhase(store, args.runId, {
|
|
426
428
|
phaseId: phase,
|
|
427
429
|
command: args.command.length > 0 ? args.command : (spec.command ?? ""),
|
|
428
430
|
exitCode: args.exitCode,
|
|
429
431
|
inputHash: args.inputHash ?? rec?.inputHash ?? "",
|
|
430
432
|
skipReason: args.skipReason,
|
|
431
|
-
});
|
|
433
|
+
}, { projectRoot });
|
|
432
434
|
emit(args.json, d, d.message, !d.ok);
|
|
433
435
|
return d.ok ? 0 : 1;
|
|
434
436
|
}
|
|
@@ -508,7 +510,12 @@ export function run(argv) {
|
|
|
508
510
|
process.stderr.write("pre_pr_run: --complete requires --run-id\n");
|
|
509
511
|
return 2;
|
|
510
512
|
}
|
|
511
|
-
|
|
513
|
+
// #5804 / #5994: projectRoot is required so completeRun can stamp
|
|
514
|
+
// pushBinding.reviewedDeletedPaths from base..head.
|
|
515
|
+
const projectRoot = args.projectRoot?.trim() || process.cwd();
|
|
516
|
+
const d = completeRun(store, controllerPublisher(), args.runId, undefined, {
|
|
517
|
+
projectRoot,
|
|
518
|
+
});
|
|
512
519
|
emit(args.json, d, d.message, !d.ok);
|
|
513
520
|
return d.ok ? 0 : 1;
|
|
514
521
|
}
|
package/dist/setup-wiring.js
CHANGED
|
@@ -8,7 +8,7 @@ import { dirname, join } from "node:path";
|
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { containedChmod, containedRemove, containedWrite, } from "../vendor/directive-core/dist/fs/contained-write.js";
|
|
10
10
|
import { DIRECT_WRITE_HOOK_MATCHER, KILL_HOOK_MATCHER, MCP_HOOK_MATCHER, SHELL_HOOK_MATCHER, SPAWN_HOOK_MATCHER, } from "../vendor/directive-core/dist/hooks/tools.js";
|
|
11
|
-
import {
|
|
11
|
+
import { GROK_PRETOOLUSE_WRAPPER_REL_PATH, HOST_HOOK_MISSING_PIN_PROJECT_PM_GUIDANCE, hostHookOuterCommand, hostHookOuterRelPath, hostHookOuterSha8, hostHookOuterSource, isGrokWrapperCommand, isHostHookOuterCommand, } from "../vendor/directive-core/dist/init-deposit/agent-hooks.js";
|
|
12
12
|
import { INSTALLATION_RECOVERY_GUIDANCE, RUNTIME_PACKAGE_PATH_PREFIX, } from "../vendor/directive-core/dist/install-health/constants.js";
|
|
13
13
|
import { MANAGED_SECTION_CLOSE, MANAGED_SECTION_OPEN_PREFIX, } from "../vendor/directive-core/dist/install-health/index.js";
|
|
14
14
|
import { applyAgentsRefresh } from "../vendor/directive-core/dist/platform/agents-md.js";
|
|
@@ -376,25 +376,45 @@ export function ensureOpenClawIntegrations(projectRoot) {
|
|
|
376
376
|
}
|
|
377
377
|
}
|
|
378
378
|
function hookCommand(host, event) {
|
|
379
|
-
|
|
379
|
+
const sha8 = hostHookOuterSha8();
|
|
380
|
+
return `${hostHookOuterCommand(host, sha8)} --host ${host} --event ${event}`;
|
|
380
381
|
}
|
|
381
382
|
/** Rewrite bare `deft-hook` / legacy `deft hook:dispatch` to package-relative (AC9.2). */
|
|
382
383
|
export function rewriteBareDeftHookCommand(command) {
|
|
383
384
|
const trimmed = command.trim();
|
|
384
|
-
if (trimmed
|
|
385
|
+
if (isHostHookOuterCommand(trimmed))
|
|
385
386
|
return command;
|
|
387
|
+
const hostMatch = trimmed.match(/--host\s+(\w+)/);
|
|
388
|
+
const eventMatch = trimmed.match(/--event\s+([\w.]+)/);
|
|
389
|
+
const host = hostMatch?.[1];
|
|
390
|
+
const event = eventMatch?.[1];
|
|
391
|
+
const sha8 = hostHookOuterSha8();
|
|
392
|
+
const toOuter = (h, e) => `${hostHookOuterCommand(h, sha8)} --host ${h} --event ${e}`;
|
|
393
|
+
// Legacy Grok .sh wrapper → outer
|
|
394
|
+
if (isGrokWrapperCommand(trimmed) && host && event) {
|
|
395
|
+
return toOuter(host, event);
|
|
396
|
+
}
|
|
397
|
+
if (isGrokWrapperCommand(trimmed)) {
|
|
398
|
+
return toOuter("grok", "tool.before");
|
|
399
|
+
}
|
|
400
|
+
// Direct hook-bin with host/event → outer
|
|
401
|
+
if (trimmed.includes(HOOK_BIN_COMMAND) && host && event) {
|
|
402
|
+
return toOuter(host, event);
|
|
403
|
+
}
|
|
386
404
|
const bare = /^(?:deft-hook|deft\s+hook:dispatch)(\s+.*)?$/;
|
|
387
405
|
const m = trimmed.match(bare);
|
|
388
406
|
if (m) {
|
|
389
407
|
const rest = (m[1] ?? "").trim();
|
|
408
|
+
if (host && event)
|
|
409
|
+
return toOuter(host, event);
|
|
410
|
+
// bare without host/event: leave as package-relative interim only if no host
|
|
390
411
|
return rest.length > 0 ? `${HOOK_BIN_COMMAND} ${rest}` : HOOK_BIN_COMMAND;
|
|
391
412
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
return trimmed.replace(/\bdeft-hook\b/g, HOOK_BIN_COMMAND);
|
|
413
|
+
if (/\bdeft-hook\b/.test(trimmed) && !isHostHookOuterCommand(trimmed) && host && event) {
|
|
414
|
+
return toOuter(host, event);
|
|
395
415
|
}
|
|
396
|
-
if (/\bdeft\s+hook:dispatch\b/.test(trimmed) &&
|
|
397
|
-
return
|
|
416
|
+
if (/\bdeft\s+hook:dispatch\b/.test(trimmed) && host && event) {
|
|
417
|
+
return toOuter(host, event);
|
|
398
418
|
}
|
|
399
419
|
return command;
|
|
400
420
|
}
|
|
@@ -428,7 +448,8 @@ function rewriteCommandsInValue(value) {
|
|
|
428
448
|
return { value, changed: false };
|
|
429
449
|
}
|
|
430
450
|
function isManagedHookCommand(command) {
|
|
431
|
-
return (command
|
|
451
|
+
return (isHostHookOuterCommand(command) ||
|
|
452
|
+
command.includes(HOOK_BIN_COMMAND) ||
|
|
432
453
|
isGrokWrapperCommand(command) ||
|
|
433
454
|
/(^|[\s"`'])deft-hook([\s"`']|$)/.test(command) ||
|
|
434
455
|
command.includes("deft hook:dispatch"));
|
|
@@ -469,9 +490,7 @@ function cursorManagedEntry(value) {
|
|
|
469
490
|
return typeof entry?.command === "string" && isManagedHookCommand(entry.command);
|
|
470
491
|
}
|
|
471
492
|
function nestedToolCommand(host, event) {
|
|
472
|
-
//
|
|
473
|
-
if (host === "grok" && event === "tool.before")
|
|
474
|
-
return GROK_PRETOOLUSE_WRAPPER_COMMAND;
|
|
493
|
+
// #5994 / AC9.1: every host/event uses the content-hashed `.mjs` outer.
|
|
475
494
|
return hookCommand(host, event);
|
|
476
495
|
}
|
|
477
496
|
function nestedGroup(host, event, matcher) {
|
|
@@ -690,30 +709,34 @@ export function ensureHostHooks(projectRoot, hostHooksPolicy = loadHostHooksPoli
|
|
|
690
709
|
else
|
|
691
710
|
modified.push(spec.rel);
|
|
692
711
|
}
|
|
693
|
-
// #
|
|
694
|
-
|
|
695
|
-
const
|
|
696
|
-
const
|
|
697
|
-
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
712
|
+
// #5994: deposit content-hashed `.mjs` outers; strip legacy Grok `.sh`.
|
|
713
|
+
const outerSource = hostHookOuterSource();
|
|
714
|
+
const outerSha8 = hostHookOuterSha8(outerSource);
|
|
715
|
+
for (const host of ["claude", "grok", "cursor", "codex"]) {
|
|
716
|
+
const rel = hostHookOuterRelPath(host, outerSha8);
|
|
717
|
+
const enabled = isHostHookDepositEnabled(host, hostHooksPolicy);
|
|
718
|
+
if (enabled) {
|
|
719
|
+
const prior = readText(join(projectRoot, rel));
|
|
720
|
+
if (prior !== outerSource) {
|
|
721
|
+
writeContained(projectRoot, rel, outerSource);
|
|
722
|
+
if (prior === null)
|
|
723
|
+
created.push(rel);
|
|
724
|
+
else
|
|
725
|
+
modified.push(rel);
|
|
726
|
+
}
|
|
706
727
|
}
|
|
707
|
-
if (existsSync(join(projectRoot,
|
|
728
|
+
else if (existsSync(join(projectRoot, rel))) {
|
|
708
729
|
try {
|
|
709
|
-
|
|
730
|
+
containedRemove({ root: projectRoot, target: rel });
|
|
731
|
+
modified.push(rel);
|
|
710
732
|
}
|
|
711
733
|
catch {
|
|
712
|
-
/* best-effort
|
|
734
|
+
/* best-effort strip */
|
|
713
735
|
}
|
|
714
736
|
}
|
|
715
737
|
}
|
|
716
|
-
|
|
738
|
+
const wrapperRel = GROK_PRETOOLUSE_WRAPPER_REL_PATH;
|
|
739
|
+
if (existsSync(join(projectRoot, wrapperRel))) {
|
|
717
740
|
try {
|
|
718
741
|
containedRemove({ root: projectRoot, target: wrapperRel });
|
|
719
742
|
modified.push(wrapperRel);
|
|
@@ -724,9 +747,13 @@ export function ensureHostHooks(projectRoot, hostHooksPolicy = loadHostHooksPoli
|
|
|
724
747
|
}
|
|
725
748
|
return { created, modified };
|
|
726
749
|
}
|
|
750
|
+
// Taskfile F1 disable-first + project-PM pin miss live in tasks/engine.yml +
|
|
751
|
+
// tasks/engine-invoke.cjs (#5994) — disable-active runs BEFORE pin-bin / is-buildable-source;
|
|
752
|
+
// pin-bin also quiet-exits when disable is active. This GITHOOK_HELPER is the .githooks twin.
|
|
727
753
|
const GITHOOK_HELPER = `#!/usr/bin/env sh
|
|
728
|
-
# Package-relative Directive git-hook helper (AC9.9).
|
|
754
|
+
# Package-relative Directive git-hook helper (AC9.9 / AC9.12 / #5994).
|
|
729
755
|
# Sourced by pre-commit/pre-push; defines run_directive.
|
|
756
|
+
# F1 order: disable → missing pin (project PM) → pin bin.js.
|
|
730
757
|
if [ -z "\${REPO_ROOT:-}" ]; then
|
|
731
758
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
732
759
|
fi
|
|
@@ -734,24 +761,20 @@ if [ -z "$REPO_ROOT" ]; then
|
|
|
734
761
|
echo "directive hooks: unable to resolve repo root." >&2
|
|
735
762
|
exit 1
|
|
736
763
|
fi
|
|
737
|
-
RUNTIME_BIN="$REPO_ROOT/${RUNTIME_BIN_REL}"
|
|
738
|
-
if [ ! -f "$RUNTIME_BIN" ]; then
|
|
739
|
-
echo "directive hooks: missing $RUNTIME_BIN" >&2
|
|
740
|
-
echo "Recovery: ${INSTALLATION_RECOVERY_GUIDANCE}" >&2
|
|
741
|
-
exit 1
|
|
742
|
-
fi
|
|
743
764
|
run_directive() {
|
|
744
|
-
# #3039 / #5543
|
|
745
|
-
# not a symlink, and not tracked by git (tracked flag must not disable clones).
|
|
765
|
+
# #3039 / #5543 / #5994 F1: disable BEFORE requiring pin bin.js; quiet skip.
|
|
746
766
|
_kill="$REPO_ROOT/.deft-directive-disable"
|
|
747
767
|
if [ -f "$_kill" ] && [ ! -L "$_kill" ]; then
|
|
748
768
|
if ! git -C "$REPO_ROOT" ls-files --error-unmatch -- .deft-directive-disable >/dev/null 2>&1; then
|
|
749
|
-
echo "Directive is DISABLED for this project via root .deft-directive-disable (test/local kill-switch)." >&2
|
|
750
|
-
echo "Git hooks skipping Directive CLI spawn (#5543 / #3039). Deposit may remain." >&2
|
|
751
|
-
echo "Recovery: rm .deft-directive-disable && start a new agent session." >&2
|
|
752
769
|
return 0
|
|
753
770
|
fi
|
|
754
771
|
fi
|
|
772
|
+
RUNTIME_BIN="$REPO_ROOT/${RUNTIME_BIN_REL}"
|
|
773
|
+
if [ ! -f "$RUNTIME_BIN" ]; then
|
|
774
|
+
echo "directive hooks: missing $RUNTIME_BIN" >&2
|
|
775
|
+
echo "${HOST_HOOK_MISSING_PIN_PROJECT_PM_GUIDANCE}" >&2
|
|
776
|
+
exit 1
|
|
777
|
+
fi
|
|
755
778
|
node "$RUNTIME_BIN" "$@"
|
|
756
779
|
}
|
|
757
780
|
`;
|
package/package.json
CHANGED
package/tasks/engine-invoke.cjs
CHANGED
|
@@ -23,11 +23,15 @@ const CONTENT_PACKAGE_NAME = "@deftai/directive-content";
|
|
|
23
23
|
/** Single remediation when a deposit has no global CLI (#3324 / #3265). */
|
|
24
24
|
const DEPOSIT_REMEDIATION = "npm i -g @deftai/directive";
|
|
25
25
|
const SOURCE_BUILD_REMEDIATION = "task build";
|
|
26
|
-
/** Missing checkout pin remediation (#
|
|
26
|
+
/** Missing checkout pin remediation (#5994 / AC9.12): project PM first.
|
|
27
|
+
* pin-bin path never recommends npm i -g (that is DEPOSIT_REMEDIATION only).
|
|
28
|
+
*/
|
|
27
29
|
const PIN_INSTALL_REMEDIATION =
|
|
28
|
-
"npm
|
|
30
|
+
"Run npm install or pnpm install (or yarn) in this project (missing node_modules/@deftai/directive-runtime)";
|
|
31
|
+
/** Tip dogfood secondary when project install is not enough (#5805). */
|
|
29
32
|
const PIN_MATERIALIZE_REMEDIATION = "task materialize:runtime";
|
|
30
33
|
const PIN_BIN_REL = path.join("node_modules", "@deftai", "directive-runtime", "dist", "bin.js");
|
|
34
|
+
const DISABLE_FLAG = ".deft-directive-disable";
|
|
31
35
|
|
|
32
36
|
/**
|
|
33
37
|
* cmd.exe command separators / metacharacters. Free-text DEFT_ENGINE_CMD_JSON
|
|
@@ -178,6 +182,29 @@ function resolveFrameworkPinBin(projectRoot, opts = {}) {
|
|
|
178
182
|
* @param {string} projectRoot
|
|
179
183
|
* @param {{ fs?: typeof fs, path?: typeof path }} [opts]
|
|
180
184
|
*/
|
|
185
|
+
/**
|
|
186
|
+
* AC9.12 / #5994: untracked root .deft-directive-disable → quiet skip before pin require.
|
|
187
|
+
* @param {string} projectRoot
|
|
188
|
+
* @param {{ fs?: typeof fs, path?: typeof path, spawnSync?: typeof spawnSync }} [opts]
|
|
189
|
+
*/
|
|
190
|
+
function isDirectiveDisableActive(projectRoot, opts = {}) {
|
|
191
|
+
const io = opts.fs || fs;
|
|
192
|
+
const pathMod = opts.path || path;
|
|
193
|
+
const spawn = opts.spawnSync || spawnSync;
|
|
194
|
+
if (!projectRoot) return false;
|
|
195
|
+
const killPath = pathMod.join(projectRoot, DISABLE_FLAG);
|
|
196
|
+
try {
|
|
197
|
+
if (!io.existsSync(killPath)) return false;
|
|
198
|
+
if (io.lstatSync(killPath).isSymbolicLink()) return false;
|
|
199
|
+
} catch {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const r = spawn("git", ["-C", projectRoot, "ls-files", "--error-unmatch", "--", DISABLE_FLAG], {
|
|
203
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
204
|
+
});
|
|
205
|
+
return r.status !== 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
181
208
|
function hasFrameworkPinBin(projectRoot, opts = {}) {
|
|
182
209
|
const io = opts.fs || fs;
|
|
183
210
|
const pin = resolveFrameworkPinBin(projectRoot, opts);
|
|
@@ -399,8 +426,14 @@ if (require.main === module) {
|
|
|
399
426
|
if (mode === "is-buildable-source") {
|
|
400
427
|
process.exit(isBuildableSource(process.argv[3] || "") ? 0 : 1);
|
|
401
428
|
}
|
|
429
|
+
if (mode === "disable-active") {
|
|
430
|
+
process.exit(isDirectiveDisableActive(process.argv[3] || "") ? 0 : 1);
|
|
431
|
+
}
|
|
402
432
|
if (mode === "pin-bin") {
|
|
403
433
|
const root = process.argv[3] || "";
|
|
434
|
+
if (isDirectiveDisableActive(root)) {
|
|
435
|
+
process.exit(0);
|
|
436
|
+
}
|
|
404
437
|
const pin = resolveFrameworkPinBin(root);
|
|
405
438
|
if (hasFrameworkPinBin(root)) {
|
|
406
439
|
process.stdout.write(pin);
|
|
@@ -433,4 +466,6 @@ module.exports = {
|
|
|
433
466
|
SOURCE_BUILD_REMEDIATION,
|
|
434
467
|
PIN_INSTALL_REMEDIATION,
|
|
435
468
|
PIN_MATERIALIZE_REMEDIATION,
|
|
469
|
+
isDirectiveDisableActive,
|
|
470
|
+
DISABLE_FLAG,
|
|
436
471
|
};
|
|
@@ -615,5 +615,19 @@ describe("framework pin exclusive invoke (#5805)", () => {
|
|
|
615
615
|
const r = spawnSync(process.execPath, [script, "pin-bin", root], { encoding: "utf8" });
|
|
616
616
|
assert.equal(r.status, 2);
|
|
617
617
|
assert.match(r.stderr, /missing checkout pin/);
|
|
618
|
+
assert.match(r.stderr, /npm install or pnpm install/);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it("disable-active / pin-bin quiet-skip when untracked disable flag present (#5994)", () => {
|
|
622
|
+
const root = pinTempRoot();
|
|
623
|
+
const script = join(__dirname, "engine-invoke.cjs");
|
|
624
|
+
writeFileSync(join(root, ".deft-directive-disable"), "1\n");
|
|
625
|
+
// Ensure git repo so ls-files --error-unmatch can run (untracked → active).
|
|
626
|
+
spawnSync("git", ["init"], { cwd: root, stdio: "ignore" });
|
|
627
|
+
const d = spawnSync(process.execPath, [script, "disable-active", root], { encoding: "utf8" });
|
|
628
|
+
assert.equal(d.status, 0);
|
|
629
|
+
const r = spawnSync(process.execPath, [script, "pin-bin", root], { encoding: "utf8" });
|
|
630
|
+
assert.equal(r.status, 0);
|
|
631
|
+
assert.equal((r.stdout || "").trim(), "");
|
|
618
632
|
});
|
|
619
633
|
});
|
package/tasks/engine.yml
CHANGED
|
@@ -73,6 +73,11 @@ tasks:
|
|
|
73
73
|
cmds:
|
|
74
74
|
- |
|
|
75
75
|
set -eu
|
|
76
|
+
# #5994 / AC9.12 / F1: disable BEFORE requiring pin bin.js; quiet skip.
|
|
77
|
+
# Untracked root .deft-directive-disable → exit 0 (no pin require, no global install).
|
|
78
|
+
if node "{{.TASKFILE_DIR}}/engine-invoke.cjs" disable-active "{{.DEFT_ROOT}}"; then
|
|
79
|
+
exit 0
|
|
80
|
+
fi
|
|
76
81
|
# #3324: deposit marker forces is_buildable_source=0 (consumer / OVPR path).
|
|
77
82
|
is_buildable_source=0
|
|
78
83
|
if node "{{.TASKFILE_DIR}}/engine-invoke.cjs" is-buildable-source "{{.DEFT_ROOT}}"; then
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
|
-
# Package-relative Directive git-hook helper (AC9.9).
|
|
2
|
+
# Package-relative Directive git-hook helper (AC9.9 / AC9.12 / #5994).
|
|
3
3
|
# Sourced by pre-commit/pre-push; defines run_directive.
|
|
4
|
+
# F1 order: disable → missing pin (project PM) → pin bin.js.
|
|
4
5
|
if [ -z "${REPO_ROOT:-}" ]; then
|
|
5
6
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
6
7
|
fi
|
|
@@ -8,23 +9,19 @@ if [ -z "$REPO_ROOT" ]; then
|
|
|
8
9
|
echo "directive hooks: unable to resolve repo root." >&2
|
|
9
10
|
exit 1
|
|
10
11
|
fi
|
|
11
|
-
RUNTIME_BIN="$REPO_ROOT/node_modules/@deftai/directive-runtime/dist/bin.js"
|
|
12
|
-
if [ ! -f "$RUNTIME_BIN" ]; then
|
|
13
|
-
echo "directive hooks: missing $RUNTIME_BIN" >&2
|
|
14
|
-
echo "Recovery: npm i -g @deftai/directive, then directive install --repair" >&2
|
|
15
|
-
exit 1
|
|
16
|
-
fi
|
|
17
12
|
run_directive() {
|
|
18
|
-
# #3039 / #5543
|
|
19
|
-
# not a symlink, and not tracked by git (tracked flag must not disable clones).
|
|
13
|
+
# #3039 / #5543 / #5994 F1: disable BEFORE requiring pin bin.js; quiet skip.
|
|
20
14
|
_kill="$REPO_ROOT/.deft-directive-disable"
|
|
21
15
|
if [ -f "$_kill" ] && [ ! -L "$_kill" ]; then
|
|
22
16
|
if ! git -C "$REPO_ROOT" ls-files --error-unmatch -- .deft-directive-disable >/dev/null 2>&1; then
|
|
23
|
-
echo "Directive is DISABLED for this project via root .deft-directive-disable (test/local kill-switch)." >&2
|
|
24
|
-
echo "Git hooks skipping Directive CLI spawn (#5543 / #3039). Deposit may remain." >&2
|
|
25
|
-
echo "Recovery: rm .deft-directive-disable && start a new agent session." >&2
|
|
26
17
|
return 0
|
|
27
18
|
fi
|
|
28
19
|
fi
|
|
20
|
+
RUNTIME_BIN="$REPO_ROOT/node_modules/@deftai/directive-runtime/dist/bin.js"
|
|
21
|
+
if [ ! -f "$RUNTIME_BIN" ]; then
|
|
22
|
+
echo "directive hooks: missing $RUNTIME_BIN" >&2
|
|
23
|
+
echo "Directive hooks: missing node_modules/@deftai/directive-runtime. Run npm install or pnpm install (or yarn) in this project." >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
29
26
|
node "$RUNTIME_BIN" "$@"
|
|
30
27
|
}
|
|
@@ -5,8 +5,4 @@ REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 1
|
|
|
5
5
|
. "$REPO_ROOT/.githooks/_directive-run.sh"
|
|
6
6
|
run_directive verify:branch --project-root "$REPO_ROOT" || exit $?
|
|
7
7
|
# Enrolled bound pre-PR arm: sole-stdin (do not redirect shared run_directive to /dev/null)
|
|
8
|
-
|
|
9
|
-
_pre_pr_help="$(run_directive pre-pr:run --help </dev/null 2>&1)" || exit $?
|
|
10
|
-
case "$_pre_pr_help" in
|
|
11
|
-
*--push-admit*) run_directive pre-pr:run --push-admit --project-root "$REPO_ROOT" || exit $? ;;
|
|
12
|
-
esac
|
|
8
|
+
run_directive pre-pr:run --push-admit --project-root "$REPO_ROOT" || exit $?
|
|
@@ -23,11 +23,15 @@ const CONTENT_PACKAGE_NAME = "@deftai/directive-content";
|
|
|
23
23
|
/** Single remediation when a deposit has no global CLI (#3324 / #3265). */
|
|
24
24
|
const DEPOSIT_REMEDIATION = "npm i -g @deftai/directive";
|
|
25
25
|
const SOURCE_BUILD_REMEDIATION = "task build";
|
|
26
|
-
/** Missing checkout pin remediation (#
|
|
26
|
+
/** Missing checkout pin remediation (#5994 / AC9.12): project PM first.
|
|
27
|
+
* pin-bin path never recommends npm i -g (that is DEPOSIT_REMEDIATION only).
|
|
28
|
+
*/
|
|
27
29
|
const PIN_INSTALL_REMEDIATION =
|
|
28
|
-
"npm
|
|
30
|
+
"Run npm install or pnpm install (or yarn) in this project (missing node_modules/@deftai/directive-runtime)";
|
|
31
|
+
/** Tip dogfood secondary when project install is not enough (#5805). */
|
|
29
32
|
const PIN_MATERIALIZE_REMEDIATION = "task materialize:runtime";
|
|
30
33
|
const PIN_BIN_REL = path.join("node_modules", "@deftai", "directive-runtime", "dist", "bin.js");
|
|
34
|
+
const DISABLE_FLAG = ".deft-directive-disable";
|
|
31
35
|
|
|
32
36
|
/**
|
|
33
37
|
* cmd.exe command separators / metacharacters. Free-text DEFT_ENGINE_CMD_JSON
|
|
@@ -178,6 +182,29 @@ function resolveFrameworkPinBin(projectRoot, opts = {}) {
|
|
|
178
182
|
* @param {string} projectRoot
|
|
179
183
|
* @param {{ fs?: typeof fs, path?: typeof path }} [opts]
|
|
180
184
|
*/
|
|
185
|
+
/**
|
|
186
|
+
* AC9.12 / #5994: untracked root .deft-directive-disable → quiet skip before pin require.
|
|
187
|
+
* @param {string} projectRoot
|
|
188
|
+
* @param {{ fs?: typeof fs, path?: typeof path, spawnSync?: typeof spawnSync }} [opts]
|
|
189
|
+
*/
|
|
190
|
+
function isDirectiveDisableActive(projectRoot, opts = {}) {
|
|
191
|
+
const io = opts.fs || fs;
|
|
192
|
+
const pathMod = opts.path || path;
|
|
193
|
+
const spawn = opts.spawnSync || spawnSync;
|
|
194
|
+
if (!projectRoot) return false;
|
|
195
|
+
const killPath = pathMod.join(projectRoot, DISABLE_FLAG);
|
|
196
|
+
try {
|
|
197
|
+
if (!io.existsSync(killPath)) return false;
|
|
198
|
+
if (io.lstatSync(killPath).isSymbolicLink()) return false;
|
|
199
|
+
} catch {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const r = spawn("git", ["-C", projectRoot, "ls-files", "--error-unmatch", "--", DISABLE_FLAG], {
|
|
203
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
204
|
+
});
|
|
205
|
+
return r.status !== 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
181
208
|
function hasFrameworkPinBin(projectRoot, opts = {}) {
|
|
182
209
|
const io = opts.fs || fs;
|
|
183
210
|
const pin = resolveFrameworkPinBin(projectRoot, opts);
|
|
@@ -399,8 +426,14 @@ if (require.main === module) {
|
|
|
399
426
|
if (mode === "is-buildable-source") {
|
|
400
427
|
process.exit(isBuildableSource(process.argv[3] || "") ? 0 : 1);
|
|
401
428
|
}
|
|
429
|
+
if (mode === "disable-active") {
|
|
430
|
+
process.exit(isDirectiveDisableActive(process.argv[3] || "") ? 0 : 1);
|
|
431
|
+
}
|
|
402
432
|
if (mode === "pin-bin") {
|
|
403
433
|
const root = process.argv[3] || "";
|
|
434
|
+
if (isDirectiveDisableActive(root)) {
|
|
435
|
+
process.exit(0);
|
|
436
|
+
}
|
|
404
437
|
const pin = resolveFrameworkPinBin(root);
|
|
405
438
|
if (hasFrameworkPinBin(root)) {
|
|
406
439
|
process.stdout.write(pin);
|
|
@@ -433,4 +466,6 @@ module.exports = {
|
|
|
433
466
|
SOURCE_BUILD_REMEDIATION,
|
|
434
467
|
PIN_INSTALL_REMEDIATION,
|
|
435
468
|
PIN_MATERIALIZE_REMEDIATION,
|
|
469
|
+
isDirectiveDisableActive,
|
|
470
|
+
DISABLE_FLAG,
|
|
436
471
|
};
|
|
@@ -615,5 +615,19 @@ describe("framework pin exclusive invoke (#5805)", () => {
|
|
|
615
615
|
const r = spawnSync(process.execPath, [script, "pin-bin", root], { encoding: "utf8" });
|
|
616
616
|
assert.equal(r.status, 2);
|
|
617
617
|
assert.match(r.stderr, /missing checkout pin/);
|
|
618
|
+
assert.match(r.stderr, /npm install or pnpm install/);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
it("disable-active / pin-bin quiet-skip when untracked disable flag present (#5994)", () => {
|
|
622
|
+
const root = pinTempRoot();
|
|
623
|
+
const script = join(__dirname, "engine-invoke.cjs");
|
|
624
|
+
writeFileSync(join(root, ".deft-directive-disable"), "1\n");
|
|
625
|
+
// Ensure git repo so ls-files --error-unmatch can run (untracked → active).
|
|
626
|
+
spawnSync("git", ["init"], { cwd: root, stdio: "ignore" });
|
|
627
|
+
const d = spawnSync(process.execPath, [script, "disable-active", root], { encoding: "utf8" });
|
|
628
|
+
assert.equal(d.status, 0);
|
|
629
|
+
const r = spawnSync(process.execPath, [script, "pin-bin", root], { encoding: "utf8" });
|
|
630
|
+
assert.equal(r.status, 0);
|
|
631
|
+
assert.equal((r.stdout || "").trim(), "");
|
|
618
632
|
});
|
|
619
633
|
});
|
|
@@ -73,6 +73,11 @@ tasks:
|
|
|
73
73
|
cmds:
|
|
74
74
|
- |
|
|
75
75
|
set -eu
|
|
76
|
+
# #5994 / AC9.12 / F1: disable BEFORE requiring pin bin.js; quiet skip.
|
|
77
|
+
# Untracked root .deft-directive-disable → exit 0 (no pin require, no global install).
|
|
78
|
+
if node "{{.TASKFILE_DIR}}/engine-invoke.cjs" disable-active "{{.DEFT_ROOT}}"; then
|
|
79
|
+
exit 0
|
|
80
|
+
fi
|
|
76
81
|
# #3324: deposit marker forces is_buildable_source=0 (consumer / OVPR path).
|
|
77
82
|
is_buildable_source=0
|
|
78
83
|
if node "{{.TASKFILE_DIR}}/engine-invoke.cjs" is-buildable-source "{{.DEFT_ROOT}}"; then
|