@deftai/directive-core 0.71.0 → 0.71.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,6 +31,16 @@ export const CANONICAL_GITIGNORE_BASELINE = [
31
31
  "vbrief/.triage-cache/scope-lifecycle.jsonl",
32
32
  "vbrief/.triage-cache/decompositions/",
33
33
  "vbrief/.triage-cache/doctor-state.json",
34
+ // Symmetric `xbrief/` layout entries (#2348). On the migrated `xbrief/` tree
35
+ // the engine writes operator-private triage-cache files to
36
+ // `xbrief/.triage-cache/`; without these the paths are trackable, violating
37
+ // the #1144 hybrid policy. Both layouts are emitted (harmless extra lines on
38
+ // the layout not in use) to match the both-layout `.eval/` treatment.
39
+ "xbrief/.triage-cache/candidates.jsonl",
40
+ "xbrief/.triage-cache/summary-history.jsonl",
41
+ "xbrief/.triage-cache/scope-lifecycle.jsonl",
42
+ "xbrief/.triage-cache/decompositions/",
43
+ "xbrief/.triage-cache/doctor-state.json",
34
44
  "vbrief/*.lock",
35
45
  ".deft/core.bak-*/",
36
46
  ".deft/*.bak-*",
@@ -1,4 +1,3 @@
1
- export declare const DEFAULT_LOG_PATH: string;
2
1
  export declare class CandidatesLogError extends Error {
3
2
  constructor(message: string);
4
3
  }
@@ -2,7 +2,10 @@ import { randomUUID } from "node:crypto";
2
2
  import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync, } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { pyRepr } from "../scm/py-format.js";
5
- export const DEFAULT_LOG_PATH = resolve(import.meta.dirname, "..", "..", "..", "..", "vbrief", ".eval", "candidates.jsonl");
5
+ import { resolveCandidatesLogPath } from "../triage/cache-path.js";
6
+ function defaultLogPath() {
7
+ return resolveCandidatesLogPath(process.cwd());
8
+ }
6
9
  const VALID_DECISIONS = new Set([
7
10
  "accept",
8
11
  "reject",
@@ -105,7 +108,7 @@ function validateEntry(entry) {
105
108
  }
106
109
  }
107
110
  function resolvePath(path) {
108
- return path !== undefined && path !== null ? resolve(path) : DEFAULT_LOG_PATH;
111
+ return path !== undefined && path !== null ? resolve(path) : defaultLogPath();
109
112
  }
110
113
  function acquireAppendLock(logPath) {
111
114
  while (threadLocked) {
@@ -44,6 +44,14 @@ export interface FetchIssueOptions {
44
44
  readonly cacheRoot?: string | null;
45
45
  readonly scmCall?: ScmCallFn;
46
46
  }
47
+ /**
48
+ * Strip the `# #<number>: <title>` header that `renderContent` prepends when it
49
+ * materializes an issue's `content.md` at cache-put (#2314). The header is the
50
+ * only shape difference between the cache-read body and the live/raw-body path;
51
+ * removing it makes an ingested xBRIEF's `Overview` identical whether the source
52
+ * was a cache hit or a live fetch. A missing/older-shape header is left intact.
53
+ */
54
+ export declare function stripRenderedIssueHeader(content: string, number: number): string;
47
55
  export declare function fetchFromCache(repo: string, number: number, options?: FetchIssueOptions): Record<string, unknown> | null;
48
56
  export declare function fetchIssueComments(repo: string, number: number, options?: FetchIssueOptions): IssueComment[];
49
57
  export declare function attachIssueCommentThread(issue: Record<string, unknown>, comments: readonly IssueComment[]): Record<string, unknown>;
@@ -386,6 +386,20 @@ export function targetFilename(number, title, artifactSuffix = LEGACY_ARTIFACT_S
386
386
  const slug = slugify(title) || `issue-${number}`;
387
387
  return `${TODAY}-${number}-${slug}${artifactSuffix}`;
388
388
  }
389
+ /**
390
+ * Strip the `# #<number>: <title>` header that `renderContent` prepends when it
391
+ * materializes an issue's `content.md` at cache-put (#2314). The header is the
392
+ * only shape difference between the cache-read body and the live/raw-body path;
393
+ * removing it makes an ingested xBRIEF's `Overview` identical whether the source
394
+ * was a cache hit or a live fetch. A missing/older-shape header is left intact.
395
+ */
396
+ export function stripRenderedIssueHeader(content, number) {
397
+ if (!Number.isFinite(number)) {
398
+ return content;
399
+ }
400
+ const header = new RegExp(`^# #${number}:[^\\n]*\\n\\n`);
401
+ return content.replace(header, "");
402
+ }
389
403
  export function fetchFromCache(repo, number, options = {}) {
390
404
  const key = `${repo}/${number}`;
391
405
  try {
@@ -405,7 +419,11 @@ export function fetchFromCache(repo, number, options = {}) {
405
419
  // buildIssueVbrief.
406
420
  if (result.contentPath !== null) {
407
421
  try {
408
- issue.body = readFileSync(result.contentPath, "utf8");
422
+ // #2314: content.md is `renderContent`-prefixed with a `# #<n>: <title>`
423
+ // header at cache-put. Strip that header so the cache-read Overview
424
+ // matches the live/raw-body path (which has no header), keeping the
425
+ // durable xBRIEF identical for a cache hit vs a live fetch.
426
+ issue.body = stripRenderedIssueHeader(readFileSync(result.contentPath, "utf8"), Number(issue.number));
409
427
  }
410
428
  catch {
411
429
  // fall back to the raw body (re-scanned downstream)
@@ -6,6 +6,7 @@ import { call } from "../scm/call.js";
6
6
  import { updateDecomposedChildBackReferences } from "../scope/decomposed-refs.js";
7
7
  import { resolveProjectRoot } from "../scope/project-context.js";
8
8
  import { resolveProjectRepo } from "../slice/project-context.js";
9
+ import { LEGACY_INFO_ROOT_KEY, MIGRATED_INFO_ROOT_KEY } from "../xbrief-migrate/constants.js";
9
10
  export const LIFECYCLE_FOLDERS = [
10
11
  "proposed",
11
12
  "pending",
@@ -633,8 +634,14 @@ export function applyLifecycleFixes(vbriefDir, report, projectRoot = null) {
633
634
  const terminalStatus = destFolder === "cancelled" ? "cancelled" : "completed";
634
635
  plan.status = terminalStatus;
635
636
  const stamp = utcNowIso();
636
- const info = (data.vBRIEFInfo ?? {});
637
- data.vBRIEFInfo = info;
637
+ // Stamp `updated` into whichever info envelope the file already uses (#2346).
638
+ // Canonical v0.8 briefs use `xBRIEFInfo`; stamping `vBRIEFInfo` unconditionally
639
+ // appended a stray, version-less `vBRIEFInfo` block that then failed
640
+ // `vbrief:validate` ('vBRIEFInfo.version' must be one of ..., got 'undefined').
641
+ // Legacy briefs (or files without either envelope) keep the `vBRIEFInfo` key.
642
+ const infoKey = MIGRATED_INFO_ROOT_KEY in data ? MIGRATED_INFO_ROOT_KEY : LEGACY_INFO_ROOT_KEY;
643
+ const info = (data[infoKey] ?? {});
644
+ data[infoKey] = info;
638
645
  info.updated = stamp;
639
646
  plan.updated = stamp;
640
647
  propagateItemStatus(plan.items, terminalStatus, stamp);
@@ -379,8 +379,8 @@ export function cmdSubagentMonitor(argv, cwd = process.cwd()) {
379
379
  process.stderr.write(`Error: ${args.error}\n`);
380
380
  return EXIT_EXTERNAL_ERROR;
381
381
  }
382
- if (args.thresholdMinutes <= 0) {
383
- process.stderr.write(`Error: --threshold-minutes must be positive, got ${args.thresholdMinutes}\n`);
382
+ if (Number.isNaN(args.thresholdMinutes) || args.thresholdMinutes <= 0) {
383
+ process.stderr.write(`Error: --threshold-minutes must be a positive number, got ${args.thresholdMinutes}\n`);
384
384
  return EXIT_EXTERNAL_ERROR;
385
385
  }
386
386
  const scratchEntries = args.scratchDirs.length > 0
@@ -37,7 +37,10 @@ export function runChangelogCheck(projectRoot, io) {
37
37
  io.writeOut("FAIL: CHANGELOG.md not found\n");
38
38
  return 1;
39
39
  }
40
- const text = readFileSync(path, "utf8");
40
+ // Normalize CRLF -> LF before matching (#2329). On Windows checkouts with
41
+ // core.autocrlf=true the working tree uses CRLF, and the `[ \t]*\n` header
42
+ // pattern does not consume the `\r`, so the section falsely reads as absent.
43
+ const text = readFileSync(path, "utf8").replace(/\r\n/g, "\n");
41
44
  const match = UNRELEASED_RE.exec(text);
42
45
  if (match === null) {
43
46
  io.writeOut("FAIL: No [Unreleased] section found in CHANGELOG.md\n");
@@ -1,8 +1,7 @@
1
- import { spawnSync } from "node:child_process";
2
- import { dirname, join, resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
1
+ import { join } from "node:path";
4
2
  import { CacheNotFoundError } from "../../cache/errors.js";
5
3
  import { cacheGet } from "../../cache/operations.js";
4
+ import { ingestSingleForAccept as ingestSingleForAcceptTs } from "../../intake/issue-ingest.js";
6
5
  import { call } from "../../scm/call.js";
7
6
  import { ScmStubError } from "../../scm/errors.js";
8
7
  import { createCandidatesLog, findByIssue, resolveAuditLogPath, rollbackAuditEntry, } from "./candidates-log.js";
@@ -18,12 +17,6 @@ const TERMINAL_DECISIONS = new Set(["accept", "reject", "mark-duplicate"]);
18
17
  const DEFAULT_ACTOR = "agent:triage";
19
18
  const DEFAULT_NEEDS_AC_COMMENT = "This issue lacks acceptance criteria. Please add a Test/Acceptance " +
20
19
  "narrative before this can be triaged. (deft #845)";
21
- function resolveDeftRoot() {
22
- if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
23
- return resolve(process.env.DEFT_ROOT);
24
- }
25
- return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "..", "..");
26
- }
27
20
  function defaultNowIso() {
28
21
  return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
29
22
  }
@@ -62,39 +55,22 @@ function defaultScmRunner() {
62
55
  },
63
56
  };
64
57
  }
65
- function defaultIssueIngest(deftRoot) {
58
+ function defaultIssueIngest() {
66
59
  return {
67
60
  ingestSingleForAccept(issueNumber, repo, options = {}) {
68
61
  const projectRoot = options.projectRoot ?? process.cwd();
69
- const script = [
70
- "import sys",
71
- "from pathlib import Path",
72
- `sys.path.insert(0, ${JSON.stringify(join(deftRoot, "scripts"))})`,
73
- "import issue_ingest",
74
- "issue_ingest.ingest_single_for_accept(",
75
- `${issueNumber},`,
76
- `${JSON.stringify(repo)},`,
77
- `project_root=Path(${JSON.stringify(projectRoot)}),`,
78
- ")",
79
- ].join("\n");
80
- const result = spawnSync("uv", ["run", "python", "-c", script], {
81
- cwd: deftRoot,
82
- encoding: "utf8",
83
- stdio: ["ignore", "pipe", "pipe"],
84
- });
85
- if (result.status !== 0) {
86
- const stderr = (result.stderr ?? "").trim();
87
- throw new Error(stderr || "issue:ingest delegation failed");
88
- }
62
+ // Delegate to the native TS intake path (#2350). The legacy Python
63
+ // `scripts/issue_ingest.py` shell-out was orphaned when #1933 removed the
64
+ // Python surface, leaving `triage:accept` raising ModuleNotFoundError.
65
+ ingestSingleForAcceptTs(issueNumber, repo, { projectRoot });
89
66
  },
90
67
  };
91
68
  }
92
69
  /** Default dependency bundle for production CLI use. */
93
70
  export function createDefaultDeps(projectRoot) {
94
- const deftRoot = resolveDeftRoot();
95
71
  const deps = {
96
72
  candidatesLog: createCandidatesLog(projectRoot),
97
- issueIngest: defaultIssueIngest(deftRoot),
73
+ issueIngest: defaultIssueIngest(),
98
74
  scm: defaultScmRunner(),
99
75
  nowIso: defaultNowIso,
100
76
  stderr: (message) => process.stderr.write(`${message}\n`),
@@ -9,6 +9,8 @@ export declare function gitattributesTriageCacheGlob(projectRoot: string): strin
9
9
  export declare const GITATTRIBUTES_EVAL_RULE = "vbrief/.triage-cache/*.jsonl merge=union";
10
10
  export declare const FORBIDDEN_BLANKET_EVAL_LINES: readonly string[];
11
11
  export declare const EVAL_README_BODY = "# `vbrief/.triage-cache/` -- triage working-set artefacts\n\nThis directory holds the append-only JSON-lines logs that the triage and\nslicing skills emit. The framework governs which files in here are tracked\nby git versus gitignored using a **hybrid policy** (#1144, child of #1119).\n\n## Tracking policy\n\n| File | Tracked? | Why |\n| --- | --- | --- |\n| `slices.jsonl` | Yes -- **committed** | Team-shared cohort records produced by slicing skills (D13 / #1132). New operators joining the team need to see prior cohort outputs to detect orphans and avoid re-slicing the same scope. |\n| `candidates.jsonl` | No -- **gitignored** | Operator-private triage decisions (#845 Story 2). Each operator's local accept / defer / reject stream is per-machine state; sharing it would conflate operators' timing + identity across the team. Re-derive on a fresh clone via `task triage:bootstrap`. |\n| `summary-history.jsonl` | No -- **gitignored** | Operator-private observability for `task triage:summary` output time-series. Not load-bearing for any decision. |\n| `scope-lifecycle.jsonl` | No -- **gitignored** | Operator-private scope-lifecycle audit decisions (D1 / #1121). Each demote (`task scope:demote`) appends one entry including a `demote_meta` block (`was_promoted`, `original_promotion_decision_id`, `days_in_pending`, `demote_reason`, `demoted_from`). Per-operator stream; sharing would conflate operators' demote timing across the team. Lightweight metrics over this log are tracked separately at #1180. |\n| `decompositions/` | No -- **gitignored** | Temporary story-decomposition proposal drafts. These JSON drafts are local scratch artifacts, not vBRIEFs; generated child story vBRIEFs are created by `task scope:decompose` in lifecycle folders, defaulting to `vbrief/pending/`. |\n| `doctor-state.json` | No -- **gitignored** | Per-machine `task doctor` throttle state (last exit code + timestamps) persisted to gate the 24h/4h re-probe window (#1308 / #1464). Local to each clone; never committed. |\n\nThe gitignore lines live in the repo-root `.gitignore` (`vbrief/.triage-cache/candidates.jsonl`,\n`vbrief/.triage-cache/summary-history.jsonl`, `vbrief/.triage-cache/scope-lifecycle.jsonl`,\n`vbrief/.triage-cache/decompositions/`, and `vbrief/.triage-cache/doctor-state.json`). All paths\nnot listed above remain committed by default.\n\n## Fresh-clone regeneration\n\nOn a fresh clone (or any machine that has never run triage), `candidates.jsonl`\nis absent. Regenerate it with:\n\n```\ntask triage:bootstrap\n```\n\nThe bootstrap path detects the missing file, runs the auto-classifier, and\nwrites a fresh `vbrief/.triage-cache/candidates.jsonl`. It does NOT touch the tracked\n`slices.jsonl`; cohort records remain a team-shared resource.\n\n## `merge=union` policy for `*.jsonl`\n\nThe repo-root `.gitattributes` declares:\n\n```\nvbrief/.triage-cache/*.jsonl merge=union\n```\n\nThe `union` merge driver concatenates both sides' appended lines on\nauto-merge, so two branches that each appended a different record to the\nsame JSON-lines file rebase cleanly without operator surgery. Two things\noperators should know:\n\n- **Concatenation, not set-union.** When two branches append DIFFERENT\n records to the file, the merge driver concatenates both sides' lines\n -- there is no smart deduplication of \"semantically similar\" records.\n (Identical line-for-line appends collapse because git's three-way\n merge sees them as the same change, but distinct records always\n survive verbatim, even if a downstream reader would consider them\n redundant.) The append-only writers in `scripts/candidates_log.py`\n mint a fresh `decision_id` per call, so genuinely duplicate records\n are not the expected case, but downstream readers MUST tolerate\n multiple records describing the same logical decision.\n- **Single-operator scope only.** This is the foundational rebase\n ergonomic for the single-operator case (operator A rebases their\n feature branch onto a master that grew while they were AFK).\n Multi-operator merge-conflict resolution is explicitly out of scope per\n #1119 R4 (tracked separately as M1-M4 in #1183).\n\n## See also\n\n- Current Shape comment on #1144 for the canonical decisions (the source\n of truth this README documents).\n- `.gitignore` -- selective gitignore entries for the operator-private\n files.\n- `.gitattributes` -- the `merge=union` rule.\n- `scripts/candidates_log.py` -- the writer for `candidates.jsonl`.\n";
12
+ /** Layout-aware triage-cache README body for the active lifecycle tree (#2344 / #2349). */
13
+ export declare function generateTriageCacheReadmeBody(projectRoot: string): string;
12
14
  /** Strip an inline `# ...` comment from a gitignore line. */
13
15
  export declare function stripGitignoreInlineComment(line: string): string;
14
16
  /** Append `.deft-cache/` to `.gitignore` when absent. */
@@ -152,6 +152,12 @@ operators should know:
152
152
  - \`.gitattributes\` -- the \`merge=union\` rule.
153
153
  - \`scripts/candidates_log.py\` -- the writer for \`candidates.jsonl\`.
154
154
  `;
155
+ /** Layout-aware triage-cache README body for the active lifecycle tree (#2344 / #2349). */
156
+ export function generateTriageCacheReadmeBody(projectRoot) {
157
+ const layout = resolveLifecycleLayout(projectRoot);
158
+ const triagePrefix = `${layout.artifactDir}/${TRIAGE_CACHE_DIR_NAME}`;
159
+ return EVAL_README_BODY.replaceAll("vbrief/.triage-cache", triagePrefix);
160
+ }
155
161
  function stepOutcome(name, ok, message, details = {}, error = null) {
156
162
  return { name, ok, message, error, details };
157
163
  }
@@ -338,7 +344,8 @@ function ensureGitattributesMergeUnion(gitattributesPath, stepName, glob, ruleLi
338
344
  gitattributes_created: true,
339
345
  });
340
346
  }
341
- function ensureEvalReadme(readmePath, readmeRel, stepName) {
347
+ function ensureEvalReadme(options) {
348
+ const { projectRoot, readmePath, readmeRel, stepName } = options;
342
349
  try {
343
350
  readFileSync(readmePath, { encoding: "utf8" });
344
351
  return stepOutcome(stepName, true, `${readmeRel} already present (no-op)`, {
@@ -351,7 +358,7 @@ function ensureEvalReadme(readmePath, readmeRel, stepName) {
351
358
  }
352
359
  try {
353
360
  mkdirSync(dirname(readmePath), { recursive: true });
354
- writeFileSync(readmePath, EVAL_README_BODY, { encoding: "utf8" });
361
+ writeFileSync(readmePath, generateTriageCacheReadmeBody(projectRoot), { encoding: "utf8" });
355
362
  }
356
363
  catch (exc) {
357
364
  return stepOutcome(stepName, false, `could not create ${readmePath}`, { readme_created: false }, String(exc));
@@ -385,7 +392,7 @@ export function stepEnsureGitignoreEvalEntries(projectRoot) {
385
392
  return stepOutcome(stepName, false, gaResult.message, details, gaResult.error ?? null);
386
393
  }
387
394
  Object.assign(details, gaResult.details);
388
- const rdResult = ensureEvalReadme(readmePath, readmeRel, stepName);
395
+ const rdResult = ensureEvalReadme({ projectRoot, readmePath, readmeRel, stepName });
389
396
  if (!rdResult.ok) {
390
397
  Object.assign(details, rdResult.details);
391
398
  return stepOutcome(stepName, false, rdResult.message, details, rdResult.error ?? null);
@@ -16,6 +16,8 @@ export interface TriageCacheMigrationResult {
16
16
  readonly migratedFiles: readonly string[];
17
17
  readonly skippedFiles: readonly string[];
18
18
  readonly migratedDirs: readonly string[];
19
+ readonly regeneratedFiles: readonly string[];
20
+ readonly removedLegacyFiles: readonly string[];
19
21
  }
20
22
  /** Absolute path to the layout-aware `.triage-cache/` directory. */
21
23
  export declare function resolveTriageCacheDir(projectRoot: string): string;
@@ -4,9 +4,10 @@
4
4
  * Triage append-only logs and scratch dirs live under `.triage-cache/` so the
5
5
  * `.eval/` namespace can be reclaimed for version-eval results (#1703 Tier 2).
6
6
  */
7
- import { existsSync, mkdirSync, renameSync } from "node:fs";
7
+ import { existsSync, mkdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
8
8
  import { join, relative } from "node:path";
9
9
  import { resolveEvalDir, resolveLifecycleLayout, resolveLifecycleRoot } from "../layout/resolve.js";
10
+ import { generateTriageCacheReadmeBody } from "./bootstrap/gitignore.js";
10
11
  /** Directory name for the triage working-set cache (not version-eval results). */
11
12
  export const TRIAGE_CACHE_DIR_NAME = ".triage-cache";
12
13
  /** Legacy directory that previously held triage cache files before #1703. */
@@ -42,8 +43,10 @@ export function migrateLegacyTriageCacheFromEval(projectRoot) {
42
43
  const migratedFiles = [];
43
44
  const skippedFiles = [];
44
45
  const migratedDirs = [];
46
+ const regeneratedFiles = [];
47
+ const removedLegacyFiles = [];
45
48
  if (!existsSync(legacyDir)) {
46
- return { migratedFiles, skippedFiles, migratedDirs };
49
+ return { migratedFiles, skippedFiles, migratedDirs, regeneratedFiles, removedLegacyFiles };
47
50
  }
48
51
  mkdirSync(targetDir, { recursive: true });
49
52
  for (const name of TRIAGE_CACHE_FILE_NAMES) {
@@ -52,8 +55,21 @@ export function migrateLegacyTriageCacheFromEval(projectRoot) {
52
55
  if (!existsSync(legacyPath)) {
53
56
  continue;
54
57
  }
58
+ if (name === "README.md") {
59
+ if (existsSync(targetPath)) {
60
+ unlinkSync(legacyPath);
61
+ removedLegacyFiles.push(name);
62
+ }
63
+ else {
64
+ writeFileSync(targetPath, generateTriageCacheReadmeBody(projectRoot), "utf8");
65
+ unlinkSync(legacyPath);
66
+ regeneratedFiles.push(name);
67
+ }
68
+ continue;
69
+ }
55
70
  if (existsSync(targetPath)) {
56
- skippedFiles.push(name);
71
+ unlinkSync(legacyPath);
72
+ removedLegacyFiles.push(name);
57
73
  continue;
58
74
  }
59
75
  renameSync(legacyPath, targetPath);
@@ -72,7 +88,7 @@ export function migrateLegacyTriageCacheFromEval(projectRoot) {
72
88
  renameSync(legacyPath, targetPath);
73
89
  migratedDirs.push(name);
74
90
  }
75
- return { migratedFiles, skippedFiles, migratedDirs };
91
+ return { migratedFiles, skippedFiles, migratedDirs, regeneratedFiles, removedLegacyFiles };
76
92
  }
77
93
  /** Resolve a path under `.triage-cache/`, migrating legacy `.eval/` files first. */
78
94
  export function resolveTriageCachePath(projectRoot, ...segments) {
@@ -91,6 +107,7 @@ export function resolveCandidatesLogPath(projectRoot) {
91
107
  }
92
108
  /** Ensure the triage cache directory exists (post-migration). */
93
109
  export function ensureTriageCacheDir(projectRoot) {
110
+ migrateLegacyTriageCacheFromEval(projectRoot);
94
111
  const dir = resolveTriageCacheDir(projectRoot);
95
112
  mkdirSync(dir, { recursive: true });
96
113
  return dir;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-core",
3
- "version": "0.71.0",
3
+ "version": "0.71.1",
4
4
  "description": "TypeScript engine core for the Directive framework.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -281,8 +281,8 @@
281
281
  "provenance": true
282
282
  },
283
283
  "dependencies": {
284
- "@deftai/directive-content": "^0.71.0",
285
- "@deftai/directive-types": "^0.71.0",
284
+ "@deftai/directive-content": "^0.71.1",
285
+ "@deftai/directive-types": "^0.71.1",
286
286
  "archiver": "^8.0.0"
287
287
  },
288
288
  "scripts": {