@deftai/directive-core 0.72.0 → 0.73.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.
Files changed (86) hide show
  1. package/dist/category-b-namespace/index.js +16 -2
  2. package/dist/codebase/default-extractor.js +9 -1
  3. package/dist/codebase/map.js +1 -1
  4. package/dist/doctor/checks.d.ts +9 -0
  5. package/dist/doctor/checks.js +85 -5
  6. package/dist/doctor/main.js +2 -1
  7. package/dist/eval/health.js +7 -1
  8. package/dist/eval/readback.js +7 -1
  9. package/dist/init-deposit/gitignore.js +6 -0
  10. package/dist/init-deposit/hygiene.d.ts +24 -0
  11. package/dist/init-deposit/hygiene.js +55 -0
  12. package/dist/init-deposit/refresh.js +22 -6
  13. package/dist/init-deposit/scaffold.d.ts +11 -1
  14. package/dist/init-deposit/scaffold.js +4 -4
  15. package/dist/integration-e2e/helpers.js +7 -7
  16. package/dist/layout/index.d.ts +1 -1
  17. package/dist/layout/index.js +1 -1
  18. package/dist/layout/resolve.d.ts +47 -31
  19. package/dist/layout/resolve.js +93 -36
  20. package/dist/lifecycle/lifecycle-hygiene.d.ts +1 -1
  21. package/dist/lifecycle/lifecycle-hygiene.js +1 -1
  22. package/dist/migrate-preflight/index.js +10 -10
  23. package/dist/policy/resolve.d.ts +2 -2
  24. package/dist/policy/resolve.js +11 -3
  25. package/dist/policy/wip.d.ts +1 -1
  26. package/dist/policy/wip.js +15 -3
  27. package/dist/preflight-cache/evaluate.js +1 -1
  28. package/dist/release/native-steps.js +14 -2
  29. package/dist/render/export-spec.js +2 -2
  30. package/dist/render/project-render.js +40 -9
  31. package/dist/scope/decompose.js +12 -2
  32. package/dist/session/resume-conditions.js +2 -2
  33. package/dist/session/ritual-sentinel.d.ts +1 -1
  34. package/dist/session/ritual-sentinel.js +6 -4
  35. package/dist/slice/constants.d.ts +1 -1
  36. package/dist/slice/constants.js +1 -1
  37. package/dist/slice/project-context.js +1 -1
  38. package/dist/spec-authority/resolver.js +9 -2
  39. package/dist/swarm/complete-cohort.js +14 -1
  40. package/dist/swarm/readiness.js +33 -3
  41. package/dist/task-surface/index.js +3 -3
  42. package/dist/triage/actions/candidates-log.d.ts +1 -1
  43. package/dist/triage/bootstrap/gitignore.js +22 -10
  44. package/dist/triage/bootstrap/index.d.ts +1 -1
  45. package/dist/triage/bootstrap/index.js +9 -3
  46. package/dist/triage/cache-path.d.ts +1 -1
  47. package/dist/triage/cache-path.js +32 -6
  48. package/dist/triage/classify/index.d.ts +1 -1
  49. package/dist/triage/classify/index.js +11 -4
  50. package/dist/triage/help/registry-data.d.ts +2 -2
  51. package/dist/triage/help/registry-data.js +2 -2
  52. package/dist/triage/queue/constants.d.ts +4 -4
  53. package/dist/triage/queue/constants.js +4 -4
  54. package/dist/triage/queue/scope-walk.js +7 -1
  55. package/dist/triage/reconcile/reconcile.js +23 -3
  56. package/dist/triage/reconcile/types.d.ts +1 -1
  57. package/dist/triage/reconcile/types.js +1 -1
  58. package/dist/triage/refresh/refresh.js +9 -2
  59. package/dist/triage/scope/constants.d.ts +2 -2
  60. package/dist/triage/scope/constants.js +2 -2
  61. package/dist/triage/scope/renderers.js +7 -1
  62. package/dist/triage/smoketest/index.js +9 -6
  63. package/dist/triage/subscribe/index.d.ts +2 -2
  64. package/dist/triage/subscribe/index.js +2 -2
  65. package/dist/triage/summary/index.d.ts +2 -2
  66. package/dist/triage/summary/index.js +1 -1
  67. package/dist/triage/summary/reconcilable.d.ts +1 -1
  68. package/dist/triage/welcome/constants.d.ts +2 -2
  69. package/dist/triage/welcome/constants.js +2 -2
  70. package/dist/triage/welcome/onboard.js +8 -1
  71. package/dist/triage/welcome/prior-state.js +14 -2
  72. package/dist/triage/welcome/summary.js +14 -2
  73. package/dist/triage/welcome/writers.js +7 -1
  74. package/dist/validate-content/validate-strategy-output.js +11 -1
  75. package/dist/vbrief-build/parity-scenarios.js +3 -3
  76. package/dist/vbrief-reconcile/labels.js +16 -1
  77. package/dist/vbrief-reconcile/parity-scenarios.js +10 -10
  78. package/dist/vbrief-reconcile/umbrellas.js +16 -1
  79. package/dist/vbrief-validate/main.js +13 -1
  80. package/dist/vbrief-validate/precutover.js +33 -5
  81. package/dist/vbrief-validate/staleness.d.ts +1 -1
  82. package/dist/vbrief-validate/staleness.js +5 -2
  83. package/dist/verify-source/code-structure-validate.js +7 -1
  84. package/dist/xbrief-migrate/signpost.d.ts +4 -4
  85. package/dist/xbrief-migrate/signpost.js +11 -15
  86. package/package.json +3 -3
@@ -5,8 +5,15 @@ import { SPEC_RENDER_BANNER } from "../render/constants.js";
5
5
  import { contentHasGeneratedPdSource, contentHasGeneratedSpecSource, EXPORT_SPEC_PD_BANNER, GENERATED_SPEC_PURPOSE, } from "./constants.js";
6
6
  export function resolveSpecAuthority(projectRoot) {
7
7
  const root = projectRoot;
8
- const layout = resolveLifecycleLayout(root);
9
- const vbriefDir = resolveLifecycleRoot(root);
8
+ let layout;
9
+ let vbriefDir;
10
+ try {
11
+ layout = resolveLifecycleLayout(root);
12
+ vbriefDir = resolveLifecycleRoot(root);
13
+ }
14
+ catch {
15
+ return null; // No xbrief/ layout; spec authority unavailable.
16
+ }
10
17
  const projectDefPath = resolveProjectDefinitionPath(root);
11
18
  if (!existsSync(projectDefPath))
12
19
  return null;
@@ -230,7 +230,20 @@ function completeParent(parentPath, vbriefDir, projectRoot, settled, dryRun) {
230
230
  };
231
231
  }
232
232
  export function sweepCohort(storyPaths, projectRoot, dryRun) {
233
- const vbriefDir = resolveLifecycleRoot(projectRoot);
233
+ let vbriefDir;
234
+ try {
235
+ vbriefDir = resolveLifecycleRoot(projectRoot);
236
+ }
237
+ catch {
238
+ return {
239
+ project_root: resolve(projectRoot),
240
+ dry_run: dryRun,
241
+ stories: [],
242
+ parents: [],
243
+ errors: [],
244
+ ok: true,
245
+ };
246
+ }
234
247
  const result = {
235
248
  project_root: resolve(projectRoot),
236
249
  dry_run: dryRun,
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readdirSync, readFileSync } from "node:fs";
2
2
  import { basename, join, resolve } from "node:path";
3
3
  import { referenceTypeMatches } from "@deftai/directive-types";
4
- import { ARTIFACT_SUFFIXES, hasArtifactSuffix, LIFECYCLE_DIR_NAMES, resolveLifecycleLayout, resolveLifecycleRoot, stripArtifactSuffix, } from "../layout/resolve.js";
4
+ import { ARTIFACT_SUFFIXES, hasArtifactSuffix, LEGACY_ARTIFACT_DIR, LIFECYCLE_DIR_NAMES, MIGRATED_ARTIFACT_DIR, MIGRATED_ARTIFACT_SUFFIX, MIGRATED_INFO_ROOT_KEY, resolveLifecycleLayout, resolveLifecycleRoot, stripArtifactSuffix, } from "../layout/resolve.js";
5
5
  import { acceptanceTextsFromItems, asStrList, deprecatedSubitemsIssues, itemHasTraces, itemsHaveAcceptance, missingRequiredSwarmFields, storyQualityIssues, } from "../vbrief-validation/story-quality.js";
6
6
  import { LIFECYCLE_FOLDERS, READY } from "./constants.js";
7
7
  function loadJson(path) {
@@ -26,7 +26,31 @@ function projectRel(projectRoot, path) {
26
26
  }
27
27
  }
28
28
  function expandPaths(projectRoot, patterns) {
29
- const layout = resolveLifecycleLayout(projectRoot);
29
+ // Use the canonical xbrief layout; re-throw only if a legacy vbrief/-only tree is detected (#2112).
30
+ let layout;
31
+ try {
32
+ layout = resolveLifecycleLayout(projectRoot);
33
+ }
34
+ catch (err) {
35
+ const xbriefDir = join(projectRoot, MIGRATED_ARTIFACT_DIR);
36
+ if (existsSync(xbriefDir)) {
37
+ // xbrief/ dir exists but has no artifacts yet -- treat as valid (empty) layout.
38
+ layout = {
39
+ root: xbriefDir,
40
+ artifactDir: MIGRATED_ARTIFACT_DIR,
41
+ artifactSuffix: MIGRATED_ARTIFACT_SUFFIX,
42
+ infoRootKey: MIGRATED_INFO_ROOT_KEY,
43
+ migrated: true,
44
+ };
45
+ }
46
+ else if (existsSync(join(projectRoot, LEGACY_ARTIFACT_DIR))) {
47
+ throw err; // Legacy-only project: operator must run deft migrate:xbrief.
48
+ }
49
+ else {
50
+ // Neither exists -- return empty list.
51
+ return [];
52
+ }
53
+ }
30
54
  const usePatterns = patterns.length > 0 ? patterns : [`${layout.artifactDir}/active/*${layout.artifactSuffix}`];
31
55
  const out = [];
32
56
  const seen = new Set();
@@ -210,7 +234,13 @@ function acceptanceCountJustification(plan, swarm) {
210
234
  }
211
235
  function allScopeIds(projectRoot) {
212
236
  const ids = new Map();
213
- const vbriefDir = resolveLifecycleRoot(projectRoot);
237
+ let vbriefDir;
238
+ try {
239
+ vbriefDir = resolveLifecycleRoot(projectRoot);
240
+ }
241
+ catch {
242
+ return ids; // No xbrief/ layout; no scope IDs.
243
+ }
214
244
  for (const folder of LIFECYCLE_FOLDERS) {
215
245
  const dir = join(vbriefDir, folder);
216
246
  if (!existsSync(dir)) {
@@ -72,10 +72,10 @@ export function runChangeInit(projectRoot, name, io) {
72
72
  return 1;
73
73
  }
74
74
  mkdirSync(join(base, "specs"), { recursive: true });
75
- writeFileSync(join(base, "proposal.vbrief.json"), `${JSON.stringify(proposalTemplate(trimmed), null, 2)}\n`, "utf8");
76
- writeFileSync(join(base, "tasks.vbrief.json"), `${JSON.stringify(tasksTemplate(trimmed), null, 2)}\n`, "utf8");
75
+ writeFileSync(join(base, "proposal.xbrief.json"), `${JSON.stringify(proposalTemplate(trimmed), null, 2)}\n`, "utf8");
76
+ writeFileSync(join(base, "tasks.xbrief.json"), `${JSON.stringify(tasksTemplate(trimmed), null, 2)}\n`, "utf8");
77
77
  io.writeOut(`OK: Created change proposal at ${base}/\n`);
78
- for (const file of ["proposal.vbrief.json", "tasks.vbrief.json", "specs/"]) {
78
+ for (const file of ["proposal.xbrief.json", "tasks.xbrief.json", "specs/"]) {
79
79
  io.writeOut(` - ${file}\n`);
80
80
  }
81
81
  return 0;
@@ -1,7 +1,7 @@
1
1
  import { resolveCandidatesLogPath } from "../cache-path.js";
2
2
  import type { AuditEntry, CandidatesLog } from "./types.js";
3
3
  /** Display/back-compat constant; resolution flows through resolveTriageCachePath (#1703). */
4
- export declare const AUDIT_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
4
+ export declare const AUDIT_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
5
5
  export { resolveCandidatesLogPath };
6
6
  /** Read every well-formed audit-log row in insertion order (#1698 shared reader). */
7
7
  export declare function readAuditLog(logPath: string, repo?: string | null): AuditEntry[];
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, relative } from "node:path";
3
- import { resolveLifecycleLayout } from "../../layout/resolve.js";
3
+ import { MIGRATED_ARTIFACT_DIR, resolveLifecycleLayout } from "../../layout/resolve.js";
4
4
  import { resolveCandidatesLogPath, resolveTriageCachePath, TRIAGE_CACHE_DIR_NAME, triageCacheRelPath, } from "../cache-path.js";
5
5
  /** POSIX-style display path for `absPath` relative to `projectRoot` (#2109). */
6
6
  function evalRelDisplay(projectRoot, absPath) {
@@ -13,11 +13,11 @@ export const GITIGNORE_DEFT_RUNTIME_SENTINELS = [
13
13
  ];
14
14
  /** Legacy static vbrief paths kept for tests referencing the pre-#1703 constant shape. */
15
15
  export const GITIGNORE_EVAL_ENTRIES = [
16
- "vbrief/.triage-cache/candidates.jsonl",
17
- "vbrief/.triage-cache/summary-history.jsonl",
18
- "vbrief/.triage-cache/scope-lifecycle.jsonl",
19
- "vbrief/.triage-cache/decompositions/",
20
- "vbrief/.triage-cache/doctor-state.json",
16
+ "xbrief/.triage-cache/candidates.jsonl",
17
+ "xbrief/.triage-cache/summary-history.jsonl",
18
+ "xbrief/.triage-cache/scope-lifecycle.jsonl",
19
+ "xbrief/.triage-cache/decompositions/",
20
+ "xbrief/.triage-cache/doctor-state.json",
21
21
  ];
22
22
  /** Layout-aware gitignore lines for triage working-set files (#1703). */
23
23
  export function gitignoreTriageCacheEntries(projectRoot) {
@@ -31,8 +31,14 @@ export function gitignoreTriageCacheEntries(projectRoot) {
31
31
  ];
32
32
  }
33
33
  export function gitattributesTriageCacheGlob(projectRoot) {
34
- const layout = resolveLifecycleLayout(projectRoot);
35
- return `${layout.artifactDir}/${TRIAGE_CACHE_DIR_NAME}/*.jsonl`;
34
+ let artifactDir;
35
+ try {
36
+ artifactDir = resolveLifecycleLayout(projectRoot).artifactDir;
37
+ }
38
+ catch {
39
+ artifactDir = MIGRATED_ARTIFACT_DIR; // No layout; default to xbrief/.
40
+ }
41
+ return `${artifactDir}/${TRIAGE_CACHE_DIR_NAME}/*.jsonl`;
36
42
  }
37
43
  export const GITATTRIBUTES_EVAL_RULE = "vbrief/.triage-cache/*.jsonl merge=union";
38
44
  export const FORBIDDEN_BLANKET_EVAL_LINES = [
@@ -154,8 +160,14 @@ operators should know:
154
160
  `;
155
161
  /** Layout-aware triage-cache README body for the active lifecycle tree (#2344 / #2349). */
156
162
  export function generateTriageCacheReadmeBody(projectRoot) {
157
- const layout = resolveLifecycleLayout(projectRoot);
158
- const triagePrefix = `${layout.artifactDir}/${TRIAGE_CACHE_DIR_NAME}`;
163
+ let artifactDir;
164
+ try {
165
+ artifactDir = resolveLifecycleLayout(projectRoot).artifactDir;
166
+ }
167
+ catch {
168
+ artifactDir = MIGRATED_ARTIFACT_DIR; // No layout; default to xbrief/.
169
+ }
170
+ const triagePrefix = `${artifactDir}/${TRIAGE_CACHE_DIR_NAME}`;
159
171
  return EVAL_README_BODY.replaceAll("vbrief/.triage-cache", triagePrefix);
160
172
  }
161
173
  function stepOutcome(name, ok, message, details = {}, error = null) {
@@ -2,7 +2,7 @@ import type { BootstrapResult, CacheModule, RunBootstrapOptions, StepOutcome } f
2
2
  export * from "./gitignore.js";
3
3
  export * from "./types.js";
4
4
  export declare const CACHE_DIR_NAME = ".deft-cache";
5
- export declare const AUDIT_LOG_RELPATH = "vbrief/.triage-cache/candidates.jsonl";
5
+ export declare const AUDIT_LOG_RELPATH = "xbrief/.triage-cache/candidates.jsonl";
6
6
  export declare const BACKFILL_FOLDERS: readonly ["proposed", "pending", "active"];
7
7
  export declare const BOOTSTRAP_ACTOR = "agent:bootstrap";
8
8
  export declare const DEFAULT_FETCH_TIMEOUT_S = 3600;
@@ -11,7 +11,7 @@ import { PROGRESS_DEFAULT } from "./types.js";
11
11
  export * from "./gitignore.js";
12
12
  export * from "./types.js";
13
13
  export const CACHE_DIR_NAME = ".deft-cache";
14
- export const AUDIT_LOG_RELPATH = "vbrief/.triage-cache/candidates.jsonl";
14
+ export const AUDIT_LOG_RELPATH = "xbrief/.triage-cache/candidates.jsonl";
15
15
  export const BACKFILL_FOLDERS = ["proposed", "pending", "active"];
16
16
  export const BOOTSTRAP_ACTOR = "agent:bootstrap";
17
17
  export const DEFAULT_FETCH_TIMEOUT_S = 3600;
@@ -374,9 +374,15 @@ export function stepBackfillAuditLog(projectRoot, repo, options = {}) {
374
374
  if (repo === null) {
375
375
  return stepOutcome("backfill_audit_log", true, "skipped (no --repo provided; pass --repo OWNER/NAME to backfill)", { skipped: "no-repo" });
376
376
  }
377
- const vbriefRoot = resolveLifecycleRoot(projectRoot);
377
+ let vbriefRoot;
378
+ try {
379
+ vbriefRoot = resolveLifecycleRoot(projectRoot);
380
+ }
381
+ catch {
382
+ return stepOutcome("backfill_audit_log", true, `skipped (no xbrief/ layout under ${projectRoot})`, { skipped: "no-xbrief" });
383
+ }
378
384
  if (!existsSync(vbriefRoot)) {
379
- return stepOutcome("backfill_audit_log", true, `skipped (no vbrief/ directory under ${projectRoot})`, { skipped: "no-vbrief" });
385
+ return stepOutcome("backfill_audit_log", true, `skipped (no xbrief/ directory under ${projectRoot})`, { skipped: "no-xbrief" });
380
386
  }
381
387
  const auditPath = resolveCandidatesLogPath(projectRoot);
382
388
  const alreadyLogged = existingAuditIssueNumbers(auditPath);
@@ -33,7 +33,7 @@ export declare function resolveTriageCachePath(projectRoot: string, ...segments:
33
33
  /** Display helper: project-root-relative POSIX path for logs and gitignore copy. */
34
34
  export declare function triageCacheDisplayPath(projectRoot: string, absPath: string): string;
35
35
  /** Back-compat display constant; resolution flows through `resolveTriageCachePath`. */
36
- export declare const TRIAGE_CANDIDATES_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
36
+ export declare const TRIAGE_CANDIDATES_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
37
37
  /** Layout-aware candidates audit-log path. */
38
38
  export declare function resolveCandidatesLogPath(projectRoot: string): string;
39
39
  /** Ensure the triage cache directory exists (post-migration). */
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { existsSync, mkdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
8
8
  import { join, relative } from "node:path";
9
- import { resolveEvalDir, resolveLifecycleLayout, resolveLifecycleRoot } from "../layout/resolve.js";
9
+ import { MIGRATED_ARTIFACT_DIR, resolveEvalDir, resolveLifecycleLayout, resolveLifecycleRoot, } from "../layout/resolve.js";
10
10
  import { generateTriageCacheReadmeBody } from "./bootstrap/gitignore.js";
11
11
  /** Directory name for the triage working-set cache (not version-eval results). */
12
12
  export const TRIAGE_CACHE_DIR_NAME = ".triage-cache";
@@ -26,19 +26,45 @@ export const TRIAGE_CACHE_FILE_NAMES = [
26
26
  export const TRIAGE_CACHE_DIR_NAMES = ["decompositions"];
27
27
  /** Absolute path to the layout-aware `.triage-cache/` directory. */
28
28
  export function resolveTriageCacheDir(projectRoot) {
29
- return join(resolveLifecycleRoot(projectRoot), TRIAGE_CACHE_DIR_NAME);
29
+ let layoutRoot;
30
+ try {
31
+ layoutRoot = resolveLifecycleRoot(projectRoot);
32
+ }
33
+ catch {
34
+ layoutRoot = join(projectRoot, MIGRATED_ARTIFACT_DIR); // No xbrief/ layout; use canonical path.
35
+ }
36
+ return join(layoutRoot, TRIAGE_CACHE_DIR_NAME);
30
37
  }
31
38
  /** POSIX-style path relative to project root (e.g. `xbrief/.triage-cache/foo`). */
32
39
  export function triageCacheRelPath(projectRoot, ...segments) {
33
- const layout = resolveLifecycleLayout(projectRoot);
34
- return [layout.artifactDir, TRIAGE_CACHE_DIR_NAME, ...segments].join("/");
40
+ let artifactDir;
41
+ try {
42
+ const layout = resolveLifecycleLayout(projectRoot);
43
+ artifactDir = layout.artifactDir;
44
+ }
45
+ catch {
46
+ artifactDir = "xbrief"; // No layout; default to xbrief/ path for display purposes.
47
+ }
48
+ return [artifactDir, TRIAGE_CACHE_DIR_NAME, ...segments].join("/");
35
49
  }
36
50
  /**
37
51
  * Idempotently move triage working-set artefacts from legacy `.eval/` into
38
52
  * `.triage-cache/` when the new location is absent.
39
53
  */
40
54
  export function migrateLegacyTriageCacheFromEval(projectRoot) {
41
- const legacyDir = resolveEvalDir(projectRoot);
55
+ let legacyDir;
56
+ try {
57
+ legacyDir = resolveEvalDir(projectRoot);
58
+ }
59
+ catch {
60
+ return {
61
+ migratedFiles: [],
62
+ skippedFiles: [],
63
+ migratedDirs: [],
64
+ regeneratedFiles: [],
65
+ removedLegacyFiles: [],
66
+ };
67
+ }
42
68
  const targetDir = resolveTriageCacheDir(projectRoot);
43
69
  const migratedFiles = [];
44
70
  const skippedFiles = [];
@@ -100,7 +126,7 @@ export function triageCacheDisplayPath(projectRoot, absPath) {
100
126
  return relative(projectRoot, absPath).split(/[\\/]/).join("/");
101
127
  }
102
128
  /** Back-compat display constant; resolution flows through `resolveTriageCachePath`. */
103
- export const TRIAGE_CANDIDATES_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
129
+ export const TRIAGE_CANDIDATES_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
104
130
  /** Layout-aware candidates audit-log path. */
105
131
  export function resolveCandidatesLogPath(projectRoot) {
106
132
  return resolveTriageCachePath(projectRoot, "candidates.jsonl");
@@ -1,5 +1,5 @@
1
1
  /** Filesystem-relative location of the PROJECT-DEFINITION vBRIEF. */
2
- export declare const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
2
+ export declare const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
3
3
  /** Threshold in days for the "dormant" universal rule (Decision 1). */
4
4
  export declare const DORMANT_AGE_DAYS = 90;
5
5
  /** Threshold in characters for "thin body" used by the dormant rule. */
@@ -30,7 +30,7 @@ function pythonRepr(value) {
30
30
  return pyRepr(value);
31
31
  }
32
32
  /** Filesystem-relative location of the PROJECT-DEFINITION vBRIEF. */
33
- export const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
33
+ export const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
34
34
  /** Threshold in days for the "dormant" universal rule (Decision 1). */
35
35
  export const DORMANT_AGE_DAYS = 90;
36
36
  /** Threshold in characters for "thin body" used by the dormant rule. */
@@ -255,7 +255,14 @@ export function validateHoldMarkers(markers) {
255
255
  return { errors, warnings };
256
256
  }
257
257
  export function projectDefinitionPath(projectRoot) {
258
- return resolveProjectDefinitionPath(projectRoot ?? process.cwd());
258
+ const root = projectRoot ?? process.cwd();
259
+ try {
260
+ return resolveProjectDefinitionPath(root);
261
+ }
262
+ catch {
263
+ // No xbrief/ layout; return canonical path so callers get a predictable "not found" result.
264
+ return join(root, "xbrief", "PROJECT-DEFINITION.xbrief.json");
265
+ }
259
266
  }
260
267
  function loadProjectDefinition(projectRoot) {
261
268
  const path = projectDefinitionPath(projectRoot);
@@ -698,7 +705,7 @@ export function validateProject(projectRoot) {
698
705
  return {
699
706
  code: 0,
700
707
  stdout: "OK: no PROJECT-DEFINITION at " +
701
- `${resolveProjectDefinitionPath(root)} -- ` +
708
+ `${projectDefinitionPath(root)} -- ` +
702
709
  "framework defaults apply with no consumer overrides.\n",
703
710
  stderr: "",
704
711
  };
@@ -711,7 +718,7 @@ export function validateProject(projectRoot) {
711
718
  stderr: "FAIL: PROJECT-DEFINITION.plan is not an object\n",
712
719
  };
713
720
  }
714
- const rel = resolveProjectDefinitionPath(root);
721
+ const rel = projectDefinitionPath(root);
715
722
  const classifyErrs = validateTriageAutoClassifyOnPlan(plan, rel);
716
723
  const holderErrs = validateTriageHoldMarkersOnPlan(plan, rel);
717
724
  const errors = [...classifyErrs, ...holderErrs];
@@ -1,11 +1,11 @@
1
- /** Auto-generated from scripts/triage_help.py -- do not edit by hand. */
1
+ /** Hand-maintained help registry. Edit directly; no generator script. */
2
2
  export declare const registryData: {
3
3
  readonly registry: {
4
4
  readonly "task triage:summary": {
5
5
  readonly name: "task triage:summary";
6
6
  readonly summary: "One-line state for session-start ritual";
7
7
  readonly refs: "(D2 / #1122)";
8
- readonly description: "Emit the one-line triage state consumed by the session-start ritual. Always exits 0 (status surface, not a gate); appends a JSONL record to vbrief/.triage-cache/summary-history.jsonl for observability.";
8
+ readonly description: "Emit the one-line triage state consumed by the session-start ritual. Always exits 0 (status surface, not a gate); appends a JSONL record to <lifecycle-root>/.triage-cache/summary-history.jsonl for observability.";
9
9
  readonly usage: "task triage:summary [-- --json] [--no-history]";
10
10
  readonly flags: readonly [readonly ["--json", "(off)", "Emit the structured record as JSON instead of the one-liner."], readonly ["--no-history", "(off)", "Suppress the history sidecar append (test-only)."], readonly ["--project-root PATH", "(cwd)", "Project root override (Taskfile threads USER_WORKING_DIR)."]];
11
11
  readonly examples: readonly ["task triage:summary", "task triage:summary -- --json | jq"];
@@ -1,11 +1,11 @@
1
- /** Auto-generated from scripts/triage_help.py -- do not edit by hand. */
1
+ /** Hand-maintained help registry. Edit directly; no generator script. */
2
2
  export const registryData = {
3
3
  registry: {
4
4
  "task triage:summary": {
5
5
  name: "task triage:summary",
6
6
  summary: "One-line state for session-start ritual",
7
7
  refs: "(D2 / #1122)",
8
- description: "Emit the one-line triage state consumed by the session-start ritual. Always exits 0 (status surface, not a gate); appends a JSONL record to vbrief/.triage-cache/summary-history.jsonl for observability.",
8
+ description: "Emit the one-line triage state consumed by the session-start ritual. Always exits 0 (status surface, not a gate); appends a JSONL record to <lifecycle-root>/.triage-cache/summary-history.jsonl for observability.",
9
9
  usage: "task triage:summary [-- --json] [--no-history]",
10
10
  flags: [
11
11
  ["--json", "(off)", "Emit the structured record as JSON instead of the one-liner."],
@@ -4,14 +4,14 @@ export declare const CACHE_DIR_NAME = ".deft-cache";
4
4
  export declare const CACHE_SOURCE_GITHUB_ISSUE = "github-issue";
5
5
  /** Env var honoured for repo inference when `--repo` is absent (#1238). */
6
6
  export declare const ENV_TRIAGE_REPO = "DEFT_TRIAGE_REPO";
7
- /** PROJECT-DEFINITION vBRIEF location for typed-policy lookup. */
8
- export declare const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
7
+ /** PROJECT-DEFINITION xBRIEF location for typed-policy lookup. */
8
+ export declare const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
9
9
  /** Default queue limit when `--limit` is omitted on the CLI surface. */
10
10
  export declare const DEFAULT_QUEUE_LIMIT = 25;
11
11
  /** Default audit log path relative to the deft framework root (candidates_log.REPO_ROOT). */
12
- export declare const DEFAULT_AUDIT_LOG_REL_PATH = "vbrief/.eval/candidates.jsonl";
12
+ export declare const DEFAULT_AUDIT_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
13
13
  /** Default slices log path relative to project root. */
14
- export declare const DEFAULT_SLICES_LOG_REL_PATH = "vbrief/.eval/slices.jsonl";
14
+ export declare const DEFAULT_SLICES_LOG_REL_PATH = "xbrief/.triage-cache/slices.jsonl";
15
15
  /** Group display order (#1128 / D13 / #1286). */
16
16
  export declare const GROUP_ORDER: readonly ["ORPHAN", "RESUME", "URGENT", "untriaged", "other", "BLOCKED"];
17
17
  export type QueueGroup = (typeof GROUP_ORDER)[number];
@@ -4,14 +4,14 @@ export const CACHE_DIR_NAME = ".deft-cache";
4
4
  export const CACHE_SOURCE_GITHUB_ISSUE = "github-issue";
5
5
  /** Env var honoured for repo inference when `--repo` is absent (#1238). */
6
6
  export const ENV_TRIAGE_REPO = "DEFT_TRIAGE_REPO";
7
- /** PROJECT-DEFINITION vBRIEF location for typed-policy lookup. */
8
- export const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
7
+ /** PROJECT-DEFINITION xBRIEF location for typed-policy lookup. */
8
+ export const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
9
9
  /** Default queue limit when `--limit` is omitted on the CLI surface. */
10
10
  export const DEFAULT_QUEUE_LIMIT = 25;
11
11
  /** Default audit log path relative to the deft framework root (candidates_log.REPO_ROOT). */
12
- export const DEFAULT_AUDIT_LOG_REL_PATH = "vbrief/.eval/candidates.jsonl";
12
+ export const DEFAULT_AUDIT_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
13
13
  /** Default slices log path relative to project root. */
14
- export const DEFAULT_SLICES_LOG_REL_PATH = "vbrief/.eval/slices.jsonl";
14
+ export const DEFAULT_SLICES_LOG_REL_PATH = "xbrief/.triage-cache/slices.jsonl";
15
15
  /** Group display order (#1128 / D13 / #1286). */
16
16
  export const GROUP_ORDER = ["ORPHAN", "RESUME", "URGENT", "untriaged", "other", "BLOCKED"];
17
17
  /** Display labels per group (left-of-issue marker). */
@@ -113,7 +113,13 @@ export function scopeIsBlocked(plan, completedIds) {
113
113
  return deps.length > 0 && deps.some((dep) => !completedIds.has(dep));
114
114
  }
115
115
  function walkScopeFolders(projectRoot, folders, visitor) {
116
- const base = resolveLifecycleRoot(projectRoot);
116
+ let base;
117
+ try {
118
+ base = resolveLifecycleRoot(projectRoot);
119
+ }
120
+ catch {
121
+ return; // No xbrief/ layout present -- nothing to walk.
122
+ }
117
123
  for (const folder of folders) {
118
124
  const folderDir = join(base, folder);
119
125
  if (!existsSync(folderDir)) {
@@ -40,7 +40,13 @@ export function findReconcilable(projectRoot, options = {}) {
40
40
  const items = [];
41
41
  const seen = new Set();
42
42
  for (const folderName of BACKFILL_FOLDERS) {
43
- const folderPath = resolveLifecycleFolder(root, folderName);
43
+ let folderPath;
44
+ try {
45
+ folderPath = resolveLifecycleFolder(root, folderName);
46
+ }
47
+ catch {
48
+ continue; // No xbrief/ layout; skip this folder.
49
+ }
44
50
  for (const [refRepo, number, path] of scanLifecycleRefs(folderPath)) {
45
51
  const effectiveRepo = refRepo ?? defaultRepo;
46
52
  if (effectiveRepo === null)
@@ -65,7 +71,14 @@ function countSkippedExisting(projectRoot, defaultRepo, auditPath) {
65
71
  let count = 0;
66
72
  const root = resolve(projectRoot);
67
73
  for (const folderName of BACKFILL_FOLDERS) {
68
- for (const [refRepo, number] of scanLifecycleRefs(resolveLifecycleFolder(root, folderName))) {
74
+ let folderPath;
75
+ try {
76
+ folderPath = resolveLifecycleFolder(root, folderName);
77
+ }
78
+ catch {
79
+ continue; // No xbrief/ layout; skip this folder.
80
+ }
81
+ for (const [refRepo, number] of scanLifecycleRefs(folderPath)) {
69
82
  const effectiveRepo = refRepo ?? defaultRepo;
70
83
  if (effectiveRepo === null)
71
84
  continue;
@@ -88,7 +101,14 @@ function countNoRepo(projectRoot, defaultRepo, auditPath) {
88
101
  let count = 0;
89
102
  const root = resolve(projectRoot);
90
103
  for (const folderName of BACKFILL_FOLDERS) {
91
- for (const [refRepo, number] of scanLifecycleRefs(resolveLifecycleFolder(root, folderName))) {
104
+ let folderPath;
105
+ try {
106
+ folderPath = resolveLifecycleFolder(root, folderName);
107
+ }
108
+ catch {
109
+ continue; // No xbrief/ layout; skip this folder.
110
+ }
111
+ for (const [refRepo, number] of scanLifecycleRefs(folderPath)) {
92
112
  if ((refRepo ?? defaultRepo) === null && !existingNumbers.has(number))
93
113
  count += 1;
94
114
  }
@@ -1,4 +1,4 @@
1
- export declare const AUDIT_LOG_RELPATH = "vbrief/.eval/candidates.jsonl";
1
+ export declare const AUDIT_LOG_RELPATH = "xbrief/.triage-cache/candidates.jsonl";
2
2
  export declare const BACKFILL_FOLDERS: readonly ["proposed", "pending", "active"];
3
3
  export declare const RECONCILE_ACTOR = "agent:reconcile";
4
4
  export interface ReconcileItem {
@@ -1,4 +1,4 @@
1
- export const AUDIT_LOG_RELPATH = "vbrief/.eval/candidates.jsonl";
1
+ export const AUDIT_LOG_RELPATH = "xbrief/.triage-cache/candidates.jsonl";
2
2
  export const BACKFILL_FOLDERS = ["proposed", "pending", "active"];
3
3
  export const RECONCILE_ACTOR = "agent:reconcile";
4
4
  export function reconcileSummary(result) {
@@ -1,4 +1,4 @@
1
- import { resolve } from "node:path";
1
+ import { join, resolve } from "node:path";
2
2
  import { resolveLifecycleFolder } from "../../layout/resolve.js";
3
3
  import { detectDrift } from "./drift.js";
4
4
  import { iterActiveVbriefs } from "./extract.js";
@@ -21,7 +21,14 @@ function defaultAuditWriter(repo, issueNumber, annotation, log) {
21
21
  }
22
22
  export function refreshActive(projectRoot, options = {}) {
23
23
  const root = resolve(projectRoot);
24
- const activeDir = options.activeDir ?? resolveLifecycleFolder(root, "active");
24
+ let defaultActiveDir;
25
+ try {
26
+ defaultActiveDir = resolveLifecycleFolder(root, "active");
27
+ }
28
+ catch {
29
+ defaultActiveDir = join(root, "xbrief", "active"); // No xbrief/ layout; use canonical path.
30
+ }
31
+ const activeDir = options.activeDir ?? defaultActiveDir;
25
32
  const log = options.log ?? ((line) => process.stdout.write(`${line}\n`));
26
33
  const inputFn = options.inputFn ?? (() => "");
27
34
  const refreshLocal = options.refreshLocal ?? (() => { });
@@ -1,6 +1,6 @@
1
1
  /** Framework default when plan.policy.triageScope is unset (#1131). */
2
2
  export declare const DEFAULT_TRIAGE_SCOPE: ReadonlyArray<Record<string, unknown>>;
3
- export declare const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
3
+ export declare const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
4
4
  export declare const CACHE_DIR_NAME = ".deft-cache";
5
5
  export declare const COVERAGE_FILENAME = "coverage.json";
6
6
  export declare const ENV_COVERAGE_TTL_HOURS = "DEFT_COVERAGE_MAX_AGE_HOURS";
@@ -11,6 +11,6 @@ export declare const VALID_IGNORE_KEYS: Set<string>;
11
11
  export declare const VALID_IGNORE_RULES: Set<string>;
12
12
  export declare const REFERENCED_BY_VBRIEF_SCOPES: Set<string>;
13
13
  export declare const SLICED_FROM_SCOPES: Set<string>;
14
- export declare const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.eval/subscription-history.jsonl";
14
+ export declare const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
15
15
  export declare const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
16
16
  //# sourceMappingURL=constants.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /** Framework default when plan.policy.triageScope is unset (#1131). */
2
2
  export const DEFAULT_TRIAGE_SCOPE = [{ rule: "all-open" }];
3
- export const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
3
+ export const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
4
4
  export const CACHE_DIR_NAME = ".deft-cache";
5
5
  export const COVERAGE_FILENAME = "coverage.json";
6
6
  export const ENV_COVERAGE_TTL_HOURS = "DEFT_COVERAGE_MAX_AGE_HOURS";
@@ -20,6 +20,6 @@ export const VALID_IGNORE_KEYS = new Set(["label", "milestone"]);
20
20
  export const VALID_IGNORE_RULES = new Set(["author"]);
21
21
  export const REFERENCED_BY_VBRIEF_SCOPES = new Set(["any", "active"]);
22
22
  export const SLICED_FROM_SCOPES = new Set(["any-umbrella-in-cache"]);
23
- export const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.eval/subscription-history.jsonl";
23
+ export const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
24
24
  export const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
25
25
  //# sourceMappingURL=constants.js.map
@@ -6,7 +6,13 @@ import { subscriptionHash } from "./normalize.js";
6
6
  import { pyListRepr } from "./python-repr.js";
7
7
  const LIFECYCLE_FOLDERS = ["proposed", "pending", "active", "completed", "cancelled"];
8
8
  export function extractReferencedIssues(projectRoot, lifecycleFolders = LIFECYCLE_FOLDERS) {
9
- const root = resolveLifecycleRoot(projectRoot);
9
+ let root;
10
+ try {
11
+ root = resolveLifecycleRoot(projectRoot);
12
+ }
13
+ catch {
14
+ return { any: new Set(), active: new Set() };
15
+ }
10
16
  const anySet = new Set();
11
17
  const activeSet = new Set();
12
18
  if (!existsSync(root))
@@ -119,21 +119,24 @@ function defaultScriptRunner(scriptsDir) {
119
119
  export function copyFixtureToTmp(fixtureRoot, tmpRoot) {
120
120
  const project = tmpRoot;
121
121
  mkdirSync(project, { recursive: true });
122
- mkdirSync(join(project, "vbrief"), { recursive: true });
123
- copyFileSync(join(fixtureRoot, "PROJECT-DEFINITION.vbrief.json"), join(project, "vbrief", "PROJECT-DEFINITION.vbrief.json"));
122
+ mkdirSync(join(project, "xbrief"), { recursive: true });
123
+ const srcPD = join(fixtureRoot, "PROJECT-DEFINITION.xbrief.json");
124
+ if (existsSync(srcPD)) {
125
+ copyFileSync(srcPD, join(project, "xbrief", "PROJECT-DEFINITION.xbrief.json"));
126
+ }
124
127
  for (const sub of ["active", "proposed", "pending", "completed", "cancelled"]) {
125
- const srcDir = join(fixtureRoot, "vbrief", sub);
126
- const dstDir = join(project, "vbrief", sub);
128
+ const srcDir = join(fixtureRoot, "xbrief", sub);
129
+ const dstDir = join(project, "xbrief", sub);
127
130
  mkdirSync(dstDir, { recursive: true });
128
131
  if (existsSync(srcDir)) {
129
132
  for (const name of readdirSync(srcDir)) {
130
- if (name.endsWith(".vbrief.json")) {
133
+ if (name.endsWith(".xbrief.json")) {
131
134
  copyFileSync(join(srcDir, name), join(dstDir, name));
132
135
  }
133
136
  }
134
137
  }
135
138
  }
136
- mkdirSync(join(project, "vbrief", ".eval"), { recursive: true });
139
+ mkdirSync(join(project, "xbrief", ".eval"), { recursive: true });
137
140
  return project;
138
141
  }
139
142
  function defaultInlineRunner() {
@@ -1,6 +1,6 @@
1
- export declare const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.triage-cache/subscription-history.jsonl";
1
+ export declare const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
2
2
  export declare const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
3
- export declare const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
3
+ export declare const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
4
4
  /** Python ``!r``-style quoting for parity with triage_subscribe.py messages. */
5
5
  export declare function pyRepr(value: string): string;
6
6
  export declare class ProjectDefinitionIOError extends Error {
@@ -5,9 +5,9 @@ import { resolveProjectDefinitionPath } from "../../layout/resolve.js";
5
5
  import { migrateLegacyPolicyKey, PLAN_POLICY_KEY } from "../../policy/plan-extensions.js";
6
6
  import { projectDefinitionMutationLock } from "../../vbrief-build/project-definition-io.js";
7
7
  import { resolveTriageCachePath } from "../cache-path.js";
8
- export const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.triage-cache/subscription-history.jsonl";
8
+ export const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
9
9
  export const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
10
- export const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
10
+ export const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
11
11
  /** Python ``!r``-style quoting for parity with triage_subscribe.py messages. */
12
12
  export function pyRepr(value) {
13
13
  return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;