@deftai/directive-runtime 0.129.0 → 0.129.2

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.
Files changed (79) hide show
  1. package/.githooks/_directive-run.sh +9 -12
  2. package/.githooks/pre-push +1 -5
  3. package/UPGRADING.md +2 -2
  4. package/dist/doctor-diagnose.d.ts +8 -3
  5. package/dist/doctor-diagnose.js +29 -8
  6. package/dist/hook-dispatch.js +2 -1
  7. package/dist/pre-pr-run.js +9 -2
  8. package/dist/self-complete.d.ts +4 -0
  9. package/dist/self-complete.js +18 -0
  10. package/dist/setup-wiring.d.ts +5 -0
  11. package/dist/setup-wiring.js +123 -41
  12. package/dist/setup.js +73 -1
  13. package/package.json +1 -1
  14. package/packs/skills/skills-pack-0.1.json +2 -2
  15. package/skills/deft-directive-refinement/SKILL.md +2 -2
  16. package/skills/deft-directive-setup/SKILL.md +2 -2
  17. package/skills/deft-directive-swarm/references/core-phase-0.md +1 -1
  18. package/tasks/docs.yml +1 -1
  19. package/tasks/engine-invoke.cjs +37 -2
  20. package/tasks/engine-invoke.test.cjs +14 -0
  21. package/tasks/engine.yml +5 -0
  22. package/vendor/directive-content/.githooks/_directive-run.sh +9 -12
  23. package/vendor/directive-content/.githooks/pre-push +1 -5
  24. package/vendor/directive-content/UPGRADING.md +2 -2
  25. package/vendor/directive-content/packs/skills/skills-pack-0.1.json +2 -2
  26. package/vendor/directive-content/skills/deft-directive-refinement/SKILL.md +2 -2
  27. package/vendor/directive-content/skills/deft-directive-setup/SKILL.md +2 -2
  28. package/vendor/directive-content/skills/deft-directive-swarm/references/core-phase-0.md +1 -1
  29. package/vendor/directive-content/tasks/docs.yml +1 -1
  30. package/vendor/directive-content/tasks/engine-invoke.cjs +37 -2
  31. package/vendor/directive-content/tasks/engine-invoke.test.cjs +14 -0
  32. package/vendor/directive-content/tasks/engine.yml +5 -0
  33. package/vendor/directive-core/dist/.tsbuildinfo +1 -1
  34. package/vendor/directive-core/dist/class-checks/evaluate.d.ts.map +1 -1
  35. package/vendor/directive-core/dist/class-checks/evaluate.js +25 -0
  36. package/vendor/directive-core/dist/class-checks/evaluate.js.map +1 -1
  37. package/vendor/directive-core/dist/coverage-applicability/evaluate.d.ts.map +1 -1
  38. package/vendor/directive-core/dist/coverage-applicability/evaluate.js +135 -6
  39. package/vendor/directive-core/dist/coverage-applicability/evaluate.js.map +1 -1
  40. package/vendor/directive-core/dist/coverage-hotspots/evaluate.d.ts +2 -0
  41. package/vendor/directive-core/dist/coverage-hotspots/evaluate.d.ts.map +1 -1
  42. package/vendor/directive-core/dist/coverage-hotspots/evaluate.js +19 -6
  43. package/vendor/directive-core/dist/coverage-hotspots/evaluate.js.map +1 -1
  44. package/vendor/directive-core/dist/fs/contained-write.d.ts +12 -0
  45. package/vendor/directive-core/dist/fs/contained-write.d.ts.map +1 -1
  46. package/vendor/directive-core/dist/fs/contained-write.js +35 -1
  47. package/vendor/directive-core/dist/fs/contained-write.js.map +1 -1
  48. package/vendor/directive-core/dist/init-deposit/agent-hooks.d.ts +1 -0
  49. package/vendor/directive-core/dist/init-deposit/agent-hooks.d.ts.map +1 -1
  50. package/vendor/directive-core/dist/init-deposit/agent-hooks.js +75 -72
  51. package/vendor/directive-core/dist/init-deposit/agent-hooks.js.map +1 -1
  52. package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts +26 -0
  53. package/vendor/directive-core/dist/init-deposit/host-hook-outer.d.ts.map +1 -0
  54. package/vendor/directive-core/dist/init-deposit/host-hook-outer.js +158 -0
  55. package/vendor/directive-core/dist/init-deposit/host-hook-outer.js.map +1 -0
  56. package/vendor/directive-core/dist/init-deposit/hygiene.d.ts.map +1 -1
  57. package/vendor/directive-core/dist/init-deposit/hygiene.js +29 -1
  58. package/vendor/directive-core/dist/init-deposit/hygiene.js.map +1 -1
  59. package/vendor/directive-core/dist/install-health/wiring.d.ts.map +1 -1
  60. package/vendor/directive-core/dist/install-health/wiring.js +141 -1
  61. package/vendor/directive-core/dist/install-health/wiring.js.map +1 -1
  62. package/vendor/directive-core/dist/pre-pr-controller/controller.d.ts +1 -1
  63. package/vendor/directive-core/dist/pre-pr-controller/controller.d.ts.map +1 -1
  64. package/vendor/directive-core/dist/pre-pr-controller/controller.js +43 -15
  65. package/vendor/directive-core/dist/pre-pr-controller/controller.js.map +1 -1
  66. package/vendor/directive-core/dist/pre-pr-controller/coverage-report.d.ts +22 -0
  67. package/vendor/directive-core/dist/pre-pr-controller/coverage-report.d.ts.map +1 -0
  68. package/vendor/directive-core/dist/pre-pr-controller/coverage-report.js +48 -0
  69. package/vendor/directive-core/dist/pre-pr-controller/coverage-report.js.map +1 -0
  70. package/vendor/directive-core/dist/pre-pr-controller/types.d.ts +7 -0
  71. package/vendor/directive-core/dist/pre-pr-controller/types.d.ts.map +1 -1
  72. package/vendor/directive-core/dist/pre-pr-controller/types.js.map +1 -1
  73. package/vendor/directive-core/dist/xbrief-migrate/migrate-project.d.ts +5 -4
  74. package/vendor/directive-core/dist/xbrief-migrate/migrate-project.d.ts.map +1 -1
  75. package/vendor/directive-core/dist/xbrief-migrate/migrate-project.js +65 -46
  76. package/vendor/directive-core/dist/xbrief-migrate/migrate-project.js.map +1 -1
  77. package/vendor/directive-core/dist/xbrief-migrate/transforms.d.ts.map +1 -1
  78. package/vendor/directive-core/dist/xbrief-migrate/transforms.js +13 -6
  79. package/vendor/directive-core/dist/xbrief-migrate/transforms.js.map +1 -1
@@ -173,7 +173,7 @@ The agent may suggest the next phase, but the user decides. Phases can be entere
173
173
  - **Batch**: `task issue:ingest -- --all [--label <L>] [--status <S>]` — ingests every open issue matching the filters, skipping duplicates by `references.uri` match.
174
174
  - **Preview**: add `--dry-run` to either form to preview without writing files.
175
175
 
176
- The task emits xBRIEFs conforming to the canonical v0.6 schema (`xbrief/schemas/xbrief-core.schema.json`) with origin references in the form documented in [`../../conventions/references.md`](../../conventions/references.md):
176
+ The task emits xBRIEFs conforming to the canonical xBRIEF v0.8 schema (`node_modules/@deftai/directive-runtime/vbrief/schemas/xbrief-core-0.8.schema.json`; OVPR pin is schema SoT) with origin references in the form documented in [`../../conventions/references.md`](../../conventions/references.md):
177
177
 
178
178
  ```json
179
179
  "references": [
@@ -187,7 +187,7 @@ The task emits xBRIEFs conforming to the canonical v0.6 schema (`xbrief/schemas/
187
187
 
188
188
  - ! New scope xBRIEFs MUST target `"xBRIEFInfo": { "version": "0.8" }` (the task handles this automatically)
189
189
  - ! `plan.status` starts at `"proposed"`; the task sets this
190
- - ! Conform to `xbrief/schemas/xbrief-core.schema.json` (v0.6) -- the task validates before writing
190
+ - ! Conform to `node_modules/@deftai/directive-runtime/vbrief/schemas/xbrief-core-0.8.schema.json` (v0.8; pin schema SoT) -- the task validates before writing
191
191
  - ~ After ingest, review the generated xBRIEFs with the user before promoting any of them to `pending/`
192
192
 
193
193
  ⊗ Hand-author scope xBRIEFs inside the skill when the ingest task exists — duplicating the narrative logic is how #534 (non-conformant references) and #537 (drift between skill and task) arise
@@ -673,7 +673,7 @@ omit = [
673
673
 
674
674
  ### Template
675
675
 
676
- ! The output MUST conform to the canonical xBRIEF v0.8 schema (`xbrief/schemas/xbrief-core-0.8.schema.json`, strict `const: "0.8"`). See [`../../conventions/references.md`](../../conventions/references.md). Write-path default is **0.8 only** (#2971); legacy 0.6 remains read-accepted until `deft migrate:xbrief`.
676
+ ! The output MUST conform to the canonical xBRIEF v0.8 schema (`node_modules/@deftai/directive-runtime/vbrief/schemas/xbrief-core-0.8.schema.json`, strict `const: "0.8"`; OVPR pin is schema SoT — install does not deposit project-root `xbrief/schemas/`). See [`../../conventions/references.md`](../../conventions/references.md). Write-path default is **0.8 only** (#2971); legacy 0.6 remains read-accepted until `deft migrate:xbrief`.
677
677
 
678
678
  ! Do not write this document onto `xbrief/PROJECT-DEFINITION.xbrief.json` yourself. After confirmation, write it to a temporary narratives file that is not that artifact, then run `deft project:write-narratives --project-root <policy-project-root> --narratives-file <path>`. The command stores Overview, TechStack, Strategy, Quality, ProjectRules, and Branching while `xbrief/active/` is empty. Optional `--title` sets `plan.title` only. A policy block in the temporary file is ignored. Policy still goes through the public writer in the gate above.
679
679
 
@@ -893,7 +893,7 @@ Per [strategies/interview.md](../../strategies/interview.md#interview-rules-shar
893
893
  - ⊗ Create a separate PRD.md on the Light path
894
894
  - ⊗ Generate an authoritative PRD.md — if needed, users run `task prd:render`
895
895
 
896
- ! The xBRIEF files MUST conform to `xbrief/schemas/xbrief-core-0.8.schema.json` (v0.8):
896
+ ! The xBRIEF files MUST conform to `node_modules/@deftai/directive-runtime/vbrief/schemas/xbrief-core-0.8.schema.json` (v0.8; pin schema SoT):
897
897
 
898
898
  - ! All `narratives` and `narrative` values MUST be plain strings — never objects or arrays
899
899
  - ! Nested children within a PlanItem use `items` (preferred field); `subItems` is the deprecated legacy alias kept for backward compatibility only
@@ -153,7 +153,7 @@ Loop body, per candidate (top-of-queue first):
153
153
  ? When the operator explicitly opts out of the queue (e.g. a one-off ad-hoc cohort that has not been ingested into the triage cache yet, or a swarm batch driven from a hand-supplied list of issue numbers), the monitor MAY fall back to the legacy GitHub-issue path:
154
154
 
155
155
  1. ! Fetch issue data: `gh api repos/<owner>/<repo>/issues/<N>` (REST per `templates/agent-prompt-preamble.md` § 5; never the GraphQL `gh issue view --json` surface).
156
- 2. ! Generate a minimal xBRIEF in `xbrief/proposed/` following the `YYYY-MM-DD-descriptive-slug.xbrief.json` naming convention (slug rules: [`../../conventions/vbrief-filenames.md`](../../conventions/vbrief-filenames.md)) and conforming to the canonical v0.6 schema (`xbrief/schemas/xbrief-core.schema.json`, strict `const: "0.6"`; see [`../../conventions/references.md`](../../conventions/references.md)).
156
+ 2. ! Generate a minimal xBRIEF in `xbrief/proposed/` following the `YYYY-MM-DD-descriptive-slug.xbrief.json` naming convention (slug rules: [`../../conventions/vbrief-filenames.md`](../../conventions/vbrief-filenames.md)) and conforming to the canonical xBRIEF v0.8 schema (`node_modules/@deftai/directive-runtime/vbrief/schemas/xbrief-core-0.8.schema.json`, strict `const: "0.8"`; OVPR pin is schema SoT — see [`../../conventions/references.md`](../../conventions/references.md)).
157
157
  3. ! Promote through the canonical lifecycle (`task scope:promote -- <path>` then `task scope:activate -- <path>`), respecting the WIP cap and the same `--force` audit-logged override semantics as the queue-driven loop.
158
158
  4. ! Surface the opt-out reason in the Step 4 (Present Analysis) summary so a reviewer can see WHY the queue was bypassed.
159
159
 
package/tasks/docs.yml CHANGED
@@ -49,4 +49,4 @@ tasks:
49
49
  cmds:
50
50
  - task: :engine:invoke
51
51
  vars:
52
- ENGINE_CMD: 'capability-map --project-root "{{.USER_WORKING_DIR}}" --check'
52
+ ENGINE_CMD: 'capability-map --project-root "{{.USER_WORKING_DIR}}" --check'
@@ -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 (#5805 Prefer-A Bound P1). */
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 i -g @deftai/directive, then directive install --repair (or package-manager install of @deftai/directive-runtime)";
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: root local kill-switch — skip CLI spawn when flag is present,
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
- # Pins older than #5804 lack --push-admit: keep the pre-#5804 hook there (verify:branch only).
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 $?
@@ -79,7 +79,7 @@ npm install -g --allow-scripts=<pkg,...> <package>
79
79
 
80
80
  ### Framework monorepo contributors
81
81
 
82
- Install source of truth for this repo is **pnpm** (`packageManager` field; CI uses `pnpm install --frozen-lockfile`). Install-script builds are gated by `pnpm-workspace.yaml` **`allowBuilds`** (currently `esbuild: true`). Do **not** treat `npm approve-scripts` under the pnpm virtual store as monorepo SoT.
82
+ Install source of truth for this repo is **pnpm** (`packageManager` field; CI uses `pnpm install --frozen-lockfile`). Install-script builds are gated by `pnpm-workspace.yaml` **`allowBuilds`** (currently `esbuild: true` where needed). **`allowBuilds` is PM-owned**: Directive install/upgrade uses the package manager for `package.json` / lockfile pin ops and does **not** hand-edit `allowBuilds`. If pnpm fails with `ERR_PNPM_IGNORED_BUILDS`, recover with `pnpm approve-builds` or set a real `true`/`false` under `allowBuilds` — do **not** commit pnpm's interactive placeholder text. Pin/add paths already pass `--ignore-scripts` so ordinary consumer upgrades should not need a runtime `allowBuilds` entry. Do **not** treat `npm approve-scripts` under the pnpm virtual store as monorepo SoT.
83
83
 
84
84
  ### Git / remote package sources and publish
85
85
 
@@ -456,7 +456,7 @@ import schema from "@deftai/directive-types/schemas/xbrief-core-0.8.schema.json"
456
456
 
457
457
  **Supported public API:** `@deftai/directive-types` and its published schema subpaths only. **`@deftai/directive-core` is published for npm dependency resolution but is not a supported library surface** — use the `deft` / `directive` CLI for behavior.
458
458
 
459
- **Schema source of truth:** `content/vbrief/schemas/vbrief-core.schema.json` in the directive repo. The types package mirrors it to `packages/types/schemas/` at build time; `deft` install also deposits schemas under project-root `xbrief/schemas/`. When in doubt, treat the directive repo canonical file as authoritative and refresh mirrors with `deft update` (install) or `@deftai/directive-types` (npm).
459
+ **Schema source of truth (OVPR):** the pinned runtime ships schemas under `node_modules/@deftai/directive-runtime/vbrief/schemas/` (current write schema: `xbrief-core-0.8.schema.json`). The types package publishes the same artifacts as `@deftai/directive-types/schemas/…`. Framework source authors at `content/vbrief/schemas/`. Install does **not** deposit project-root `xbrief/schemas/`. Refresh via `directive upgrade` (pin) or `@deftai/directive-types` (npm).
460
460
 
461
461
  ### `deft migrate` vs pre-v0.20 document-model migration
462
462