@dotdotgod/claude-code 0.6.4 → 0.6.6

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/mcp/cli.mjs CHANGED
@@ -538,7 +538,7 @@ var init_languages = __esm({
538
538
  ".zsh",
539
539
  ".fish"
540
540
  ]);
541
- EXTRACTOR_ID = "outline-v3:vscode-tree-sitter-wasm-0.3.1";
541
+ EXTRACTOR_ID = "outline-v4:vscode-0.3.1:typescript-import-types-1";
542
542
  DECLARATIONS = {
543
543
  function_declaration: "function",
544
544
  generator_function_declaration: "function",
@@ -576,19 +576,24 @@ var init_languages = __esm({
576
576
 
577
577
  // packages/cli/src/symbols/runtime.mjs
578
578
  import { createRequire } from "node:module";
579
- import { existsSync as existsSync9, readFileSync as readFileSync9 } from "node:fs";
580
- import { dirname as dirname5, join as join8 } from "node:path";
579
+ import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
580
+ import { dirname as dirname6, join as join9 } from "node:path";
581
581
  import { fileURLToPath } from "node:url";
582
582
  import { createHash as createHash4 } from "node:crypto";
583
+ function languageAsset(language) {
584
+ const patched = fileURLToPath(new URL(`./parsers/tree-sitter-${language}.wasm`, import.meta.url));
585
+ return existsSync10(patched) ? patched : join9(dirname6(parserEntry()), `tree-sitter-${language}.wasm`);
586
+ }
583
587
  function parserEntry() {
584
588
  const bundled = fileURLToPath(new URL("./parsers/tree-sitter.cjs", import.meta.url));
585
- return existsSync9(bundled) ? bundled : require2.resolve("@vscode/tree-sitter-wasm");
589
+ return existsSync10(bundled) ? bundled : require2.resolve("@vscode/tree-sitter-wasm");
586
590
  }
587
591
  function parserIdentity() {
588
592
  if (!identity) {
589
593
  const entry = parserEntry();
590
- const hash2 = createHash4("sha256").update(readFileSync9(entry));
591
- for (const name of ["tree-sitter.wasm", ...Object.keys(LANGUAGE_EXTENSIONS).map((language) => `tree-sitter-${language}.wasm`)]) hash2.update(name).update(readFileSync9(join8(dirname5(entry), name)));
594
+ const hash2 = createHash4("sha256").update(readFileSync10(entry));
595
+ hash2.update(readFileSync10(join9(dirname6(entry), "tree-sitter.wasm")));
596
+ for (const language of Object.keys(LANGUAGE_EXTENSIONS)) hash2.update(language).update(readFileSync10(languageAsset(language)));
592
597
  identity = hash2.digest("hex");
593
598
  }
594
599
  return identity;
@@ -609,17 +614,17 @@ var parser_exports = {};
609
614
  __export(parser_exports, {
610
615
  extractSymbols: () => extractSymbols
611
616
  });
612
- import { dirname as dirname6, join as join10 } from "node:path";
617
+ import { dirname as dirname7 } from "node:path";
613
618
  import { createHash as createHash5 } from "node:crypto";
614
619
  async function parserFor(language) {
615
620
  if (!runtime) runtime = (async () => {
616
621
  const entry = parserEntry();
617
622
  const api2 = loadParserApi();
618
623
  await api2.Parser.init();
619
- return { api: api2, directory: dirname6(entry) };
624
+ return { api: api2, directory: dirname7(entry) };
620
625
  })();
621
626
  const { api, directory } = await runtime;
622
- if (!languages.has(language)) languages.set(language, api.Language.load(join10(directory, `tree-sitter-${language}.wasm`)));
627
+ if (!languages.has(language)) languages.set(language, api.Language.load(languageAsset(language)));
623
628
  const loaded = await languages.get(language);
624
629
  const parser = new api.Parser();
625
630
  parser.setLanguage(loaded);
@@ -756,8 +761,8 @@ var init_parser = __esm({
756
761
  });
757
762
 
758
763
  // packages/cli/src/init.mjs
759
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, statSync, writeFileSync } from "node:fs";
760
- import { basename, dirname, join as join4, resolve as resolve2 } from "node:path";
764
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync2 } from "node:fs";
765
+ import { basename, dirname as dirname2, join as join5, resolve as resolve3 } from "node:path";
761
766
 
762
767
  // packages/cli/src/config/templates.mjs
763
768
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
@@ -855,6 +860,15 @@ import { homedir } from "node:os";
855
860
  import { join } from "node:path";
856
861
  var DEFAULT_EMBEDDING_PROFILE = Object.freeze({ provider: "local", model: "Xenova/multilingual-e5-small" });
857
862
  var EMBEDDING_PROVIDERS = Object.freeze(["local", "openai-compatible", "ollama"]);
863
+ var DEFAULT_INPUT_FORMAT = Object.freeze({ queryPrefix: "query: ", documentPrefix: "passage: " });
864
+ function embeddingInputFormat(profile, label = "embedding") {
865
+ if (profile.inputFormat === void 0) return { ...DEFAULT_INPUT_FORMAT };
866
+ const format = profile.inputFormat;
867
+ if (!format || typeof format !== "object" || Array.isArray(format) || Object.keys(format).some((key) => !Object.hasOwn(DEFAULT_INPUT_FORMAT, key)) || Object.keys(DEFAULT_INPUT_FORMAT).some((key) => typeof format[key] !== "string")) {
868
+ throw new Error(`${label}.inputFormat must contain exactly queryPrefix and documentPrefix strings.`);
869
+ }
870
+ return { queryPrefix: format.queryPrefix, documentPrefix: format.documentPrefix };
871
+ }
858
872
  function readJson(path, label) {
859
873
  if (!existsSync(path)) return null;
860
874
  try {
@@ -865,7 +879,7 @@ function readJson(path, label) {
865
879
  }
866
880
  function validateEmbeddingProfile(profile, label = "embedding") {
867
881
  if (!profile || typeof profile !== "object" || Array.isArray(profile)) throw new Error(`${label} must be an object.`);
868
- const allowed = /* @__PURE__ */ new Set(["provider", "model", "baseUrl", "apiKey", "apiKeyEnv"]);
882
+ const allowed = /* @__PURE__ */ new Set(["provider", "model", "baseUrl", "apiKey", "apiKeyEnv", "inputFormat"]);
869
883
  const unknown = Object.keys(profile).find((key) => !allowed.has(key));
870
884
  if (unknown) throw new Error(`${label}.${unknown} is not supported.`);
871
885
  if (!EMBEDDING_PROVIDERS.includes(profile.provider)) throw new Error(`${label}.provider must be local, openai-compatible, or ollama.`);
@@ -883,15 +897,22 @@ function validateEmbeddingProfile(profile, label = "embedding") {
883
897
  if (!["http:", "https:"].includes(url.protocol)) throw new Error(`${label}.baseUrl must use HTTP or HTTPS.`);
884
898
  if (url.username || url.password) throw new Error(`${label}.baseUrl must not contain credentials.`);
885
899
  }
900
+ embeddingInputFormat(profile, label);
886
901
  return { ...profile, model: profile.model.trim(), ...profile.baseUrl ? { baseUrl: profile.baseUrl.replace(/\/$/, "") } : {} };
887
902
  }
888
903
  function sanitizeEmbeddingProfile(profile) {
904
+ if (!profile) return null;
889
905
  const { apiKey, ...safe } = profile;
890
906
  return { ...safe, ...apiKey ? { apiKey: "[redacted]" } : {} };
891
907
  }
892
908
  function embeddingProfileIdentity(profile) {
893
- const { apiKey, apiKeyEnv, ...identity2 } = profile;
894
- return identity2;
909
+ return {
910
+ provider: profile.provider,
911
+ model: profile.model,
912
+ ...profile.baseUrl !== void 0 ? { baseUrl: profile.baseUrl } : {},
913
+ inputFormatVersion: 1,
914
+ inputFormat: embeddingInputFormat(profile)
915
+ };
895
916
  }
896
917
  function resolveEmbeddingProfile(root = ".", options = {}) {
897
918
  const home = options.home ?? homedir();
@@ -901,7 +922,7 @@ function resolveEmbeddingProfile(root = ".", options = {}) {
901
922
  if (projectConfig && Object.hasOwn(projectConfig, "embedding")) return { profile: validateEmbeddingProfile(projectConfig.embedding, "project embedding"), source: "project", path: projectPath };
902
923
  const globalConfig = readJson(globalPath, "global config");
903
924
  if (globalConfig && Object.hasOwn(globalConfig, "embedding")) return { profile: validateEmbeddingProfile(globalConfig.embedding, "global embedding"), source: "global", path: globalPath };
904
- return { profile: { ...DEFAULT_EMBEDDING_PROFILE }, source: "default", path: null };
925
+ return { profile: null, source: "not-configured", path: null };
905
926
  }
906
927
 
907
928
  // packages/cli/src/memory/config.mjs
@@ -1687,6 +1708,60 @@ function resolveInitializationTemplate(explicitName = null, home = dotdotgodHome
1687
1708
  ` };
1688
1709
  }
1689
1710
 
1711
+ // packages/cli/src/claude-plans.mjs
1712
+ import { existsSync as existsSync4, lstatSync, readFileSync as readFileSync4, realpathSync, writeFileSync, mkdirSync } from "node:fs";
1713
+ import { dirname, join as join4, relative as relative2, resolve as resolve2, isAbsolute } from "node:path";
1714
+ function prepareClaudePlans(root, documentationRoot) {
1715
+ const path = join4(root, ".claude", "settings.json");
1716
+ for (const target of [join4(root, ".claude"), path]) {
1717
+ try {
1718
+ if (lstatSync(target).isSymbolicLink()) throw new Error(`Refusing symlink: ${target}`);
1719
+ } catch (error) {
1720
+ if (error.code !== "ENOENT") throw error;
1721
+ }
1722
+ }
1723
+ const base = resolve2(root);
1724
+ if (existsSync4(dirname(path))) {
1725
+ const rel2 = relative2(realpathSync(base), realpathSync(dirname(path)));
1726
+ if (rel2.startsWith("..") || isAbsolute(rel2)) throw new Error("Claude settings must stay inside the project.");
1727
+ }
1728
+ const current = existsSync4(path) ? readFileSync4(path, "utf8") : null;
1729
+ const settings = current === null ? {} : JSON.parse(current);
1730
+ if (!settings || typeof settings !== "object" || Array.isArray(settings)) throw new Error("Claude settings must be a JSON object.");
1731
+ const value = `./${documentationRoot}/plan`;
1732
+ if (Object.hasOwn(settings, "plansDirectory")) return {
1733
+ status: "skipped",
1734
+ path,
1735
+ reason: "Existing plansDirectory preserved.",
1736
+ value: settings.plansDirectory
1737
+ };
1738
+ return {
1739
+ status: current === null ? "created" : "updated",
1740
+ path,
1741
+ value,
1742
+ current,
1743
+ content: `${JSON.stringify({ ...settings, plansDirectory: value }, null, 2)}
1744
+ `
1745
+ };
1746
+ }
1747
+ function applyClaudePlans(prepared, dryRun) {
1748
+ const { content, current, ...result } = prepared;
1749
+ if (!content) return result;
1750
+ if (dryRun) return { ...result, status: `would_${result.status === "created" ? "create" : "update"}` };
1751
+ for (const target of [dirname(prepared.path), prepared.path]) {
1752
+ try {
1753
+ if (lstatSync(target).isSymbolicLink()) throw new Error(`Refusing symlink: ${target}`);
1754
+ } catch (error) {
1755
+ if (error.code !== "ENOENT") throw error;
1756
+ }
1757
+ }
1758
+ const latest = existsSync4(prepared.path) ? readFileSync4(prepared.path, "utf8") : null;
1759
+ if (latest !== current) throw new Error("Claude settings changed during initialization; retry without overwriting them.");
1760
+ mkdirSync(dirname(prepared.path), { recursive: true });
1761
+ writeFileSync(prepared.path, content, { flag: current === null ? "wx" : "w" });
1762
+ return result;
1763
+ }
1764
+
1690
1765
  // packages/cli/src/init.mjs
1691
1766
  function action(status, path, extra = {}) {
1692
1767
  return { status, path, ...extra };
@@ -1702,6 +1777,7 @@ function parseInitOptions(argv) {
1702
1777
  if (arg === "--json") options.json = true;
1703
1778
  else if (arg === "--dotdot-setting") options.dotdotSetting = true;
1704
1779
  else if (arg === "--dry-run") options.dryRun = true;
1780
+ else if (arg === "--claude-plans") options.claudePlans = true;
1705
1781
  else if (arg === "--project-name" || arg === "--template" || arg === "--documentation-root") {
1706
1782
  const value = argv[i + 1];
1707
1783
  if (!value || value.startsWith("-")) throw new Error(`${arg} requires a value`);
@@ -1722,7 +1798,7 @@ function parseInitOptions(argv) {
1722
1798
  }
1723
1799
  if (!options.root) throw new Error("Missing required argument: <root>");
1724
1800
  if (!isValidDocumentationRoot(options.documentationRoot)) throw new Error("Invalid --documentation-root: expected a safe repository-relative directory");
1725
- options.root = resolve2(options.root);
1801
+ options.root = resolve3(options.root);
1726
1802
  if (!options.projectName) options.projectName = basename(options.root);
1727
1803
  return options;
1728
1804
  }
@@ -1735,8 +1811,8 @@ function initError(options, code, message) {
1735
1811
  process.exit(2);
1736
1812
  }
1737
1813
  function writeInitFile(options, relativePath, content, actions) {
1738
- const target = join4(options.root, relativePath);
1739
- if (existsSync4(target)) {
1814
+ const target = join5(options.root, relativePath);
1815
+ if (existsSync5(target)) {
1740
1816
  actions.push(action("skipped", target));
1741
1817
  return;
1742
1818
  }
@@ -1744,14 +1820,14 @@ function writeInitFile(options, relativePath, content, actions) {
1744
1820
  actions.push(action("would_create", target));
1745
1821
  return;
1746
1822
  }
1747
- mkdirSync(dirname(target), { recursive: true });
1748
- writeFileSync(target, content.endsWith("\n") ? content : `${content}
1823
+ mkdirSync2(dirname2(target), { recursive: true });
1824
+ writeFileSync2(target, content.endsWith("\n") ? content : `${content}
1749
1825
  `);
1750
1826
  actions.push(action("created", target));
1751
1827
  }
1752
1828
  function ensureInitDirectory(options, relativePath, actions) {
1753
- const target = join4(options.root, relativePath);
1754
- if (existsSync4(target)) {
1829
+ const target = join5(options.root, relativePath);
1830
+ if (existsSync5(target)) {
1755
1831
  actions.push(action("skipped", target));
1756
1832
  return;
1757
1833
  }
@@ -1759,22 +1835,22 @@ function ensureInitDirectory(options, relativePath, actions) {
1759
1835
  actions.push(action("would_create", target));
1760
1836
  return;
1761
1837
  }
1762
- mkdirSync(target, { recursive: true });
1838
+ mkdirSync2(target, { recursive: true });
1763
1839
  actions.push(action("created", target));
1764
1840
  }
1765
1841
  function ensureGitignoreEntry(options, entry, actions) {
1766
- const target = join4(options.root, ".gitignore");
1767
- const existed = existsSync4(target);
1768
- let current = existed ? readFileSync4(target, "utf8") : "";
1842
+ const target = join5(options.root, ".gitignore");
1843
+ const existed = existsSync5(target);
1844
+ let current = existed ? readFileSync5(target, "utf8") : "";
1769
1845
  if (current.split(/\r?\n/).includes(entry)) return;
1770
1846
  if (options.dryRun) {
1771
1847
  actions.push(action(existed ? "would_update" : "would_create", target, { add: entry }));
1772
1848
  return;
1773
1849
  }
1774
- mkdirSync(options.root, { recursive: true });
1850
+ mkdirSync2(options.root, { recursive: true });
1775
1851
  if (current.length > 0 && !current.endsWith("\n")) current = `${current}
1776
1852
  `;
1777
- writeFileSync(target, `${current}${entry}
1853
+ writeFileSync2(target, `${current}${entry}
1778
1854
  `);
1779
1855
  actions.push(action(existed ? "updated" : "created", target, { add: entry }));
1780
1856
  }
@@ -1978,15 +2054,26 @@ function runInit(argv, usage2) {
1978
2054
  usage2(error instanceof Error ? error.message : String(error), "init");
1979
2055
  return;
1980
2056
  }
1981
- if (!options.dryRun && existsSync4(options.root)) {
2057
+ if (!options.dryRun && existsSync5(options.root)) {
1982
2058
  try {
1983
2059
  if (!statSync(options.root).isDirectory()) initError(options, "ROOT_NOT_DIRECTORY", `Project root is not a directory: ${options.root}`);
1984
2060
  } catch {
1985
2061
  initError(options, "ROOT_NOT_FOUND", `Project root not found: ${options.root}`);
1986
2062
  }
1987
2063
  }
1988
- if (!options.dryRun) mkdirSync(options.root, { recursive: true });
1989
- const configExists = existsSync4(join4(options.root, "dotdotgod.config.json"));
2064
+ if (options.claudePlans && !options.documentationRootExplicit && existsSync5(join5(options.root, "dotdotgod.config.json"))) {
2065
+ options.documentationRoot = readMemoryConfig(options.root).documentation.root;
2066
+ }
2067
+ let claudePlans;
2068
+ if (options.claudePlans) {
2069
+ try {
2070
+ claudePlans = prepareClaudePlans(options.root, options.documentationRoot);
2071
+ } catch (error) {
2072
+ initError(options, "CLAUDE_SETTINGS_INVALID", error.message);
2073
+ }
2074
+ }
2075
+ if (!options.dryRun) mkdirSync2(options.root, { recursive: true });
2076
+ const configExists = existsSync5(join5(options.root, "dotdotgod.config.json"));
1990
2077
  if (configExists && options.documentationRootExplicit) {
1991
2078
  const existingRoot = readMemoryConfig(options.root).documentation.root;
1992
2079
  if (existingRoot !== options.documentationRoot) initError(options, "DOCUMENTATION_ROOT_CONFLICT", `Existing config uses documentation root ${existingRoot}; initialization does not migrate documentation.`);
@@ -2009,6 +2096,13 @@ function runInit(argv, usage2) {
2009
2096
  }
2010
2097
  writeInitFile(options, "dotdotgod.config.json", template?.text ?? "", actions);
2011
2098
  for (const entry of [`${options.documentationRoot}/plan`, `${options.documentationRoot}/archive`, ".dotdotgod"]) ensureGitignoreEntry(options, entry, actions);
2099
+ if (claudePlans) {
2100
+ try {
2101
+ actions.push(applyClaudePlans(claudePlans, options.dryRun));
2102
+ } catch (error) {
2103
+ initError(options, "CLAUDE_SETTINGS_CHANGED", error.message);
2104
+ }
2105
+ }
2012
2106
  const payload = { ok: true, command: "init", root: options.root, projectName: options.projectName, documentationRoot: options.documentationRoot, dryRun: options.dryRun, dotdotSetting: options.dotdotSetting, template: template ? { name: template.name, source: template.source, selectedBy: template.selectedBy } : null, actions };
2013
2107
  if (options.json) console.log(JSON.stringify(payload, null, 2));
2014
2108
  else {
@@ -2018,8 +2112,8 @@ function runInit(argv, usage2) {
2018
2112
  }
2019
2113
 
2020
2114
  // packages/cli/src/cli/usage.mjs
2021
- import { readFileSync as readFileSync5 } from "node:fs";
2022
- import { resolve as resolve3 } from "node:path";
2115
+ import { readFileSync as readFileSync6 } from "node:fs";
2116
+ import { resolve as resolve4 } from "node:path";
2023
2117
  var HELP_TOKENS = /* @__PURE__ */ new Set(["help", "--help", "-h"]);
2024
2118
  var VERSION_TOKENS = /* @__PURE__ */ new Set(["version", "--version", "-v"]);
2025
2119
  function commandUsage(command = "root") {
@@ -2029,9 +2123,10 @@ function commandUsage(command = "root") {
2029
2123
  dotdotgod validate <root> [--include-local-memory] [--check-index] [--max-lines n] [--max-chars n] [--no-link-check] [--json]`;
2030
2124
  case "init":
2031
2125
  return `Usage:
2032
- dotdotgod init <root> [--project-name NAME] [--template NAME] [--documentation-root PATH] [--dotdot-setting] [--dry-run] [--json]
2126
+ dotdotgod init <root> [--project-name NAME] [--template NAME] [--documentation-root PATH] [--dotdot-setting] [--claude-plans] [--dry-run] [--json]
2033
2127
 
2034
- Create AGENTS.md, agent entrypoints, docs indexes, a project config from an initialization template, and local memory gitignore entries.`;
2128
+ Create AGENTS.md, agent entrypoints, docs indexes, a project config from an initialization template, and local memory gitignore entries.
2129
+ Use --claude-plans only after opting into project-local native plan storage; existing Claude settings are preserved.`;
2035
2130
  case "index":
2036
2131
  return `Usage:
2037
2132
  dotdotgod index <root> [--json]`;
@@ -2051,9 +2146,9 @@ Create dotdotgod.config.json from a bundled or user template. Without --template
2051
2146
  dotdotgod status <root> [--json]`;
2052
2147
  case "query":
2053
2148
  return `Usage:
2054
- dotdotgod query <root> <query> [--limit n] [--scope docs|code|all] [--search hybrid|keyword|vector] [--allow-code-embedding] [--json]
2149
+ dotdotgod query <root> <query> [--limit n] [--scope docs|code|all] [--search hybrid|keyword|vector] [--json]
2055
2150
 
2056
- Search full documentation and code outlines/comments. Default: hybrid docs+code. Remote code metadata requires explicit consent.`;
2151
+ Search full documentation and code outlines/comments. Default: hybrid docs+code. Selecting a remote embedding profile authorizes code metadata transmission.`;
2057
2152
  case "embedding":
2058
2153
  return `Usage:
2059
2154
  dotdotgod embedding status [<root>] [--json]
@@ -2158,7 +2253,7 @@ function isVersionToken(value) {
2158
2253
  function printVersion() {
2159
2254
  let version = "unknown";
2160
2255
  try {
2161
- const data = JSON.parse(readFileSync5(new URL("../../package.json", import.meta.url), "utf8"));
2256
+ const data = JSON.parse(readFileSync6(new URL("../../package.json", import.meta.url), "utf8"));
2162
2257
  if (typeof data.version === "string") version = data.version;
2163
2258
  } catch {
2164
2259
  }
@@ -2180,17 +2275,17 @@ function parseCommon(argv) {
2180
2275
  if (arg === "--json") options.json = true;
2181
2276
  else if (!arg.startsWith("-") && options.root === ".") options.root = arg;
2182
2277
  }
2183
- options.root = resolve3(options.root);
2278
+ options.root = resolve4(options.root);
2184
2279
  return options;
2185
2280
  }
2186
2281
 
2187
2282
  // packages/cli/src/validate/run.mjs
2188
- import { existsSync as existsSync13, readFileSync as readFileSync13, readdirSync as readdirSync3 } from "node:fs";
2189
- import { basename as basename7, dirname as dirname10, extname as extname6, join as join13, resolve as resolve8 } from "node:path";
2283
+ import { existsSync as existsSync14, readFileSync as readFileSync14, readdirSync as readdirSync3 } from "node:fs";
2284
+ import { basename as basename7, dirname as dirname11, extname as extname6, join as join13, resolve as resolve9 } from "node:path";
2190
2285
 
2191
2286
  // packages/cli/src/docs/traceability.mjs
2192
- import { existsSync as existsSync5 } from "node:fs";
2193
- import { basename as basename2, dirname as dirname2, extname, relative as relative2, resolve as resolve4 } from "node:path";
2287
+ import { existsSync as existsSync6 } from "node:fs";
2288
+ import { basename as basename2, dirname as dirname3, extname, relative as relative3, resolve as resolve5 } from "node:path";
2194
2289
  function isSecretIndexPath(path) {
2195
2290
  return /(^|\/)(\.env|\.npmrc|\.pypirc|id_rsa|id_dsa|id_ed25519|credentials|secrets?)(\.|\/|$)/i.test(path);
2196
2291
  }
@@ -2289,9 +2384,9 @@ function stripTraceabilityLinksRegion(content) {
2289
2384
  return stripped.replace(/(?:^[ \t]*\r?\n)*^##[ \t]+Traceability[ \t]*\r?(?:\n(?:[ \t]*\r?\n)*|$)/gm, "");
2290
2385
  }
2291
2386
  function markdownLinkPath(root, file, target) {
2292
- const fromDir = dirname2(file);
2293
- const absoluteTarget = resolve4(root, target);
2294
- let link = relative2(fromDir, absoluteTarget).split("\\").join("/");
2387
+ const fromDir = dirname3(file);
2388
+ const absoluteTarget = resolve5(root, target);
2389
+ let link = relative3(fromDir, absoluteTarget).split("\\").join("/");
2295
2390
  if (!link.startsWith(".") && !link.startsWith("/")) link = link || basename2(target);
2296
2391
  return link;
2297
2392
  }
@@ -2390,7 +2485,7 @@ function validateTraceabilityPathArray(data, field2, add, root, config, { requir
2390
2485
  add("TRACEABILITY_LOCAL_MEMORY_TARGET", displayField, `target points to local memory area "${area2.id}": ${value}. Traceability must point to shared durable files, not active plans or archive memory.`);
2391
2486
  continue;
2392
2487
  }
2393
- if (!existsSync5(resolve4(root, value))) add("TRACEABILITY_MISSING_TARGET", displayField, `target does not exist: ${value}.`);
2488
+ if (!existsSync6(resolve5(root, value))) add("TRACEABILITY_MISSING_TARGET", displayField, `target does not exist: ${value}.`);
2394
2489
  }
2395
2490
  }
2396
2491
  function validateTraceabilityCommandArray(data, field2, add, { required = true, displayField = field2 } = {}) {
@@ -2458,9 +2553,9 @@ function validateTraceabilityBlock(data, root, file, line = null, config = defau
2458
2553
 
2459
2554
  // packages/cli/src/index/files.mjs
2460
2555
  import { createHash } from "node:crypto";
2461
- import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync, statSync as statSync2 } from "node:fs";
2556
+ import { existsSync as existsSync7, readFileSync as readFileSync7, readdirSync, statSync as statSync2 } from "node:fs";
2462
2557
  import { spawnSync } from "node:child_process";
2463
- import { basename as basename3, extname as extname2, join as join5 } from "node:path";
2558
+ import { basename as basename3, extname as extname2, join as join6 } from "node:path";
2464
2559
 
2465
2560
  // packages/cli/src/index/constants.mjs
2466
2561
  var CACHE_VERSION = 15;
@@ -2621,7 +2716,7 @@ function walkIndexCandidates(root, config = readMemoryConfig(root)) {
2621
2716
  const files = [];
2622
2717
  const walk = (dir) => {
2623
2718
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
2624
- const path = join5(dir, entry.name);
2719
+ const path = join6(dir, entry.name);
2625
2720
  const pathRel = rel(root, path);
2626
2721
  if (entry.isDirectory()) {
2627
2722
  const area2 = resolveMemoryArea(pathRel, config);
@@ -2635,7 +2730,7 @@ function walkIndexCandidates(root, config = readMemoryConfig(root)) {
2635
2730
  function addConfiguredLocalMemoryCandidates(root, candidates, config, limit = 5e3) {
2636
2731
  let added = 0;
2637
2732
  const addPath = (path) => {
2638
- if (added >= limit || !existsSync6(path)) return;
2733
+ if (added >= limit || !existsSync7(path)) return;
2639
2734
  let stat;
2640
2735
  try {
2641
2736
  stat = statSync2(path);
@@ -2651,7 +2746,7 @@ function addConfiguredLocalMemoryCandidates(root, candidates, config, limit = 5e
2651
2746
  if (!stat.isDirectory() || isExcludedIndexDir(pathRel)) return;
2652
2747
  for (const entry of readdirSync(path, { withFileTypes: true })) {
2653
2748
  if (added >= limit) return;
2654
- addPath(join5(path, entry.name));
2749
+ addPath(join6(path, entry.name));
2655
2750
  }
2656
2751
  };
2657
2752
  for (const area2 of config.areas ?? []) {
@@ -2659,30 +2754,30 @@ function addConfiguredLocalMemoryCandidates(root, candidates, config, limit = 5e
2659
2754
  for (const pattern of area2.paths ?? []) {
2660
2755
  if (pattern.startsWith("**/")) continue;
2661
2756
  const base = pattern.endsWith("/**") ? pattern.slice(0, -3) : pattern;
2662
- addPath(join5(root, base));
2757
+ addPath(join6(root, base));
2663
2758
  }
2664
2759
  }
2665
2760
  }
2666
2761
  function collectIndexFiles(root, config = readMemoryConfig(root)) {
2667
2762
  const candidates = new Set(gitIndexCandidates(root) ?? walkIndexCandidates(root, config));
2668
2763
  addConfiguredLocalMemoryCandidates(root, candidates, config);
2669
- return [...candidates].filter((path) => shouldIndexPath(path, config)).map((path) => join5(root, path)).filter(existsSync6).sort();
2764
+ return [...candidates].filter((path) => shouldIndexPath(path, config)).map((path) => join6(root, path)).filter(existsSync7).sort();
2670
2765
  }
2671
2766
  function fingerprint(file) {
2672
- const content = readFileSync6(file);
2767
+ const content = readFileSync7(file);
2673
2768
  return createHash("sha256").update(content).digest("hex");
2674
2769
  }
2675
2770
  function cacheFile(root) {
2676
- return join5(root, CACHE_DIR, MANIFEST_FILE);
2771
+ return join6(root, CACHE_DIR, MANIFEST_FILE);
2677
2772
  }
2678
2773
 
2679
2774
  // packages/cli/src/index/cache.mjs
2680
- import { existsSync as existsSync12, readFileSync as readFileSync12, statSync as statSync4 } from "node:fs";
2775
+ import { existsSync as existsSync13, readFileSync as readFileSync13, statSync as statSync4 } from "node:fs";
2681
2776
  import { basename as basename6, join as join12 } from "node:path";
2682
2777
 
2683
2778
  // packages/cli/src/graph/store.mjs
2684
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, statSync as statSync3, writeFileSync as writeFileSync2 } from "node:fs";
2685
- import { dirname as dirname3, join as join6 } from "node:path";
2779
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
2780
+ import { dirname as dirname4, join as join7 } from "node:path";
2686
2781
  var GRAPH_NODE_SHARDS = ["docs", "packages", "source"];
2687
2782
  var GRAPH_EDGE_SHARDS = ["docs-links", "packages", "other"];
2688
2783
  function graphNodeShard(node2) {
@@ -2713,14 +2808,14 @@ function expandEdge(row) {
2713
2808
  return { source, target, relation, ...data };
2714
2809
  }
2715
2810
  function shardFile(root, kind, name) {
2716
- return join6(root, CACHE_DIR, "graph", kind, `${name}.json`);
2811
+ return join7(root, CACHE_DIR, "graph", kind, `${name}.json`);
2717
2812
  }
2718
2813
  function jsonSize(file) {
2719
- return existsSync7(file) ? statSync3(file).size : 0;
2814
+ return existsSync8(file) ? statSync3(file).size : 0;
2720
2815
  }
2721
2816
  function writeJson(file, value) {
2722
- mkdirSync2(dirname3(file), { recursive: true });
2723
- writeFileSync2(file, `${JSON.stringify(value)}
2817
+ mkdirSync3(dirname4(file), { recursive: true });
2818
+ writeFileSync3(file, `${JSON.stringify(value)}
2724
2819
  `);
2725
2820
  }
2726
2821
  function compactGraph(graph) {
@@ -2783,13 +2878,13 @@ function addEdge(graph, source, target, relation, data = {}) {
2783
2878
  }
2784
2879
 
2785
2880
  // packages/cli/src/graph/extract.mjs
2786
- import { readFileSync as readFileSync7 } from "node:fs";
2787
- import { basename as basename5, dirname as dirname4, resolve as resolve6 } from "node:path";
2881
+ import { readFileSync as readFileSync8 } from "node:fs";
2882
+ import { basename as basename5, dirname as dirname5, resolve as resolve7 } from "node:path";
2788
2883
 
2789
2884
  // packages/cli/src/graph/metadata.mjs
2790
2885
  import { createHash as createHash2 } from "node:crypto";
2791
- import { existsSync as existsSync8 } from "node:fs";
2792
- import { basename as basename4, extname as extname3, resolve as resolve5 } from "node:path";
2886
+ import { existsSync as existsSync9 } from "node:fs";
2887
+ import { basename as basename4, extname as extname3, resolve as resolve6 } from "node:path";
2793
2888
  function isReadmeIndexPath(path = "") {
2794
2889
  return basename4(path) === "README.md";
2795
2890
  }
@@ -2848,7 +2943,7 @@ function addReferenceEvidence(graph, sourceId, reference) {
2848
2943
  function addTraceabilityTarget(graph, sourceId, root, relation, targetPath, data = {}, config = defaultMemoryConfig()) {
2849
2944
  if (!isLocalRelativeTraceabilityPath(targetPath)) return;
2850
2945
  addReferenceEvidence(graph, sourceId, { targetPath, href: targetPath, relation, data: { confidence: "CURATED_TRACEABILITY", ...data } });
2851
- if (!existsSync8(resolve5(root, targetPath))) return;
2946
+ if (!existsSync9(resolve6(root, targetPath))) return;
2852
2947
  const targetId = `file:${targetPath}`;
2853
2948
  addNode(graph, targetId, "file", fileNodeMetadata(targetPath, null, config));
2854
2949
  addEdge(graph, sourceId, targetId, relation, { confidence: "CURATED_TRACEABILITY", ...data });
@@ -2900,7 +2995,7 @@ function headingId(path, title) {
2900
2995
  // packages/cli/src/graph/extract.mjs
2901
2996
  function extractMarkdownGraph(root, file, graph, config = defaultMemoryConfig()) {
2902
2997
  const path = rel(root, file);
2903
- const content = readFileSync7(file, "utf8");
2998
+ const content = readFileSync8(file, "utf8");
2904
2999
  const fileId = `file:${path}`;
2905
3000
  const headingRe = /^(#{1,6})\s+(.+)$/gm;
2906
3001
  let match;
@@ -2914,7 +3009,7 @@ function extractMarkdownGraph(root, file, graph, config = defaultMemoryConfig())
2914
3009
  const hashIndex = href.indexOf("#");
2915
3010
  const pathPart = hashIndex < 0 ? href : href.slice(0, hashIndex);
2916
3011
  const anchor = hashIndex < 0 ? "" : href.slice(hashIndex + 1);
2917
- const targetPath = pathPart ? rel(root, resolve6(dirname4(file), pathPart)) : path;
3012
+ const targetPath = pathPart ? rel(root, resolve7(dirname5(file), pathPart)) : path;
2918
3013
  const data = { line, confidence: "EXTRACTED" };
2919
3014
  addReferenceEvidence(graph, fileId, { targetPath, href, anchor, relation: "links_to", data });
2920
3015
  if (pathPart && isReadmeIndexPath(path)) addReferenceEvidence(graph, fileId, { targetPath, href, anchor, relation: "routes_to", data: { line, confidence: "CURATED_INDEX", sourceRole: "readme-index" } });
@@ -2931,7 +3026,7 @@ function extractPackageGraph(root, file, graph) {
2931
3026
  const fileId = `file:${path}`;
2932
3027
  let pkg;
2933
3028
  try {
2934
- pkg = JSON.parse(readFileSync7(file, "utf8"));
3029
+ pkg = JSON.parse(readFileSync8(file, "utf8"));
2935
3030
  } catch {
2936
3031
  return;
2937
3032
  }
@@ -2977,18 +3072,18 @@ function buildGraph(root, files, config = defaultMemoryConfig()) {
2977
3072
  }
2978
3073
 
2979
3074
  // packages/cli/src/symbols/store.mjs
2980
- import { existsSync as existsSync11, lstatSync as lstatSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync11, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
3075
+ import { existsSync as existsSync12, lstatSync as lstatSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync12, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
2981
3076
  import { randomUUID } from "node:crypto";
2982
- import { dirname as dirname7, join as join11 } from "node:path";
3077
+ import { dirname as dirname8, join as join11 } from "node:path";
2983
3078
 
2984
3079
  // packages/cli/src/symbols/discovery.mjs
2985
3080
  var import_ignore = __toESM(require_ignore(), 1);
2986
- import { existsSync as existsSync10, lstatSync, readFileSync as readFileSync10, realpathSync } from "node:fs";
2987
- import { extname as extname5, join as join9, relative as relative4, isAbsolute } from "node:path";
3081
+ import { existsSync as existsSync11, lstatSync as lstatSync2, readFileSync as readFileSync11, realpathSync as realpathSync2 } from "node:fs";
3082
+ import { extname as extname5, join as join10, relative as relative5, isAbsolute as isAbsolute2 } from "node:path";
2988
3083
 
2989
3084
  // packages/cli/src/query/chunks.mjs
2990
- import { readFileSync as readFileSync8, readdirSync as readdirSync2 } from "node:fs";
2991
- import { join as join7, relative as relative3 } from "node:path";
3085
+ import { readFileSync as readFileSync9, readdirSync as readdirSync2 } from "node:fs";
3086
+ import { join as join8, relative as relative4 } from "node:path";
2992
3087
  import { createHash as createHash3 } from "node:crypto";
2993
3088
  var MAX_CHUNK_CHARS = 1600;
2994
3089
  var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage", ".git", ".dotdotgod"]);
@@ -2996,7 +3091,7 @@ function textFingerprint(text) {
2996
3091
  return createHash3("sha256").update(text).digest("hex");
2997
3092
  }
2998
3093
  function collectDocumentationMarkdown(root, exclude = ["docs/plan", "docs/archive"], documentationRoot = "docs") {
2999
- const docsRoot = join7(root, documentationRoot);
3094
+ const docsRoot = join8(root, documentationRoot);
3000
3095
  const files = [];
3001
3096
  const walk = (directory) => {
3002
3097
  let entries;
@@ -3008,8 +3103,8 @@ function collectDocumentationMarkdown(root, exclude = ["docs/plan", "docs/archiv
3008
3103
  entries.sort((a, b) => a.name.localeCompare(b.name));
3009
3104
  for (const entry of entries) {
3010
3105
  if (entry.name.startsWith(".")) continue;
3011
- const absolute = join7(directory, entry.name);
3012
- const path = relative3(root, absolute).replaceAll("\\", "/");
3106
+ const absolute = join8(directory, entry.name);
3107
+ const path = relative4(root, absolute).replaceAll("\\", "/");
3013
3108
  if (isSecretLikePathPattern(path) || exclude.some((pattern) => matchPathPattern(path, pattern) || path === pattern || path.startsWith(`${pattern}/`))) continue;
3014
3109
  if (entry.isDirectory()) {
3015
3110
  if (!SKIPPED_DIRECTORIES.has(entry.name)) walk(absolute);
@@ -3071,7 +3166,7 @@ ${piece}`;
3071
3166
  }
3072
3167
  function collectDocumentationChunks(root, exclude, documentationRoot = "docs") {
3073
3168
  return collectDocumentationMarkdown(root, exclude, documentationRoot).flatMap((path) => {
3074
- const content = readFileSync8(join7(root, path), "utf8");
3169
+ const content = readFileSync9(join8(root, path), "utf8");
3075
3170
  return chunkMarkdown(path, content);
3076
3171
  });
3077
3172
  }
@@ -3080,14 +3175,14 @@ function collectDocumentationChunks(root, exclude, documentationRoot = "docs") {
3080
3175
  init_languages();
3081
3176
  init_runtime();
3082
3177
  function inside(root, file) {
3083
- if (!lstatSync(file).isFile()) return false;
3084
- const path = relative4(realpathSync(root), realpathSync(file));
3085
- return !path.startsWith("..") && !isAbsolute(path);
3178
+ if (!lstatSync2(file).isFile()) return false;
3179
+ const path = relative5(realpathSync2(root), realpathSync2(file));
3180
+ return !path.startsWith("..") && !isAbsolute2(path);
3086
3181
  }
3087
3182
  function ignoreRules(root, directory, cache) {
3088
3183
  if (!cache.has(directory)) {
3089
- const file = join9(root, directory, ".gitignore");
3090
- cache.set(directory, (0, import_ignore.default)().add(existsSync10(file) && inside(root, file) ? readFileSync10(file, "utf8") : ""));
3184
+ const file = join10(root, directory, ".gitignore");
3185
+ cache.set(directory, (0, import_ignore.default)().add(existsSync11(file) && inside(root, file) ? readFileSync11(file, "utf8") : ""));
3091
3186
  }
3092
3187
  return cache.get(directory);
3093
3188
  }
@@ -3110,18 +3205,18 @@ function ignored(root, path, cache) {
3110
3205
  function sourceFiles(root) {
3111
3206
  const cache = /* @__PURE__ */ new Map();
3112
3207
  return collectIndexFiles(root).filter((file) => {
3113
- const path = relative4(root, file).replaceAll("\\", "/");
3208
+ const path = relative5(root, file).replaceAll("\\", "/");
3114
3209
  if (!SOURCE_EXTENSIONS.has(extname5(path)) || path.split("/").some((part) => part.startsWith(".")) || isSecretLikePathPattern(path)) return false;
3115
3210
  if (!inside(root, file) || ignored(root, path, cache)) return false;
3116
- return !/^#![^\n]*\n\/\/ Generated|^\/\/ Generated|@generated/m.test(readFileSync10(file, "utf8").slice(0, 256));
3211
+ return !/^#![^\n]*\n\/\/ Generated|^\/\/ Generated|@generated/m.test(readFileSync11(file, "utf8").slice(0, 256));
3117
3212
  }).map((file) => {
3118
- const source = readFileSync10(file, "utf8");
3119
- return { path: relative4(root, file).replaceAll("\\", "/"), hash: fingerprint(file), language: languageForPath(file), sourceLength: source.length, lineCount: source.split("\n").length };
3213
+ const source = readFileSync11(file, "utf8");
3214
+ return { path: relative5(root, file).replaceAll("\\", "/"), hash: fingerprint(file), language: languageForPath(file), sourceLength: source.length, lineCount: source.split("\n").length };
3120
3215
  });
3121
3216
  }
3122
3217
  function outlinePolicy(root) {
3123
3218
  const config = readMemoryConfig(root);
3124
- const ignores = collectIndexFiles(root).filter((file) => file.endsWith("/.gitignore") && inside(root, file)).map((file) => [relative4(root, file), fingerprint(file)]);
3219
+ const ignores = collectIndexFiles(root).filter((file) => file.endsWith("/.gitignore") && inside(root, file)).map((file) => [relative5(root, file), fingerprint(file)]);
3125
3220
  return textFingerprint(JSON.stringify({ areas: config.areas, ignores, extractor: EXTRACTOR_ID, declarations: DECLARATIONS, extensions: LANGUAGE_EXTENSIONS, parser: parserIdentity() }));
3126
3221
  }
3127
3222
 
@@ -3130,10 +3225,10 @@ init_languages();
3130
3225
  var OUTLINE_SCHEMA = 1;
3131
3226
  var outlinePath = (root) => join11(root, ".dotdotgod", "outlines.json");
3132
3227
  function assertCachePath(root) {
3133
- for (const path of [dirname7(outlinePath(root)), outlinePath(root)]) {
3228
+ for (const path of [dirname8(outlinePath(root)), outlinePath(root)]) {
3134
3229
  let stat;
3135
3230
  try {
3136
- stat = lstatSync2(path);
3231
+ stat = lstatSync3(path);
3137
3232
  } catch (error) {
3138
3233
  if (error.code !== "ENOENT") throw error;
3139
3234
  }
@@ -3143,7 +3238,7 @@ function assertCachePath(root) {
3143
3238
  function readOutlines(root) {
3144
3239
  try {
3145
3240
  assertCachePath(root);
3146
- const index = JSON.parse(readFileSync11(outlinePath(root), "utf8"));
3241
+ const index = JSON.parse(readFileSync12(outlinePath(root), "utf8"));
3147
3242
  if (index.schema !== OUTLINE_SCHEMA || index.extractor !== EXTRACTOR_ID || !Array.isArray(index.files)) return null;
3148
3243
  const paths = /* @__PURE__ */ new Set();
3149
3244
  const ids = /* @__PURE__ */ new Set();
@@ -3176,7 +3271,7 @@ function outlineStatus(root) {
3176
3271
  assertCachePath(root);
3177
3272
  const files = sourceFiles(root);
3178
3273
  const index = readOutlines(root);
3179
- if (!index) return { ok: files.length === 0 && !existsSync11(outlinePath(root)), reason: existsSync11(outlinePath(root)) ? "missing-or-invalid" : "missing", paths: files.map((file) => file.path) };
3274
+ if (!index) return { ok: files.length === 0 && !existsSync12(outlinePath(root)), reason: existsSync12(outlinePath(root)) ? "missing-or-invalid" : "missing", paths: files.map((file) => file.path) };
3180
3275
  const old = new Map(index.files.map((file) => [file.path, file]));
3181
3276
  const current = new Set(files.map((file) => file.path));
3182
3277
  const changed = files.filter((file) => old.get(file.path)?.hash !== file.hash || old.get(file.path)?.sourceLength !== file.sourceLength || old.get(file.path)?.lineCount !== file.lineCount).map((file) => file.path);
@@ -3205,7 +3300,7 @@ async function buildOutlines(root) {
3205
3300
  continue;
3206
3301
  }
3207
3302
  const { extractSymbols: extractSymbols2 } = await Promise.resolve().then(() => (init_parser(), parser_exports));
3208
- const source = readFileSync11(join11(root, file.path), "utf8");
3303
+ const source = readFileSync12(join11(root, file.path), "utf8");
3209
3304
  const extracted = await extractSymbols2(file.path, source, file.language);
3210
3305
  if (fingerprint(join11(root, file.path)) !== file.hash) throw new Error(`Source changed during outline extraction: ${file.path}`);
3211
3306
  records.push({ ...file, ...extracted });
@@ -3213,9 +3308,9 @@ async function buildOutlines(root) {
3213
3308
  }
3214
3309
  const index = { schema: OUTLINE_SCHEMA, extractor: EXTRACTOR_ID, policy: outlinePolicy(root), files: records, refresh: { parsed, reused } };
3215
3310
  const target = outlinePath(root);
3216
- mkdirSync3(dirname7(target), { recursive: true });
3311
+ mkdirSync4(dirname8(target), { recursive: true });
3217
3312
  const temporary = `${target}.tmp-${process.pid}-${randomUUID()}`;
3218
- writeFileSync3(temporary, JSON.stringify(index), { flag: "wx" });
3313
+ writeFileSync4(temporary, JSON.stringify(index), { flag: "wx" });
3219
3314
  renameSync(temporary, target);
3220
3315
  return index;
3221
3316
  }
@@ -3233,10 +3328,10 @@ ${text}`;
3233
3328
  }
3234
3329
 
3235
3330
  // packages/cli/src/symbols/graph.mjs
3236
- import { dirname as dirname8, posix } from "node:path";
3331
+ import { dirname as dirname9, posix } from "node:path";
3237
3332
  function importTarget(file, specifier, paths) {
3238
3333
  if (!specifier.startsWith(".")) return null;
3239
- const base = posix.normalize(posix.join(dirname8(file).replaceAll("\\", "/"), specifier));
3334
+ const base = posix.normalize(posix.join(dirname9(file).replaceAll("\\", "/"), specifier));
3240
3335
  if (base.startsWith("../")) return null;
3241
3336
  const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
3242
3337
  const candidates = [base, ...[".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"].map((extension) => `${stem}${extension}`), ...[".ts", ".js", ".py"].map((extension) => `${base}/index${extension}`)];
@@ -3323,14 +3418,14 @@ function writeIndex(root, index) {
3323
3418
  }
3324
3419
  function readIndex(root) {
3325
3420
  const file = cacheFile(root);
3326
- if (!existsSync12(file)) return null;
3421
+ if (!existsSync13(file)) return null;
3327
3422
  try {
3328
- const manifest = JSON.parse(readFileSync12(file, "utf8"));
3423
+ const manifest = JSON.parse(readFileSync13(file, "utf8"));
3329
3424
  const shards = manifest.graph?.shards;
3330
3425
  if (!shards) return manifest;
3331
3426
  const compact = { nodes: {}, edges: {} };
3332
- for (const [name, path] of Object.entries(shards.nodes ?? {})) compact.nodes[name] = existsSync12(join12(root, path)) ? JSON.parse(readFileSync12(join12(root, path), "utf8")) : [];
3333
- for (const [name, path] of Object.entries(shards.edges ?? {})) compact.edges[name] = existsSync12(join12(root, path)) ? JSON.parse(readFileSync12(join12(root, path), "utf8")) : [];
3427
+ for (const [name, path] of Object.entries(shards.nodes ?? {})) compact.nodes[name] = existsSync13(join12(root, path)) ? JSON.parse(readFileSync13(join12(root, path), "utf8")) : [];
3428
+ for (const [name, path] of Object.entries(shards.edges ?? {})) compact.edges[name] = existsSync13(join12(root, path)) ? JSON.parse(readFileSync13(join12(root, path), "utf8")) : [];
3334
3429
  return { ...manifest, graph: expandGraph(compact) };
3335
3430
  } catch {
3336
3431
  return null;
@@ -3386,7 +3481,7 @@ function graphSummary(index) {
3386
3481
 
3387
3482
  // packages/cli/src/validate/references.mjs
3388
3483
  import { statSync as statSync5 } from "node:fs";
3389
- import { dirname as dirname9, relative as relative5, resolve as resolve7 } from "node:path";
3484
+ import { dirname as dirname10, relative as relative6, resolve as resolve8 } from "node:path";
3390
3485
  var blank = (text) => text.replace(/[^\n\r]/g, " ");
3391
3486
  var unescape = (text) => text.replace(/\\([!"#$%&'()*+,\-./:;<=>?@[\]\\^_`{|}~])/g, "$1");
3392
3487
  var labelKey = (text) => unescape(text).trim().replace(/\s+/g, " ").toLowerCase();
@@ -3486,7 +3581,7 @@ function extractMemoryReferences(content) {
3486
3581
  return references;
3487
3582
  }
3488
3583
  function sharedLocalReferences(content, root, file, config) {
3489
- const source = resolveMemoryArea(relative5(root, file).split("\\").join("/"), config);
3584
+ const source = resolveMemoryArea(relative6(root, file).split("\\").join("/"), config);
3490
3585
  if (source?.scope !== "shared") return [];
3491
3586
  const errors = [];
3492
3587
  for (const item of extractMemoryReferences(content)) {
@@ -3498,14 +3593,14 @@ function sharedLocalReferences(content, root, file, config) {
3498
3593
  continue;
3499
3594
  }
3500
3595
  if (!path) continue;
3501
- const base = item.kind === "markdown-link" || /^\.\.?\//.test(path) ? dirname9(file) : root;
3502
- const target = relative5(root, resolve7(base, path)).split("\\").join("/");
3596
+ const base = item.kind === "markdown-link" || /^\.\.?\//.test(path) ? dirname10(file) : root;
3597
+ const target = relative6(root, resolve8(base, path)).split("\\").join("/");
3503
3598
  if (target === ".." || target.startsWith("../")) continue;
3504
3599
  if (item.kind === "inline-code") {
3505
3600
  const configuredDirectory = (config.areas ?? []).some((area3) => (area3.paths ?? []).some((pattern) => pattern === `${target}/**`));
3506
3601
  let directory = configuredDirectory;
3507
3602
  try {
3508
- directory ||= statSync5(resolve7(root, target)).isDirectory();
3603
+ directory ||= statSync5(resolve8(root, target)).isDirectory();
3509
3604
  } catch {
3510
3605
  }
3511
3606
  if (directory) continue;
@@ -3530,7 +3625,7 @@ function runValidate(argv) {
3530
3625
  else if (!arg.startsWith("-")) options.root = arg;
3531
3626
  else usage(`Unknown option: ${arg}`, "validate");
3532
3627
  }
3533
- const root = resolve8(options.root);
3628
+ const root = resolve9(options.root);
3534
3629
  const memoryConfig = readMemoryConfig(root);
3535
3630
  const documentationRoot = memoryConfig.documentation?.root ?? "docs";
3536
3631
  const docs = join13(root, documentationRoot);
@@ -3551,7 +3646,7 @@ Fix: ${fix}` : message, ...prompt ? { prompt } : {} });
3551
3646
  return false;
3552
3647
  };
3553
3648
  const walk = (dir) => {
3554
- if (!existsSync13(dir) || shouldSkipDir(dir)) return;
3649
+ if (!existsSync14(dir) || shouldSkipDir(dir)) return;
3555
3650
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
3556
3651
  const path = join13(dir, entry.name);
3557
3652
  if (entry.isDirectory()) {
@@ -3563,7 +3658,7 @@ Fix: ${fix}` : message, ...prompt ? { prompt } : {} });
3563
3658
  } else if (entry.isFile() && entry.name.endsWith(".md")) markdownFiles.push(path);
3564
3659
  }
3565
3660
  };
3566
- if (!existsSync13(docs)) usage(`docs directory not found: ${docs}`);
3661
+ if (!existsSync14(docs)) usage(`docs directory not found: ${docs}`);
3567
3662
  const validationPolicy = cloneValidationPolicy(memoryConfig.validation ?? DEFAULT_VALIDATION_POLICY);
3568
3663
  const maxLines = options.maxLines ?? validationPolicy.markdown.maxLines;
3569
3664
  const maxChars = options.maxChars ?? validationPolicy.markdown.maxChars;
@@ -3594,7 +3689,7 @@ README.md directory indexes, clear HTTP-status filenames such as RESPONSE_200_OK
3594
3689
  walk(docs);
3595
3690
  const dirSiblingMap = /* @__PURE__ */ new Map();
3596
3691
  for (const f of markdownFiles) {
3597
- const dir = dirname10(f);
3692
+ const dir = dirname11(f);
3598
3693
  if (!dirSiblingMap.has(dir)) dirSiblingMap.set(dir, []);
3599
3694
  dirSiblingMap.get(dir).push(basename7(f));
3600
3695
  }
@@ -3603,14 +3698,14 @@ README.md directory indexes, clear HTTP-status filenames such as RESPONSE_200_OK
3603
3698
  const docsRel = rel(docs, file);
3604
3699
  const rootRel = rel(root, file);
3605
3700
  if (docsRel && !docsRel.startsWith("..") && !isUpperSnakeMarkdown(name)) addError(file, "FILE_NAMING", `Markdown file must be UPPER_SNAKE_CASE.md or README.md: ${name}`, null, "rename the markdown file to UPPER_SNAKE_CASE.md or README.md and update any links that reference it.");
3606
- const content = readFileSync13(file, "utf8");
3701
+ const content = readFileSync14(file, "utf8");
3607
3702
  fileCache.set(file, content);
3608
3703
  const docArea = docsRel?.split("/")[0];
3609
3704
  if (name !== "README.md" && isUpperSnakeMarkdown(name) && FILENAME_QUALITY_AREAS.has(docArea)) {
3610
3705
  const fp = validationPolicy.markdown?.filename ?? {};
3611
3706
  const allow = fp.allow ?? [];
3612
3707
  if (!allow.some((p) => matchPathPattern(rootRel, p)) && (fp.warnNumberedSeries ?? true)) {
3613
- const siblings = dirSiblingMap.get(dirname10(file)) ?? [];
3708
+ const siblings = dirSiblingMap.get(dirname11(file)) ?? [];
3614
3709
  if (isNumberedSeriesFilename(name, siblings)) {
3615
3710
  const heading = extractFirstHeading(content);
3616
3711
  const suggestion = suggestFilenameFromHeading(heading);
@@ -3652,7 +3747,7 @@ ${traceabilityExample()}`, block.line);
3652
3747
  }
3653
3748
  }
3654
3749
  const byDir = /* @__PURE__ */ new Map();
3655
- for (const file of markdownFiles) byDir.set(dirname10(file), [...byDir.get(dirname10(file)) ?? [], file]);
3750
+ for (const file of markdownFiles) byDir.set(dirname11(file), [...byDir.get(dirname11(file)) ?? [], file]);
3656
3751
  for (const [dir, files] of byDir) {
3657
3752
  if (files.length > 1 && !files.some((file) => basename7(file) === "README.md")) addError(dir, "MISSING_README", "Directory with multiple markdown files must include README.md", null, "add a README.md in this directory that indexes the important markdown files and their purpose.");
3658
3753
  }
@@ -3663,18 +3758,18 @@ ${traceabilityExample()}`, block.line);
3663
3758
  }
3664
3759
  if (options.linkCheck) {
3665
3760
  for (const [file, content] of fileCache) {
3666
- const fileDir = dirname10(file);
3761
+ const fileDir = dirname11(file);
3667
3762
  for (const { href, line } of extractLinks(content)) {
3668
3763
  const hashIndex = href.indexOf("#");
3669
3764
  const pathPart = hashIndex === -1 ? href : href.slice(0, hashIndex);
3670
3765
  const anchor = hashIndex === -1 ? "" : href.slice(hashIndex + 1);
3671
- const target = pathPart ? resolve8(fileDir, pathPart) : file;
3672
- if (pathPart && !existsSync13(target)) {
3766
+ const target = pathPart ? resolve9(fileDir, pathPart) : file;
3767
+ if (pathPart && !existsSync14(target)) {
3673
3768
  addError(file, "BROKEN_LINK", `Local link target does not exist: ${pathPart}`, line, "update the link target to an existing local file, create the intended file, or remove the stale link.");
3674
3769
  continue;
3675
3770
  }
3676
3771
  if (anchor && extname6(target) === ".md") {
3677
- const targetContent = fileCache.get(target) ?? (existsSync13(target) ? readFileSync13(target, "utf8") : "");
3772
+ const targetContent = fileCache.get(target) ?? (existsSync14(target) ? readFileSync14(target, "utf8") : "");
3678
3773
  if (targetContent && !extractAnchors(targetContent).has(decodeURIComponent(anchor))) addError(file, "BROKEN_ANCHOR", `Local anchor target does not exist: ${href}`, line, "update the fragment to a heading that exists in the target markdown file, or add the missing heading.");
3679
3774
  }
3680
3775
  }
@@ -3709,19 +3804,19 @@ ${traceabilityExample()}`, block.line);
3709
3804
  if (options.includeLocalMemory) {
3710
3805
  for (const area2 of ["plan", "archive/plan", "archive/report"]) {
3711
3806
  const areaRoot = join13(docs, area2);
3712
- if (!existsSync13(areaRoot)) continue;
3807
+ if (!existsSync14(areaRoot)) continue;
3713
3808
  for (const entry of readdirSync3(areaRoot, { withFileTypes: true })) {
3714
3809
  if (!entry.isDirectory()) continue;
3715
3810
  if (!isKebabCase(entry.name)) addError(join13(areaRoot, entry.name), "SLUG_NAMING", `Archive/plan/report slug must be kebab-case: ${entry.name}`, null, "rename the task/report directory to kebab-case and update any README index links that reference it.");
3716
3811
  const readme = join13(areaRoot, entry.name, "README.md");
3717
- if (!existsSync13(readme)) addError(readme, "MISSING_README", `Expected README.md in ${documentationRoot}/${area2}/${entry.name}/`, null, "add a README.md that summarizes the task/report and links any supporting files.");
3812
+ if (!existsSync14(readme)) addError(readme, "MISSING_README", `Expected README.md in ${documentationRoot}/${area2}/${entry.name}/`, null, "add a README.md that summarizes the task/report and links any supporting files.");
3718
3813
  }
3719
3814
  }
3720
3815
  }
3721
3816
  const gitignore = join13(root, ".gitignore");
3722
- if (!existsSync13(gitignore)) addError(gitignore, "MISSING_GITIGNORE", "Expected .gitignore", null, `create .gitignore and include ${documentationRoot}/plan, ${documentationRoot}/archive, and .dotdotgod entries.`);
3817
+ if (!existsSync14(gitignore)) addError(gitignore, "MISSING_GITIGNORE", "Expected .gitignore", null, `create .gitignore and include ${documentationRoot}/plan, ${documentationRoot}/archive, and .dotdotgod entries.`);
3723
3818
  else {
3724
- const content = readFileSync13(gitignore, "utf8").split("\n").map((line) => line.trim());
3819
+ const content = readFileSync14(gitignore, "utf8").split("\n").map((line) => line.trim());
3725
3820
  for (const required of [`${documentationRoot}/plan`, `${documentationRoot}/archive`, CACHE_DIR]) if (!content.includes(required)) addError(gitignore, "MISSING_GITIGNORE_ENTRY", `Expected .gitignore entry: ${required}`, null, `add ${required} to .gitignore so local plans, archives, and cache files stay untracked.`);
3726
3821
  }
3727
3822
  if (options.json) console.log(JSON.stringify({ ok: errors.length === 0, errors, warnings }, null, 2));
@@ -3746,8 +3841,8 @@ Prompt: ${error.prompt}` : ""}`);
3746
3841
  }
3747
3842
 
3748
3843
  // packages/cli/src/commands/config.mjs
3749
- import { existsSync as existsSync14, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
3750
- import { join as join14, resolve as resolve9 } from "node:path";
3844
+ import { existsSync as existsSync15, statSync as statSync6, writeFileSync as writeFileSync5 } from "node:fs";
3845
+ import { join as join14, resolve as resolve10 } from "node:path";
3751
3846
  function parseConfigOptions(argv, usageKey = "config") {
3752
3847
  const options = { root: ".", json: false, template: null };
3753
3848
  let rootSet = false;
@@ -3765,7 +3860,7 @@ function parseConfigOptions(argv, usageKey = "config") {
3765
3860
  } else if (!arg.startsWith("-")) usage(`Unexpected argument: ${arg}`, usageKey);
3766
3861
  else usage(`Unknown option: ${arg}`, usageKey);
3767
3862
  }
3768
- options.root = resolve9(options.root);
3863
+ options.root = resolve10(options.root);
3769
3864
  return options;
3770
3865
  }
3771
3866
  function configInitError(options, code, message, path = null) {
@@ -3783,7 +3878,7 @@ function formatConfigOutput(payload) {
3783
3878
  lines.push(`- path: ${payload.path ?? "none"}`);
3784
3879
  lines.push(`- documentation root: ${payload.config.documentation.root}`);
3785
3880
  lines.push(`- memory areas: ${payload.config.areas.length}`);
3786
- lines.push(`- embedding: ${payload.embedding.profile.provider}/${payload.embedding.profile.model} (${payload.embedding.source})`);
3881
+ lines.push(`- embedding: ${payload.embedding.profile ? `${payload.embedding.profile.provider}/${payload.embedding.profile.model}` : "not configured; keyword search"} (${payload.embedding.source})`);
3787
3882
  lines.push(`- traceability required: ${(payload.config.traceability.required ?? []).join(", ") || "none"}`);
3788
3883
  lines.push(`- traceability exclude: ${(payload.config.traceability.exclude ?? []).join(", ") || "none"}`);
3789
3884
  lines.push("- traceability keys:");
@@ -3807,17 +3902,17 @@ function runConfig(argv) {
3807
3902
  const isInit = argv[0] === "init";
3808
3903
  const options = parseConfigOptions(isInit ? argv.slice(1) : argv, isInit ? "config init" : "config");
3809
3904
  if (isInit) {
3810
- if (!existsSync14(options.root)) configInitError(options, "ROOT_NOT_FOUND", `Project root not found: ${options.root}`);
3905
+ if (!existsSync15(options.root)) configInitError(options, "ROOT_NOT_FOUND", `Project root not found: ${options.root}`);
3811
3906
  try {
3812
3907
  if (!statSync6(options.root).isDirectory()) configInitError(options, "ROOT_NOT_DIRECTORY", `Project root is not a directory: ${options.root}`);
3813
3908
  } catch {
3814
3909
  configInitError(options, "ROOT_NOT_FOUND", `Project root not found: ${options.root}`);
3815
3910
  }
3816
3911
  const target = join14(options.root, "dotdotgod.config.json");
3817
- if (existsSync14(target)) configInitError(options, "CONFIG_EXISTS", "dotdotgod.config.json already exists.", target);
3912
+ if (existsSync15(target)) configInitError(options, "CONFIG_EXISTS", "dotdotgod.config.json already exists.", target);
3818
3913
  const template = resolveInitializationTemplate(options.template);
3819
3914
  if (!template.ok) configInitError(options, template.error.code, template.error.message, template.error.path ?? target);
3820
- writeFileSync4(target, template.text);
3915
+ writeFileSync5(target, template.text);
3821
3916
  const payload2 = { ok: true, command: "config init", root: options.root, path: target, created: true, template: { name: template.name, source: template.source, selectedBy: template.selectedBy } };
3822
3917
  if (options.json) console.log(JSON.stringify(payload2, null, 2));
3823
3918
  else console.log(`dotdotgod config init: created ${target} from ${template.source}:${template.name} (${template.selectedBy})`);
@@ -3831,7 +3926,7 @@ function runConfig(argv) {
3831
3926
  embedding = { source: resolved.source, path: resolved.path, profile: sanitizeEmbeddingProfile(resolved.profile) };
3832
3927
  } catch (error) {
3833
3928
  errors.push({ file: "embedding config", code: "EMBEDDING_CONFIG_INVALID", message: error instanceof Error ? error.message : String(error) });
3834
- embedding = { source: "invalid", path: null, profile: sanitizeEmbeddingProfile({ provider: "local", model: "Xenova/multilingual-e5-small" }) };
3929
+ embedding = { source: "invalid", path: null, profile: null };
3835
3930
  }
3836
3931
  const payload = { ok: errors.length === 0, command: "config", root: options.root, source: config.source ?? "default", path: config.source && config.source !== "default" ? join14(options.root, config.source) : null, embedding, config: memoryConfigSummary(config), errors };
3837
3932
  if (options.json) console.log(JSON.stringify(payload, null, 2));
@@ -3840,10 +3935,10 @@ function runConfig(argv) {
3840
3935
  }
3841
3936
 
3842
3937
  // packages/cli/src/commands/query.mjs
3843
- import { resolve as resolve10 } from "node:path";
3938
+ import { resolve as resolve11 } from "node:path";
3844
3939
 
3845
3940
  // packages/cli/src/query/embedding-runtime.mjs
3846
- import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync14, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
3941
+ import { existsSync as existsSync16, mkdirSync as mkdirSync5, readFileSync as readFileSync15, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
3847
3942
  import { spawnSync as spawnSync2 } from "node:child_process";
3848
3943
  import { createRequire as createRequire2 } from "node:module";
3849
3944
  import { homedir as homedir3 } from "node:os";
@@ -3876,7 +3971,7 @@ function embeddingRuntimeStatus(options = {}) {
3876
3971
  const require3 = createRequire2(join15(root, "package.json"));
3877
3972
  require3.resolve(EMBEDDING_RUNTIME_PACKAGE);
3878
3973
  const packagePath = join15(root, "node_modules", ...EMBEDDING_RUNTIME_PACKAGE.split("/"), "package.json");
3879
- const version = JSON.parse(readFileSync14(packagePath, "utf8")).version;
3974
+ const version = JSON.parse(readFileSync15(packagePath, "utf8")).version;
3880
3975
  return { ok: true, installed: true, installAvailable: true, package: EMBEDDING_RUNTIME_PACKAGE, requiredVersion: EMBEDDING_RUNTIME_VERSION, packageVersion: version, location: root };
3881
3976
  } catch {
3882
3977
  return { ok: true, installed: false, installAvailable: true, package: EMBEDDING_RUNTIME_PACKAGE, requiredVersion: EMBEDDING_RUNTIME_VERSION, packageVersion: null, location: root };
@@ -3886,9 +3981,9 @@ function installEmbeddingRuntime(options = {}) {
3886
3981
  if (options.confirm !== true) throw new Error("Embedding runtime installation requires explicit confirmation.");
3887
3982
  const root = embeddingRuntimeRoot(options);
3888
3983
  const lock = join15(root, ".installing");
3889
- if (existsSync15(lock)) throw new Error("Embedding runtime installation is already in progress.");
3890
- mkdirSync4(root, { recursive: true });
3891
- writeFileSync5(lock, `${process.pid}
3984
+ if (existsSync16(lock)) throw new Error("Embedding runtime installation is already in progress.");
3985
+ mkdirSync5(root, { recursive: true });
3986
+ writeFileSync6(lock, `${process.pid}
3892
3987
  `, { flag: "wx" });
3893
3988
  try {
3894
3989
  const spawn = options.spawnImpl ?? spawnSync2;
@@ -3944,7 +4039,12 @@ async function postJson(url, body, profile) {
3944
4039
  const response = await fetch(url, { method: "POST", headers: { "content-type": "application/json", ...key ? { authorization: `Bearer ${key}` } : {} }, body: JSON.stringify(body), signal: controller.signal });
3945
4040
  if (!response.ok) {
3946
4041
  const category = response.status === 401 || response.status === 403 ? "authentication" : response.status === 429 ? "rate limit" : `HTTP ${response.status}`;
3947
- throw new Error(`Remote embedding ${category} failure.`);
4042
+ const error = new Error(`Remote embedding ${category} failure.`);
4043
+ if (response.status === 400 || response.status === 413) {
4044
+ const body2 = (await response.text()).slice(0, 8192);
4045
+ error.tokenLimit = /(?:exceed\w*[\s\S]{0,120}tokens?|tokens?[\s\S]{0,120}(?:exceed|limit|too (?:long|many))|maximum context length)/i.test(body2);
4046
+ }
4047
+ throw error;
3948
4048
  }
3949
4049
  try {
3950
4050
  return await response.json();
@@ -3971,25 +4071,41 @@ function remoteEmbedder(profile) {
3971
4071
  return ordered.map(normalize);
3972
4072
  };
3973
4073
  }
4074
+ function withInputFormat(embed, profile) {
4075
+ const format = embeddingInputFormat(profile);
4076
+ return (texts, role) => {
4077
+ if (role !== void 0 && role !== "query" && role !== "document") throw new Error("Embedding role must be query or document.");
4078
+ return embed(role === void 0 ? texts : texts.map((text) => format[`${role}Prefix`] + text));
4079
+ };
4080
+ }
3974
4081
  async function createEmbedder(profile) {
3975
4082
  const embed = profile.provider === "local" ? await localEmbedder(profile) : remoteEmbedder(profile);
3976
- return async (texts) => {
4083
+ async function embedBatch(texts) {
3977
4084
  if (texts.length === 0) return [];
3978
- const rows = await embed(texts);
4085
+ let rows;
4086
+ try {
4087
+ rows = await embed(texts);
4088
+ } catch (error) {
4089
+ if (!error.tokenLimit || texts.length === 1) throw error;
4090
+ const middle = Math.ceil(texts.length / 2);
4091
+ rows = [...await embedBatch(texts.slice(0, middle)), ...await embedBatch(texts.slice(middle))];
4092
+ }
3979
4093
  if (!Array.isArray(rows) || rows.length !== texts.length) throw new Error("Embedding provider returned an unexpected vector count.");
3980
4094
  const dimensions = rows[0]?.length;
3981
4095
  if (!dimensions || rows.some((row) => row.length !== dimensions)) throw new Error("Embedding provider returned inconsistent vector dimensions.");
3982
4096
  return rows;
3983
- };
4097
+ }
4098
+ return withInputFormat(embedBatch, profile);
3984
4099
  }
3985
4100
  async function resolveEmbedder(root, options = {}) {
3986
- const resolved = options.profile ? { profile: options.profile, source: options.source ?? "injected", path: null } : resolveEmbeddingProfile(root, options);
3987
- return { ...resolved, identity: embeddingProfileIdentity(resolved.profile), embed: options.embed ?? await createEmbedder(resolved.profile) };
4101
+ const resolved = options.profile || options.embed ? { profile: options.profile ?? DEFAULT_EMBEDDING_PROFILE, source: options.source ?? "injected", path: null } : resolveEmbeddingProfile(root, options);
4102
+ if (!resolved.profile) throw new Error("Embedding is not configured. Set embedding in project or global configuration to use vector search.");
4103
+ return { ...resolved, identity: embeddingProfileIdentity(resolved.profile), embed: options.embed ? withInputFormat(options.embed, resolved.profile) : await createEmbedder(resolved.profile) };
3988
4104
  }
3989
4105
 
3990
4106
  // packages/cli/src/query/store.mjs
3991
4107
  import { createHash as createHash6 } from "node:crypto";
3992
- import { existsSync as existsSync16, mkdirSync as mkdirSync5, readFileSync as readFileSync15, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
4108
+ import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync16, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
3993
4109
  import { join as join16 } from "node:path";
3994
4110
  var VECTOR_SCHEMA_VERSION = 2;
3995
4111
  var VECTOR_DIMENSIONS = 384;
@@ -4015,13 +4131,13 @@ function vectorCachePaths(root) {
4015
4131
  }
4016
4132
  function readVectorCache(root, identity2 = null) {
4017
4133
  const paths = vectorCachePaths(root);
4018
- if (!existsSync16(paths.manifest) || !existsSync16(paths.chunks) || !existsSync16(paths.embeddings)) return null;
4134
+ if (!existsSync17(paths.manifest) || !existsSync17(paths.chunks) || !existsSync17(paths.embeddings)) return null;
4019
4135
  try {
4020
- const manifest = JSON.parse(readFileSync15(paths.manifest, "utf8"));
4136
+ const manifest = JSON.parse(readFileSync16(paths.manifest, "utf8"));
4021
4137
  if (manifest.schemaVersion !== VECTOR_SCHEMA_VERSION || !Number.isInteger(manifest.dimensions) || manifest.dimensions < 1) return null;
4022
4138
  if (identity2 && manifest.profileFingerprint !== profileFingerprint(identity2)) return null;
4023
- const chunks = readFileSync15(paths.chunks, "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
4024
- const buffer = readFileSync15(paths.embeddings);
4139
+ const chunks = readFileSync16(paths.chunks, "utf8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
4140
+ const buffer = readFileSync16(paths.embeddings);
4025
4141
  if (buffer.byteLength !== chunks.length * manifest.dimensions * 4) return null;
4026
4142
  const vectors = new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 4);
4027
4143
  if (!isValidNormalizedVectorValues(vectors, manifest.dimensions)) return null;
@@ -4032,14 +4148,14 @@ function readVectorCache(root, identity2 = null) {
4032
4148
  }
4033
4149
  function atomicWrite(path, data) {
4034
4150
  const temporary = `${path}.tmp-${process.pid}`;
4035
- writeFileSync6(temporary, data);
4151
+ writeFileSync7(temporary, data);
4036
4152
  renameSync2(temporary, path);
4037
4153
  }
4038
4154
  function writeVectorCache(root, chunks, vectors, metadata = {}) {
4039
4155
  const paths = vectorCachePaths(root);
4040
4156
  const dimensions = metadata.dimensions;
4041
4157
  if (!Number.isInteger(dimensions) || dimensions < 1) throw new Error("Vector dimensions must be a positive integer.");
4042
- mkdirSync5(paths.directory, { recursive: true });
4158
+ mkdirSync6(paths.directory, { recursive: true });
4043
4159
  if (vectors.length !== chunks.length * dimensions) throw new Error("Vector count does not match chunk metadata.");
4044
4160
  if (!isValidNormalizedVectorValues(vectors, dimensions)) throw new Error("Vectors must contain finite normalized values.");
4045
4161
  const manifest = { schemaVersion: VECTOR_SCHEMA_VERSION, chunks: chunks.length, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), ...metadata };
@@ -4098,11 +4214,6 @@ async function projectCorpus(root, scope) {
4098
4214
  const outlines = scope === "docs" ? null : await buildOutlines(root);
4099
4215
  return { chunks: [...docs, ...outlines ? outlineChunks(outlines) : []], outlines };
4100
4216
  }
4101
- function assertCodeEmbeddingConsent(root, options, chunks) {
4102
- if (!chunks.some((chunk) => chunk.kind === "symbol")) return;
4103
- const profile = options.profile ?? resolveEmbeddingProfile(root).profile;
4104
- if (profile.provider !== "local" && options.allowCodeEmbedding !== true) throw new Error("Remote code-metadata embedding requires --allow-code-embedding; use --search keyword or --scope docs instead.");
4105
- }
4106
4217
  function attachRelationships(results, outlines) {
4107
4218
  if (!outlines) return results;
4108
4219
  const graph = addOutlineGraph({ nodes: [], edges: [] }, outlines);
@@ -4117,7 +4228,7 @@ var DEFAULT_LIMIT = 30;
4117
4228
  var MAX_LIMIT = 100;
4118
4229
  var EMBED_BATCH_SIZE = 16;
4119
4230
  function parseQueryOptions(argv) {
4120
- const options = { root: ".", query: "", limit: DEFAULT_LIMIT, json: false, scope: "all", search: "hybrid", allowCodeEmbedding: false };
4231
+ const options = { root: ".", query: "", limit: DEFAULT_LIMIT, json: false, scope: "all", search: "hybrid" };
4121
4232
  let rootSet = false;
4122
4233
  const queryParts = [];
4123
4234
  for (let i = 0; i < argv.length; i += 1) {
@@ -4129,14 +4240,13 @@ function parseQueryOptions(argv) {
4129
4240
  } else if (arg === "--search") {
4130
4241
  options.search = argv[++i];
4131
4242
  if (!["hybrid", "keyword", "vector"].includes(options.search)) usage("--search must be hybrid, keyword or vector.", "query");
4132
- } else if (arg === "--allow-code-embedding") options.allowCodeEmbedding = true;
4133
- else if (arg === "--limit") {
4243
+ } else if (arg === "--limit") {
4134
4244
  const value = Number(argv[++i]);
4135
4245
  if (!Number.isInteger(value) || value < 1 || value > MAX_LIMIT) usage(`--limit must be an integer from 1 to ${MAX_LIMIT}.`, "query");
4136
4246
  options.limit = value;
4137
4247
  } else if (arg.startsWith("-")) usage(`Unknown option: ${arg}`, "query");
4138
4248
  else if (!rootSet) {
4139
- options.root = resolve10(arg);
4249
+ options.root = resolve11(arg);
4140
4250
  rootSet = true;
4141
4251
  } else queryParts.push(arg);
4142
4252
  }
@@ -4190,7 +4300,7 @@ async function buildVectorIndex(root, embedOrOptions = {}) {
4190
4300
  });
4191
4301
  for (let offset = 0; offset < missing.length; offset += EMBED_BATCH_SIZE) {
4192
4302
  const batch = missing.slice(offset, offset + EMBED_BATCH_SIZE);
4193
- const embedded = await resolved.embed(batch.map(({ chunk }) => `passage: ${chunk.passage}`));
4303
+ const embedded = await resolved.embed(batch.map(({ chunk }) => chunk.passage), "document");
4194
4304
  embedded.forEach((vector, index) => {
4195
4305
  rows[batch[index].index] = vector;
4196
4306
  });
@@ -4216,11 +4326,20 @@ async function queryProject(root, query, options = {}) {
4216
4326
  let vector = [];
4217
4327
  let index;
4218
4328
  let vectorError;
4219
- if (search !== "keyword" && corpus.chunks.length) {
4329
+ let configured = false;
4330
+ if (search !== "keyword") {
4331
+ try {
4332
+ configured = Boolean(options.profile || options.embed || resolveEmbeddingProfile(root, options).profile);
4333
+ } catch (error) {
4334
+ if (search === "vector") throw error;
4335
+ vectorError = error.message;
4336
+ }
4337
+ if (!configured && !vectorError && search === "vector") throw new Error("Embedding is not configured. Set embedding in project or global configuration to use vector search.");
4338
+ }
4339
+ if (search !== "keyword" && configured && corpus.chunks.length) {
4220
4340
  try {
4221
- assertCodeEmbeddingConsent(root, options, corpus.chunks);
4222
4341
  index = await buildVectorIndex(root, { ...options, chunks: corpus.chunks });
4223
- const [queryVector] = await index.embedding.embed([`query: ${query}`]);
4342
+ const [queryVector] = await index.embedding.embed([query], "query");
4224
4343
  vector = index.chunks.map((chunk, position) => ({ ...chunk, vectorScore: cosineScore(queryVector, index.vectors, position * index.manifest.dimensions, index.manifest.dimensions) })).sort((a, b) => b.vectorScore - a.vectorScore || a.id.localeCompare(b.id));
4225
4344
  } catch (error) {
4226
4345
  if (search === "vector") throw error;
@@ -4269,7 +4388,7 @@ async function runQuery(argv) {
4269
4388
  }
4270
4389
 
4271
4390
  // packages/cli/src/commands/embedding.mjs
4272
- import { resolve as resolve11 } from "node:path";
4391
+ import { resolve as resolve12 } from "node:path";
4273
4392
  function parse(argv) {
4274
4393
  const [action2 = "status", ...rest] = argv;
4275
4394
  let root = ".";
@@ -4281,12 +4400,18 @@ function parse(argv) {
4281
4400
  else if (!arg.startsWith("-") && root === ".") root = arg;
4282
4401
  else usage(`Unknown embedding option: ${arg}`, `embedding ${action2}`);
4283
4402
  }
4284
- return { action: action2, root: resolve11(root), json: json2, confirm };
4403
+ return { action: action2, root: resolve12(root), json: json2, confirm };
4285
4404
  }
4286
4405
  function runEmbedding(argv, options = {}) {
4287
4406
  const parsed = parse(argv);
4288
4407
  if (!["status", "install"].includes(parsed.action)) usage(`Unknown embedding command: ${parsed.action}`, "embedding");
4289
4408
  const resolved = resolveEmbeddingProfile(parsed.root, options);
4409
+ if (!resolved.profile) {
4410
+ if (parsed.action === "install") throw new Error("Configure an explicit local embedding profile before installing its runtime.");
4411
+ const result2 = { ok: true, command: "embedding status", provider: null, required: false, installed: false, installAvailable: false, source: "not-configured" };
4412
+ console.log(parsed.json ? JSON.stringify(result2, null, 2) : "Embedding is not configured; keyword search is used.");
4413
+ return result2;
4414
+ }
4290
4415
  if (resolved.profile.provider !== "local") {
4291
4416
  const result2 = { ok: true, command: `embedding ${parsed.action}`, provider: resolved.profile.provider, required: false, installed: false, installAvailable: false };
4292
4417
  console.log(parsed.json ? JSON.stringify(result2, null, 2) : "Local embedding runtime is not required for the configured remote provider.");
@@ -4301,11 +4426,11 @@ function runEmbedding(argv, options = {}) {
4301
4426
  }
4302
4427
 
4303
4428
  // packages/cli/src/commands/map.mjs
4304
- import { resolve as resolve13 } from "node:path";
4429
+ import { resolve as resolve14 } from "node:path";
4305
4430
 
4306
4431
  // packages/cli/src/memory/documentation-map.mjs
4307
- import { existsSync as existsSync17, readdirSync as readdirSync4, statSync as statSync7 } from "node:fs";
4308
- import { join as join17, resolve as resolve12 } from "node:path";
4432
+ import { existsSync as existsSync18, readdirSync as readdirSync4, statSync as statSync7 } from "node:fs";
4433
+ import { join as join17, resolve as resolve13 } from "node:path";
4309
4434
  var SKIPPED_DIRECTORIES2 = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "coverage", ".git", ".dotdotgod"]);
4310
4435
  function node() {
4311
4436
  return { directories: /* @__PURE__ */ new Map(), files: [] };
@@ -4385,8 +4510,8 @@ function discoverMarkdown(root, documentationRoot, exclude) {
4385
4510
  return paths.sort();
4386
4511
  }
4387
4512
  function buildDocumentationMap(projectRoot = ".", { depth = 5 } = {}) {
4388
- const root = resolve12(projectRoot);
4389
- if (!existsSync17(root)) return { ok: false, error: { code: "ROOT_NOT_FOUND", message: `Project root not found: ${root}` } };
4513
+ const root = resolve13(projectRoot);
4514
+ if (!existsSync18(root)) return { ok: false, error: { code: "ROOT_NOT_FOUND", message: `Project root not found: ${root}` } };
4390
4515
  try {
4391
4516
  if (!statSync7(root).isDirectory()) return { ok: false, error: { code: "ROOT_NOT_FOUND", message: `Project root not found: ${root}` } };
4392
4517
  } catch {
@@ -4434,7 +4559,7 @@ function parseMapOptions(argv) {
4434
4559
  } else if (!arg.startsWith("-")) fail(options.json, "UNEXPECTED_ARGUMENT", `Unexpected argument: ${arg}`);
4435
4560
  else fail(options.json, "UNKNOWN_OPTION", `Unknown option: ${arg}`);
4436
4561
  }
4437
- options.root = resolve13(options.root);
4562
+ options.root = resolve14(options.root);
4438
4563
  return options;
4439
4564
  }
4440
4565
  function runMap(argv) {
@@ -4446,7 +4571,7 @@ function runMap(argv) {
4446
4571
  }
4447
4572
 
4448
4573
  // packages/cli/src/reference/resolve.mjs
4449
- import { resolve as resolve16 } from "node:path";
4574
+ import { resolve as resolve17 } from "node:path";
4450
4575
 
4451
4576
  // node_modules/.pnpm/leiden-ts@0.1.0/node_modules/leiden-ts/dist/index.js
4452
4577
  var GraphValidationError = class extends Error {
@@ -5817,8 +5942,8 @@ function compareImpactItems(seeds) {
5817
5942
  }
5818
5943
 
5819
5944
  // packages/cli/src/impact/references.mjs
5820
- import { readFileSync as readFileSync16, statSync as statSync8 } from "node:fs";
5821
- import { extname as extname7, resolve as resolve14 } from "node:path";
5945
+ import { readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
5946
+ import { extname as extname7, resolve as resolve15 } from "node:path";
5822
5947
  var WARNING_LIMIT = 20;
5823
5948
  var edgeKey = (source, target, relation) => `${source}\0${target}\0${relation}`;
5824
5949
  function prepareImpactReferences(index, root, changedPaths) {
@@ -5830,10 +5955,10 @@ function prepareImpactReferences(index, root, changedPaths) {
5830
5955
  if (checks.has(path)) return checks.get(path);
5831
5956
  let result;
5832
5957
  try {
5833
- const absolute = resolve14(root, path);
5958
+ const absolute = resolve15(root, path);
5834
5959
  const stat = statSync8(absolute);
5835
5960
  result = { status: "exists" };
5836
- if (stat.isFile() && extname7(absolute) === ".md") result.anchors = extractAnchors(readFileSync16(absolute, "utf8"));
5961
+ if (stat.isFile() && extname7(absolute) === ".md") result.anchors = extractAnchors(readFileSync17(absolute, "utf8"));
5837
5962
  } catch (error) {
5838
5963
  result = { status: ["ENOENT", "ENOTDIR"].includes(error.code) ? "missing" : "unavailable" };
5839
5964
  }
@@ -5895,15 +6020,15 @@ function prepareImpactReferences(index, root, changedPaths) {
5895
6020
  }
5896
6021
 
5897
6022
  // packages/cli/src/impact/vector-profile.mjs
5898
- import { lstatSync as lstatSync3, readFileSync as readFileSync17, realpathSync as realpathSync2 } from "node:fs";
5899
- import { extname as extname8, relative as relative6, resolve as resolve15, sep } from "node:path";
6023
+ import { lstatSync as lstatSync4, readFileSync as readFileSync18, realpathSync as realpathSync3 } from "node:fs";
6024
+ import { extname as extname8, relative as relative7, resolve as resolve16, sep } from "node:path";
5900
6025
  var MAX_VECTOR_PROFILE_FILE_BYTES = 64 * 1024;
5901
6026
  var MAX_VECTOR_PROFILE_CHARS = 4e3;
5902
6027
  var MAX_VECTOR_PROFILE_METADATA_ITEMS = 20;
5903
6028
  var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([".c", ".cc", ".cpp", ".css", ".go", ".h", ".hpp", ".html", ".java", ".js", ".json", ".jsx", ".md", ".mjs", ".py", ".rb", ".rs", ".sh", ".ts", ".tsx", ".txt", ".yaml", ".yml"]);
5904
6029
  var GENERATED_SEGMENTS = /* @__PURE__ */ new Set([".dotdotgod", "build", "coverage", "dist", "node_modules"]);
5905
6030
  function insideRoot(root, absolute) {
5906
- const normalizedRoot = resolve15(root);
6031
+ const normalizedRoot = resolve16(root);
5907
6032
  return absolute === normalizedRoot || absolute.startsWith(`${normalizedRoot}${sep}`);
5908
6033
  }
5909
6034
  function normalizeChangedPath(path) {
@@ -5914,17 +6039,17 @@ function normalizeChangedPath(path) {
5914
6039
  function canonicalizeChangedPath(root, path) {
5915
6040
  const normalized = normalizeChangedPath(path);
5916
6041
  if (!normalized) return null;
5917
- const rootAbsolute = resolve15(root);
5918
- const absolute = resolve15(rootAbsolute, normalized);
6042
+ const rootAbsolute = resolve16(root);
6043
+ const absolute = resolve16(rootAbsolute, normalized);
5919
6044
  if (!insideRoot(rootAbsolute, absolute)) return normalized;
5920
6045
  try {
5921
- const canonicalRoot = realpathSync2(rootAbsolute);
5922
- const canonicalAbsolute = realpathSync2(absolute);
6046
+ const canonicalRoot = realpathSync3(rootAbsolute);
6047
+ const canonicalAbsolute = realpathSync3(absolute);
5923
6048
  if (!insideRoot(canonicalRoot, canonicalAbsolute)) return normalized;
5924
- const canonical = relative6(canonicalRoot, canonicalAbsolute).replaceAll("\\", "/");
6049
+ const canonical = relative7(canonicalRoot, canonicalAbsolute).replaceAll("\\", "/");
5925
6050
  return canonical || normalized;
5926
6051
  } catch {
5927
- return relative6(rootAbsolute, absolute).replaceAll("\\", "/") || normalized;
6052
+ return relative7(rootAbsolute, absolute).replaceAll("\\", "/") || normalized;
5928
6053
  }
5929
6054
  }
5930
6055
  function unsafeProfilePath(path) {
@@ -5946,15 +6071,15 @@ function graphMetadata(graph, seedId) {
5946
6071
  function safeTextPrefix(root, path) {
5947
6072
  if (unsafeProfilePath(path) || !TEXT_EXTENSIONS.has(extname8(path).toLowerCase())) return "";
5948
6073
  try {
5949
- const absolute = resolve15(root, path);
6074
+ const absolute = resolve16(root, path);
5950
6075
  if (!insideRoot(root, absolute)) return "";
5951
- const canonicalAbsolute = realpathSync2(absolute);
5952
- if (!insideRoot(realpathSync2(root), canonicalAbsolute)) return "";
5953
- const canonicalPath = relative6(realpathSync2(root), canonicalAbsolute).replaceAll("\\", "/");
6076
+ const canonicalAbsolute = realpathSync3(absolute);
6077
+ if (!insideRoot(realpathSync3(root), canonicalAbsolute)) return "";
6078
+ const canonicalPath = relative7(realpathSync3(root), canonicalAbsolute).replaceAll("\\", "/");
5954
6079
  if (canonicalPath !== path || unsafeProfilePath(canonicalPath) || !TEXT_EXTENSIONS.has(extname8(canonicalPath).toLowerCase())) return "";
5955
- const stats = lstatSync3(canonicalAbsolute);
6080
+ const stats = lstatSync4(canonicalAbsolute);
5956
6081
  if (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_VECTOR_PROFILE_FILE_BYTES) return "";
5957
- const buffer = readFileSync17(canonicalAbsolute);
6082
+ const buffer = readFileSync18(canonicalAbsolute);
5958
6083
  if (buffer.includes(0)) return "";
5959
6084
  const text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
5960
6085
  return text.slice(0, MAX_VECTOR_PROFILE_CHARS);
@@ -5988,6 +6113,7 @@ async function buildVectorImpactOverlay(root, index, changedPaths, options = {})
5988
6113
  const threshold = semantic.threshold ?? 0.5;
5989
6114
  const topK = semantic.topKPerFile ?? 5;
5990
6115
  try {
6116
+ if (!options.profile && !options.embed && !options.buildIndex && !resolveEmbeddingProfile(root, options).profile) return { status: "disabled", edges: [], diagnostics: { enabled: false, reason: "Embedding is not configured." } };
5991
6117
  const vectorIndex = await (options.buildIndex ?? buildVectorIndex)(root, options);
5992
6118
  const edges = [];
5993
6119
  const normalizedChangedPaths = [...new Set(changedPaths.map((path) => canonicalizeChangedPath(root, path)).filter(Boolean))];
@@ -5996,7 +6122,7 @@ async function buildVectorImpactOverlay(root, index, changedPaths, options = {})
5996
6122
  if (!profile) continue;
5997
6123
  const embed = vectorIndex.embedding?.embed ?? options.embed;
5998
6124
  if (!embed) throw new Error("Vector index did not provide an embedder.");
5999
- const [queryVector] = await embed([`query: ${profile.text}`]);
6125
+ const [queryVector] = await embed([profile.text], "query");
6000
6126
  if (!queryVector) throw new Error("Changed-file embedding was empty.");
6001
6127
  const matches = rankVectorFiles(queryVector, vectorIndex).filter((match) => match.path !== changed && match.vectorScore >= threshold).slice(0, topK);
6002
6128
  for (const match of matches) {
@@ -6174,7 +6300,7 @@ function buildCompactImpactReport(impact, limits = {}) {
6174
6300
  }
6175
6301
 
6176
6302
  // packages/cli/src/reference/extract.mjs
6177
- import { basename as basename8, dirname as dirname11, extname as extname9 } from "node:path";
6303
+ import { basename as basename8, dirname as dirname12, extname as extname9 } from "node:path";
6178
6304
  var DEFAULT_REFERENCE_LIMIT = 5;
6179
6305
  function extractBracketReferences(prompt = "") {
6180
6306
  const refs = [];
@@ -6225,7 +6351,7 @@ function aliasEntriesForPath(path = "") {
6225
6351
  const parts = withoutMd.split("/").filter(Boolean);
6226
6352
  for (let i = 0; i < parts.length; i += 1) entries.push({ alias: parts.slice(i).join("/"), kind: "path-suffix" });
6227
6353
  if (base === "README.md") {
6228
- const dir = dirname11(path).replace(/\\/g, "/");
6354
+ const dir = dirname12(path).replace(/\\/g, "/");
6229
6355
  entries.push({ alias: basename8(dir), kind: "path" });
6230
6356
  }
6231
6357
  for (const alias of [path, withoutMd, base, stem]) entries.push({ alias, kind: "path" });
@@ -6355,7 +6481,7 @@ function parseReferenceOptions(argv, command) {
6355
6481
  else filtered.push(arg);
6356
6482
  }
6357
6483
  const operands = filtered.filter((arg) => !arg.startsWith("-"));
6358
- return { ...options, root: resolve16(operands[0] ?? "."), json: filtered.includes("--json"), rootArgv: operands.slice(1) };
6484
+ return { ...options, root: resolve17(operands[0] ?? "."), json: filtered.includes("--json"), rootArgv: operands.slice(1) };
6359
6485
  }
6360
6486
  function formatReferenceOutput(payload) {
6361
6487
  const refreshNote = payload.metadata.cacheRefreshed ? ", refreshed" : "";
@@ -6404,13 +6530,13 @@ function runExpand(argv) {
6404
6530
  }
6405
6531
 
6406
6532
  // packages/cli/src/commands/traceability.mjs
6407
- import { existsSync as existsSync18, readFileSync as readFileSync18, readdirSync as readdirSync5, writeFileSync as writeFileSync7 } from "node:fs";
6408
- import { join as join18, resolve as resolve17 } from "node:path";
6533
+ import { existsSync as existsSync19, readFileSync as readFileSync19, readdirSync as readdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
6534
+ import { join as join18, resolve as resolve18 } from "node:path";
6409
6535
  function collectDocsMarkdownFiles(root) {
6410
6536
  const docs = join18(root, "docs");
6411
6537
  const files = [];
6412
6538
  const walk = (dir) => {
6413
- if (!existsSync18(dir)) return;
6539
+ if (!existsSync19(dir)) return;
6414
6540
  for (const entry of readdirSync5(dir, { withFileTypes: true })) {
6415
6541
  const path = join18(dir, entry.name);
6416
6542
  if (entry.isDirectory()) walk(path);
@@ -6437,7 +6563,7 @@ function parseTraceabilityOptions(argv) {
6437
6563
  }
6438
6564
  if (options.check && options.write) usage("Choose only one traceability links mode: --check or --write.", "traceability links");
6439
6565
  options.check = options.check || !options.write;
6440
- options.root = resolve17(options.root);
6566
+ options.root = resolve18(options.root);
6441
6567
  return options;
6442
6568
  }
6443
6569
  function runTraceability(argv) {
@@ -6448,7 +6574,7 @@ function runTraceability(argv) {
6448
6574
  const errors = [...config.errors ?? []];
6449
6575
  for (const file of files) {
6450
6576
  if (options.write && errors.length > 0) break;
6451
- const content = readFileSync18(file, "utf8");
6577
+ const content = readFileSync19(file, "utf8");
6452
6578
  for (const error of validateTraceabilityLinksRegion(content, options.root, file)) errors.push(error);
6453
6579
  const blocks = extractDotdotgodTraceabilityBlocks(content).filter((block) => !block.error);
6454
6580
  if (blocks.length === 0) continue;
@@ -6457,7 +6583,7 @@ function runTraceability(argv) {
6457
6583
  for (const error of result.errors ?? []) errors.push(error);
6458
6584
  continue;
6459
6585
  }
6460
- if (options.write && result.changed) writeFileSync7(file, result.content);
6586
+ if (options.write && result.changed) writeFileSync8(file, result.content);
6461
6587
  if (result.changed) results.push({ file: rel(options.root, file), changed: true });
6462
6588
  }
6463
6589
  const ok = errors.length === 0 && (!options.check || results.length === 0);
@@ -6478,8 +6604,8 @@ function runTraceability(argv) {
6478
6604
 
6479
6605
  // packages/cli/src/graph-view/server.mjs
6480
6606
  import { createServer } from "node:http";
6481
- import { readFileSync as readFileSync19 } from "node:fs";
6482
- import { dirname as dirname12, extname as extname10, join as join19 } from "node:path";
6607
+ import { readFileSync as readFileSync20 } from "node:fs";
6608
+ import { dirname as dirname13, extname as extname10, join as join19 } from "node:path";
6483
6609
  import { fileURLToPath as fileURLToPath2 } from "node:url";
6484
6610
 
6485
6611
  // packages/cli/src/graph-view/payload.mjs
@@ -6591,7 +6717,7 @@ function buildImpactGraphPayload(index, impact) {
6591
6717
  }
6592
6718
 
6593
6719
  // packages/cli/src/graph-view/server.mjs
6594
- var ASSET_ROOT = join19(dirname12(fileURLToPath2(import.meta.url)), "assets");
6720
+ var ASSET_ROOT = join19(dirname13(fileURLToPath2(import.meta.url)), "assets");
6595
6721
  var CONTENT_TYPES = { ".css": "text/css; charset=utf-8", ".html": "text/html; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".map": "application/json; charset=utf-8" };
6596
6722
  var VENDOR_FILES = {
6597
6723
  "/vendor/sigma.js": new URL("../../node_modules/sigma/dist/sigma.min.js", import.meta.url),
@@ -6604,7 +6730,7 @@ function json(response, status, value) {
6604
6730
  }
6605
6731
  function asset(response, file) {
6606
6732
  try {
6607
- const body = readFileSync19(file);
6733
+ const body = readFileSync20(file);
6608
6734
  response.writeHead(200, { "content-type": CONTENT_TYPES[extname10(file)] ?? "application/octet-stream", "cache-control": "no-store" });
6609
6735
  response.end(body);
6610
6736
  } catch {
@@ -6641,16 +6767,16 @@ async function startImpactGraphServer({ root, changed, host = "127.0.0.1", port
6641
6767
  }
6642
6768
  }
6643
6769
  if (VENDOR_FILES[url.pathname]) return asset(response, fileURLToPath2(VENDOR_FILES[url.pathname]));
6644
- const relative7 = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
6645
- if (!["index.html", "app.css", "app.js"].includes(relative7)) {
6770
+ const relative8 = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
6771
+ if (!["index.html", "app.css", "app.js"].includes(relative8)) {
6646
6772
  response.writeHead(404);
6647
6773
  return response.end("Not found");
6648
6774
  }
6649
- return asset(response, join19(ASSET_ROOT, relative7));
6775
+ return asset(response, join19(ASSET_ROOT, relative8));
6650
6776
  });
6651
- await new Promise((resolve18, reject) => {
6777
+ await new Promise((resolve19, reject) => {
6652
6778
  server.once("error", reject);
6653
- server.listen(port, host, resolve18);
6779
+ server.listen(port, host, resolve19);
6654
6780
  });
6655
6781
  const address = server.address();
6656
6782
  const actualPort = typeof address === "object" && address ? address.port : port;