teamai-cli 0.21.0-beta.9 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1452,10 +1452,10 @@ function tgitAuthHeaders(token, scheme) {
1452
1452
  }
1453
1453
  return { "PRIVATE-TOKEN": token };
1454
1454
  }
1455
- async function tgitFetch(path109, init2) {
1455
+ async function tgitFetch(path110, init2) {
1456
1456
  const { token, scheme: resolvedScheme } = getTGitToken();
1457
1457
  const scheme = cachedScheme ?? resolvedScheme;
1458
- const url = `${TGIT_API_BASE}${path109}`;
1458
+ const url = `${TGIT_API_BASE}${path110}`;
1459
1459
  const callerHeaders = { ...init2?.headers };
1460
1460
  const baseHeaders = { "Content-Type": "application/json", ...callerHeaders };
1461
1461
  const doFetch = (activeScheme) => fetch(url, {
@@ -3883,7 +3883,7 @@ async function resolveOpenclawWorkspaceDir(workspacePath) {
3883
3883
  return candidate;
3884
3884
  }
3885
3885
  }
3886
- log.warn(`openclaw: no workspace dir found (tried: ${candidates.join(", ") || "none"})`);
3886
+ log.debug(`openclaw: no workspace dir found (tried: ${candidates.join(", ") || "none"})`);
3887
3887
  return null;
3888
3888
  }
3889
3889
  var OPENCLAW_HOOK_DIR, TEAMAI_MARKER, EVENT_MAP, CLAUDE_TO_OPENCLAW_EVENTS;
@@ -10426,83 +10426,21 @@ var init_env = __esm({
10426
10426
  }
10427
10427
  });
10428
10428
 
10429
- // src/builtin-agents.ts
10430
- var builtin_agents_exports = {};
10431
- __export(builtin_agents_exports, {
10432
- BUILTIN_AGENT_NAMES: () => BUILTIN_AGENT_NAMES,
10433
- deployBuiltinAgents: () => deployBuiltinAgents
10434
- });
10435
- import fs12 from "fs";
10436
- import path31 from "path";
10437
- import { fileURLToPath as fileURLToPath3 } from "url";
10438
- function getBuiltinAgentsDir() {
10439
- const distDir = path31.dirname(fileURLToPath3(import.meta.url));
10440
- return path31.join(distDir, "..", "agents");
10441
- }
10442
- async function deployBuiltinAgents(teamConfig, localConfig, options) {
10443
- const builtinDir = getBuiltinAgentsDir();
10444
- if (!await pathExists(builtinDir)) {
10445
- log.debug("No built-in agents directory found, skipping deployment");
10446
- return 0;
10447
- }
10448
- let entries;
10449
- try {
10450
- entries = await fs12.promises.readdir(builtinDir);
10451
- } catch {
10452
- return 0;
10453
- }
10454
- const agentFiles = entries.filter((f) => f.endsWith(".md") && !f.startsWith(".")).filter((f) => !(options?.skipRecall && f === "teamai-recall.md"));
10455
- if (agentFiles.length === 0) return 0;
10456
- const baseDir = localConfig ? resolveBaseDir(localConfig) : getUserHome();
10457
- let deployed = 0;
10458
- for (const [tool, toolPath] of Object.entries(scopedToolPaths(teamConfig, localConfig ?? {}))) {
10459
- if (!toolPath.agents) {
10460
- log.debug(`Skipping built-in agent deployment for ${tool}: no agents path`);
10461
- continue;
10462
- }
10463
- if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) {
10464
- log.debug(`Skipping built-in agent deployment for ${tool}: tool not installed`);
10465
- continue;
10466
- }
10467
- if (localConfig && isAgentDisabled(localConfig, tool)) continue;
10468
- const targetAgentsDir = path31.join(baseDir, toolPath.agents);
10469
- try {
10470
- await ensureDir(targetAgentsDir);
10471
- } catch (e) {
10472
- log.warn(`Failed to create agents dir for ${tool}: ${e.message}`);
10473
- continue;
10474
- }
10475
- for (const file of agentFiles) {
10476
- const src = path31.join(builtinDir, file);
10477
- const dest = path31.join(targetAgentsDir, file);
10478
- try {
10479
- await copyFile(src, dest);
10480
- deployed++;
10481
- } catch (e) {
10482
- log.warn(`Failed to deploy built-in agent ${file} to ${tool}: ${e.message}`);
10483
- }
10484
- }
10485
- }
10486
- return deployed;
10487
- }
10488
- var BUILTIN_AGENT_NAMES;
10489
- var init_builtin_agents = __esm({
10490
- "src/builtin-agents.ts"() {
10491
- "use strict";
10492
- init_fs();
10493
- init_logger();
10494
- init_types();
10495
- init_base();
10496
- init_home();
10497
- BUILTIN_AGENT_NAMES = /* @__PURE__ */ new Set(["teamai-recall"]);
10498
- }
10499
- });
10500
-
10501
10429
  // src/resources/agent-format.ts
10502
- import path32 from "path";
10430
+ import path31 from "path";
10503
10431
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
10504
10432
  import matter from "gray-matter";
10505
10433
  import { stringify as stringifyToml, parse as parseToml } from "smol-toml";
10434
+ function agentFileExtensionForTool(tool) {
10435
+ switch (tool) {
10436
+ case "codex":
10437
+ case "codex-internal":
10438
+ case "tcodex":
10439
+ return ".toml";
10440
+ default:
10441
+ return ".md";
10442
+ }
10443
+ }
10506
10444
  function parseAgentYaml(content, filename) {
10507
10445
  let raw;
10508
10446
  try {
@@ -10536,19 +10474,34 @@ function serializeAgentYaml(spec) {
10536
10474
  return stringifyYaml(spec, { lineWidth: 120 });
10537
10475
  }
10538
10476
  function renderForClaude(spec) {
10539
- return { ext: ".md", content: renderMarkdownAgent(spec, spec.tool_extras?.["claude"]) };
10477
+ return {
10478
+ ext: agentFileExtensionForTool("claude"),
10479
+ content: renderMarkdownAgent(spec, spec.tool_extras?.["claude"])
10480
+ };
10540
10481
  }
10541
10482
  function renderForClaudeInternal(spec) {
10542
- return { ext: ".md", content: renderMarkdownAgent(spec, spec.tool_extras?.["claude-internal"]) };
10483
+ return {
10484
+ ext: agentFileExtensionForTool("claude-internal"),
10485
+ content: renderMarkdownAgent(spec, spec.tool_extras?.["claude-internal"])
10486
+ };
10543
10487
  }
10544
10488
  function renderForCodebuddy(spec) {
10545
- return { ext: ".md", content: renderMarkdownAgent(spec, spec.tool_extras?.["codebuddy"]) };
10489
+ return {
10490
+ ext: agentFileExtensionForTool("codebuddy"),
10491
+ content: renderMarkdownAgent(spec, spec.tool_extras?.["codebuddy"])
10492
+ };
10546
10493
  }
10547
10494
  function renderForCodex(spec) {
10548
- return { ext: ".toml", content: renderTomlAgent(spec, spec.tool_extras?.["codex"]) };
10495
+ return {
10496
+ ext: agentFileExtensionForTool("codex"),
10497
+ content: renderTomlAgent(spec, spec.tool_extras?.["codex"])
10498
+ };
10549
10499
  }
10550
10500
  function renderForCodexInternal(spec) {
10551
- return { ext: ".toml", content: renderTomlAgent(spec, spec.tool_extras?.["codex-internal"]) };
10501
+ return {
10502
+ ext: agentFileExtensionForTool("codex-internal"),
10503
+ content: renderTomlAgent(spec, spec.tool_extras?.["codex-internal"])
10504
+ };
10552
10505
  }
10553
10506
  function renderForCursor(spec) {
10554
10507
  const frontmatterData = {
@@ -10565,7 +10518,7 @@ function renderForCursor(spec) {
10565
10518
  }
10566
10519
  }
10567
10520
  const content = matter.stringify(spec.instructions, frontmatterData);
10568
- return { ext: ".md", content };
10521
+ return { ext: agentFileExtensionForTool("cursor"), content };
10569
10522
  }
10570
10523
  function renderForOpencode(spec) {
10571
10524
  const frontmatterData = {
@@ -10582,7 +10535,7 @@ function renderForOpencode(spec) {
10582
10535
  }
10583
10536
  }
10584
10537
  const content = matter.stringify(spec.instructions, frontmatterData);
10585
- return { ext: ".md", content };
10538
+ return { ext: agentFileExtensionForTool("opencode"), content };
10586
10539
  }
10587
10540
  function renderMarkdownAgent(spec, extras) {
10588
10541
  const frontmatterData = {
@@ -10627,7 +10580,7 @@ function reverseFromClaude(filePath, content) {
10627
10580
  }
10628
10581
  const fm = parsed.data;
10629
10582
  const body = parsed.content.trim();
10630
- const name = fm["name"] ?? path32.basename(filePath, ".md");
10583
+ const name = fm["name"] ?? path31.basename(filePath, ".md");
10631
10584
  if (!name) return { ok: false, reason: "missing field name" };
10632
10585
  if (!fm["description"]) return { ok: false, reason: "missing field description" };
10633
10586
  if (!body) return { ok: false, reason: "missing field instructions (empty body)" };
@@ -10663,7 +10616,7 @@ function reverseFromCodex(filePath, content) {
10663
10616
  } catch (err) {
10664
10617
  return { ok: false, reason: `parse error: ${err.message}` };
10665
10618
  }
10666
- const name = parsed["name"] ?? path32.basename(filePath, ".toml");
10619
+ const name = parsed["name"] ?? path31.basename(filePath, ".toml");
10667
10620
  if (!name) return { ok: false, reason: "missing field name" };
10668
10621
  if (!parsed["description"]) return { ok: false, reason: "missing field description" };
10669
10622
  if (!parsed["developer_instructions"]) return { ok: false, reason: "missing field developer_instructions" };
@@ -10691,7 +10644,7 @@ function reverseFromCursor(filePath, content) {
10691
10644
  }
10692
10645
  const fm = parsed.data;
10693
10646
  const body = parsed.content.trim();
10694
- const name = fm["agent_id"] ?? path32.basename(filePath, ".md");
10647
+ const name = fm["agent_id"] ?? path31.basename(filePath, ".md");
10695
10648
  if (!name) return { ok: false, reason: "missing field agent_id" };
10696
10649
  if (!fm["description"]) return { ok: false, reason: "missing field description" };
10697
10650
  if (!body) return { ok: false, reason: "missing field instructions (empty body)" };
@@ -10720,7 +10673,7 @@ function reverseFromOpencode(filePath, content) {
10720
10673
  }
10721
10674
  const fm = parsed.data;
10722
10675
  const body = parsed.content.trim();
10723
- const name = path32.basename(filePath, ".md");
10676
+ const name = path31.basename(filePath, ".md");
10724
10677
  if (!name) return { ok: false, reason: "missing agent name (empty filename)" };
10725
10678
  if (!fm["description"]) return { ok: false, reason: "missing field description" };
10726
10679
  if (!body) return { ok: false, reason: "missing field instructions (empty body)" };
@@ -10833,6 +10786,91 @@ var init_agent_format = __esm({
10833
10786
  }
10834
10787
  });
10835
10788
 
10789
+ // src/builtin-agents.ts
10790
+ var builtin_agents_exports = {};
10791
+ __export(builtin_agents_exports, {
10792
+ BUILTIN_AGENT_NAMES: () => BUILTIN_AGENT_NAMES,
10793
+ deployBuiltinAgents: () => deployBuiltinAgents
10794
+ });
10795
+ import fs12 from "fs";
10796
+ import path32 from "path";
10797
+ import { fileURLToPath as fileURLToPath3 } from "url";
10798
+ function getBuiltinAgentsDir() {
10799
+ const distDir = path32.dirname(fileURLToPath3(import.meta.url));
10800
+ return path32.join(distDir, "..", "agents");
10801
+ }
10802
+ async function deployBuiltinAgents(teamConfig, localConfig, options) {
10803
+ const builtinDir = getBuiltinAgentsDir();
10804
+ if (!await pathExists(builtinDir)) {
10805
+ log.debug("No built-in agents directory found, skipping deployment");
10806
+ return 0;
10807
+ }
10808
+ let entries;
10809
+ try {
10810
+ entries = await fs12.promises.readdir(builtinDir);
10811
+ } catch {
10812
+ return 0;
10813
+ }
10814
+ const agentFiles = entries.filter((f) => f.endsWith(".md") && !f.startsWith(".")).filter((f) => !(options?.skipRecall && f === "teamai-recall.md"));
10815
+ if (agentFiles.length === 0) return 0;
10816
+ const baseDir = localConfig ? resolveBaseDir(localConfig) : getUserHome();
10817
+ let deployed = 0;
10818
+ for (const [tool, toolPath] of Object.entries(scopedToolPaths(teamConfig, localConfig ?? {}))) {
10819
+ if (!toolPath.agents) {
10820
+ log.debug(`Skipping built-in agent deployment for ${tool}: no agents path`);
10821
+ continue;
10822
+ }
10823
+ if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) {
10824
+ log.debug(`Skipping built-in agent deployment for ${tool}: tool not installed`);
10825
+ continue;
10826
+ }
10827
+ if (localConfig && isAgentDisabled(localConfig, tool)) continue;
10828
+ if (!ALL_SUPPORTED_TOOLS.includes(tool)) {
10829
+ log.warn(
10830
+ `Skipping built-in agent deployment for ${tool}: unsupported agent format; disable this target or add a native renderer`
10831
+ );
10832
+ continue;
10833
+ }
10834
+ const targetAgentsDir = path32.join(baseDir, toolPath.agents);
10835
+ try {
10836
+ await ensureDir(targetAgentsDir);
10837
+ } catch (e) {
10838
+ log.warn(`Failed to create agents dir for ${tool}: ${e.message}`);
10839
+ continue;
10840
+ }
10841
+ for (const file of agentFiles) {
10842
+ const src = path32.join(builtinDir, file);
10843
+ try {
10844
+ const source = await readFileSafe(src);
10845
+ const parsed = source ? reverseFromClaude(src, source) : { ok: false, reason: "cannot read source file" };
10846
+ if (!parsed.ok) {
10847
+ throw new Error(`invalid built-in agent ${file}: ${parsed.reason}`);
10848
+ }
10849
+ const rendered = renderForTool(parsed.spec, tool);
10850
+ const dest = path32.join(targetAgentsDir, `${path32.basename(file, ".md")}${rendered.ext}`);
10851
+ await writeFile(dest, rendered.content);
10852
+ deployed++;
10853
+ } catch (e) {
10854
+ log.warn(`Failed to deploy built-in agent ${file} to ${tool}: ${e.message}`);
10855
+ }
10856
+ }
10857
+ }
10858
+ return deployed;
10859
+ }
10860
+ var BUILTIN_AGENT_NAMES;
10861
+ var init_builtin_agents = __esm({
10862
+ "src/builtin-agents.ts"() {
10863
+ "use strict";
10864
+ init_fs();
10865
+ init_logger();
10866
+ init_types();
10867
+ init_base();
10868
+ init_home();
10869
+ init_agent_format();
10870
+ BUILTIN_AGENT_NAMES = /* @__PURE__ */ new Set(["teamai-recall"]);
10871
+ }
10872
+ });
10873
+
10836
10874
  // src/resources/agents.ts
10837
10875
  import path33 from "path";
10838
10876
  function getAgentStem(filename) {
@@ -21365,15 +21403,66 @@ var init_hook_dispatch = __esm({
21365
21403
  }
21366
21404
  });
21367
21405
 
21368
- // src/recall-quality.ts
21406
+ // src/project-agent-root.ts
21407
+ var project_agent_root_exports = {};
21408
+ __export(project_agent_root_exports, {
21409
+ seedProjectAgentRoot: () => seedProjectAgentRoot
21410
+ });
21369
21411
  import path65 from "path";
21412
+ function isSafeRelativeRoot(root) {
21413
+ if (!root) return false;
21414
+ const posix = root.replaceAll("\\", "/");
21415
+ if (path65.isAbsolute(root) || path65.isAbsolute(posix)) return false;
21416
+ if (posix === "~" || posix.startsWith("~/")) return false;
21417
+ const segments = posix.split("/");
21418
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) return false;
21419
+ return segments[0].startsWith(".");
21420
+ }
21421
+ function resolveSkillsPath(tool, teamConfig, localConfig) {
21422
+ if (teamConfig) {
21423
+ const fromTeam = scopedToolPaths(teamConfig, localConfig)[tool]?.skills;
21424
+ if (fromTeam) return fromTeam;
21425
+ }
21426
+ return KNOWN_AGENTS.find((agent) => agent.id === tool)?.skillsPath;
21427
+ }
21428
+ async function seedProjectAgentRoot(tool, cwd) {
21429
+ const id = tool.trim();
21430
+ if (!id) return;
21431
+ const projectConfig = await detectProjectConfig(cwd);
21432
+ if (!projectConfig) return;
21433
+ if (isAgentDisabled(projectConfig, id)) return;
21434
+ const enabled = projectConfig.enabledAgents;
21435
+ if (enabled && enabled.length > 0 && !enabled.includes(id)) return;
21436
+ const teamConfig = await loadTeamConfig(projectConfig.repo.localPath);
21437
+ const skillsPath = resolveSkillsPath(id, teamConfig, projectConfig);
21438
+ if (!skillsPath) return;
21439
+ const root = toolInstallRoot(skillsPath);
21440
+ if (!isSafeRelativeRoot(root)) return;
21441
+ const dest = path65.join(resolveBaseDir(projectConfig), root);
21442
+ await ensureDir(dest);
21443
+ log.debug(`Seeded project agent root for ${id}: ${dest}`);
21444
+ }
21445
+ var init_project_agent_root = __esm({
21446
+ "src/project-agent-root.ts"() {
21447
+ "use strict";
21448
+ init_config();
21449
+ init_known_agents();
21450
+ init_base();
21451
+ init_types();
21452
+ init_fs();
21453
+ init_logger();
21454
+ }
21455
+ });
21456
+
21457
+ // src/recall-quality.ts
21458
+ import path66 from "path";
21370
21459
  import fs19 from "fs";
21371
21460
  function sanitizeSessionId(sessionId) {
21372
21461
  return sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
21373
21462
  }
21374
21463
  function getCachePath(sessionId) {
21375
21464
  const safeName = sanitizeSessionId(sessionId);
21376
- return path65.join(
21465
+ return path66.join(
21377
21466
  getUserHome(),
21378
21467
  ".teamai",
21379
21468
  "sessions",
@@ -21404,7 +21493,7 @@ function readCache(sessionId) {
21404
21493
  function writeCache(sessionId, cache) {
21405
21494
  try {
21406
21495
  const cachePath = getCachePath(sessionId);
21407
- const dir = path65.dirname(cachePath);
21496
+ const dir = path66.dirname(cachePath);
21408
21497
  if (!fs19.existsSync(dir)) {
21409
21498
  fs19.mkdirSync(dir, { recursive: true });
21410
21499
  }
@@ -21491,7 +21580,7 @@ __export(contribute_check_exports, {
21491
21580
  writeContributeState: () => writeContributeState
21492
21581
  });
21493
21582
  import fs20 from "fs";
21494
- import path66 from "path";
21583
+ import path67 from "path";
21495
21584
  import { execFileSync as execFileSync2 } from "child_process";
21496
21585
  function sanitizeSessionId2(sessionId) {
21497
21586
  return sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -21517,7 +21606,7 @@ function normalizePromptSummary(raw) {
21517
21606
  return `${truncated}\u2026`;
21518
21607
  }
21519
21608
  function getSessionPath(sessionId) {
21520
- return path66.join(
21609
+ return path67.join(
21521
21610
  getUserHome(),
21522
21611
  ".teamai",
21523
21612
  "sessions",
@@ -21555,14 +21644,14 @@ async function readContributeState(sessionId) {
21555
21644
  async function writeContributeState(sessionId, state) {
21556
21645
  try {
21557
21646
  const filePath = getSessionPath(sessionId);
21558
- await ensureDir(path66.dirname(filePath));
21647
+ await ensureDir(path67.dirname(filePath));
21559
21648
  const persistedState = {
21560
21649
  ...state,
21561
21650
  friction: parseSessionFriction(state.friction),
21562
21651
  promptSummary: normalizePromptSummary(state.promptSummary)
21563
21652
  };
21564
21653
  await writeJson(filePath, persistedState);
21565
- await cleanupStaleSessions(path66.dirname(filePath), sessionId);
21654
+ await cleanupStaleSessions(path67.dirname(filePath), sessionId);
21566
21655
  } catch (e) {
21567
21656
  log.error(`Failed to write contribute state: ${e.message}`);
21568
21657
  }
@@ -21575,7 +21664,7 @@ async function cleanupStaleSessions(dir, currentSessionId) {
21575
21664
  if (!entry.endsWith(".json")) continue;
21576
21665
  const name = entry.replace(".json", "");
21577
21666
  if (name === currentBasename) continue;
21578
- const filePath = path66.join(dir, entry);
21667
+ const filePath = path67.join(dir, entry);
21579
21668
  try {
21580
21669
  const stat6 = await fs20.promises.stat(filePath);
21581
21670
  if (now - stat6.mtimeMs > STALE_SESSION_MS) {
@@ -21868,7 +21957,7 @@ __export(transcript_parser_exports, {
21868
21957
  parseTranscriptForVotes: () => parseTranscriptForVotes
21869
21958
  });
21870
21959
  import fs21 from "fs";
21871
- import path67 from "path";
21960
+ import path68 from "path";
21872
21961
  import readline4 from "readline";
21873
21962
  async function parseTranscriptForVotes(transcriptPath) {
21874
21963
  const recalledSet = /* @__PURE__ */ new Set();
@@ -21938,7 +22027,7 @@ function extractRecalledDocIds(text, out) {
21938
22027
  let match;
21939
22028
  while ((match = filePattern.exec(region)) !== null) {
21940
22029
  const filePath = match[1].trim();
21941
- const docId = path67.basename(filePath).replace(/\.md$/i, "");
22030
+ const docId = path68.basename(filePath).replace(/\.md$/i, "");
21942
22031
  if (isValidDocId(docId)) out.add(docId);
21943
22032
  }
21944
22033
  searchFrom = endIdx + END.length;
@@ -21970,10 +22059,10 @@ __export(todowrite_hint_exports, {
21970
22059
  shouldSkipTodoWriteHint: () => shouldSkipTodoWriteHint,
21971
22060
  todoWriteHint: () => todoWriteHint
21972
22061
  });
21973
- import path68 from "path";
22062
+ import path69 from "path";
21974
22063
  import fs22 from "fs";
21975
22064
  function getTodoWriteHintCachePath(sessionId) {
21976
- return path68.join(
22065
+ return path69.join(
21977
22066
  getUserHome(),
21978
22067
  ".teamai",
21979
22068
  "sessions",
@@ -21996,7 +22085,7 @@ function readCache2(sessionId) {
21996
22085
  function writeCache2(sessionId, cache) {
21997
22086
  try {
21998
22087
  const cachePath = getTodoWriteHintCachePath(sessionId);
21999
- const dir = path68.dirname(cachePath);
22088
+ const dir = path69.dirname(cachePath);
22000
22089
  if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
22001
22090
  fs22.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
22002
22091
  } catch {
@@ -22079,12 +22168,12 @@ __export(mr_hint_exports, {
22079
22168
  });
22080
22169
  import { spawnSync as spawnSync6 } from "child_process";
22081
22170
  import fs23 from "fs";
22082
- import path69 from "path";
22171
+ import path70 from "path";
22083
22172
  function repoSlug(owner, repo) {
22084
22173
  return `${owner}/${repo}`.replace(/[^a-zA-Z0-9_-]/g, "_");
22085
22174
  }
22086
22175
  function getCachePath2(owner, repo) {
22087
- return path69.join(
22176
+ return path70.join(
22088
22177
  getUserHome(),
22089
22178
  ".teamai",
22090
22179
  "sessions",
@@ -22107,7 +22196,7 @@ function loadCache(owner, repo) {
22107
22196
  function saveCache(owner, repo, cache) {
22108
22197
  try {
22109
22198
  const cachePath = getCachePath2(owner, repo);
22110
- const dir = path69.dirname(cachePath);
22199
+ const dir = path70.dirname(cachePath);
22111
22200
  if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
22112
22201
  fs23.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
22113
22202
  } catch {
@@ -22254,7 +22343,7 @@ function buildHintMessage2(mrs) {
22254
22343
  async function computeMrHintOutput() {
22255
22344
  if (process.env.TEAMAI_MR_HINT_DISABLED === "1") return null;
22256
22345
  const rawCwd = process.env.TEAMAI_MR_HINT_CWD ?? process.cwd();
22257
- const cwd = path69.resolve(rawCwd);
22346
+ const cwd = path70.resolve(rawCwd);
22258
22347
  try {
22259
22348
  if (!fs23.statSync(cwd).isDirectory()) {
22260
22349
  return null;
@@ -22323,7 +22412,7 @@ var init_mr_hint = __esm({
22323
22412
  });
22324
22413
 
22325
22414
  // src/hook-handlers.ts
22326
- import path70 from "path";
22415
+ import path71 from "path";
22327
22416
  function buildHandlerRegistry() {
22328
22417
  return [
22329
22418
  // ─── SessionStart ─────────────────────────────────
@@ -22368,6 +22457,7 @@ var init_hook_handlers = __esm({
22368
22457
  "src/hook-handlers.ts"() {
22369
22458
  "use strict";
22370
22459
  init_session_id();
22460
+ init_logger();
22371
22461
  init_tool_names();
22372
22462
  FOREGROUND_HOOK_TIMEOUT_MS = 4500;
22373
22463
  TODOWRITE_HINT_TIMEOUT_MS = 2500;
@@ -22375,7 +22465,14 @@ var init_hook_handlers = __esm({
22375
22465
  LOCAL_AGENT_TIMEOUT_MS = 15e3;
22376
22466
  pullHandler = {
22377
22467
  name: "pull",
22378
- async execute(_stdin, _tool) {
22468
+ async execute(stdin, tool) {
22469
+ const cwd = typeof stdin.cwd === "string" ? stdin.cwd : void 0;
22470
+ try {
22471
+ const { seedProjectAgentRoot: seedProjectAgentRoot2 } = await Promise.resolve().then(() => (init_project_agent_root(), project_agent_root_exports));
22472
+ await seedProjectAgentRoot2(tool, cwd);
22473
+ } catch (e) {
22474
+ log.debug(`hook-dispatch: seedProjectAgentRoot failed: ${e.message}`);
22475
+ }
22379
22476
  const { pull: pull2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
22380
22477
  await pull2({ silent: true });
22381
22478
  return null;
@@ -22475,7 +22572,7 @@ var init_hook_handlers = __esm({
22475
22572
  const { localConfig } = await autoDetectInit2();
22476
22573
  const { VOTES_LOCAL_DIR: VOTES_LOCAL_DIR2, TEAMAI_SESSIONS_DIR: TEAMAI_SESSIONS_DIR2 } = await Promise.resolve().then(() => (init_types(), types_exports));
22477
22574
  const votesDir = VOTES_LOCAL_DIR2;
22478
- const votePath = path70.join(votesDir, `${localConfig.username}.yaml`);
22575
+ const votePath = path71.join(votesDir, `${localConfig.username}.yaml`);
22479
22576
  if (voteData.referencedDocIds.length > 0) {
22480
22577
  await incrementUpvoted2(votePath, voteData.referencedDocIds);
22481
22578
  }
@@ -22500,7 +22597,7 @@ var init_hook_handlers = __esm({
22500
22597
  if (recalled.length > 0 && declared.length === 0) {
22501
22598
  const fsp = await import("fs/promises");
22502
22599
  const safeId = sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
22503
- const marker = path70.join(TEAMAI_SESSIONS_DIR2, `${safeId}-adoption-nudged`);
22600
+ const marker = path71.join(TEAMAI_SESSIONS_DIR2, `${safeId}-adoption-nudged`);
22504
22601
  let already = false;
22505
22602
  try {
22506
22603
  await fsp.access(marker);
@@ -22704,21 +22801,21 @@ __export(contribute_exports, {
22704
22801
  contribute: () => contribute
22705
22802
  });
22706
22803
  import fs24 from "fs";
22707
- import path71 from "path";
22804
+ import path72 from "path";
22708
22805
  import fse11 from "fs-extra";
22709
22806
  async function rebuildIndexAfterContribute(localConfig) {
22710
22807
  const repoPath = localConfig.repo.localPath;
22711
- const learningsRepoDir = path71.join(repoPath, "learnings");
22712
- const docsRepoDir = path71.join(repoPath, "docs");
22713
- const rulesRepoDir = path71.join(repoPath, "rules");
22714
- const skillsRepoDir = path71.join(repoPath, "skills");
22715
- const votesDir = path71.join(repoPath, "votes");
22808
+ const learningsRepoDir = path72.join(repoPath, "learnings");
22809
+ const docsRepoDir = path72.join(repoPath, "docs");
22810
+ const rulesRepoDir = path72.join(repoPath, "rules");
22811
+ const skillsRepoDir = path72.join(repoPath, "skills");
22812
+ const votesDir = path72.join(repoPath, "votes");
22716
22813
  let effectiveLearningsDir;
22717
22814
  if (localConfig.scope === "user") {
22718
22815
  if (await pathExists(learningsRepoDir)) {
22719
22816
  await fse11.copy(learningsRepoDir, LEARNINGS_LOCAL_DIR, {
22720
22817
  overwrite: true,
22721
- filter: (src) => !path71.basename(src).startsWith(".")
22818
+ filter: (src) => !path72.basename(src).startsWith(".")
22722
22819
  });
22723
22820
  }
22724
22821
  effectiveLearningsDir = await pathExists(LEARNINGS_LOCAL_DIR) ? LEARNINGS_LOCAL_DIR : void 0;
@@ -22726,7 +22823,7 @@ async function rebuildIndexAfterContribute(localConfig) {
22726
22823
  effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
22727
22824
  }
22728
22825
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
22729
- const indexPath = path71.join(teamaiHome, "search-index.json");
22826
+ const indexPath = path72.join(teamaiHome, "search-index.json");
22730
22827
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
22731
22828
  await buildIndex2({
22732
22829
  learningsDir: effectiveLearningsDir,
@@ -22789,9 +22886,9 @@ async function contribute(options) {
22789
22886
  const pushSpin = spinner("Contributing session knowledge...").start();
22790
22887
  const filename = generateFilename(options.title);
22791
22888
  try {
22792
- const aiDocsDir = path71.join(repoPath, "learnings");
22889
+ const aiDocsDir = path72.join(repoPath, "learnings");
22793
22890
  await ensureDir(aiDocsDir);
22794
- const destPath = path71.join(aiDocsDir, filename);
22891
+ const destPath = path72.join(aiDocsDir, filename);
22795
22892
  await fs24.promises.writeFile(destPath, content, "utf-8");
22796
22893
  try {
22797
22894
  await pullRepo(repoPath);
@@ -22841,23 +22938,23 @@ async function contributeSelf(localConfig, content, options) {
22841
22938
  const teamConfig = await loadTeamConfig(localConfig.repo.localPath);
22842
22939
  await withKnowledgeWorktree2(localConfig, async (wtConfig) => {
22843
22940
  const wtRepo = wtConfig.repo.localPath;
22844
- await ensureDir(path71.join(wtRepo, "learnings"));
22845
- await fs24.promises.writeFile(path71.join(wtRepo, relPath), content, "utf-8");
22941
+ await ensureDir(path72.join(wtRepo, "learnings"));
22942
+ await fs24.promises.writeFile(path72.join(wtRepo, relPath), content, "utf-8");
22846
22943
  try {
22847
22944
  const { pathExists: pathExists3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
22848
- const wtLearnings = path71.join(wtRepo, "learnings");
22945
+ const wtLearnings = path72.join(wtRepo, "learnings");
22849
22946
  await fse11.copy(wtLearnings, LEARNINGS_LOCAL_DIR, {
22850
22947
  overwrite: true,
22851
- filter: (src) => !path71.basename(src).startsWith(".")
22948
+ filter: (src) => !path72.basename(src).startsWith(".")
22852
22949
  });
22853
22950
  const repoPath = localConfig.repo.localPath;
22854
- const docsDir = path71.join(repoPath, "docs");
22855
- const rulesDir = path71.join(repoPath, "rules");
22856
- const skillsDir = path71.join(repoPath, "skills");
22951
+ const docsDir = path72.join(repoPath, "docs");
22952
+ const rulesDir = path72.join(repoPath, "rules");
22953
+ const skillsDir = path72.join(repoPath, "skills");
22857
22954
  let votesDir;
22858
22955
  try {
22859
22956
  const { ensureReportsWorktree: ensureReportsWorktree2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
22860
- const candidate = path71.join(await ensureReportsWorktree2(localConfig), "votes");
22957
+ const candidate = path72.join(await ensureReportsWorktree2(localConfig), "votes");
22861
22958
  if (await pathExists3(candidate)) votesDir = candidate;
22862
22959
  } catch {
22863
22960
  }
@@ -22869,7 +22966,7 @@ async function contributeSelf(localConfig, content, options) {
22869
22966
  rulesDir: await pathExists3(rulesDir) ? rulesDir : void 0,
22870
22967
  skillsDir: await pathExists3(skillsDir) ? skillsDir : void 0,
22871
22968
  votesDir,
22872
- indexPath: path71.join(teamaiHome, "search-index.json")
22969
+ indexPath: path72.join(teamaiHome, "search-index.json")
22873
22970
  });
22874
22971
  } catch (e) {
22875
22972
  log.debug(`contribute(self): local index refresh skipped: ${e.message}`);
@@ -22915,7 +23012,7 @@ var init_contribute = __esm({
22915
23012
  });
22916
23013
 
22917
23014
  // src/wiki-engine/core/wiki-protocol.ts
22918
- import path72 from "path";
23015
+ import path73 from "path";
22919
23016
  function safeIgnore(filePath) {
22920
23017
  const normalized = toPosix(filePath);
22921
23018
  const parts = normalized.split("/").filter(Boolean);
@@ -22929,7 +23026,7 @@ function safeIgnore(filePath) {
22929
23026
  return /\.(pem|key|p12|pfx)$/i.test(base);
22930
23027
  }
22931
23028
  function toPosix(value) {
22932
- return value.split(path72.sep).join("/");
23029
+ return value.split(path73.sep).join("/");
22933
23030
  }
22934
23031
  var CONFIDENCE_SCORE_DEFAULTS, SAFE_IGNORE_SEGMENTS, SENSITIVE_FILE_NAMES;
22935
23032
  var init_wiki_protocol = __esm({
@@ -22976,7 +23073,7 @@ __export(graph_index_schema_exports, {
22976
23073
  validateGraph: () => validateGraph
22977
23074
  });
22978
23075
  import { readFile as readFile2, writeFile as writeFile4, mkdir } from "fs/promises";
22979
- import path73 from "path";
23076
+ import path74 from "path";
22980
23077
  function toPageSlug(relativePath) {
22981
23078
  return relativePath.replace(/\.md$/u, "").replace(/\\/g, "/");
22982
23079
  }
@@ -23147,7 +23244,7 @@ function computeGraphHealth(graph) {
23147
23244
  };
23148
23245
  }
23149
23246
  async function loadGraphIndex(wikiRoot) {
23150
- const graphPath = path73.join(wikiRoot, ".indices", "graph-index.json");
23247
+ const graphPath = path74.join(wikiRoot, ".indices", "graph-index.json");
23151
23248
  try {
23152
23249
  const raw = await readFile2(graphPath, "utf8");
23153
23250
  const parsed = JSON.parse(raw);
@@ -23163,9 +23260,9 @@ async function loadGraphIndex(wikiRoot) {
23163
23260
  }
23164
23261
  }
23165
23262
  async function saveGraphIndex(wikiRoot, graph) {
23166
- const dir = path73.join(wikiRoot, ".indices");
23263
+ const dir = path74.join(wikiRoot, ".indices");
23167
23264
  await mkdir(dir, { recursive: true });
23168
- const outPath = path73.join(dir, "graph-index.json");
23265
+ const outPath = path74.join(dir, "graph-index.json");
23169
23266
  await writeFile4(outPath, JSON.stringify(graph, null, 2), "utf8");
23170
23267
  return outPath;
23171
23268
  }
@@ -23218,7 +23315,7 @@ var init_graph_index_schema = __esm({
23218
23315
 
23219
23316
  // src/code-knowledge-recall.ts
23220
23317
  import { readFile as readFile3, readdir } from "fs/promises";
23221
- import path74 from "path";
23318
+ import path75 from "path";
23222
23319
  import matter5 from "gray-matter";
23223
23320
  function countOccurrences(text, token) {
23224
23321
  let count = 0;
@@ -23353,7 +23450,7 @@ function extractSnippet(content, queryTokens, maxLen = 300) {
23353
23450
  async function loadWikiPages(wikiRoot, depth) {
23354
23451
  const pages = [];
23355
23452
  if (depth === "route") {
23356
- const routerPath = path74.join(wikiRoot, "router.md");
23453
+ const routerPath = path75.join(wikiRoot, "router.md");
23357
23454
  try {
23358
23455
  const content = await readFile3(routerPath, "utf-8");
23359
23456
  const titleMatch = content.match(/^title:\s*(.+)$/m);
@@ -23369,7 +23466,7 @@ async function loadWikiPages(wikiRoot, depth) {
23369
23466
  }
23370
23467
  return pages;
23371
23468
  }
23372
- const evidenceDir = path74.join(wikiRoot, "evidence", "code");
23469
+ const evidenceDir = path75.join(wikiRoot, "evidence", "code");
23373
23470
  let projectDirs;
23374
23471
  try {
23375
23472
  const entries = await readdir(evidenceDir, { withFileTypes: true });
@@ -23378,7 +23475,7 @@ async function loadWikiPages(wikiRoot, depth) {
23378
23475
  return pages;
23379
23476
  }
23380
23477
  for (const project of projectDirs) {
23381
- const projectDir = path74.join(evidenceDir, project);
23478
+ const projectDir = path75.join(evidenceDir, project);
23382
23479
  await loadPagesRecursive(projectDir, `evidence/code/${project}`, pages, depth);
23383
23480
  }
23384
23481
  return pages;
@@ -23449,7 +23546,7 @@ async function loadPagesRecursive(dir, relativePath, pages, depth, currentDepth
23449
23546
  if (currentDepth >= MAX_RECURSION_DEPTH) return;
23450
23547
  const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
23451
23548
  for (const entry of entries) {
23452
- const fullPath = path74.join(dir, entry.name);
23549
+ const fullPath = path75.join(dir, entry.name);
23453
23550
  if (entry.isDirectory()) {
23454
23551
  await loadPagesRecursive(
23455
23552
  fullPath,
@@ -23624,7 +23721,7 @@ __export(recall_exports, {
23624
23721
  isRelevantScore: () => isRelevantScore,
23625
23722
  recall: () => recall
23626
23723
  });
23627
- import path75 from "path";
23724
+ import path76 from "path";
23628
23725
  function isRelevantScore(score, isCodebaseHit, idfBaseline) {
23629
23726
  if (isCodebaseHit) return score >= CODEBASE_RELEVANCE_THRESHOLD;
23630
23727
  const baseline = idfBaseline > 0 ? idfBaseline : 1;
@@ -23640,7 +23737,7 @@ function computeIdfBaseline(indexes) {
23640
23737
  return Math.log((maxEntries + 1) / 2) + 1;
23641
23738
  }
23642
23739
  function getVotesLocalDir() {
23643
- return path75.join(getUserHome(), ".teamai", "votes");
23740
+ return path76.join(getUserHome(), ".teamai", "votes");
23644
23741
  }
23645
23742
  function formatResults(results) {
23646
23743
  const lines = [];
@@ -23699,7 +23796,7 @@ async function autoUpvote(results, username, _repoPath) {
23699
23796
  try {
23700
23797
  const { incrementRecalled: incrementRecalled2 } = await Promise.resolve().then(() => (init_votes(), votes_exports));
23701
23798
  const votesDir = getVotesLocalDir();
23702
- const localVotePath = path75.join(votesDir, `${username}.yaml`);
23799
+ const localVotePath = path76.join(votesDir, `${username}.yaml`);
23703
23800
  await ensureDir(votesDir);
23704
23801
  const docIds = results.map((r) => r.entry.filename.replace(/\.md$/i, ""));
23705
23802
  await incrementRecalled2(localVotePath, docIds);
@@ -23710,9 +23807,9 @@ async function autoUpvote(results, username, _repoPath) {
23710
23807
  }
23711
23808
  async function loadOrBuildScopeIndex(localConfig, scopeLabel) {
23712
23809
  const teamaiHome = localConfig.scope === "project" && localConfig.projectRoot ? getTeamaiHome("project", localConfig.projectRoot) : getTeamaiHome("user");
23713
- const indexPath = path75.join(teamaiHome, "search-index.json");
23714
- const localLearningsDir = path75.join(teamaiHome, "learnings");
23715
- const repoLearningsDir = path75.join(localConfig.repo.localPath, "learnings");
23810
+ const indexPath = path76.join(teamaiHome, "search-index.json");
23811
+ const localLearningsDir = path76.join(teamaiHome, "learnings");
23812
+ const repoLearningsDir = path76.join(localConfig.repo.localPath, "learnings");
23716
23813
  let effectiveLearningsDir = null;
23717
23814
  if (scopeLabel === "user" && await pathExists(localLearningsDir)) {
23718
23815
  effectiveLearningsDir = localLearningsDir;
@@ -23721,14 +23818,14 @@ async function loadOrBuildScopeIndex(localConfig, scopeLabel) {
23721
23818
  }
23722
23819
  let index = await loadIndex(indexPath);
23723
23820
  const needsRebuild = !index || isLegacyIndex(index);
23724
- if (needsRebuild && (effectiveLearningsDir || await pathExists(path75.join(localConfig.repo.localPath, "docs")) || await pathExists(path75.join(localConfig.repo.localPath, "rules")) || await pathExists(path75.join(localConfig.repo.localPath, "skills")))) {
23821
+ if (needsRebuild && (effectiveLearningsDir || await pathExists(path76.join(localConfig.repo.localPath, "docs")) || await pathExists(path76.join(localConfig.repo.localPath, "rules")) || await pathExists(path76.join(localConfig.repo.localPath, "skills")))) {
23725
23822
  const { getReportsDir: getReportsDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
23726
- const votesDir = path75.join(getReportsDir2(localConfig), "votes");
23823
+ const votesDir = path76.join(getReportsDir2(localConfig), "votes");
23727
23824
  const votesExist = await pathExists(votesDir);
23728
- const docsDir = path75.join(localConfig.repo.localPath, "docs");
23729
- const rulesDir = path75.join(localConfig.repo.localPath, "rules");
23730
- const skillsDir = path75.join(localConfig.repo.localPath, "skills");
23731
- const repoCodebaseDir = path75.join(localConfig.repo.localPath, "docs", "team-codebase");
23825
+ const docsDir = path76.join(localConfig.repo.localPath, "docs");
23826
+ const rulesDir = path76.join(localConfig.repo.localPath, "rules");
23827
+ const skillsDir = path76.join(localConfig.repo.localPath, "skills");
23828
+ const repoCodebaseDir = path76.join(localConfig.repo.localPath, "docs", "team-codebase");
23732
23829
  const hasLegacyCodebase = await pathExists(repoCodebaseDir);
23733
23830
  if (hasLegacyCodebase) {
23734
23831
  log.warn(`Legacy 'docs/team-codebase' is no longer indexed. Migrate to 'teamwiki/' for code-knowledge recall.`);
@@ -23831,7 +23928,7 @@ async function recall(query, options) {
23831
23928
  }
23832
23929
  }
23833
23930
  const wikiConfig = projectConfig ?? scopeIndexes[0]?.config;
23834
- const wikiRoot = wikiConfig ? path75.join(wikiConfig.repo.localPath, "teamwiki") : path75.join(process.cwd(), ".teamai", "team-repo", "teamwiki");
23931
+ const wikiRoot = wikiConfig ? path76.join(wikiConfig.repo.localPath, "teamwiki") : path76.join(process.cwd(), ".teamai", "team-repo", "teamwiki");
23835
23932
  const hasWiki = await pathExists(wikiRoot);
23836
23933
  if (scopeIndexes.length === 0 && !hasWiki) {
23837
23934
  if (options.check) {
@@ -23872,7 +23969,7 @@ async function recall(query, options) {
23872
23969
  votes: 0,
23873
23970
  type: "docs",
23874
23971
  domain: "technical",
23875
- path: path75.join(wikiRoot, cr.page),
23972
+ path: path76.join(wikiRoot, cr.page),
23876
23973
  snippet: cr.snippet
23877
23974
  },
23878
23975
  score: Math.min(10, Math.log2(cr.score + 1) * 2),
@@ -23945,27 +24042,34 @@ __export(recall_toggle_exports, {
23945
24042
  recallEnable: () => recallEnable,
23946
24043
  recallStatus: () => recallStatus
23947
24044
  });
23948
- import path76 from "path";
24045
+ import path77 from "path";
23949
24046
  async function removeRecallArtifacts(teamConfig, localConfig) {
23950
24047
  const baseDir = resolveBaseDir(localConfig);
23951
24048
  for (const [tool, toolPath] of Object.entries(scopedToolPaths(teamConfig, localConfig))) {
23952
24049
  if (toolPath.rules) {
23953
- const ruleFile = path76.join(baseDir, toolPath.rules, "teamai-recall.md");
24050
+ const ruleFile = path77.join(baseDir, toolPath.rules, "teamai-recall.md");
23954
24051
  if (await pathExists(ruleFile)) {
23955
24052
  await remove(ruleFile);
23956
24053
  log.debug(`Removed recall rule from ${tool}`);
23957
24054
  }
23958
24055
  }
23959
24056
  if (toolPath.agents) {
23960
- const agentFile = path76.join(baseDir, toolPath.agents, "teamai-recall.md");
23961
- if (await pathExists(agentFile)) {
23962
- await remove(agentFile);
23963
- log.debug(`Removed recall agent from ${tool}`);
24057
+ const agentsDir = path77.join(baseDir, toolPath.agents);
24058
+ const extensions = /* @__PURE__ */ new Set([".md"]);
24059
+ if (ALL_SUPPORTED_TOOLS.includes(tool)) {
24060
+ extensions.add(agentFileExtensionForTool(tool));
24061
+ }
24062
+ for (const extension of extensions) {
24063
+ const agentFile = path77.join(agentsDir, `teamai-recall${extension}`);
24064
+ if (await pathExists(agentFile)) {
24065
+ await remove(agentFile);
24066
+ log.debug(`Removed recall agent from ${tool}`);
24067
+ }
23964
24068
  }
23965
24069
  }
23966
24070
  if (toolPath.skills) {
23967
24071
  for (const skillName of RECALL_DEPENDENT_SKILLS) {
23968
- const skillDir = path76.join(baseDir, toolPath.skills, skillName);
24072
+ const skillDir = path77.join(baseDir, toolPath.skills, skillName);
23969
24073
  if (await pathExists(skillDir)) {
23970
24074
  await remove(skillDir);
23971
24075
  log.debug(`Removed recall skill ${skillName} from ${tool}`);
@@ -23973,7 +24077,7 @@ async function removeRecallArtifacts(teamConfig, localConfig) {
23973
24077
  }
23974
24078
  }
23975
24079
  if (toolPath.claudemd) {
23976
- const claudeMdPath = path76.join(baseDir, toolPath.claudemd);
24080
+ const claudeMdPath = path77.join(baseDir, toolPath.claudemd);
23977
24081
  const content = await readFileSafe(claudeMdPath);
23978
24082
  if (content && content.includes(TEAMAI_RECALL_RULES_START)) {
23979
24083
  const startIdx = content.indexOf(TEAMAI_RECALL_RULES_START);
@@ -24007,7 +24111,7 @@ async function deployRecallArtifacts(teamConfig, localConfig) {
24007
24111
  for (const [tool, toolPath] of Object.entries(scopedToolPaths(teamConfig, localConfig))) {
24008
24112
  if (!toolPath.claudemd || !toolPath.agents) continue;
24009
24113
  if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) continue;
24010
- const claudeMdPath = path76.join(baseDir, toolPath.claudemd);
24114
+ const claudeMdPath = path77.join(baseDir, toolPath.claudemd);
24011
24115
  try {
24012
24116
  await injectClaudeMdSection2(
24013
24117
  claudeMdPath,
@@ -24053,26 +24157,27 @@ var init_recall_toggle = __esm({
24053
24157
  init_logger();
24054
24158
  init_fs();
24055
24159
  init_base();
24160
+ init_agent_format();
24056
24161
  init_builtin_skills();
24057
24162
  init_types();
24058
24163
  }
24059
24164
  });
24060
24165
 
24061
24166
  // src/utils/cache-index.ts
24062
- import path77 from "path";
24167
+ import path78 from "path";
24063
24168
  import os7 from "os";
24064
24169
  import fs25 from "fs-extra";
24065
24170
  function getCacheRoot() {
24066
- return process.env.TEAMAI_CACHE_DIR ?? path77.join(os7.homedir(), ".teamai", "cache", "repos");
24171
+ return process.env.TEAMAI_CACHE_DIR ?? path78.join(os7.homedir(), ".teamai", "cache", "repos");
24067
24172
  }
24068
24173
  function buildKey(provider, owner, repo) {
24069
24174
  return `${provider}/${owner}/${repo}`;
24070
24175
  }
24071
24176
  function keyToAbsPath(key) {
24072
- return path77.join(getCacheRoot(), key);
24177
+ return path78.join(getCacheRoot(), key);
24073
24178
  }
24074
24179
  async function loadCacheIndex() {
24075
- const indexPath = path77.join(getCacheRoot(), INDEX_FILENAME);
24180
+ const indexPath = path78.join(getCacheRoot(), INDEX_FILENAME);
24076
24181
  try {
24077
24182
  const stat6 = await fs25.stat(indexPath);
24078
24183
  if (stat6.size > MAX_CONFIG_FILE_BYTES) {
@@ -24095,7 +24200,7 @@ async function loadCacheIndex() {
24095
24200
  async function saveCacheIndex(idx) {
24096
24201
  const root = getCacheRoot();
24097
24202
  await fs25.ensureDir(root);
24098
- const indexPath = path77.join(root, INDEX_FILENAME);
24203
+ const indexPath = path78.join(root, INDEX_FILENAME);
24099
24204
  const updated = { ...idx, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
24100
24205
  await fs25.writeFile(indexPath, JSON.stringify(updated, null, 2), "utf8");
24101
24206
  }
@@ -24128,7 +24233,7 @@ async function statDirSize(absPath) {
24128
24233
  return 0;
24129
24234
  }
24130
24235
  for (const entry of entries) {
24131
- const childPath = path77.join(absPath, entry.name);
24236
+ const childPath = path78.join(absPath, entry.name);
24132
24237
  if (entry.isSymbolicLink()) {
24133
24238
  continue;
24134
24239
  }
@@ -24616,7 +24721,7 @@ var init_ai_client = __esm({
24616
24721
 
24617
24722
  // src/import-local.ts
24618
24723
  import fs26 from "fs";
24619
- import path78 from "path";
24724
+ import path79 from "path";
24620
24725
  import readline5 from "readline";
24621
24726
  function toSlug(title) {
24622
24727
  return title.toLowerCase().replace(/[^a-z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
@@ -24652,7 +24757,7 @@ function parseClassifyOutput(sourcePath, rawContent, output) {
24652
24757
  sourcePath,
24653
24758
  rawContent,
24654
24759
  type: knownType,
24655
- title: typeof parsed.title === "string" ? parsed.title : path78.basename(sourcePath),
24760
+ title: typeof parsed.title === "string" ? parsed.title : path79.basename(sourcePath),
24656
24761
  summary: typeof parsed.summary === "string" ? parsed.summary : "",
24657
24762
  tags: Array.isArray(parsed.tags) ? parsed.tags.filter((t) => typeof t === "string") : [],
24658
24763
  confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0,
@@ -24664,7 +24769,7 @@ function parseClassifyOutput(sourcePath, rawContent, output) {
24664
24769
  sourcePath,
24665
24770
  rawContent,
24666
24771
  type: "learning",
24667
- title: path78.basename(sourcePath),
24772
+ title: path79.basename(sourcePath),
24668
24773
  summary: "",
24669
24774
  tags: [],
24670
24775
  confidence: 0,
@@ -24710,9 +24815,9 @@ async function scanCandidates(opts) {
24710
24815
  const relPaths = await listFilesRecursive(expandedDir);
24711
24816
  for (const relPath of relPaths) {
24712
24817
  if (relPath.split("/").some((seg) => seg.startsWith("."))) continue;
24713
- const ext = path78.extname(relPath).toLowerCase();
24818
+ const ext = path79.extname(relPath).toLowerCase();
24714
24819
  if (ext !== ".md" && ext !== ".txt") continue;
24715
- const absPath = path78.join(expandedDir, relPath);
24820
+ const absPath = path79.join(expandedDir, relPath);
24716
24821
  try {
24717
24822
  const stat6 = fs26.statSync(absPath);
24718
24823
  if (stat6.size > MAX_FILE_SIZE_BYTES) continue;
@@ -24734,8 +24839,8 @@ async function scanCandidates(opts) {
24734
24839
  if (!fs26.existsSync(baseDir)) continue;
24735
24840
  const relPaths = await listFilesRecursive(baseDir);
24736
24841
  for (const relPath of relPaths) {
24737
- if (path78.extname(relPath).toLowerCase() !== ".md") continue;
24738
- const absPath = path78.join(baseDir, relPath);
24842
+ if (path79.extname(relPath).toLowerCase() !== ".md") continue;
24843
+ const absPath = path79.join(baseDir, relPath);
24739
24844
  try {
24740
24845
  const stat6 = fs26.statSync(absPath);
24741
24846
  if (stat6.size > MAX_FILE_SIZE_BYTES) continue;
@@ -24766,7 +24871,7 @@ async function classifyWithAI(candidates) {
24766
24871
  sourcePath: c.path,
24767
24872
  rawContent: c.rawContent,
24768
24873
  type: "learning",
24769
- title: path78.basename(c.path),
24874
+ title: path79.basename(c.path),
24770
24875
  summary: "",
24771
24876
  tags: [],
24772
24877
  confidence: 0,
@@ -24846,7 +24951,7 @@ async function interactiveReview(items, opts) {
24846
24951
  for (const sessionItem of pendingItems) {
24847
24952
  const currentIndex = session.items.indexOf(sessionItem) + 1;
24848
24953
  const classified = classifiedMap.get(sessionItem.sourcePath ?? "");
24849
- const title = sessionItem.learningDraft?.title ?? classified?.title ?? path78.basename(sessionItem.sourcePath ?? "");
24954
+ const title = sessionItem.learningDraft?.title ?? classified?.title ?? path79.basename(sessionItem.sourcePath ?? "");
24850
24955
  const itemType = classified?.type ?? "learning";
24851
24956
  const summary = classified?.summary ?? "";
24852
24957
  const tags = classified?.tags ?? [];
@@ -24913,9 +25018,9 @@ async function pushAccepted(session, repoPath, opts) {
24913
25018
  } else {
24914
25019
  const typeInContent = detectTypeFromContent(draft.content);
24915
25020
  const subDir = typeInContent === "rule" ? "rules" : typeInContent === "doc" ? "docs" : "learnings";
24916
- destDir = path78.join(expandHome(repoPath), subDir);
25021
+ destDir = path79.join(expandHome(repoPath), subDir);
24917
25022
  }
24918
- const destPath = path78.join(destDir, filename);
25023
+ const destPath = path79.join(destDir, filename);
24919
25024
  if (opts.dryRun) {
24920
25025
  log.info(`[dry-run] would write: ${destPath}`);
24921
25026
  pushed++;
@@ -24944,7 +25049,7 @@ var init_import_local = __esm({
24944
25049
  init_home();
24945
25050
  MAX_FILE_SIZE_BYTES = 50 * 1024;
24946
25051
  MAX_CONTENT_CHARS = 3e3;
24947
- DEFAULT_SESSION_PATH = path78.join(getUserHome(), ".teamai", "import-session.json");
25052
+ DEFAULT_SESSION_PATH = path79.join(getUserHome(), ".teamai", "import-session.json");
24948
25053
  AI_CONCURRENCY = 3;
24949
25054
  }
24950
25055
  });
@@ -25181,7 +25286,7 @@ var init_iwiki_client = __esm({
25181
25286
  });
25182
25287
 
25183
25288
  // src/import-iwiki.ts
25184
- import path79 from "path";
25289
+ import path80 from "path";
25185
25290
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
25186
25291
  function parseIWikiInput(input) {
25187
25292
  const trimmed = input.trim();
@@ -25270,8 +25375,8 @@ async function importFromIWiki(opts) {
25270
25375
  dryRun: opts.dryRun,
25271
25376
  outputDir: opts.outputDir
25272
25377
  });
25273
- const teamwikiRoot = path79.join(repoPath, "teamwiki");
25274
- if (await pathExists(path79.join(teamwikiRoot, ".indices", "graph-index.json"))) {
25378
+ const teamwikiRoot = path80.join(repoPath, "teamwiki");
25379
+ if (await pathExists(path80.join(teamwikiRoot, ".indices", "graph-index.json"))) {
25275
25380
  try {
25276
25381
  const mapsToEdges = await reconcileIwikiWithCodebase(documents, teamwikiRoot);
25277
25382
  if (mapsToEdges.length > 0) {
@@ -25290,7 +25395,7 @@ async function importFromIWiki(opts) {
25290
25395
  log.success("iWiki import complete");
25291
25396
  }
25292
25397
  async function reconcileIwikiWithCodebase(documents, teamwikiRoot) {
25293
- const graphPath = path79.join(teamwikiRoot, ".indices", "graph-index.json");
25398
+ const graphPath = path80.join(teamwikiRoot, ".indices", "graph-index.json");
25294
25399
  const graphRaw = await readFile4(graphPath, "utf-8");
25295
25400
  const graph = JSON.parse(graphRaw);
25296
25401
  const codeLabels = /* @__PURE__ */ new Map();
@@ -25299,17 +25404,17 @@ async function reconcileIwikiWithCodebase(documents, teamwikiRoot) {
25299
25404
  const words = node.label.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
25300
25405
  codeLabels.set(words, node.id);
25301
25406
  }
25302
- const evidenceDir = path79.join(teamwikiRoot, "evidence", "code");
25407
+ const evidenceDir = path80.join(teamwikiRoot, "evidence", "code");
25303
25408
  const codePageContents = /* @__PURE__ */ new Map();
25304
25409
  if (await pathExists(evidenceDir)) {
25305
25410
  const { readdir: readdir9 } = await import("fs/promises");
25306
25411
  const projects = await readdir9(evidenceDir);
25307
25412
  for (const project of projects) {
25308
- const projectDir = path79.join(evidenceDir, project);
25413
+ const projectDir = path80.join(evidenceDir, project);
25309
25414
  const files = await readdir9(projectDir).catch(() => []);
25310
25415
  for (const file of files) {
25311
25416
  if (!file.endsWith(".md")) continue;
25312
- const content = await readFile4(path79.join(projectDir, file), "utf-8").catch(() => "");
25417
+ const content = await readFile4(path80.join(projectDir, file), "utf-8").catch(() => "");
25313
25418
  codePageContents.set(`evidence/code/${project}/${file}`, content);
25314
25419
  }
25315
25420
  }
@@ -25398,7 +25503,7 @@ function parseGitHubPRUrl(url) {
25398
25503
  }
25399
25504
  return { owner: match[1], repo: match[2], number: match[3] };
25400
25505
  }
25401
- async function githubApiGet(path109) {
25506
+ async function githubApiGet(path110) {
25402
25507
  return new Promise((resolve, reject) => {
25403
25508
  const token = process.env["GITHUB_TOKEN"];
25404
25509
  const headers = {
@@ -25407,7 +25512,7 @@ async function githubApiGet(path109) {
25407
25512
  };
25408
25513
  if (token) headers["Authorization"] = `Bearer ${token}`;
25409
25514
  const req = https2.request(
25410
- { hostname: "api.github.com", path: path109, headers },
25515
+ { hostname: "api.github.com", path: path110, headers },
25411
25516
  (res) => {
25412
25517
  const chunks = [];
25413
25518
  res.on("data", (c) => chunks.push(c));
@@ -25566,7 +25671,7 @@ var init_mr_fetch3 = __esm({
25566
25671
 
25567
25672
  // src/utils/dedup.ts
25568
25673
  import fs27 from "fs/promises";
25569
- import path80 from "path";
25674
+ import path81 from "path";
25570
25675
  import matter6 from "gray-matter";
25571
25676
  function extractKeywords(text) {
25572
25677
  const keywords = /* @__PURE__ */ new Set();
@@ -25624,7 +25729,7 @@ async function findSupersededLearnings(draftKeywords, learningsDir, withinDays =
25624
25729
  const cutoffDate = new Date(Date.now() - withinDays * 24 * 60 * 60 * 1e3);
25625
25730
  const results = [];
25626
25731
  for (const filename of mdFiles) {
25627
- const filePath = path80.join(learningsDir, filename);
25732
+ const filePath = path81.join(learningsDir, filename);
25628
25733
  try {
25629
25734
  const docDate = await resolveDocDate(filePath, filename);
25630
25735
  if (docDate < cutoffDate) {
@@ -25706,7 +25811,7 @@ var init_dedup = __esm({
25706
25811
 
25707
25812
  // src/import-mr.ts
25708
25813
  import fs28 from "fs/promises";
25709
- import path81 from "path";
25814
+ import path82 from "path";
25710
25815
  import readline6 from "readline/promises";
25711
25816
  import matter7 from "gray-matter";
25712
25817
  async function fetchMR(url) {
@@ -25860,18 +25965,18 @@ async function importFromMR(opts) {
25860
25965
  async function writeLearning(draft, outputDir, repoPath) {
25861
25966
  if (outputDir) {
25862
25967
  await fs28.mkdir(outputDir, { recursive: true });
25863
- const filePath = path81.join(outputDir, "learning.md");
25968
+ const filePath = path82.join(outputDir, "learning.md");
25864
25969
  await fs28.writeFile(filePath, draft.content, "utf-8");
25865
25970
  log.info(`Learning written: ${filePath}`);
25866
25971
  return;
25867
25972
  }
25868
25973
  if (repoPath) {
25869
- const learningsDir = path81.join(repoPath, "learnings");
25974
+ const learningsDir = path82.join(repoPath, "learnings");
25870
25975
  await fs28.mkdir(learningsDir, { recursive: true });
25871
25976
  const datePrefix = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
25872
25977
  const safeTitle = draft.title.slice(0, 40).replace(/[^a-zA-Z0-9一-鿿_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
25873
25978
  const filename = `${datePrefix}-${safeTitle}.md`;
25874
- const filePath = path81.join(learningsDir, filename);
25979
+ const filePath = path82.join(learningsDir, filename);
25875
25980
  await fs28.writeFile(filePath, draft.content, "utf-8");
25876
25981
  log.info(`Learning written: ${filePath}`);
25877
25982
  return;
@@ -25889,7 +25994,7 @@ var init_import_mr = __esm({
25889
25994
  init_dedup();
25890
25995
  init_logger();
25891
25996
  init_home();
25892
- DEFAULT_LEARNINGS_DIR = path81.join(getUserHome(), ".teamai", "learnings");
25997
+ DEFAULT_LEARNINGS_DIR = path82.join(getUserHome(), ".teamai", "learnings");
25893
25998
  SUPERSEDE_THRESHOLD = 0.6;
25894
25999
  }
25895
26000
  });
@@ -25897,7 +26002,7 @@ var init_import_mr = __esm({
25897
26002
  // src/codebase.ts
25898
26003
  import { execSync as execSync6 } from "child_process";
25899
26004
  import fs29 from "fs";
25900
- import path82 from "path";
26005
+ import path83 from "path";
25901
26006
  import matter8 from "gray-matter";
25902
26007
  async function gatherRepoContext(repoPath) {
25903
26008
  const parts = [];
@@ -25921,7 +26026,7 @@ ${truncated}`);
25921
26026
  } catch (err) {
25922
26027
  log.debug(`gatherRepoContext: find \u5931\u8D25 \u2014 ${String(err)}`);
25923
26028
  }
25924
- const pkgPath = path82.join(repoPath, "package.json");
26029
+ const pkgPath = path83.join(repoPath, "package.json");
25925
26030
  if (fs29.existsSync(pkgPath)) {
25926
26031
  try {
25927
26032
  const raw = fs29.readFileSync(pkgPath, "utf-8");
@@ -25935,7 +26040,7 @@ ${excerpt}
25935
26040
  }
25936
26041
  }
25937
26042
  for (const candidate of ["src/index.ts", "src/main.ts", "index.ts", "main.py"]) {
25938
- const entryPath = path82.join(repoPath, candidate);
26043
+ const entryPath = path83.join(repoPath, candidate);
25939
26044
  if (fs29.existsSync(entryPath)) {
25940
26045
  try {
25941
26046
  const raw = fs29.readFileSync(entryPath, "utf-8");
@@ -25951,7 +26056,7 @@ ${excerpt}
25951
26056
  }
25952
26057
  }
25953
26058
  for (const candidate of ["src/types.ts", "src/types/index.ts", "types.py"]) {
25954
- const typesPath = path82.join(repoPath, candidate);
26059
+ const typesPath = path83.join(repoPath, candidate);
25955
26060
  if (fs29.existsSync(typesPath)) {
25956
26061
  try {
25957
26062
  const raw = fs29.readFileSync(typesPath, "utf-8");
@@ -25967,10 +26072,10 @@ ${excerpt}
25967
26072
  }
25968
26073
  }
25969
26074
  const docCandidates = [
25970
- path82.join(repoPath, "README.md"),
25971
- path82.join(repoPath, "ARCHITECTURE.md")
26075
+ path83.join(repoPath, "README.md"),
26076
+ path83.join(repoPath, "ARCHITECTURE.md")
25972
26077
  ];
25973
- const docsDir = path82.join(repoPath, "docs");
26078
+ const docsDir = path83.join(repoPath, "docs");
25974
26079
  if (fs29.existsSync(docsDir)) {
25975
26080
  try {
25976
26081
  const entries = fs29.readdirSync(docsDir);
@@ -25978,7 +26083,7 @@ ${excerpt}
25978
26083
  for (const entry of entries) {
25979
26084
  if (count >= DOCS_MAX_FILES) break;
25980
26085
  if (entry.endsWith(".md")) {
25981
- docCandidates.push(path82.join(docsDir, entry));
26086
+ docCandidates.push(path83.join(docsDir, entry));
25982
26087
  count++;
25983
26088
  }
25984
26089
  }
@@ -25991,7 +26096,7 @@ ${excerpt}
25991
26096
  try {
25992
26097
  const raw = fs29.readFileSync(docPath, "utf-8");
25993
26098
  const excerpt = raw.length > DOC_MAX_CHARS ? raw.slice(0, DOC_MAX_CHARS) + "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : raw;
25994
- const relPath = path82.relative(repoPath, docPath);
26099
+ const relPath = path83.relative(repoPath, docPath);
25995
26100
  parts.push(`## \u6587\u6863\u6458\u8981\uFF1A${relPath}
25996
26101
  ${excerpt}`);
25997
26102
  } catch (err) {
@@ -26022,7 +26127,7 @@ ${lines.join("\n")}`);
26022
26127
  if (fileCount >= LEARNINGS_MAX_FILES) break;
26023
26128
  if (!entry.endsWith(".md")) continue;
26024
26129
  try {
26025
- const filePath = path82.join(learningsDir, entry);
26130
+ const filePath = path83.join(learningsDir, entry);
26026
26131
  const raw = fs29.readFileSync(filePath, "utf-8");
26027
26132
  const parsed = matter8(raw);
26028
26133
  const tags = parsed.data["tags"];
@@ -26217,7 +26322,7 @@ var init_codebase = __esm({
26217
26322
  import { createHash as createHash2 } from "crypto";
26218
26323
  import { execFile as execFile4 } from "child_process";
26219
26324
  import { readFile as readFile5, readdir as readdir2, stat } from "fs/promises";
26220
- import path83 from "path";
26325
+ import path84 from "path";
26221
26326
  import { promisify as promisify3 } from "util";
26222
26327
  function isKeyFile(relativePath, language) {
26223
26328
  const patterns = KEY_FILE_PATTERNS[language];
@@ -26225,12 +26330,12 @@ function isKeyFile(relativePath, language) {
26225
26330
  return patterns.some((pattern) => pattern.test(relativePath));
26226
26331
  }
26227
26332
  async function collectCode(options) {
26228
- const root = path83.resolve(options.root);
26333
+ const root = path84.resolve(options.root);
26229
26334
  const filePaths = [];
26230
26335
  await walk(root, filePaths, options.includeTests ?? false);
26231
26336
  let filtered = filePaths.sort((a, b) => {
26232
- const relA = toPosix(path83.relative(root, a));
26233
- const relB = toPosix(path83.relative(root, b));
26337
+ const relA = toPosix(path84.relative(root, a));
26338
+ const relB = toPosix(path84.relative(root, b));
26234
26339
  const langA = languageFor(a);
26235
26340
  const langB = languageFor(b);
26236
26341
  const keyA = isKeyFile(relA, langA) ? 0 : 1;
@@ -26244,7 +26349,7 @@ async function collectCode(options) {
26244
26349
  if (options.changedFiles && options.changedFiles.length > 0) {
26245
26350
  const changedSet = new Set(options.changedFiles.map((f) => toPosix(f)));
26246
26351
  filtered = filtered.filter((fp) => {
26247
- const relativePath = toPosix(path83.relative(root, fp));
26352
+ const relativePath = toPosix(path84.relative(root, fp));
26248
26353
  return changedSet.has(relativePath);
26249
26354
  });
26250
26355
  }
@@ -26252,7 +26357,7 @@ async function collectCode(options) {
26252
26357
  const files = [];
26253
26358
  for (const filePath of limited) {
26254
26359
  const content = await readFile5(filePath, "utf8");
26255
- const relativePath = toPosix(path83.relative(root, filePath));
26360
+ const relativePath = toPosix(path84.relative(root, filePath));
26256
26361
  const language = languageFor(filePath);
26257
26362
  files.push({
26258
26363
  path: filePath,
@@ -26279,7 +26384,7 @@ async function walk(directory, results, includeTests) {
26279
26384
  return;
26280
26385
  }
26281
26386
  for (const entry of await readdir2(directory, { withFileTypes: true })) {
26282
- const fullPath = path83.join(directory, entry.name);
26387
+ const fullPath = path84.join(directory, entry.name);
26283
26388
  if (safeIgnore(fullPath) || !includeTests && isTestPath(fullPath)) {
26284
26389
  continue;
26285
26390
  }
@@ -26292,14 +26397,14 @@ async function walk(directory, results, includeTests) {
26292
26397
  }
26293
26398
  function isCodeFile(filePath) {
26294
26399
  return [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".java", ".json", ".yaml", ".yml", ".toml", ".sql", ".conf", ".ini"].includes(
26295
- path83.extname(filePath).toLowerCase()
26400
+ path84.extname(filePath).toLowerCase()
26296
26401
  );
26297
26402
  }
26298
26403
  function isTestPath(filePath) {
26299
26404
  return /(^|\/|\\)(test|tests|__tests__|fixtures)(\/|\\)|\.test\.|\.spec\./u.test(filePath);
26300
26405
  }
26301
26406
  function languageFor(filePath) {
26302
- const ext = path83.extname(filePath).toLowerCase();
26407
+ const ext = path84.extname(filePath).toLowerCase();
26303
26408
  const map = {
26304
26409
  ".ts": "typescript",
26305
26410
  ".tsx": "typescript",
@@ -26982,14 +27087,14 @@ var init_code_extractors = __esm({
26982
27087
  });
26983
27088
 
26984
27089
  // src/wiki-engine/code-knowledge/code-graph.ts
26985
- import path84 from "path";
27090
+ import path85 from "path";
26986
27091
  function buildCodeGraph(facts) {
26987
27092
  const nodes = facts.filter((fact) => fact.kind !== "relation").map((fact) => ({
26988
27093
  slug: `${fact.kind}/${fact.name}`,
26989
27094
  type: mapFactKindToCategory(fact.kind),
26990
27095
  confidence: fact.confidence === "EXTRACTED" ? "EXTRACTED" : "INFERRED",
26991
27096
  title: fact.name,
26992
- domain: path84.dirname(fact.file).split("/")[0] || void 0
27097
+ domain: path85.dirname(fact.file).split("/")[0] || void 0
26993
27098
  }));
26994
27099
  const nodeFiles = new Set(facts.filter((f) => f.kind !== "relation").map((f) => f.file));
26995
27100
  const edges = facts.filter((fact) => fact.kind === "relation").flatMap((fact) => {
@@ -27032,7 +27137,7 @@ var init_code_graph = __esm({
27032
27137
 
27033
27138
  // src/wiki-engine/code-knowledge/code-incremental.ts
27034
27139
  import { readFile as readFile6, writeFile as writeFile6, stat as stat2, mkdir as mkdir3 } from "fs/promises";
27035
- import path85 from "path";
27140
+ import path86 from "path";
27036
27141
  async function detectCodeIncrementalChanges(root, manifestPath, project) {
27037
27142
  const previous = await exists(manifestPath) ? JSON.parse(await readFile6(manifestPath, "utf8")) : { files: [] };
27038
27143
  const oldSha = previous.headSha;
@@ -27072,14 +27177,14 @@ function affectedPages(project, files) {
27072
27177
  }
27073
27178
  async function exists(filePath) {
27074
27179
  try {
27075
- await stat2(path85.resolve(filePath));
27180
+ await stat2(path86.resolve(filePath));
27076
27181
  return true;
27077
27182
  } catch {
27078
27183
  return false;
27079
27184
  }
27080
27185
  }
27081
27186
  async function loadFactsCache(indicesDir) {
27082
- const cachePath = path85.join(indicesDir, FACTS_CACHE_FILENAME);
27187
+ const cachePath = path86.join(indicesDir, FACTS_CACHE_FILENAME);
27083
27188
  try {
27084
27189
  const raw = await readFile6(cachePath, "utf-8");
27085
27190
  const parsed = JSON.parse(raw);
@@ -27090,10 +27195,10 @@ async function loadFactsCache(indicesDir) {
27090
27195
  }
27091
27196
  async function saveFactsCache(indicesDir, facts) {
27092
27197
  await mkdir3(indicesDir, { recursive: true });
27093
- await writeFile6(path85.join(indicesDir, FACTS_CACHE_FILENAME), JSON.stringify(facts), "utf-8");
27198
+ await writeFile6(path86.join(indicesDir, FACTS_CACHE_FILENAME), JSON.stringify(facts), "utf-8");
27094
27199
  }
27095
27200
  async function loadInterfacesCache(indicesDir) {
27096
- const cachePath = path85.join(indicesDir, INTERFACES_CACHE_FILENAME);
27201
+ const cachePath = path86.join(indicesDir, INTERFACES_CACHE_FILENAME);
27097
27202
  try {
27098
27203
  const raw = await readFile6(cachePath, "utf-8");
27099
27204
  const parsed = JSON.parse(raw);
@@ -27105,7 +27210,7 @@ async function loadInterfacesCache(indicesDir) {
27105
27210
  async function saveInterfacesCache(indicesDir, inventory) {
27106
27211
  await mkdir3(indicesDir, { recursive: true });
27107
27212
  await writeFile6(
27108
- path85.join(indicesDir, INTERFACES_CACHE_FILENAME),
27213
+ path86.join(indicesDir, INTERFACES_CACHE_FILENAME),
27109
27214
  JSON.stringify(inventory, null, 2),
27110
27215
  "utf-8"
27111
27216
  );
@@ -27131,7 +27236,7 @@ var init_code_incremental = __esm({
27131
27236
  });
27132
27237
 
27133
27238
  // src/wiki-engine/interface-scanner.ts
27134
- import path86 from "path";
27239
+ import path87 from "path";
27135
27240
  async function scanInterfaces(files) {
27136
27241
  const componentMap = groupByComponent(files);
27137
27242
  const entries = [];
@@ -27199,7 +27304,7 @@ function groupByComponent(files) {
27199
27304
  if (file.repo) {
27200
27305
  component = parts.length > 1 ? `${file.repo}/${parts[0]}` : file.repo;
27201
27306
  } else {
27202
- component = parts.length > 1 ? parts[0] : path86.basename(path86.dirname(file.path));
27307
+ component = parts.length > 1 ? parts[0] : path87.basename(path87.dirname(file.path));
27203
27308
  }
27204
27309
  const group = map.get(component) ?? [];
27205
27310
  group.push(file);
@@ -27485,7 +27590,7 @@ var init_reconciler_v2_types = __esm({
27485
27590
 
27486
27591
  // src/wiki-engine/knowledge-reconciler.ts
27487
27592
  import { readFile as readFile7, readdir as readdir3, stat as stat3 } from "fs/promises";
27488
- import path87 from "path";
27593
+ import path88 from "path";
27489
27594
  async function exists2(p) {
27490
27595
  return stat3(p).then(() => true).catch(() => false);
27491
27596
  }
@@ -27494,7 +27599,7 @@ async function readPages(dirPath) {
27494
27599
  const entries = await readdir3(dirPath, { withFileTypes: true });
27495
27600
  const pages = [];
27496
27601
  for (const entry of entries) {
27497
- const full = path87.join(dirPath, entry.name);
27602
+ const full = path88.join(dirPath, entry.name);
27498
27603
  if (entry.isDirectory()) {
27499
27604
  pages.push(...await readPages(full));
27500
27605
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -27587,17 +27692,17 @@ async function reconcileKnowledge(options) {
27587
27692
  const productDirNames = options.productDirs ?? ["product", "docs"];
27588
27693
  const codeDirNames = options.codeDirs ?? ["evidence/code"];
27589
27694
  for (const dir of [...productDirNames, ...codeDirNames]) {
27590
- if (dir.includes("..") || path87.isAbsolute(dir)) {
27695
+ if (dir.includes("..") || path88.isAbsolute(dir)) {
27591
27696
  throw new Error(`Unsafe directory path rejected: ${dir}`);
27592
27697
  }
27593
27698
  }
27594
27699
  const productPages = [];
27595
27700
  for (const dir of productDirNames) {
27596
- productPages.push(...await readPages(path87.join(wikiRoot, dir)));
27701
+ productPages.push(...await readPages(path88.join(wikiRoot, dir)));
27597
27702
  }
27598
27703
  const codePages = [];
27599
27704
  for (const dir of codeDirNames) {
27600
- codePages.push(...await readPages(path87.join(wikiRoot, dir)));
27705
+ codePages.push(...await readPages(path88.join(wikiRoot, dir)));
27601
27706
  }
27602
27707
  const graphEdges = [];
27603
27708
  const gaps = [];
@@ -27624,8 +27729,8 @@ async function reconcileKnowledge(options) {
27624
27729
  ];
27625
27730
  const nc = buildConfidence(factors);
27626
27731
  graphEdges.push({
27627
- from: toPageSlug(path87.relative(wikiRoot, productPage.path)),
27628
- to: toPageSlug(path87.relative(wikiRoot, codePage.path)),
27732
+ from: toPageSlug(path88.relative(wikiRoot, productPage.path)),
27733
+ to: toPageSlug(path88.relative(wikiRoot, codePage.path)),
27629
27734
  relation: "MAPS_TO",
27630
27735
  term,
27631
27736
  confidence: nc.label,
@@ -27706,10 +27811,10 @@ async function reconcileKnowledge(options) {
27706
27811
  const MS_PER_DAY = 864e5;
27707
27812
  for (const edge of graphEdges) {
27708
27813
  const fromPage = productPages.find(
27709
- (p) => toPageSlug(path87.relative(wikiRoot, p.path)) === edge.from
27814
+ (p) => toPageSlug(path88.relative(wikiRoot, p.path)) === edge.from
27710
27815
  );
27711
27816
  const toPage = codePages.find(
27712
- (p) => toPageSlug(path87.relative(wikiRoot, p.path)) === edge.to
27817
+ (p) => toPageSlug(path88.relative(wikiRoot, p.path)) === edge.to
27713
27818
  );
27714
27819
  if (!fromPage?.updated || !toPage?.updated) continue;
27715
27820
  const fromMs = new Date(fromPage.updated).getTime();
@@ -27968,7 +28073,7 @@ __export(enrich_with_ai_exports, {
27968
28073
  enrichWithAI: () => enrichWithAI,
27969
28074
  writeManifest: () => writeManifest
27970
28075
  });
27971
- import path88 from "path";
28076
+ import path89 from "path";
27972
28077
  import { writeFile as writeFile8, mkdir as mkdir5 } from "fs/promises";
27973
28078
  function sanitizeForPrompt(text) {
27974
28079
  return text.replace(/[\n\r]/g, " ").replace(/[<>]/g, "").slice(0, 200);
@@ -28019,8 +28124,8 @@ function parseJSON(raw) {
28019
28124
  }
28020
28125
  function resolveImportToModule(importerFile, importPath) {
28021
28126
  if (importPath.startsWith(".")) {
28022
- const importerDir = path88.dirname(importerFile);
28023
- const resolved = path88.normalize(path88.join(importerDir, importPath));
28127
+ const importerDir = path89.dirname(importerFile);
28128
+ const resolved = path89.normalize(path89.join(importerDir, importPath));
28024
28129
  const topLevel = resolved.split("/")[0];
28025
28130
  if (!topLevel || topLevel === ".." || topLevel === ".") return void 0;
28026
28131
  return topLevel;
@@ -28126,7 +28231,7 @@ async function enrichWithAI(ctx) {
28126
28231
  }
28127
28232
  async function writeManifest(manifest, outputDir) {
28128
28233
  await mkdir5(outputDir, { recursive: true });
28129
- const manifestPath = path88.join(outputDir, "_manifest.json");
28234
+ const manifestPath = path89.join(outputDir, "_manifest.json");
28130
28235
  await writeFile8(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
28131
28236
  return manifestPath;
28132
28237
  }
@@ -28144,7 +28249,7 @@ __export(codebase_extract_exports, {
28144
28249
  extractCodebase: () => extractCodebase
28145
28250
  });
28146
28251
  import { mkdir as mkdir6, writeFile as writeFile9, readFile as readFile8 } from "fs/promises";
28147
- import path89 from "path";
28252
+ import path90 from "path";
28148
28253
  import chalk3 from "chalk";
28149
28254
  function detectKnowledgeGaps(facts, graph, files) {
28150
28255
  const gaps = [];
@@ -28161,7 +28266,7 @@ function detectKnowledgeGaps(facts, graph, files) {
28161
28266
  const target = rel.name;
28162
28267
  if (target.startsWith(".")) continue;
28163
28268
  if (target.startsWith("node:")) continue;
28164
- const matchesAnyFile = [...scannedFiles].some((f) => f.includes(target.replace(/\//g, path89.sep)));
28269
+ const matchesAnyFile = [...scannedFiles].some((f) => f.includes(target.replace(/\//g, path90.sep)));
28165
28270
  if (!matchesAnyFile) {
28166
28271
  unresolvedImports.add(target);
28167
28272
  }
@@ -28505,21 +28610,21 @@ function buildOverview(facts, graph, project, interfaceInventory, callChains) {
28505
28610
  lines.push("## Key Dependency Paths");
28506
28611
  lines.push("");
28507
28612
  for (const chain of callChains.slice(0, 5)) {
28508
- const path109 = chain.steps.map((s) => s.symbol).join(" \u2192 ");
28509
- lines.push(`- ${chain.entryPoint}: ${path109}`);
28613
+ const path110 = chain.steps.map((s) => s.symbol).join(" \u2192 ");
28614
+ lines.push(`- ${chain.entryPoint}: ${path110}`);
28510
28615
  }
28511
28616
  }
28512
28617
  lines.push("");
28513
28618
  return lines.join("\n");
28514
28619
  }
28515
28620
  async function extractCodebase(opts) {
28516
- const root = path89.resolve(opts.path || ".");
28517
- const project = opts.project || path89.basename(root);
28621
+ const root = path90.resolve(opts.path || ".");
28622
+ const project = opts.project || path90.basename(root);
28518
28623
  const maxFiles = opts.maxFiles || 200;
28519
- const outputBase = opts.outputRoot ? path89.resolve(opts.outputRoot) : root;
28520
- const wikiRoot = path89.join(outputBase, "teamwiki");
28521
- const evidenceDir = path89.join(wikiRoot, "evidence", "code", project);
28522
- const manifestPath = path89.join(wikiRoot, "source-manifest.json");
28624
+ const outputBase = opts.outputRoot ? path90.resolve(opts.outputRoot) : root;
28625
+ const wikiRoot = path90.join(outputBase, "teamwiki");
28626
+ const evidenceDir = path90.join(wikiRoot, "evidence", "code", project);
28627
+ const manifestPath = path90.join(wikiRoot, "source-manifest.json");
28523
28628
  let changedFiles;
28524
28629
  let deletedFiles = [];
28525
28630
  if (opts.incremental) {
@@ -28556,7 +28661,7 @@ async function extractCodebase(opts) {
28556
28661
  const newFacts = files.length > 0 ? extractCodeFacts(files) : [];
28557
28662
  let facts;
28558
28663
  let interfaceInventory;
28559
- const indicesDir = path89.join(wikiRoot, ".indices");
28664
+ const indicesDir = path90.join(wikiRoot, ".indices");
28560
28665
  if (changedFiles !== void 0) {
28561
28666
  const oldFacts = await loadFactsCache(indicesDir);
28562
28667
  const oldInterfaces = await loadInterfacesCache(indicesDir);
@@ -28584,7 +28689,7 @@ async function extractCodebase(opts) {
28584
28689
  }
28585
28690
  const graph = buildCodeGraph(facts);
28586
28691
  let callChains;
28587
- const depPathsFile = path89.join(evidenceDir, "dependency-paths.md");
28692
+ const depPathsFile = path90.join(evidenceDir, "dependency-paths.md");
28588
28693
  if (changedFiles) {
28589
28694
  let reused = false;
28590
28695
  try {
@@ -28612,7 +28717,7 @@ async function extractCodebase(opts) {
28612
28717
  }
28613
28718
  }
28614
28719
  for (const [filename, content] of pages) {
28615
- await writeIfChanged(path89.join(evidenceDir, filename), content);
28720
+ await writeIfChanged(path90.join(evidenceDir, filename), content);
28616
28721
  }
28617
28722
  const pageSlugs = [...pages.keys()].map((p) => `evidence/code/${project}/${p.replace(".md", "")}`);
28618
28723
  const overlay = buildIndexHubOverlay(project, "evidence/code", pageSlugs);
@@ -28641,7 +28746,7 @@ async function extractCodebase(opts) {
28641
28746
  keywords: enrichResult.repoKeywords || [],
28642
28747
  components: enrichResult.domains[0]?.components ?? []
28643
28748
  };
28644
- await writeFile9(path89.join(evidenceDir, "_domains.json"), JSON.stringify(domainMeta, null, 2), "utf-8");
28749
+ await writeFile9(path90.join(evidenceDir, "_domains.json"), JSON.stringify(domainMeta, null, 2), "utf-8");
28645
28750
  if (!opts.json) {
28646
28751
  const domainLabel = domainMeta.domain || "uncategorized";
28647
28752
  console.log(` AI enrich: ${enrichResult.manifest.components.length} modules, domain=${domainLabel}`);
@@ -28654,14 +28759,14 @@ async function extractCodebase(opts) {
28654
28759
  }
28655
28760
  const moduleSummaries = buildModuleSummaries(facts, graph, project);
28656
28761
  if (moduleSummaries.size > 0) {
28657
- const modulesDir = path89.join(evidenceDir, "modules");
28762
+ const modulesDir = path90.join(evidenceDir, "modules");
28658
28763
  await mkdir6(modulesDir, { recursive: true });
28659
28764
  for (const [filename, content] of moduleSummaries) {
28660
- await writeIfChanged(path89.join(modulesDir, filename), content);
28765
+ await writeIfChanged(path90.join(modulesDir, filename), content);
28661
28766
  }
28662
28767
  }
28663
28768
  const overview = buildOverview(facts, repoGraph, project, interfaceInventory, callChains);
28664
- await writeIfChanged(path89.join(evidenceDir, "overview.md"), overview);
28769
+ await writeIfChanged(path90.join(evidenceDir, "overview.md"), overview);
28665
28770
  const proj = [{ slug: project, label: project }];
28666
28771
  const ifByType = {};
28667
28772
  for (const e of interfaceInventory.entries) {
@@ -28674,11 +28779,11 @@ async function extractCodebase(opts) {
28674
28779
  interfaces: Object.keys(ifByType).length > 0 ? ifByType : void 0,
28675
28780
  callChains: callChains.length > 0 ? callChains.length : void 0
28676
28781
  };
28677
- await writeIfChanged(path89.join(wikiRoot, "router.md"), routerTemplate(proj, aiDomains.length > 0 ? aiDomains : void 0));
28678
- await writeIfChanged(path89.join(wikiRoot, "hot.md"), HOT_TEMPLATE);
28679
- await writeIfChanged(path89.join(wikiRoot, "index.md"), indexTemplate(proj, indexStats));
28782
+ await writeIfChanged(path90.join(wikiRoot, "router.md"), routerTemplate(proj, aiDomains.length > 0 ? aiDomains : void 0));
28783
+ await writeIfChanged(path90.join(wikiRoot, "hot.md"), HOT_TEMPLATE);
28784
+ await writeIfChanged(path90.join(wikiRoot, "index.md"), indexTemplate(proj, indexStats));
28680
28785
  const gaps = detectKnowledgeGaps(facts, graph, files);
28681
- const gapsDir = path89.join(wikiRoot, "gaps");
28786
+ const gapsDir = path90.join(wikiRoot, "gaps");
28682
28787
  await mkdir6(gapsDir, { recursive: true });
28683
28788
  const gapLines = [
28684
28789
  "---",
@@ -28701,7 +28806,7 @@ async function extractCodebase(opts) {
28701
28806
  gapLines.push("| \u2014 | \u2014 | \u2014 | \u672A\u53D1\u73B0\u660E\u663E\u77E5\u8BC6\u7F3A\u53E3 | \u2014 |");
28702
28807
  }
28703
28808
  gapLines.push("");
28704
- await writeIfChanged(path89.join(gapsDir, "detected.md"), gapLines.join("\n"));
28809
+ await writeIfChanged(path90.join(gapsDir, "detected.md"), gapLines.join("\n"));
28705
28810
  await saveFactsCache(indicesDir, facts);
28706
28811
  await saveInterfacesCache(indicesDir, interfaceInventory);
28707
28812
  let allManifestFiles = collectionManifest.files.map((f) => ({
@@ -28970,14 +29075,14 @@ __export(repo_cache_exports, {
28970
29075
  readLastSync: () => readLastSync,
28971
29076
  writeLastSync: () => writeLastSync
28972
29077
  });
28973
- import path90 from "path";
29078
+ import path91 from "path";
28974
29079
  import os8 from "os";
28975
29080
  import fs31 from "fs-extra";
28976
29081
  function getCacheRoot2() {
28977
- return process.env.TEAMAI_CACHE_DIR ?? path90.join(os8.homedir(), ".teamai", "cache", "repos");
29082
+ return process.env.TEAMAI_CACHE_DIR ?? path91.join(os8.homedir(), ".teamai", "cache", "repos");
28978
29083
  }
28979
29084
  function getRepoCacheDir(provider, owner, repo) {
28980
- return path90.join(getCacheRoot2(), provider, owner, repo);
29085
+ return path91.join(getCacheRoot2(), provider, owner, repo);
28981
29086
  }
28982
29087
  function getRepoSlug(provider, owner, repo) {
28983
29088
  const safeOwner = owner.replace(/\//g, "-");
@@ -28988,10 +29093,10 @@ async function writeLastSync(cacheDir, sha) {
28988
29093
  const content = `${sha}
28989
29094
  ${isoTs}
28990
29095
  `;
28991
- await fs31.writeFile(path90.join(cacheDir, LAST_SYNC_FILE), content, "utf8");
29096
+ await fs31.writeFile(path91.join(cacheDir, LAST_SYNC_FILE), content, "utf8");
28992
29097
  }
28993
29098
  async function readLastSync(cacheDir) {
28994
- const filePath = path90.join(cacheDir, LAST_SYNC_FILE);
29099
+ const filePath = path91.join(cacheDir, LAST_SYNC_FILE);
28995
29100
  const exists3 = await fs31.pathExists(filePath);
28996
29101
  if (!exists3) {
28997
29102
  return null;
@@ -29022,7 +29127,7 @@ __export(deep_enrich_exports, {
29022
29127
  deepEnrich: () => deepEnrich
29023
29128
  });
29024
29129
  import { readFile as readFile9, writeFile as writeFile10, readdir as readdir4, mkdir as mkdir7 } from "fs/promises";
29025
- import path91 from "path";
29130
+ import path92 from "path";
29026
29131
  async function readFileSafe4(filePath) {
29027
29132
  try {
29028
29133
  return await readFile9(filePath, "utf-8");
@@ -29031,7 +29136,7 @@ async function readFileSafe4(filePath) {
29031
29136
  }
29032
29137
  }
29033
29138
  async function loadContext(evidenceDir) {
29034
- const manifestRaw = await readFileSafe4(path91.join(evidenceDir, "_manifest.json"));
29139
+ const manifestRaw = await readFileSafe4(path92.join(evidenceDir, "_manifest.json"));
29035
29140
  let manifest = {};
29036
29141
  try {
29037
29142
  manifest = JSON.parse(manifestRaw);
@@ -29039,18 +29144,18 @@ async function loadContext(evidenceDir) {
29039
29144
  log.debug("deep-enrich: failed to parse _manifest.json");
29040
29145
  }
29041
29146
  const [indexMd, callChains, overview] = await Promise.all([
29042
- readFileSafe4(path91.join(evidenceDir, "index.md")),
29043
- readFileSafe4(path91.join(evidenceDir, "dependency-paths.md")),
29044
- readFileSafe4(path91.join(evidenceDir, "overview.md"))
29147
+ readFileSafe4(path92.join(evidenceDir, "index.md")),
29148
+ readFileSafe4(path92.join(evidenceDir, "dependency-paths.md")),
29149
+ readFileSafe4(path92.join(evidenceDir, "overview.md"))
29045
29150
  ]);
29046
- const modulesDir = path91.join(evidenceDir, "modules");
29151
+ const modulesDir = path92.join(evidenceDir, "modules");
29047
29152
  const moduleDocs = /* @__PURE__ */ new Map();
29048
29153
  if (await pathExists(modulesDir)) {
29049
29154
  try {
29050
29155
  const entries = await readdir4(modulesDir);
29051
29156
  await Promise.all(
29052
29157
  entries.filter((e) => e.endsWith(".md")).map(async (e) => {
29053
- const content = await readFileSafe4(path91.join(modulesDir, e));
29158
+ const content = await readFileSafe4(path92.join(modulesDir, e));
29054
29159
  moduleDocs.set(e.replace(/\.md$/, ""), content);
29055
29160
  })
29056
29161
  );
@@ -29061,7 +29166,7 @@ async function loadContext(evidenceDir) {
29061
29166
  return { manifest, indexMd, callChains, overview, moduleDocs };
29062
29167
  }
29063
29168
  function progressPath(evidenceDir) {
29064
- return path91.join(evidenceDir, PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME);
29169
+ return path92.join(evidenceDir, PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME);
29065
29170
  }
29066
29171
  function isValidProgressState(v, project) {
29067
29172
  if (typeof v !== "object" || v === null) return false;
@@ -29087,7 +29192,7 @@ async function loadProgress(evidenceDir, project, allComponents) {
29087
29192
  }
29088
29193
  async function saveProgress(evidenceDir, state) {
29089
29194
  const p = progressPath(evidenceDir);
29090
- await mkdir7(path91.dirname(p), { recursive: true });
29195
+ await mkdir7(path92.dirname(p), { recursive: true });
29091
29196
  const updated = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
29092
29197
  await writeFile10(p, JSON.stringify(updated, null, 2), "utf-8");
29093
29198
  }
@@ -29326,7 +29431,7 @@ async function runPhaseComponents(opts, ctx, progress, docsDir) {
29326
29431
  log.warn(`deep-enrich[${project}]: Skipping unsafe component slug "${comp.slug}": ${e.message}`);
29327
29432
  continue;
29328
29433
  }
29329
- const outPath = path91.join(docsDir, `${comp.slug}.md`);
29434
+ const outPath = path92.join(docsDir, `${comp.slug}.md`);
29330
29435
  await mkdir7(docsDir, { recursive: true });
29331
29436
  await writeFile10(outPath, content, "utf-8");
29332
29437
  progress.componentsDone.push(comp.slug);
@@ -29354,7 +29459,7 @@ async function runPhaseArchitecture(opts, ctx, docsDir) {
29354
29459
  log.warn(`deep-enrich[${project}]: Architecture overview: AI returned empty, skipping write`);
29355
29460
  return;
29356
29461
  }
29357
- const outPath = path91.join(docsDir, "architecture.md");
29462
+ const outPath = path92.join(docsDir, "architecture.md");
29358
29463
  await mkdir7(docsDir, { recursive: true });
29359
29464
  await writeFile10(outPath, content, "utf-8");
29360
29465
  log.debug(`deep-enrich[${project}]: Architecture overview written: ${outPath}`);
@@ -29362,15 +29467,15 @@ async function runPhaseArchitecture(opts, ctx, docsDir) {
29362
29467
  async function runPhaseGraph(opts, ctx, docsDir) {
29363
29468
  const { project, evidenceDir } = opts;
29364
29469
  log.info(`deep-enrich[${project}]: Phase 3 \u2014 Generating deterministic graph docs`);
29365
- const interfacesMd = await readFileSafe4(path91.join(evidenceDir, "interfaces.md"));
29470
+ const interfacesMd = await readFileSafe4(path92.join(evidenceDir, "interfaces.md"));
29366
29471
  const g1 = buildG1RelationsDoc(ctx.manifest);
29367
29472
  const g2 = buildG2DataflowDoc(ctx.callChains);
29368
29473
  const g3 = buildG3InterfacesDoc(interfacesMd);
29369
29474
  await mkdir7(docsDir, { recursive: true });
29370
29475
  await Promise.all([
29371
- writeFile10(path91.join(docsDir, "graph-g1-relations.md"), g1, "utf-8"),
29372
- writeFile10(path91.join(docsDir, "graph-g2-dataflow.md"), g2, "utf-8"),
29373
- writeFile10(path91.join(docsDir, "graph-g3-interfaces.md"), g3, "utf-8")
29476
+ writeFile10(path92.join(docsDir, "graph-g1-relations.md"), g1, "utf-8"),
29477
+ writeFile10(path92.join(docsDir, "graph-g2-dataflow.md"), g2, "utf-8"),
29478
+ writeFile10(path92.join(docsDir, "graph-g3-interfaces.md"), g3, "utf-8")
29374
29479
  ]);
29375
29480
  log.debug(`deep-enrich[${project}]: Graph docs written: ${docsDir}`);
29376
29481
  }
@@ -29476,14 +29581,14 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
29476
29581
  await mkdir7(docsDir, { recursive: true });
29477
29582
  const g6HasEdges = (ctx.manifest.edges ?? []).length > 0;
29478
29583
  const g6 = buildG6Content(project, ctx.manifest);
29479
- await writeFile10(path91.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
29584
+ await writeFile10(path92.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
29480
29585
  log.debug(`deep-enrich[${project}]: G6 multi-hop analysis written`);
29481
29586
  let g5Generated = false;
29482
29587
  if (ctx.moduleDocs.size < 2) {
29483
29588
  log.warn(`deep-enrich[${project}]: Insufficient modules (${ctx.moduleDocs.size} < 2), skipping G5`);
29484
29589
  return { g5Generated, g6Generated: g6HasEdges };
29485
29590
  }
29486
- const architectureMd = await readFileSafe4(path91.join(docsDir, "architecture.md"));
29591
+ const architectureMd = await readFileSafe4(path92.join(docsDir, "architecture.md"));
29487
29592
  if (!architectureMd.trim()) {
29488
29593
  log.warn(`deep-enrich[${project}]: No architecture doc, skipping G5 scenarios`);
29489
29594
  return { g5Generated, g6Generated: g6HasEdges };
@@ -29493,7 +29598,7 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
29493
29598
  try {
29494
29599
  const g5Content = await callClaude(prompt);
29495
29600
  if (g5Content.trim()) {
29496
- await writeFile10(path91.join(docsDir, "graph-g5-scenarios.md"), g5Content, "utf-8");
29601
+ await writeFile10(path92.join(docsDir, "graph-g5-scenarios.md"), g5Content, "utf-8");
29497
29602
  log.debug(`deep-enrich[${project}]: G5 scenario diagrams written`);
29498
29603
  g5Generated = true;
29499
29604
  }
@@ -29511,10 +29616,10 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
29511
29616
  hasG5: graphFlags?.g5Generated ?? false,
29512
29617
  hasG6: graphFlags?.g6Generated ?? true
29513
29618
  });
29514
- await writeFile10(path91.join(docsDir, "README.md"), graphReadme, "utf-8");
29619
+ await writeFile10(path92.join(docsDir, "README.md"), graphReadme, "utf-8");
29515
29620
  log.debug(`deep-enrich[${project}]: graph/README.md routing table written`);
29516
29621
  const { wikiRoot } = opts;
29517
- const domainsJson = await readFileSafe4(path91.join(evidenceDir, "_domains.json"));
29622
+ const domainsJson = await readFileSafe4(path92.join(evidenceDir, "_domains.json"));
29518
29623
  let keywords = [];
29519
29624
  let description = "";
29520
29625
  try {
@@ -29523,7 +29628,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
29523
29628
  description = domains.description ?? "";
29524
29629
  } catch {
29525
29630
  }
29526
- const routerPath = path91.join(wikiRoot, "router.md");
29631
+ const routerPath = path92.join(wikiRoot, "router.md");
29527
29632
  const routerContent = await readFileSafe4(routerPath);
29528
29633
  const projectLink = `[[evidence/code/${project}/index]]`;
29529
29634
  if (routerContent && !routerContent.includes(projectLink)) {
@@ -29533,7 +29638,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
29533
29638
  `;
29534
29639
  await writeFile10(routerPath, routerContent.trimEnd() + "\n" + line, "utf-8");
29535
29640
  }
29536
- const indexPath = path91.join(wikiRoot, "index.md");
29641
+ const indexPath = path92.join(wikiRoot, "index.md");
29537
29642
  const indexContent = await readFileSafe4(indexPath);
29538
29643
  if (indexContent && !indexContent.includes(`evidence/code/${project}/`)) {
29539
29644
  const navBlock = [
@@ -29558,7 +29663,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
29558
29663
  }
29559
29664
  async function deepEnrich(opts) {
29560
29665
  const { project, evidenceDir } = opts;
29561
- const docsDir = path91.join(evidenceDir, "docs");
29666
+ const docsDir = path92.join(evidenceDir, "docs");
29562
29667
  log.info(`deep-enrich[${project}]: Starting deep knowledge generation, evidenceDir=${evidenceDir}`);
29563
29668
  const ctx = await loadContext(evidenceDir);
29564
29669
  let components = ctx.manifest.components ?? [];
@@ -29647,11 +29752,11 @@ var graph_aggregate_exports = {};
29647
29752
  __export(graph_aggregate_exports, {
29648
29753
  aggregateGlobalGraph: () => aggregateGlobalGraph
29649
29754
  });
29650
- import path92 from "path";
29755
+ import path93 from "path";
29651
29756
  import { readdir as readdir5 } from "fs/promises";
29652
29757
  import fs32 from "fs-extra";
29653
29758
  async function aggregateGlobalGraph(teamwikiRoot) {
29654
- const evidenceBase = path92.join(teamwikiRoot, "evidence", "code");
29759
+ const evidenceBase = path93.join(teamwikiRoot, "evidence", "code");
29655
29760
  if (!await fs32.pathExists(evidenceBase)) return null;
29656
29761
  const { mergeGraphs: mergeGraphs2 } = await Promise.resolve().then(() => (init_adapters(), adapters_exports));
29657
29762
  const { detectCrossRepoEdges: detectCrossRepoEdges2 } = await Promise.resolve().then(() => (init_import_repo(), import_repo_exports));
@@ -29659,7 +29764,7 @@ async function aggregateGlobalGraph(teamwikiRoot) {
29659
29764
  const projectDirs = await readdir5(evidenceBase, { withFileTypes: true });
29660
29765
  for (const dir of projectDirs) {
29661
29766
  if (!dir.isDirectory()) continue;
29662
- const graphPath = path92.join(evidenceBase, dir.name, ".indices", "graph-index.json");
29767
+ const graphPath = path93.join(evidenceBase, dir.name, ".indices", "graph-index.json");
29663
29768
  if (!await fs32.pathExists(graphPath)) continue;
29664
29769
  try {
29665
29770
  const overlay = JSON.parse(await fs32.readFile(graphPath, "utf8"));
@@ -29677,8 +29782,8 @@ async function aggregateGlobalGraph(teamwikiRoot) {
29677
29782
  }
29678
29783
  }
29679
29784
  if (globalGraph) {
29680
- const destPath = path92.join(teamwikiRoot, ".indices", "graph-index.json");
29681
- await fs32.ensureDir(path92.dirname(destPath));
29785
+ const destPath = path93.join(teamwikiRoot, ".indices", "graph-index.json");
29786
+ await fs32.ensureDir(path93.dirname(destPath));
29682
29787
  await fs32.writeFile(destPath, JSON.stringify(globalGraph, null, 2), "utf8");
29683
29788
  log.info(`global graph-index.json aggregated (${globalGraph.nodes.length} nodes, ${globalGraph.edges.length} edges)`);
29684
29789
  return { nodes: globalGraph.nodes.length, edges: globalGraph.edges.length };
@@ -29698,9 +29803,9 @@ __export(rebuild_wiki_index_exports, {
29698
29803
  rebuildWikiIndex: () => rebuildWikiIndex
29699
29804
  });
29700
29805
  import { readFile as readFile10, readdir as readdir6, stat as stat4, writeFile as writeFile11 } from "fs/promises";
29701
- import path93 from "path";
29806
+ import path94 from "path";
29702
29807
  async function rebuildWikiIndex(teamwikiRoot) {
29703
- const evidenceCodeDir = path93.join(teamwikiRoot, "evidence", "code");
29808
+ const evidenceCodeDir = path94.join(teamwikiRoot, "evidence", "code");
29704
29809
  if (!await pathExists(evidenceCodeDir)) return;
29705
29810
  const projects = [];
29706
29811
  let totalFacts = 0, totalNodes = 0, totalEdges = 0;
@@ -29708,7 +29813,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29708
29813
  let totalCallChains = 0;
29709
29814
  const dirs = await readdir6(evidenceCodeDir);
29710
29815
  for (const dir of dirs) {
29711
- const dirPath = path93.join(evidenceCodeDir, dir);
29816
+ const dirPath = path94.join(evidenceCodeDir, dir);
29712
29817
  const dirStat = await stat4(dirPath).catch(() => null);
29713
29818
  if (!dirStat?.isDirectory()) continue;
29714
29819
  const info = {
@@ -29721,7 +29826,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29721
29826
  keywords: [],
29722
29827
  domain: ""
29723
29828
  };
29724
- const overviewPath = path93.join(dirPath, "overview.md");
29829
+ const overviewPath = path94.join(dirPath, "overview.md");
29725
29830
  if (await pathExists(overviewPath)) {
29726
29831
  const content = await readFile10(overviewPath, "utf-8");
29727
29832
  const bodyStart = content.indexOf("\n\n", content.indexOf("---", 3));
@@ -29734,7 +29839,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29734
29839
  }
29735
29840
  }
29736
29841
  }
29737
- const projectIndex = path93.join(dirPath, "index.md");
29842
+ const projectIndex = path94.join(dirPath, "index.md");
29738
29843
  if (await pathExists(projectIndex)) {
29739
29844
  const content = await readFile10(projectIndex, "utf-8");
29740
29845
  const factsMatch = content.match(/Facts:\s*(\d+)/);
@@ -29744,7 +29849,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29744
29849
  info.interfaces[m[1]] = (info.interfaces[m[1]] ?? 0) + parseInt(m[2], 10);
29745
29850
  }
29746
29851
  }
29747
- const manifestPath = path93.join(dirPath, "_manifest.json");
29852
+ const manifestPath = path94.join(dirPath, "_manifest.json");
29748
29853
  if (await pathExists(manifestPath)) {
29749
29854
  try {
29750
29855
  const raw = await readFile10(manifestPath, "utf-8");
@@ -29756,7 +29861,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29756
29861
  } catch {
29757
29862
  }
29758
29863
  }
29759
- const domainsPath = path93.join(dirPath, "_domains.json");
29864
+ const domainsPath = path94.join(dirPath, "_domains.json");
29760
29865
  if (await pathExists(domainsPath)) {
29761
29866
  try {
29762
29867
  const raw = await readFile10(domainsPath, "utf-8");
@@ -29773,7 +29878,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29773
29878
  } catch {
29774
29879
  }
29775
29880
  }
29776
- const chainsPath = path93.join(dirPath, "dependency-paths.md");
29881
+ const chainsPath = path94.join(dirPath, "dependency-paths.md");
29777
29882
  if (await pathExists(chainsPath)) {
29778
29883
  const content = await readFile10(chainsPath, "utf-8");
29779
29884
  const chainMatch = content.match(/(\d+)\s*call chain/);
@@ -29789,7 +29894,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29789
29894
  }
29790
29895
  projects.push(info);
29791
29896
  }
29792
- const graphPath = path93.join(teamwikiRoot, ".indices", "graph-index.json");
29897
+ const graphPath = path94.join(teamwikiRoot, ".indices", "graph-index.json");
29793
29898
  if (await pathExists(graphPath)) {
29794
29899
  try {
29795
29900
  const raw = await readFile10(graphPath, "utf-8");
@@ -29830,7 +29935,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
29830
29935
  routerLines.push("4. **\u8C03\u7528\u94FE/\u6392\u969C** \u2192 \u67E5\u5BF9\u5E94\u4ED3\u5E93\u7684 dependency-paths.md");
29831
29936
  routerLines.push("5. **\u6A21\u5757\u804C\u8D23\u6982\u8FF0** \u2192 \u67E5 overview.md \u6216 modules/*.md");
29832
29937
  routerLines.push("");
29833
- await writeFile11(path93.join(teamwikiRoot, "router.md"), routerLines.join("\n"), "utf-8");
29938
+ await writeFile11(path94.join(teamwikiRoot, "router.md"), routerLines.join("\n"), "utf-8");
29834
29939
  const indexLines = [
29835
29940
  "# Team Wiki Index",
29836
29941
  "",
@@ -29866,9 +29971,9 @@ async function rebuildWikiIndex(teamwikiRoot) {
29866
29971
  indexLines.push("- [router.md](./router.md) \u2014 \u4EA7\u54C1\u57DF\u8DEF\u7531\uFF08\u8868\u683C + \u8DEF\u7531\u89C4\u5219\uFF09");
29867
29972
  indexLines.push("- [hot.md](./hot.md) \u2014 \u6D3B\u8DC3\u5DE5\u4F5C\u8BB0\u5FC6");
29868
29973
  indexLines.push("");
29869
- await writeFile11(path93.join(teamwikiRoot, "index.md"), indexLines.join("\n"), "utf-8");
29870
- if (!await pathExists(path93.join(teamwikiRoot, "hot.md"))) {
29871
- await writeFile11(path93.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE, "utf-8");
29974
+ await writeFile11(path94.join(teamwikiRoot, "index.md"), indexLines.join("\n"), "utf-8");
29975
+ if (!await pathExists(path94.join(teamwikiRoot, "hot.md"))) {
29976
+ await writeFile11(path94.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE, "utf-8");
29872
29977
  }
29873
29978
  log.debug(`rebuildWikiIndex: ${projects.length} projects, ${totalNodes} nodes, ${totalEdges} edges`);
29874
29979
  }
@@ -29912,7 +30017,7 @@ __export(import_repo_exports, {
29912
30017
  detectCrossRepoEdges: () => detectCrossRepoEdges,
29913
30018
  importFromRepo: () => importFromRepo
29914
30019
  });
29915
- import path94 from "path";
30020
+ import path95 from "path";
29916
30021
  import fs33 from "fs-extra";
29917
30022
  import chalk4 from "chalk";
29918
30023
  function detectCrossRepoEdges(overlay, existing) {
@@ -30024,7 +30129,7 @@ async function importFromRepo(opts) {
30024
30129
  const cacheDir = getRepoCacheDir(providerName, owner, repoName);
30025
30130
  const slug = getRepoSlug(providerName, owner, repoName);
30026
30131
  const lastSync = await readLastSync(cacheDir);
30027
- const cacheExists = await fs33.pathExists(path94.join(cacheDir, ".git"));
30132
+ const cacheExists = await fs33.pathExists(path95.join(cacheDir, ".git"));
30028
30133
  const useIncremental = incremental && cacheExists && lastSync !== null;
30029
30134
  let cloneSha;
30030
30135
  let cloneBranch;
@@ -30102,25 +30207,25 @@ async function importFromRepo(opts) {
30102
30207
  mrTeamConfig = { repo: tc.repo, provider: tc.provider, reviewers: tc.reviewers };
30103
30208
  mrLocalConfig = { repo: lc.repo, username: lc.username };
30104
30209
  } catch {
30105
- teamRepoDir = path94.join(process.cwd(), ".teamai", "team-repo");
30210
+ teamRepoDir = path95.join(process.cwd(), ".teamai", "team-repo");
30106
30211
  }
30107
- const teamwikiRoot = output ? path94.resolve(output, "..", "teamwiki") : path94.join(teamRepoDir, "teamwiki");
30212
+ const teamwikiRoot = output ? path95.resolve(output, "..", "teamwiki") : path95.join(teamRepoDir, "teamwiki");
30108
30213
  if (!dryRun) {
30109
- const cacheWiki = path94.join(cacheDir, "teamwiki");
30214
+ const cacheWiki = path95.join(cacheDir, "teamwiki");
30110
30215
  try {
30111
30216
  if (incremental) {
30112
- const destIndices = path94.join(teamwikiRoot, ".indices");
30113
- const cacheIndices = path94.join(cacheDir, "teamwiki", ".indices");
30217
+ const destIndices = path95.join(teamwikiRoot, ".indices");
30218
+ const cacheIndices = path95.join(cacheDir, "teamwiki", ".indices");
30114
30219
  await fs33.ensureDir(cacheIndices);
30115
30220
  for (const f of ["facts-cache.json", "interfaces-cache.json"]) {
30116
- const src = path94.join(destIndices, f);
30221
+ const src = path95.join(destIndices, f);
30117
30222
  if (await fs33.pathExists(src)) {
30118
- await fs33.copy(src, path94.join(cacheIndices, f));
30223
+ await fs33.copy(src, path95.join(cacheIndices, f));
30119
30224
  }
30120
30225
  }
30121
- const existingManifest = path94.join(teamwikiRoot, "source-manifest.json");
30226
+ const existingManifest = path95.join(teamwikiRoot, "source-manifest.json");
30122
30227
  if (await fs33.pathExists(existingManifest)) {
30123
- await fs33.copy(existingManifest, path94.join(cacheDir, "teamwiki", "source-manifest.json"));
30228
+ await fs33.copy(existingManifest, path95.join(cacheDir, "teamwiki", "source-manifest.json"));
30124
30229
  }
30125
30230
  }
30126
30231
  await extractCodebase({
@@ -30134,19 +30239,19 @@ async function importFromRepo(opts) {
30134
30239
  sourceMrUrl
30135
30240
  });
30136
30241
  if (await fs33.pathExists(cacheWiki)) {
30137
- const evidenceSrc = path94.join(cacheWiki, "evidence", "code", slug);
30138
- const evidenceDest = path94.join(teamwikiRoot, "evidence", "code", slug);
30242
+ const evidenceSrc = path95.join(cacheWiki, "evidence", "code", slug);
30243
+ const evidenceDest = path95.join(teamwikiRoot, "evidence", "code", slug);
30139
30244
  if (await fs33.pathExists(evidenceDest)) {
30140
30245
  const entries = await fs33.readdir(evidenceDest);
30141
30246
  for (const entry of entries) {
30142
30247
  if (entry === ".indices") continue;
30143
- await fs33.remove(path94.join(evidenceDest, entry));
30248
+ await fs33.remove(path95.join(evidenceDest, entry));
30144
30249
  }
30145
30250
  }
30146
30251
  await fs33.ensureDir(evidenceDest);
30147
30252
  await fs33.copy(evidenceSrc, evidenceDest, { overwrite: true });
30148
30253
  if (codebaseMd) {
30149
- const overviewPath = path94.join(evidenceDest, "overview.md");
30254
+ const overviewPath = path95.join(evidenceDest, "overview.md");
30150
30255
  const existing = await fs33.readFile(overviewPath, "utf8").catch(() => "");
30151
30256
  const aiNarrative = codebaseMd.replace(/^---[\s\S]*?---\n*/m, "");
30152
30257
  const marker = "## AI Architecture Narrative";
@@ -30169,31 +30274,31 @@ ${aiNarrative}`;
30169
30274
  }
30170
30275
  await fs33.writeFile(overviewPath, combined, "utf8");
30171
30276
  }
30172
- const srcGraph = path94.join(cacheWiki, ".indices", "graph-index.json");
30277
+ const srcGraph = path95.join(cacheWiki, ".indices", "graph-index.json");
30173
30278
  if (await fs33.pathExists(srcGraph)) {
30174
- const evidenceGraphDir = path94.join(teamwikiRoot, "evidence", "code", slug, ".indices");
30279
+ const evidenceGraphDir = path95.join(teamwikiRoot, "evidence", "code", slug, ".indices");
30175
30280
  await fs33.ensureDir(evidenceGraphDir);
30176
- await fs33.copy(srcGraph, path94.join(evidenceGraphDir, "graph-index.json"));
30281
+ await fs33.copy(srcGraph, path95.join(evidenceGraphDir, "graph-index.json"));
30177
30282
  } else {
30178
30283
  log.debug(`[graph] per-repo graph-index.json not found, skipping copy`);
30179
30284
  }
30180
- const cacheIndices = path94.join(cacheWiki, ".indices");
30181
- const destIndices = path94.join(teamwikiRoot, ".indices");
30285
+ const cacheIndices = path95.join(cacheWiki, ".indices");
30286
+ const destIndices = path95.join(teamwikiRoot, ".indices");
30182
30287
  for (const cacheFile of ["facts-cache.json", "interfaces-cache.json"]) {
30183
- const src = path94.join(cacheIndices, cacheFile);
30288
+ const src = path95.join(cacheIndices, cacheFile);
30184
30289
  if (await fs33.pathExists(src)) {
30185
30290
  await fs33.ensureDir(destIndices);
30186
- await fs33.copy(src, path94.join(destIndices, cacheFile), { overwrite: true });
30291
+ await fs33.copy(src, path95.join(destIndices, cacheFile), { overwrite: true });
30187
30292
  }
30188
30293
  }
30189
- const srcManifest = path94.join(cacheWiki, "source-manifest.json");
30294
+ const srcManifest = path95.join(cacheWiki, "source-manifest.json");
30190
30295
  if (await fs33.pathExists(srcManifest)) {
30191
- await fs33.copy(srcManifest, path94.join(teamwikiRoot, "source-manifest.json"), { overwrite: true });
30296
+ await fs33.copy(srcManifest, path95.join(teamwikiRoot, "source-manifest.json"), { overwrite: true });
30192
30297
  }
30193
30298
  await fs33.remove(cacheWiki);
30194
30299
  }
30195
30300
  if (explicitDomain) {
30196
- const domainsJsonPath = path94.join(teamwikiRoot, "evidence", "code", slug, "_domains.json");
30301
+ const domainsJsonPath = path95.join(teamwikiRoot, "evidence", "code", slug, "_domains.json");
30197
30302
  if (await fs33.pathExists(domainsJsonPath)) {
30198
30303
  try {
30199
30304
  const existing = JSON.parse(await fs33.readFile(domainsJsonPath, "utf8"));
@@ -30225,8 +30330,8 @@ ${aiNarrative}`;
30225
30330
  }
30226
30331
  }
30227
30332
  if (!dryRun && !skipEnrich && teamwikiRoot) {
30228
- const evidenceDir = path94.join(teamwikiRoot, "evidence", "code", slug);
30229
- if (await fs33.pathExists(path94.join(evidenceDir, "_manifest.json"))) {
30333
+ const evidenceDir = path95.join(teamwikiRoot, "evidence", "code", slug);
30334
+ if (await fs33.pathExists(path95.join(evidenceDir, "_manifest.json"))) {
30230
30335
  try {
30231
30336
  const { deepEnrich: deepEnrich2 } = await Promise.resolve().then(() => (init_deep_enrich(), deep_enrich_exports));
30232
30337
  await deepEnrich2({ project: slug, evidenceDir, wikiRoot: teamwikiRoot, cacheDir });
@@ -30349,7 +30454,7 @@ var init_store = __esm({
30349
30454
  });
30350
30455
 
30351
30456
  // src/import-repo-list.ts
30352
- import path95 from "path";
30457
+ import path96 from "path";
30353
30458
  import fs35 from "fs-extra";
30354
30459
  function sortByPriority(entries) {
30355
30460
  const order = { high: 0, normal: 1, low: 2 };
@@ -30427,7 +30532,7 @@ async function importFromRepoList(opts) {
30427
30532
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
30428
30533
  const { localConfig: lc } = await autoDetectInit2();
30429
30534
  const teamRepoPath = lc.repo.localPath;
30430
- const teamwikiRoot = path95.join(teamRepoPath, "teamwiki");
30535
+ const teamwikiRoot = path96.join(teamRepoPath, "teamwiki");
30431
30536
  const { aggregateGlobalGraph: aggregateGlobalGraph2 } = await Promise.resolve().then(() => (init_graph_aggregate(), graph_aggregate_exports));
30432
30537
  await aggregateGlobalGraph2(teamwikiRoot);
30433
30538
  } catch (e) {
@@ -30438,7 +30543,7 @@ async function importFromRepoList(opts) {
30438
30543
  try {
30439
30544
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
30440
30545
  const { localConfig } = await autoDetectInit2();
30441
- const teamwikiRoot = path95.join(localConfig.repo.localPath, "teamwiki");
30546
+ const teamwikiRoot = path96.join(localConfig.repo.localPath, "teamwiki");
30442
30547
  if (await fs35.pathExists(teamwikiRoot)) {
30443
30548
  const { rebuildWikiIndex: rebuildWikiIndex2 } = await Promise.resolve().then(() => (init_rebuild_wiki_index(), rebuild_wiki_index_exports));
30444
30549
  await rebuildWikiIndex2(teamwikiRoot);
@@ -30487,7 +30592,7 @@ var init_import_repo_list = __esm({
30487
30592
  });
30488
30593
 
30489
30594
  // src/import-org.ts
30490
- import path96 from "path";
30595
+ import path97 from "path";
30491
30596
  import fs36 from "fs-extra";
30492
30597
  function parseOrgInput(org) {
30493
30598
  const trimmed = org.trim();
@@ -30559,9 +30664,9 @@ async function importFromOrg(opts) {
30559
30664
  return;
30560
30665
  }
30561
30666
  log.info(`${filteredRepos.length} repos after filtering, generating whitelist...`);
30562
- const whitelistDraftPath = path96.join(cwd, WHITELIST_DRAFT_PATH);
30667
+ const whitelistDraftPath = path97.join(cwd, WHITELIST_DRAFT_PATH);
30563
30668
  if (!opts.dryRun) {
30564
- await fs36.ensureDir(path96.dirname(whitelistDraftPath));
30669
+ await fs36.ensureDir(path97.dirname(whitelistDraftPath));
30565
30670
  const lines = ["version: 1", "repos:"];
30566
30671
  for (const repo of filteredRepos) {
30567
30672
  lines.push(` - url: ${repo.url}`);
@@ -30594,7 +30699,7 @@ async function importFromOrg(opts) {
30594
30699
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
30595
30700
  const { localConfig } = await autoDetectInit2();
30596
30701
  const teamRepoPath = localConfig.repo.localPath;
30597
- const teamRepoWiki = path96.join(teamRepoPath, "teamwiki");
30702
+ const teamRepoWiki = path97.join(teamRepoPath, "teamwiki");
30598
30703
  if (await fs36.pathExists(teamRepoWiki)) {
30599
30704
  await rebuildWikiIndex2(teamRepoWiki);
30600
30705
  log.info("teamwiki router.md / index.md rebuilt");
@@ -30627,10 +30732,10 @@ var init_import_org = __esm({
30627
30732
 
30628
30733
  // src/review-store.ts
30629
30734
  import crypto5 from "crypto";
30630
- import path97 from "path";
30735
+ import path98 from "path";
30631
30736
  import fs37 from "fs-extra";
30632
30737
  function getPendingReviewPath(cwd) {
30633
- return path97.join(cwd, PENDING_REVIEW_PATH);
30738
+ return path98.join(cwd, PENDING_REVIEW_PATH);
30634
30739
  }
30635
30740
  function computeReviewId(file, section, ts) {
30636
30741
  return crypto5.createHash("sha1").update(`${file}|${section ?? ""}|${ts}`).digest("hex").slice(0, 12);
@@ -30706,7 +30811,7 @@ async function loadPendingReview(cwd) {
30706
30811
  async function savePendingReview(cwd, items) {
30707
30812
  const filePath = getPendingReviewPath(cwd);
30708
30813
  const tmpPath = `${filePath}.tmp`;
30709
- await fs37.ensureDir(path97.dirname(filePath));
30814
+ await fs37.ensureDir(path98.dirname(filePath));
30710
30815
  const content = items.map((item) => JSON.stringify(item)).join("\n") + (items.length > 0 ? "\n" : "");
30711
30816
  await fs37.writeFile(tmpPath, content, "utf8");
30712
30817
  await fs37.rename(tmpPath, filePath);
@@ -30726,7 +30831,7 @@ async function appendPendingReview(cwd, partial) {
30726
30831
  risk
30727
30832
  };
30728
30833
  const filePath = getPendingReviewPath(cwd);
30729
- await fs37.ensureDir(path97.dirname(filePath));
30834
+ await fs37.ensureDir(path98.dirname(filePath));
30730
30835
  await fs37.appendFile(filePath, JSON.stringify(item) + "\n", "utf8");
30731
30836
  return item;
30732
30837
  }
@@ -30761,14 +30866,14 @@ var init_review_store = __esm({
30761
30866
  });
30762
30867
 
30763
30868
  // src/utils/team-codebase-paths.ts
30764
- import path98 from "path";
30869
+ import path99 from "path";
30765
30870
  function getTeamCodebasePaths(cwd, output) {
30766
- const root = output ?? path98.join(cwd, "docs", TEAM_CODEBASE_DIR);
30871
+ const root = output ?? path99.join(cwd, "docs", TEAM_CODEBASE_DIR);
30767
30872
  return {
30768
30873
  root,
30769
- index: path98.join(root, "index.md"),
30770
- domainsDir: path98.join(root, "domains"),
30771
- reposDir: path98.join(root, "repos")
30874
+ index: path99.join(root, "index.md"),
30875
+ domainsDir: path99.join(root, "domains"),
30876
+ reposDir: path99.join(root, "repos")
30772
30877
  };
30773
30878
  }
30774
30879
  var TEAM_CODEBASE_DIR;
@@ -30780,7 +30885,7 @@ var init_team_codebase_paths = __esm({
30780
30885
  });
30781
30886
 
30782
30887
  // src/iwiki-dual.ts
30783
- import path99 from "path";
30888
+ import path100 from "path";
30784
30889
  import fs38 from "fs-extra";
30785
30890
  function parseIWikiInput2(input) {
30786
30891
  const trimmed = input.trim();
@@ -30945,10 +31050,10 @@ async function importFromIWikiDual(opts) {
30945
31050
  return { sectionsUpdated: [], pendingReview: false };
30946
31051
  }
30947
31052
  const paths = getTeamCodebasePaths(cwd, opts.output);
30948
- const filePath = path99.join(paths.root, "external-knowledge.md");
31053
+ const filePath = path100.join(paths.root, "external-knowledge.md");
30949
31054
  if (opts.requireReview) {
30950
31055
  if (!opts.dryRun) {
30951
- const relativeFilePath = path99.relative(cwd, filePath);
31056
+ const relativeFilePath = path100.relative(cwd, filePath);
30952
31057
  for (const sectionKey of sections) {
30953
31058
  const body = aiOutput[sectionKey] ?? "";
30954
31059
  if (!body) continue;
@@ -31015,7 +31120,7 @@ var import_exports = {};
31015
31120
  __export(import_exports, {
31016
31121
  importCmd: () => importCmd
31017
31122
  });
31018
- import path100 from "path";
31123
+ import path101 from "path";
31019
31124
  import os9 from "os";
31020
31125
  import fs39 from "fs-extra";
31021
31126
  import { Listr, PRESET_TIMER } from "listr2";
@@ -31131,7 +31236,7 @@ async function importCmd(opts) {
31131
31236
  task: async (ctx) => {
31132
31237
  const { learning, repoUrl } = await importFromMR({
31133
31238
  url: opts.fromMr,
31134
- learningsDir: path100.join(localConfig.repo.localPath, "learnings"),
31239
+ learningsDir: path101.join(localConfig.repo.localPath, "learnings"),
31135
31240
  all: opts.all,
31136
31241
  outputDir: opts.output,
31137
31242
  repoPath: opts.dryRun ? void 0 : localConfig.repo.localPath,
@@ -31145,7 +31250,7 @@ async function importCmd(opts) {
31145
31250
  title: "Incremental teamwiki update",
31146
31251
  skip: (ctx) => !ctx.repoUrl || !!opts.dryRun || !!opts.output,
31147
31252
  task: async (ctx, task) => {
31148
- const teamwikiRoot = path100.join(localConfig.repo.localPath, "teamwiki");
31253
+ const teamwikiRoot = path101.join(localConfig.repo.localPath, "teamwiki");
31149
31254
  try {
31150
31255
  const { detectProvider: detectProvider2, getProvider: getProvider2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
31151
31256
  const { getRepoSlug: getRepoSlug2 } = await Promise.resolve().then(() => (init_repo_cache(), repo_cache_exports));
@@ -31153,7 +31258,7 @@ async function importCmd(opts) {
31153
31258
  const provider = getProvider2(providerName);
31154
31259
  const repoInfo = provider.parseRepoInput(ctx.repoUrl);
31155
31260
  const slug = getRepoSlug2(providerName, repoInfo.owner, repoInfo.repo);
31156
- const evidenceDir = path100.join(teamwikiRoot, "evidence", "code", slug);
31261
+ const evidenceDir = path101.join(teamwikiRoot, "evidence", "code", slug);
31157
31262
  if (await fs39.pathExists(evidenceDir)) {
31158
31263
  task.output = `Updating ${slug}...`;
31159
31264
  await importFromRepo({
@@ -31206,18 +31311,18 @@ async function importCmd(opts) {
31206
31311
  setSilent(false);
31207
31312
  }
31208
31313
  } else if (opts.dir) {
31209
- const dirPath = path100.resolve(opts.dir);
31314
+ const dirPath = path101.resolve(opts.dir);
31210
31315
  if (!await fs39.pathExists(dirPath)) {
31211
31316
  throw new Error(`Directory not found: ${dirPath}`);
31212
31317
  }
31213
- const slug = path100.basename(dirPath);
31318
+ const slug = path101.basename(dirPath);
31214
31319
  log.info(`Scanning local directory: ${dirPath} (project: ${slug})`);
31215
31320
  if (opts.dryRun) {
31216
31321
  log.info(`[dry-run] skipping code extraction, no action taken`);
31217
31322
  log.success(`Local directory ${slug} import complete (dry-run)`);
31218
31323
  return;
31219
31324
  }
31220
- const tmpExtractDir = await fs39.mkdtemp(path100.join(os9.tmpdir(), "teamai-extract-"));
31325
+ const tmpExtractDir = await fs39.mkdtemp(path101.join(os9.tmpdir(), "teamai-extract-"));
31221
31326
  try {
31222
31327
  const { extractCodebase: extractCodebase2 } = await Promise.resolve().then(() => (init_codebase_extract(), codebase_extract_exports));
31223
31328
  await extractCodebase2({
@@ -31227,9 +31332,9 @@ async function importCmd(opts) {
31227
31332
  skipEnrich: opts.skipEnrich ?? false,
31228
31333
  outputRoot: tmpExtractDir
31229
31334
  });
31230
- const srcWiki = path100.join(tmpExtractDir, "teamwiki");
31335
+ const srcWiki = path101.join(tmpExtractDir, "teamwiki");
31231
31336
  if (opts.output) {
31232
- const outputWiki = path100.join(opts.output, "teamwiki");
31337
+ const outputWiki = path101.join(opts.output, "teamwiki");
31233
31338
  if (await fs39.pathExists(srcWiki)) {
31234
31339
  await fs39.copy(srcWiki, outputWiki, { overwrite: true });
31235
31340
  log.info(`Output written: ${outputWiki}`);
@@ -31237,19 +31342,19 @@ async function importCmd(opts) {
31237
31342
  } else {
31238
31343
  const { localConfig } = await autoDetectInit();
31239
31344
  const teamRepoPath = localConfig.repo.localPath;
31240
- const teamwikiRoot = path100.join(teamRepoPath, "teamwiki");
31345
+ const teamwikiRoot = path101.join(teamRepoPath, "teamwiki");
31241
31346
  if (await fs39.pathExists(srcWiki)) {
31242
- const evidenceSrc = path100.join(srcWiki, "evidence", "code", slug);
31243
- const evidenceDest = path100.join(teamwikiRoot, "evidence", "code", slug);
31347
+ const evidenceSrc = path101.join(srcWiki, "evidence", "code", slug);
31348
+ const evidenceDest = path101.join(teamwikiRoot, "evidence", "code", slug);
31244
31349
  if (await fs39.pathExists(evidenceSrc)) {
31245
- await fs39.ensureDir(path100.dirname(evidenceDest));
31350
+ await fs39.ensureDir(path101.dirname(evidenceDest));
31246
31351
  await fs39.copy(evidenceSrc, evidenceDest, { overwrite: true });
31247
31352
  }
31248
- const srcGraph = path100.join(srcWiki, ".indices", "graph-index.json");
31353
+ const srcGraph = path101.join(srcWiki, ".indices", "graph-index.json");
31249
31354
  if (await fs39.pathExists(srcGraph)) {
31250
- const destGraphDir = path100.join(evidenceDest, ".indices");
31355
+ const destGraphDir = path101.join(evidenceDest, ".indices");
31251
31356
  await fs39.ensureDir(destGraphDir);
31252
- await fs39.copy(srcGraph, path100.join(destGraphDir, "graph-index.json"), { overwrite: true });
31357
+ await fs39.copy(srcGraph, path101.join(destGraphDir, "graph-index.json"), { overwrite: true });
31253
31358
  }
31254
31359
  log.info(`teamwiki/ knowledge graph updated: ${slug}`);
31255
31360
  }
@@ -31317,11 +31422,11 @@ __export(codebase_upgrade_wiki_exports, {
31317
31422
  upgradeCodebaseWiki: () => upgradeCodebaseWiki
31318
31423
  });
31319
31424
  import { readdir as readdir7, readFile as readFile11 } from "fs/promises";
31320
- import path101 from "path";
31425
+ import path102 from "path";
31321
31426
  import chalk5 from "chalk";
31322
31427
  import matter9 from "gray-matter";
31323
31428
  async function upgradeCodebaseWiki(opts) {
31324
- const teamCodebaseDir = path101.join(opts.cwd, "docs", "team-codebase", "repos");
31429
+ const teamCodebaseDir = path102.join(opts.cwd, "docs", "team-codebase", "repos");
31325
31430
  if (!await pathExists(teamCodebaseDir)) {
31326
31431
  if (opts.json) {
31327
31432
  console.log(JSON.stringify({ status: "nothing-to-migrate", reason: "docs/team-codebase/repos/ not found" }));
@@ -31346,7 +31451,7 @@ async function upgradeCodebaseWiki(opts) {
31346
31451
  const result = { migrated: [], skipped: [], errors: [] };
31347
31452
  for (const file of mdFiles) {
31348
31453
  const slug = file.replace(".md", "");
31349
- const filePath = path101.join(teamCodebaseDir, file);
31454
+ const filePath = path102.join(teamCodebaseDir, file);
31350
31455
  try {
31351
31456
  const content = await readFile11(filePath, "utf-8");
31352
31457
  const parsed = matter9(content);
@@ -31359,9 +31464,9 @@ async function upgradeCodebaseWiki(opts) {
31359
31464
  result.migrated.push(`${slug} \u2192 teamwiki/evidence/code/${slug}/`);
31360
31465
  continue;
31361
31466
  }
31362
- const cacheBase = path101.join(process.env["HOME"] ?? "", ".teamai", "cache", "repos");
31467
+ const cacheBase = path102.join(process.env["HOME"] ?? "", ".teamai", "cache", "repos");
31363
31468
  const urlParts = String(source).replace(/^https?:\/\//, "").replace(/@.*$/, "").split("/");
31364
- const cachePath = path101.join(cacheBase, ...urlParts.slice(0, 3));
31469
+ const cachePath = path102.join(cacheBase, ...urlParts.slice(0, 3));
31365
31470
  if (await pathExists(cachePath)) {
31366
31471
  await extractCodebase({ path: cachePath, project: slug });
31367
31472
  result.migrated.push(slug);
@@ -31416,10 +31521,10 @@ __export(codebase_wiki_lint_exports, {
31416
31521
  lintTeamwiki: () => lintTeamwiki
31417
31522
  });
31418
31523
  import { readFile as readFile12, readdir as readdir8, stat as stat5 } from "fs/promises";
31419
- import path102 from "path";
31524
+ import path103 from "path";
31420
31525
  import chalk6 from "chalk";
31421
31526
  async function lintTeamwiki(opts) {
31422
- const wikiRoot = opts.wikiRoot ?? path102.join(opts.cwd ?? process.cwd(), "teamwiki");
31527
+ const wikiRoot = opts.wikiRoot ?? path103.join(opts.cwd ?? process.cwd(), "teamwiki");
31423
31528
  const issues = [];
31424
31529
  const minSeverity = opts.severity ?? "info";
31425
31530
  const severityOrder = ["info", "low", "medium", "high"];
@@ -31429,7 +31534,7 @@ async function lintTeamwiki(opts) {
31429
31534
  issues.push(issue);
31430
31535
  }
31431
31536
  }
31432
- const graphPath = path102.join(wikiRoot, ".indices", "graph-index.json");
31537
+ const graphPath = path103.join(wikiRoot, ".indices", "graph-index.json");
31433
31538
  let graph = null;
31434
31539
  if (!await pathExists(graphPath)) {
31435
31540
  addIssue({
@@ -31451,7 +31556,7 @@ async function lintTeamwiki(opts) {
31451
31556
  });
31452
31557
  }
31453
31558
  }
31454
- const evidenceDir = path102.join(wikiRoot, "evidence", "code");
31559
+ const evidenceDir = path103.join(wikiRoot, "evidence", "code");
31455
31560
  if (!await pathExists(evidenceDir)) {
31456
31561
  addIssue({
31457
31562
  severity: "high",
@@ -31470,7 +31575,7 @@ async function lintTeamwiki(opts) {
31470
31575
  });
31471
31576
  }
31472
31577
  for (const project of projects) {
31473
- const projectDir = path102.join(evidenceDir, project);
31578
+ const projectDir = path103.join(evidenceDir, project);
31474
31579
  const pStat = await stat5(projectDir).catch(() => null);
31475
31580
  if (!pStat?.isDirectory()) {
31476
31581
  if (!pStat) {
@@ -31490,7 +31595,7 @@ async function lintTeamwiki(opts) {
31490
31595
  }
31491
31596
  }
31492
31597
  for (const navFile of ["router.md", "index.md", "hot.md"]) {
31493
- if (!await pathExists(path102.join(wikiRoot, navFile))) {
31598
+ if (!await pathExists(path103.join(wikiRoot, navFile))) {
31494
31599
  addIssue({
31495
31600
  severity: "low",
31496
31601
  category: "nav-missing",
@@ -31499,7 +31604,7 @@ async function lintTeamwiki(opts) {
31499
31604
  });
31500
31605
  }
31501
31606
  }
31502
- const manifestPath = path102.join(wikiRoot, "source-manifest.json");
31607
+ const manifestPath = path103.join(wikiRoot, "source-manifest.json");
31503
31608
  if (!await pathExists(manifestPath)) {
31504
31609
  addIssue({
31505
31610
  severity: "low",
@@ -31615,7 +31720,7 @@ var codebase_cmd_exports = {};
31615
31720
  __export(codebase_cmd_exports, {
31616
31721
  codebaseCmd: () => codebaseCmd
31617
31722
  });
31618
- import path103 from "path";
31723
+ import path104 from "path";
31619
31724
  import { readFile as readFile13 } from "fs/promises";
31620
31725
  import chalk7 from "chalk";
31621
31726
  async function codebaseCmd(opts) {
@@ -31656,14 +31761,14 @@ async function codebaseCmd(opts) {
31656
31761
  const { pathExists: pathExists3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
31657
31762
  let teamwikiDir;
31658
31763
  if (opts.output) {
31659
- teamwikiDir = path103.resolve(opts.output, "teamwiki");
31764
+ teamwikiDir = path104.resolve(opts.output, "teamwiki");
31660
31765
  } else {
31661
31766
  try {
31662
31767
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
31663
31768
  const { localConfig: lc } = await autoDetectInit2();
31664
- teamwikiDir = path103.join(lc.repo.localPath, "teamwiki");
31769
+ teamwikiDir = path104.join(lc.repo.localPath, "teamwiki");
31665
31770
  } catch {
31666
- teamwikiDir = path103.join(cwd, ".teamai", "team-repo", "teamwiki");
31771
+ teamwikiDir = path104.join(cwd, ".teamai", "team-repo", "teamwiki");
31667
31772
  }
31668
31773
  }
31669
31774
  if (!await pathExists3(teamwikiDir)) {
@@ -31686,17 +31791,17 @@ async function printCodebaseStatus(opts) {
31686
31791
  const cwd = process.cwd();
31687
31792
  let teamwikiDir;
31688
31793
  if (opts.output) {
31689
- teamwikiDir = path103.resolve(opts.output, "teamwiki");
31794
+ teamwikiDir = path104.resolve(opts.output, "teamwiki");
31690
31795
  } else {
31691
31796
  try {
31692
31797
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
31693
31798
  const { localConfig: lc } = await autoDetectInit2();
31694
- teamwikiDir = path103.join(lc.repo.localPath, "teamwiki");
31799
+ teamwikiDir = path104.join(lc.repo.localPath, "teamwiki");
31695
31800
  } catch {
31696
- teamwikiDir = path103.join(cwd, ".teamai", "team-repo", "teamwiki");
31801
+ teamwikiDir = path104.join(cwd, ".teamai", "team-repo", "teamwiki");
31697
31802
  }
31698
31803
  }
31699
- const manifestPath = path103.join(teamwikiDir, "source-manifest.json");
31804
+ const manifestPath = path104.join(teamwikiDir, "source-manifest.json");
31700
31805
  let manifest;
31701
31806
  try {
31702
31807
  manifest = JSON.parse(await readFile13(manifestPath, "utf-8"));
@@ -31793,7 +31898,7 @@ var review_cmd_exports = {};
31793
31898
  __export(review_cmd_exports, {
31794
31899
  reviewCmd: () => reviewCmd
31795
31900
  });
31796
- import path104 from "path";
31901
+ import path105 from "path";
31797
31902
  import chalk8 from "chalk";
31798
31903
  import fs40 from "fs-extra";
31799
31904
  function riskAtMost(itemRisk, ceiling) {
@@ -31869,7 +31974,7 @@ async function applyOne(cwd, item) {
31869
31974
  if (!section) {
31870
31975
  return { ok: false, reason: "target.section \u7F3A\u5931" };
31871
31976
  }
31872
- const filePath = path104.isAbsolute(file) ? file : path104.join(cwd, file);
31977
+ const filePath = path105.isAbsolute(file) ? file : path105.join(cwd, file);
31873
31978
  if (!await fs40.pathExists(filePath)) {
31874
31979
  return { ok: false, reason: `\u76EE\u6807\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${filePath}` };
31875
31980
  }
@@ -32026,10 +32131,10 @@ function formatComment(learning, suggestions, marker) {
32026
32131
  lines.push("> _Auto-generated by `teamai ci extract-mr`_");
32027
32132
  return lines.join("\n");
32028
32133
  }
32029
- async function githubRequest(path109, method, body) {
32134
+ async function githubRequest(path110, method, body) {
32030
32135
  const token = process.env["GITHUB_TOKEN"];
32031
32136
  if (!token) throw new Error("\u672A\u8BBE\u7F6E GITHUB_TOKEN \u73AF\u5883\u53D8\u91CF");
32032
- const url = `https://api.github.com${path109}`;
32137
+ const url = `https://api.github.com${path110}`;
32033
32138
  const headers = {
32034
32139
  Authorization: `Bearer ${token}`,
32035
32140
  Accept: "application/vnd.github+json",
@@ -32078,8 +32183,8 @@ async function updateGitHubComment(owner, repo, commentId, body) {
32078
32183
  const data = await resp.json();
32079
32184
  return { created: false, url: data.html_url };
32080
32185
  }
32081
- async function tgitRequest(path109, method, body) {
32082
- return tgitFetch(path109, {
32186
+ async function tgitRequest(path110, method, body) {
32187
+ return tgitFetch(path110, {
32083
32188
  method,
32084
32189
  body: body ? JSON.stringify(body) : void 0
32085
32190
  });
@@ -32362,10 +32467,10 @@ function extractMarkerId(body) {
32362
32467
  const match = body.match(MARKER_REGEX);
32363
32468
  return match ? match[1] : null;
32364
32469
  }
32365
- async function githubRequest2(path109) {
32470
+ async function githubRequest2(path110) {
32366
32471
  const token = process.env["GITHUB_TOKEN"];
32367
32472
  if (!token) throw new Error("\u672A\u8BBE\u7F6E GITHUB_TOKEN");
32368
- return fetch(`https://api.github.com${path109}`, {
32473
+ return fetch(`https://api.github.com${path110}`, {
32369
32474
  headers: {
32370
32475
  Authorization: `Bearer ${token}`,
32371
32476
  Accept: "application/vnd.github+json",
@@ -32400,8 +32505,8 @@ async function readGitHubRejections(owner, repo, prNumber) {
32400
32505
  }
32401
32506
  return result;
32402
32507
  }
32403
- async function tgitRequest2(path109) {
32404
- return tgitFetch(path109);
32508
+ async function tgitRequest2(path110) {
32509
+ return tgitFetch(path110);
32405
32510
  }
32406
32511
  async function getMrGlobalId2(projectId, mrIid) {
32407
32512
  const resp = await tgitRequest2(`/projects/${projectId}/merge_requests?iid=${mrIid}`);
@@ -32462,7 +32567,7 @@ __export(extract_mr_exports, {
32462
32567
  ciExtractMr: () => ciExtractMr
32463
32568
  });
32464
32569
  import fs41 from "fs/promises";
32465
- import path105 from "path";
32570
+ import path106 from "path";
32466
32571
  async function configureGitUser2(repoPath, provider) {
32467
32572
  const { execFileSync: execFileSync4 } = await import("child_process");
32468
32573
  let name = "teamai-ci";
@@ -32509,8 +32614,8 @@ async function writeKnowledgeToRepo(teamRepo, learning, suggestions, writeMode,
32509
32614
  const safeTitle = learning.title.replace(/[^a-zA-Z0-9一-鿿_-]/g, "-").replace(/-+/g, "-").slice(0, 50);
32510
32615
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
32511
32616
  const filename = `${dateStr}-${safeTitle}.md`;
32512
- const learningsDir = path105.join(teamRepo, "learnings");
32513
- const learningPath = path105.join(learningsDir, filename);
32617
+ const learningsDir = path106.join(teamRepo, "learnings");
32618
+ const learningPath = path106.join(learningsDir, filename);
32514
32619
  if (!dryRun) {
32515
32620
  await fs41.mkdir(learningsDir, { recursive: true });
32516
32621
  await fs41.writeFile(learningPath, learning.content, "utf-8");
@@ -32550,11 +32655,11 @@ async function writeKnowledgeToRepo(teamRepo, learning, suggestions, writeMode,
32550
32655
  async function writeArtifacts(outputDir, learning, suggestions) {
32551
32656
  await fs41.mkdir(outputDir, { recursive: true });
32552
32657
  if (learning) {
32553
- await fs41.writeFile(path105.join(outputDir, "learning.md"), learning.content, "utf-8");
32658
+ await fs41.writeFile(path106.join(outputDir, "learning.md"), learning.content, "utf-8");
32554
32659
  }
32555
32660
  if (suggestions && suggestions.length > 0) {
32556
32661
  await fs41.writeFile(
32557
- path105.join(outputDir, "codebase-suggestions.json"),
32662
+ path106.join(outputDir, "codebase-suggestions.json"),
32558
32663
  JSON.stringify(suggestions, null, 2),
32559
32664
  "utf-8"
32560
32665
  );
@@ -32568,7 +32673,7 @@ async function ciExtractMr(opts) {
32568
32673
  const result = await importFromMR({
32569
32674
  url: opts.url,
32570
32675
  all: true,
32571
- learningsDir: opts.teamRepo ? path105.join(opts.teamRepo, "learnings") : void 0,
32676
+ learningsDir: opts.teamRepo ? path106.join(opts.teamRepo, "learnings") : void 0,
32572
32677
  dryRun: true
32573
32678
  // 不让 importFromMR 自己写文件,我们自己控制写入
32574
32679
  });
@@ -32677,21 +32782,21 @@ ${affectedModules.map((m) => `- \`${m}\` (evidence + G-document)`).join("\n")}`
32677
32782
  const projectName = parsed.repo;
32678
32783
  await extractCodebase2({ path: businessRepo, project: projectName });
32679
32784
  const fse12 = await import("fs-extra");
32680
- const srcWiki = path105.join(businessRepo, "teamwiki");
32681
- const teamWikiRoot = path105.join(path105.resolve(opts.teamRepo), "teamwiki");
32785
+ const srcWiki = path106.join(businessRepo, "teamwiki");
32786
+ const teamWikiRoot = path106.join(path106.resolve(opts.teamRepo), "teamwiki");
32682
32787
  try {
32683
32788
  if (await fse12.pathExists(srcWiki)) {
32684
- const evidenceSrc = path105.join(srcWiki, "evidence", "code", projectName);
32685
- const evidenceDest = path105.join(teamWikiRoot, "evidence", "code", projectName);
32789
+ const evidenceSrc = path106.join(srcWiki, "evidence", "code", projectName);
32790
+ const evidenceDest = path106.join(teamWikiRoot, "evidence", "code", projectName);
32686
32791
  if (await fse12.pathExists(evidenceSrc)) {
32687
32792
  await fse12.ensureDir(evidenceDest);
32688
32793
  await fse12.copy(evidenceSrc, evidenceDest, { overwrite: true });
32689
32794
  }
32690
- const srcGraph = path105.join(srcWiki, ".indices", "graph-index.json");
32795
+ const srcGraph = path106.join(srcWiki, ".indices", "graph-index.json");
32691
32796
  if (await fse12.pathExists(srcGraph)) {
32692
- const destGraphDir = path105.join(evidenceDest, ".indices");
32797
+ const destGraphDir = path106.join(evidenceDest, ".indices");
32693
32798
  await fse12.ensureDir(destGraphDir);
32694
- await fse12.copy(srcGraph, path105.join(destGraphDir, "graph-index.json"));
32799
+ await fse12.copy(srcGraph, path106.join(destGraphDir, "graph-index.json"));
32695
32800
  }
32696
32801
  const { aggregateGlobalGraph: aggregateGlobalGraph2 } = await Promise.resolve().then(() => (init_graph_aggregate(), graph_aggregate_exports));
32697
32802
  await aggregateGlobalGraph2(teamWikiRoot);
@@ -32748,7 +32853,7 @@ var init_extract_mr = __esm({
32748
32853
  });
32749
32854
 
32750
32855
  // src/maintenance/prune.ts
32751
- import path106 from "path";
32856
+ import path107 from "path";
32752
32857
  import matter10 from "gray-matter";
32753
32858
  async function findPruneCandidates(learningsDir, votesDir, options = {}) {
32754
32859
  const threshold = options.threshold ?? DEFAULT_THRESHOLD;
@@ -32759,7 +32864,7 @@ async function findPruneCandidates(learningsDir, votesDir, options = {}) {
32759
32864
  for (const file of files) {
32760
32865
  if (!file.endsWith(".md")) continue;
32761
32866
  const docId = file.replace(/\.md$/i, "");
32762
- const absPath = path106.join(learningsDir, file);
32867
+ const absPath = path107.join(learningsDir, file);
32763
32868
  const content = await readFileSafe(absPath);
32764
32869
  if (!content) continue;
32765
32870
  let date = "";
@@ -32801,9 +32906,9 @@ async function executePrune(repoPath, candidates, options = {}) {
32801
32906
  }
32802
32907
  for (const candidate of candidates) {
32803
32908
  if (options.archive) {
32804
- const archiveDir = path106.join(repoPath, "learnings", "_archive");
32909
+ const archiveDir = path107.join(repoPath, "learnings", "_archive");
32805
32910
  await ensureDir(archiveDir);
32806
- await copyFile(candidate.path, path106.join(archiveDir, candidate.filename));
32911
+ await copyFile(candidate.path, path107.join(archiveDir, candidate.filename));
32807
32912
  await remove(candidate.path);
32808
32913
  archived++;
32809
32914
  } else {
@@ -32828,7 +32933,7 @@ var init_prune = __esm({
32828
32933
  });
32829
32934
 
32830
32935
  // src/maintenance/quality-update.ts
32831
- import path107 from "path";
32936
+ import path108 from "path";
32832
32937
  async function findStaleEntries(votesDir, knowledgeDirs, options = {}) {
32833
32938
  const minRecalled = options.minRecalled ?? DEFAULT_MIN_RECALLED;
32834
32939
  const maxUpvoted = options.maxUpvoted ?? DEFAULT_MAX_UPVOTED;
@@ -32838,7 +32943,7 @@ async function findStaleEntries(votesDir, knowledgeDirs, options = {}) {
32838
32943
  for (const file of voteFiles) {
32839
32944
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
32840
32945
  const username = file.replace(/\.(yaml|yml)$/, "");
32841
- const filePath = path107.join(votesDir, file);
32946
+ const filePath = path108.join(votesDir, file);
32842
32947
  try {
32843
32948
  const data = await loadUserVotes(filePath);
32844
32949
  for (const [docId, entry] of Object.entries(data.votes)) {
@@ -32875,7 +32980,7 @@ async function resolveDocPath(docId, dirs) {
32875
32980
  const filename = docId.endsWith(".md") ? docId : `${docId}.md`;
32876
32981
  for (const dir of [dirs.docs, dirs.rules, dirs.skills]) {
32877
32982
  if (!dir) continue;
32878
- const candidate = path107.join(dir, filename);
32983
+ const candidate = path108.join(dir, filename);
32879
32984
  if (await pathExists(candidate)) return candidate;
32880
32985
  }
32881
32986
  return null;
@@ -32898,7 +33003,7 @@ async function findRelatedAdoptedLearnings(staleEntry, votesDir, learningsDir, l
32898
33003
  for (const file of voteFiles) {
32899
33004
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
32900
33005
  try {
32901
- const data = await loadUserVotes(path107.join(votesDir, file));
33006
+ const data = await loadUserVotes(path108.join(votesDir, file));
32902
33007
  for (const [docId, entry] of Object.entries(data.votes)) {
32903
33008
  if (docId === staleEntry.docId) continue;
32904
33009
  if ((entry.upvoted_count ?? 0) > 0) {
@@ -32913,7 +33018,7 @@ async function findRelatedAdoptedLearnings(staleEntry, votesDir, learningsDir, l
32913
33018
  const contents = [];
32914
33019
  for (const [docId] of sorted) {
32915
33020
  const filename = docId.endsWith(".md") ? docId : `${docId}.md`;
32916
- const filePath = path107.join(learningsDir, filename);
33021
+ const filePath = path108.join(learningsDir, filename);
32917
33022
  const content = await readFileSafe(filePath);
32918
33023
  if (content) contents.push(content);
32919
33024
  }
@@ -32969,7 +33074,7 @@ var init_quality_update = __esm({
32969
33074
  });
32970
33075
 
32971
33076
  // src/maintenance/promote.ts
32972
- import path108 from "path";
33077
+ import path109 from "path";
32973
33078
  import matter11 from "gray-matter";
32974
33079
  async function findPromotionCandidates(learningsDir, votesDir) {
32975
33080
  const confidenceMap = await computeAllConfidence(votesDir);
@@ -32986,7 +33091,7 @@ async function findPromotionCandidates(learningsDir, votesDir) {
32986
33091
  if (!docVotes) continue;
32987
33092
  if (docVotes.upvoted < MIN_UPVOTED) continue;
32988
33093
  if (docVotes.users.size < MIN_USERS) continue;
32989
- const absPath = path108.join(learningsDir, file);
33094
+ const absPath = path109.join(learningsDir, file);
32990
33095
  const content = await readFileSafe(absPath);
32991
33096
  if (!content) continue;
32992
33097
  let title = docId;
@@ -33058,9 +33163,9 @@ Output ONLY the transformed markdown content (including YAML frontmatter with ti
33058
33163
  }
33059
33164
  async function executePromotion(candidate, repoPath, options = {}) {
33060
33165
  const category = options.category ?? candidate.suggestedCategory;
33061
- const targetDir = path108.join(repoPath, category);
33166
+ const targetDir = path109.join(repoPath, category);
33062
33167
  await ensureDir(targetDir);
33063
- const targetPath = path108.join(targetDir, candidate.filename);
33168
+ const targetPath = path109.join(targetDir, candidate.filename);
33064
33169
  if (options.dryRun) {
33065
33170
  log.info(`[dry-run] Would promote ${candidate.docId} -> ${category}/${candidate.filename}`);
33066
33171
  return targetPath;
@@ -33122,7 +33227,7 @@ async function aggregatePerDocVotes(votesDir) {
33122
33227
  for (const file of voteFiles) {
33123
33228
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
33124
33229
  const username = file.replace(/\.(yaml|yml)$/, "");
33125
- const filePath = path108.join(votesDir, file);
33230
+ const filePath = path109.join(votesDir, file);
33126
33231
  try {
33127
33232
  const data = await loadUserVotes2(filePath);
33128
33233
  for (const [docId, entry] of Object.entries(data.votes)) {