teamai-cli 0.20.0-beta.0 → 0.20.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +759 -631
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1360,10 +1360,10 @@ function tgitAuthHeaders(token, scheme) {
1360
1360
  }
1361
1361
  return { "PRIVATE-TOKEN": token };
1362
1362
  }
1363
- async function tgitFetch(path106, init2) {
1363
+ async function tgitFetch(path107, init2) {
1364
1364
  const { token, scheme: resolvedScheme } = getTGitToken();
1365
1365
  const scheme = cachedScheme ?? resolvedScheme;
1366
- const url = `${TGIT_API_BASE}${path106}`;
1366
+ const url = `${TGIT_API_BASE}${path107}`;
1367
1367
  const callerHeaders = { ...init2?.headers };
1368
1368
  const baseHeaders = { "Content-Type": "application/json", ...callerHeaders };
1369
1369
  const doFetch = (activeScheme) => fetch(url, {
@@ -9211,6 +9211,7 @@ var init_update = __esm({
9211
9211
  // src/utils/reports-branch.ts
9212
9212
  var reports_branch_exports = {};
9213
9213
  __export(reports_branch_exports, {
9214
+ EmptyRepoError: () => EmptyRepoError,
9214
9215
  commitAndPushReports: () => commitAndPushReports,
9215
9216
  ensureReportsDir: () => ensureReportsDir,
9216
9217
  ensureReportsWorktree: () => ensureReportsWorktree,
@@ -9376,6 +9377,9 @@ async function withKnowledgeWorktree(localConfig, fn) {
9376
9377
  const repoRoot = businessRoot(localConfig);
9377
9378
  const wt = path30.join(localConfig.repo.localPath, KNOWLEDGE_WORKTREE_DIRNAME);
9378
9379
  const git = createGit2(repoRoot);
9380
+ if (!await hasCommits(repoRoot)) {
9381
+ throw new EmptyRepoError(repoRoot);
9382
+ }
9379
9383
  if (await pathExists(wt)) {
9380
9384
  try {
9381
9385
  await git.raw(["worktree", "remove", "--force", wt]);
@@ -9421,7 +9425,7 @@ async function withKnowledgeWorktree(localConfig, fn) {
9421
9425
  }
9422
9426
  }
9423
9427
  }
9424
- var MAX_PUSH_RETRIES;
9428
+ var EmptyRepoError, MAX_PUSH_RETRIES;
9425
9429
  var init_reports_branch = __esm({
9426
9430
  "src/utils/reports-branch.ts"() {
9427
9431
  "use strict";
@@ -9430,6 +9434,15 @@ var init_reports_branch = __esm({
9430
9434
  init_fs();
9431
9435
  init_logger();
9432
9436
  init_types();
9437
+ EmptyRepoError = class extends Error {
9438
+ constructor(repoRoot) {
9439
+ super(
9440
+ `The repository at ${repoRoot} has no commits yet, so teamai cannot open a knowledge PR. Make an initial commit and push it first (e.g. \`git add -A && git commit -m "init" && git push -u origin HEAD\`), then retry.`
9441
+ );
9442
+ this.repoRoot = repoRoot;
9443
+ this.name = "EmptyRepoError";
9444
+ }
9445
+ };
9433
9446
  MAX_PUSH_RETRIES = 5;
9434
9447
  }
9435
9448
  });
@@ -9606,8 +9619,16 @@ async function push(options) {
9606
9619
  const { localConfig, teamConfig } = await autoDetectInit();
9607
9620
  assertNotReadOnly(localConfig, "teamai push");
9608
9621
  if (localConfig.repo.kind === "self") {
9609
- const { withKnowledgeWorktree: withKnowledgeWorktree2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
9610
- await withKnowledgeWorktree2(localConfig, (wtConfig) => pushCore(wtConfig, teamConfig, options));
9622
+ const { withKnowledgeWorktree: withKnowledgeWorktree2, EmptyRepoError: EmptyRepoError2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
9623
+ try {
9624
+ await withKnowledgeWorktree2(localConfig, (wtConfig) => pushCore(wtConfig, teamConfig, options));
9625
+ } catch (e) {
9626
+ if (e instanceof EmptyRepoError2) {
9627
+ log.error(e.message);
9628
+ } else {
9629
+ log.error(`Push failed: ${e.message}`);
9630
+ }
9631
+ }
9611
9632
  return;
9612
9633
  }
9613
9634
  await pushCore(localConfig, teamConfig, options);
@@ -9936,6 +9957,7 @@ __export(git_exports, {
9936
9957
  autoPushTeamRepo: () => autoPushTeamRepo,
9937
9958
  autoPushViaMR: () => autoPushViaMR,
9938
9959
  checkoutMaster: () => checkoutMaster,
9960
+ commitPaths: () => commitPaths,
9939
9961
  configureGitUser: () => configureGitUser,
9940
9962
  createGit: () => createGit2,
9941
9963
  generateBranchName: () => generateBranchName,
@@ -9944,6 +9966,7 @@ __export(git_exports, {
9944
9966
  getHeadRev: () => getHeadRev,
9945
9967
  getRemoteUrl: () => getRemoteUrl,
9946
9968
  getRepoStatus: () => getRepoStatus,
9969
+ hasCommits: () => hasCommits,
9947
9970
  initRepo: () => initRepo,
9948
9971
  isGitRepo: () => isGitRepo,
9949
9972
  isMetadataOnlyDiff: () => isMetadataOnlyDiff,
@@ -9999,6 +10022,33 @@ async function getRemoteUrl(localPath, remoteName = "origin") {
9999
10022
  return null;
10000
10023
  }
10001
10024
  }
10025
+ async function hasCommits(localPath) {
10026
+ const git = createGit2(localPath);
10027
+ try {
10028
+ const out = (await git.raw(["rev-parse", "--verify", "HEAD^{commit}"])).trim();
10029
+ return /^[0-9a-f]{7,40}$/.test(out);
10030
+ } catch {
10031
+ return false;
10032
+ }
10033
+ }
10034
+ async function commitPaths(localPath, message, files) {
10035
+ const git = createGit2(localPath);
10036
+ const existing = files.filter((f) => fs12.existsSync(path33.join(localPath, f)));
10037
+ if (existing.length === 0) return false;
10038
+ let added = 0;
10039
+ for (const f of existing) {
10040
+ try {
10041
+ await git.add(["--", f]);
10042
+ added++;
10043
+ } catch {
10044
+ }
10045
+ }
10046
+ if (added === 0) return false;
10047
+ const status2 = await git.status();
10048
+ if (status2.staged.length === 0) return false;
10049
+ await git.commit(message);
10050
+ return true;
10051
+ }
10002
10052
  async function pullRepo(localPath) {
10003
10053
  const git = createGit2(localPath);
10004
10054
  const result = await git.pull();
@@ -10209,15 +10259,127 @@ var init_git = __esm({
10209
10259
  }
10210
10260
  });
10211
10261
 
10262
+ // src/known-agents.ts
10263
+ var known_agents_exports = {};
10264
+ __export(known_agents_exports, {
10265
+ KNOWN_AGENTS: () => KNOWN_AGENTS,
10266
+ detectInstalledAgents: () => detectInstalledAgents,
10267
+ getEffectiveAgents: () => getEffectiveAgents,
10268
+ seedSelfModeToolDirs: () => seedSelfModeToolDirs
10269
+ });
10270
+ import path34 from "path";
10271
+ async function seedSelfModeToolDirs(localConfig, teamConfig) {
10272
+ const baseDir = resolveBaseDir(localConfig);
10273
+ const configured = teamConfig.toolPaths ?? {};
10274
+ let targets = localConfig.enabledAgents && localConfig.enabledAgents.length > 0 ? localConfig.enabledAgents : ["claude"];
10275
+ targets = targets.filter((id) => !isAgentDisabled(localConfig, id));
10276
+ const seeded = [];
10277
+ for (const id of targets) {
10278
+ const skillsPath = configured[id]?.skills ?? KNOWN_AGENTS.find((a) => a.id === id)?.skillsPath;
10279
+ if (!skillsPath) continue;
10280
+ await ensureDir(path34.join(baseDir, skillsPath));
10281
+ seeded.push(id);
10282
+ }
10283
+ return seeded;
10284
+ }
10285
+ function getEffectiveAgents(teamConfig) {
10286
+ const byId = /* @__PURE__ */ new Map();
10287
+ for (const agent of KNOWN_AGENTS) {
10288
+ byId.set(agent.id, { ...agent });
10289
+ }
10290
+ for (const [id, paths] of Object.entries(teamConfig.toolPaths)) {
10291
+ if (!paths.skills) continue;
10292
+ const existing = byId.get(id);
10293
+ if (existing) {
10294
+ byId.set(id, { ...existing, skillsPath: paths.skills, fromTeamConfig: true });
10295
+ } else {
10296
+ byId.set(id, {
10297
+ id,
10298
+ displayName: id,
10299
+ category: "coding",
10300
+ skillsPath: paths.skills,
10301
+ fromTeamConfig: true
10302
+ });
10303
+ }
10304
+ }
10305
+ return [...byId.values()];
10306
+ }
10307
+ async function detectInstalledAgents(localConfig, teamConfig) {
10308
+ const baseDir = resolveBaseDir(localConfig);
10309
+ const agents = getEffectiveAgents(teamConfig);
10310
+ const fromTeamConfig = new Set(
10311
+ Object.entries(teamConfig.toolPaths).filter(([, paths]) => paths.skills).map(([id]) => id)
10312
+ );
10313
+ const results = [];
10314
+ for (const agent of agents) {
10315
+ const segments = agent.skillsPath.split("/");
10316
+ const rootSegment = segments[0] ?? "";
10317
+ const rootPath = `${baseDir}/${rootSegment}`;
10318
+ const installed = rootSegment ? await pathExists(rootPath) : false;
10319
+ results.push({
10320
+ ...agent,
10321
+ absoluteSkillsPath: `${baseDir}/${agent.skillsPath}`,
10322
+ installed,
10323
+ fromTeamConfig: fromTeamConfig.has(agent.id)
10324
+ });
10325
+ }
10326
+ return results;
10327
+ }
10328
+ var KNOWN_AGENTS;
10329
+ var init_known_agents = __esm({
10330
+ "src/known-agents.ts"() {
10331
+ "use strict";
10332
+ init_fs();
10333
+ init_types();
10334
+ KNOWN_AGENTS = [
10335
+ // Coding agents already wired through teamConfig.toolPaths defaults
10336
+ { id: "claude", displayName: "Claude Code", category: "coding", skillsPath: ".claude/skills" },
10337
+ { id: "claude-internal", displayName: "Claude Code Internal", category: "coding", skillsPath: ".claude-internal/skills" },
10338
+ { id: "tclaude", displayName: "TClaude", category: "coding", skillsPath: ".tclaude/skills" },
10339
+ { id: "codex", displayName: "Codex CLI", category: "coding", skillsPath: ".codex/skills" },
10340
+ { id: "codex-internal", displayName: "Codex CLI Internal", category: "coding", skillsPath: ".codex-internal/skills" },
10341
+ { id: "tcodex", displayName: "TCodex", category: "coding", skillsPath: ".tcodex/skills" },
10342
+ { id: "cursor", displayName: "Cursor", category: "coding", skillsPath: ".cursor/skills" },
10343
+ { id: "codebuddy", displayName: "CodeBuddy", category: "coding", skillsPath: ".codebuddy/skills" },
10344
+ // Additional coding agents from skills-manage
10345
+ { id: "gemini", displayName: "Gemini CLI", category: "coding", skillsPath: ".gemini/skills" },
10346
+ { id: "aider", displayName: "Aider", category: "coding", skillsPath: ".aider/skills" },
10347
+ { id: "amp", displayName: "Amp", category: "coding", skillsPath: ".amp/skills" },
10348
+ { id: "augment", displayName: "Augment", category: "coding", skillsPath: ".augment/skills" },
10349
+ { id: "copilot", displayName: "Copilot", category: "coding", skillsPath: ".copilot/skills" },
10350
+ { id: "factory", displayName: "Factory Droid", category: "coding", skillsPath: ".factory/skills" },
10351
+ { id: "hermes", displayName: "Hermes", category: "coding", skillsPath: ".hermes/skills" },
10352
+ { id: "junie", displayName: "Junie", category: "coding", skillsPath: ".junie/skills" },
10353
+ { id: "kilocode", displayName: "KiloCode", category: "coding", skillsPath: ".kilocode/skills" },
10354
+ { id: "kiro", displayName: "Kiro", category: "coding", skillsPath: ".kiro/skills" },
10355
+ { id: "ob1", displayName: "OB1", category: "coding", skillsPath: ".ob1/skills" },
10356
+ { id: "opencode", displayName: "OpenCode", category: "coding", skillsPath: ".opencode/skills" },
10357
+ { id: "qoder", displayName: "Qoder", category: "coding", skillsPath: ".qoder/skills" },
10358
+ { id: "qwen", displayName: "Qwen", category: "coding", skillsPath: ".qwen/skills" },
10359
+ { id: "trae", displayName: "Trae", category: "coding", skillsPath: ".trae/skills" },
10360
+ { id: "trae-cn", displayName: "Trae CN", category: "coding", skillsPath: ".trae-cn/skills" },
10361
+ { id: "windsurf", displayName: "Windsurf", category: "coding", skillsPath: ".windsurf/skills" },
10362
+ // Lobster family
10363
+ { id: "openclaw", displayName: "OpenClaw", category: "lobster", skillsPath: ".openclaw/skills" },
10364
+ { id: "qclaw", displayName: "QClaw", category: "lobster", skillsPath: ".qclaw/skills" },
10365
+ { id: "easyclaw", displayName: "EasyClaw", category: "lobster", skillsPath: ".easyclaw/skills" },
10366
+ { id: "autoclaw", displayName: "AutoClaw", category: "lobster", skillsPath: ".openclaw-autoclaw/skills" },
10367
+ { id: "workbuddy", displayName: "WorkBuddy", category: "lobster", skillsPath: ".workbuddy/skills" },
10368
+ // Central agent skills directory (codex / generic)
10369
+ { id: "agents", displayName: "Central (Agent Skills)", category: "central", skillsPath: ".agents/skills" }
10370
+ ];
10371
+ }
10372
+ });
10373
+
10212
10374
  // src/bootstrap.ts
10213
10375
  var bootstrap_exports = {};
10214
10376
  __export(bootstrap_exports, {
10215
10377
  bootstrapSelfRepo: () => bootstrapSelfRepo
10216
10378
  });
10217
- import path34 from "path";
10379
+ import path35 from "path";
10218
10380
  import YAML8 from "yaml";
10219
10381
  async function readSelfModeMarker(dir) {
10220
- const yamlPath = path34.join(dir, ".teamai", "teamai.yaml");
10382
+ const yamlPath = path35.join(dir, ".teamai", "teamai.yaml");
10221
10383
  const content = await readFileSafe(yamlPath);
10222
10384
  if (!content) return null;
10223
10385
  try {
@@ -10239,7 +10401,7 @@ async function bootstrapSelfRepo(dir, opts) {
10239
10401
  if (await pathExists(configPath)) return "already";
10240
10402
  const marker = await readSelfModeMarker(businessRepoRoot);
10241
10403
  if (!marker) return "skip";
10242
- const lockPath = path34.join(businessRepoRoot, ".teamai", BOOTSTRAP_LOCK_FILENAME);
10404
+ const lockPath = path35.join(businessRepoRoot, ".teamai", BOOTSTRAP_LOCK_FILENAME);
10243
10405
  const locked = await acquireLock(lockPath);
10244
10406
  if (!locked) {
10245
10407
  log.debug("[bootstrap] another bootstrap is in progress; skipping");
@@ -10247,7 +10409,7 @@ async function bootstrapSelfRepo(dir, opts) {
10247
10409
  }
10248
10410
  try {
10249
10411
  if (await pathExists(configPath)) return "already";
10250
- const localPath = path34.join(businessRepoRoot, ".teamai");
10412
+ const localPath = path35.join(businessRepoRoot, ".teamai");
10251
10413
  const remoteUrl = await getRemoteUrl(businessRepoRoot) ?? marker.repo ?? "";
10252
10414
  if (!remoteUrl) {
10253
10415
  log.debug("[bootstrap] no remote/repo to derive provider from; skipping");
@@ -10308,6 +10470,12 @@ async function bootstrapSelfRepo(dir, opts) {
10308
10470
  await saveStateForScope2(state, "project", businessRepoRoot);
10309
10471
  } catch {
10310
10472
  }
10473
+ try {
10474
+ const { seedSelfModeToolDirs: seedSelfModeToolDirs2 } = await Promise.resolve().then(() => (init_known_agents(), known_agents_exports));
10475
+ await seedSelfModeToolDirs2(localConfig, teamConfig);
10476
+ } catch (e) {
10477
+ log.debug(`[bootstrap] tool-dir seeding skipped: ${e.message}`);
10478
+ }
10311
10479
  try {
10312
10480
  const { reconcileTeamHooksForConfig: reconcileTeamHooksForConfig2 } = await Promise.resolve().then(() => (init_hooks2(), hooks_exports));
10313
10481
  await reconcileTeamHooksForConfig2(teamConfig, localConfig, {});
@@ -10317,9 +10485,9 @@ async function bootstrapSelfRepo(dir, opts) {
10317
10485
  try {
10318
10486
  const { ensureReportsWorktree: ensureReportsWorktree2, commitAndPushReports: commitAndPushReports2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
10319
10487
  const wt = await ensureReportsWorktree2(localConfig);
10320
- const memberDir = path34.join(wt, "members");
10488
+ const memberDir = path35.join(wt, "members");
10321
10489
  await ensureDir(memberDir);
10322
- const memberPath = path34.join(memberDir, `${username}.yaml`);
10490
+ const memberPath = path35.join(memberDir, `${username}.yaml`);
10323
10491
  if (!await pathExists(memberPath)) {
10324
10492
  await writeFile(memberPath, YAML8.stringify({
10325
10493
  username,
@@ -10369,7 +10537,7 @@ __export(config_exports, {
10369
10537
  saveStateForScope: () => saveStateForScope
10370
10538
  });
10371
10539
  import YAML9 from "yaml";
10372
- import path35 from "path";
10540
+ import path36 from "path";
10373
10541
  async function migrateLegacyRoleConfig(config, configPath) {
10374
10542
  if (config.primaryRole) {
10375
10543
  return config;
@@ -10395,7 +10563,7 @@ async function migrateLegacyRoleConfig(config, configPath) {
10395
10563
  return migrated;
10396
10564
  }
10397
10565
  async function loadTeamConfig(repoPath) {
10398
- const content = await readFileSafe(path35.join(repoPath, "teamai.yaml"));
10566
+ const content = await readFileSafe(path36.join(repoPath, "teamai.yaml"));
10399
10567
  if (!content) {
10400
10568
  log.debug("teamai.yaml not found in repo");
10401
10569
  return null;
@@ -10473,7 +10641,7 @@ async function saveStateForScope(state, scope, projectRoot) {
10473
10641
  }
10474
10642
  async function detectProjectConfig(cwd) {
10475
10643
  const dir = cwd ?? process.cwd();
10476
- const configPath = path35.join(dir, ".teamai", "config.yaml");
10644
+ const configPath = path36.join(dir, ".teamai", "config.yaml");
10477
10645
  if (!await pathExists(configPath)) {
10478
10646
  try {
10479
10647
  const { bootstrapSelfRepo: bootstrapSelfRepo2 } = await Promise.resolve().then(() => (init_bootstrap(), bootstrap_exports));
@@ -10537,9 +10705,9 @@ __export(api_key_exports, {
10537
10705
  saveApiKey: () => saveApiKey
10538
10706
  });
10539
10707
  import fs13 from "fs";
10540
- import path36 from "path";
10708
+ import path37 from "path";
10541
10709
  function getApiKeyPath() {
10542
- return path36.join(process.env.HOME ?? "", ".teamai", "apikey");
10710
+ return path37.join(process.env.HOME ?? "", ".teamai", "apikey");
10543
10711
  }
10544
10712
  function resolveApiKey() {
10545
10713
  const fromEnv = process.env.TEAMAI_API_TOKEN || process.env.TEAMAI_API_KEY;
@@ -10555,7 +10723,7 @@ async function saveApiKey(key) {
10555
10723
  const trimmed = key.trim();
10556
10724
  if (!trimmed) throw new Error("API key must not be empty");
10557
10725
  const keyPath = getApiKeyPath();
10558
- await ensureDir(path36.dirname(keyPath));
10726
+ await ensureDir(path37.dirname(keyPath));
10559
10727
  fs13.writeFileSync(keyPath, trimmed + "\n", { mode: 384 });
10560
10728
  fs13.chmodSync(keyPath, 384);
10561
10729
  }
@@ -10579,9 +10747,9 @@ __export(init_exports, {
10579
10747
  });
10580
10748
  import YAML10 from "yaml";
10581
10749
  import fs14 from "fs";
10582
- import path37 from "path";
10750
+ import path38 from "path";
10583
10751
  function resolveRealPath(p) {
10584
- const resolved = path37.resolve(p);
10752
+ const resolved = path38.resolve(p);
10585
10753
  try {
10586
10754
  return fs14.realpathSync(resolved);
10587
10755
  } catch {
@@ -10703,10 +10871,10 @@ function printScopeSummary(scope, projectRoot, explicit) {
10703
10871
  }
10704
10872
  }
10705
10873
  async function isInsideGitRepo(dir) {
10706
- let current = path37.resolve(dir);
10874
+ let current = path38.resolve(dir);
10707
10875
  for (; ; ) {
10708
- if (await pathExists(path37.join(current, ".git"))) return true;
10709
- const parent = path37.dirname(current);
10876
+ if (await pathExists(path38.join(current, ".git"))) return true;
10877
+ const parent = path38.dirname(current);
10710
10878
  if (parent === current) return false;
10711
10879
  current = parent;
10712
10880
  }
@@ -10767,9 +10935,9 @@ async function initHttp(url, options) {
10767
10935
  log.error("No API key found. Pass --token <key> to `teamai init --http`, or set TEAMAI_API_TOKEN.");
10768
10936
  process.exit(1);
10769
10937
  }
10770
- const localPath = expandHome(path37.join(teamaiHome, "team-repo"));
10938
+ const localPath = expandHome(path38.join(teamaiHome, "team-repo"));
10771
10939
  await ensureDir(localPath);
10772
- const stubPath = path37.join(localPath, "teamai.yaml");
10940
+ const stubPath = path38.join(localPath, "teamai.yaml");
10773
10941
  if (!await pathExists(stubPath)) {
10774
10942
  await writeFile(stubPath, YAML10.stringify({ team: "http-reporting", repo: url, sharing: {} }));
10775
10943
  }
@@ -10864,7 +11032,7 @@ async function initSelfRepo(options) {
10864
11032
  return;
10865
11033
  }
10866
11034
  const businessRepoRoot = cwd;
10867
- const teamaiHome = path37.join(businessRepoRoot, ".teamai");
11035
+ const teamaiHome = path38.join(businessRepoRoot, ".teamai");
10868
11036
  const localPath = teamaiHome;
10869
11037
  let inheritUserScope;
10870
11038
  try {
@@ -10921,13 +11089,13 @@ async function initSelfRepo(options) {
10921
11089
  }
10922
11090
  await ensureDir(localPath);
10923
11091
  for (const dir of ["skills", "rules", "docs", "learnings", "env"]) {
10924
- await ensureDir(path37.join(localPath, dir));
10925
- const gitkeep = path37.join(localPath, dir, ".gitkeep");
11092
+ await ensureDir(path38.join(localPath, dir));
11093
+ const gitkeep = path38.join(localPath, dir, ".gitkeep");
10926
11094
  if (!await pathExists(gitkeep)) {
10927
11095
  await writeFile(gitkeep, "");
10928
11096
  }
10929
11097
  }
10930
- const teamaiYamlPath = path37.join(localPath, "teamai.yaml");
11098
+ const teamaiYamlPath = path38.join(localPath, "teamai.yaml");
10931
11099
  if (!await pathExists(teamaiYamlPath)) {
10932
11100
  const defaultConfig = YAML10.stringify({
10933
11101
  team: repoInfo.repo,
@@ -10975,16 +11143,43 @@ async function initSelfRepo(options) {
10975
11143
  await ensureDir(teamaiHome);
10976
11144
  await saveLocalConfigForScope(localConfig, "project", businessRepoRoot);
10977
11145
  log.success(`Local config saved to ${teamaiHome}/config.yaml`);
10978
- const gitignorePath = path37.join(teamaiHome, ".gitignore");
11146
+ const gitignorePath = path38.join(teamaiHome, ".gitignore");
10979
11147
  await writeFile(gitignorePath, buildSelfModeGitignore());
10980
11148
  log.debug("Generated single-repo .teamai/.gitignore");
11149
+ if (!options.dryRun) {
11150
+ try {
11151
+ const { commitPaths: commitPaths2, hasCommits: hasCommits2 } = await Promise.resolve().then(() => (init_git(), git_exports));
11152
+ const hadCommits = await hasCommits2(businessRepoRoot);
11153
+ const skeletonPaths = [
11154
+ ".teamai/skills",
11155
+ ".teamai/rules",
11156
+ ".teamai/docs",
11157
+ ".teamai/learnings",
11158
+ ".teamai/teamai.yaml",
11159
+ ".teamai/.gitignore",
11160
+ ".claude/settings.json"
11161
+ ];
11162
+ const committed = await commitPaths2(
11163
+ businessRepoRoot,
11164
+ "[teamai] Initialize single-repo mode (skills/rules/docs/learnings skeleton)",
11165
+ skeletonPaths
11166
+ );
11167
+ if (committed) {
11168
+ log.success(
11169
+ hadCommits ? "Committed .teamai/ skeleton to the current branch" : "Created initial commit with the .teamai/ skeleton"
11170
+ );
11171
+ }
11172
+ } catch (e) {
11173
+ log.warn(`Could not commit the .teamai/ skeleton (do it manually before \`teamai push\`): ${e.message}`);
11174
+ }
11175
+ }
10981
11176
  if (!options.dryRun) {
10982
11177
  try {
10983
11178
  const { ensureReportsWorktree: ensureReportsWorktree2, commitAndPushReports: commitAndPushReports2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
10984
11179
  const wt = await ensureReportsWorktree2(localConfig);
10985
- const memberDir = path37.join(wt, "members");
11180
+ const memberDir = path38.join(wt, "members");
10986
11181
  await ensureDir(memberDir);
10987
- const memberPath = path37.join(memberDir, `${username}.yaml`);
11182
+ const memberPath = path38.join(memberDir, `${username}.yaml`);
10988
11183
  if (!await pathExists(memberPath)) {
10989
11184
  await writeFile(memberPath, YAML10.stringify({
10990
11185
  username,
@@ -11008,11 +11203,18 @@ async function initSelfRepo(options) {
11008
11203
  await saveStateForScope(state, "project", businessRepoRoot);
11009
11204
  } catch {
11010
11205
  }
11206
+ try {
11207
+ const { seedSelfModeToolDirs: seedSelfModeToolDirs2 } = await Promise.resolve().then(() => (init_known_agents(), known_agents_exports));
11208
+ const seeded = await seedSelfModeToolDirs2(localConfig, teamConfig);
11209
+ if (seeded.length > 0) log.debug(`Seeded tool dirs for: ${seeded.join(", ")}`);
11210
+ } catch (e) {
11211
+ log.debug(`Tool-dir seeding skipped: ${e.message}`);
11212
+ }
11011
11213
  const filterAgents2 = options.agent ? [options.agent] : void 0;
11012
11214
  await reconcileTeamHooksForConfig(teamConfig, localConfig, { filterAgents: filterAgents2 });
11013
11215
  log.success("teamai initialized (single-repo mode)!");
11014
- log.info("Commit .teamai/ (skills, rules, docs, learnings, teamai.yaml, .gitignore) and .claude/settings.json to main.");
11015
- log.info("Teammates who clone this repo will be auto-initialized on their next session.");
11216
+ log.info("Push your business repo (e.g. `git push -u origin HEAD`) so teammates get the .teamai/ knowledge and are auto-initialized on clone.");
11217
+ log.info("Add skills/rules later with `teamai push` \u2014 it opens a PR against your repo without touching your working tree.");
11016
11218
  closePrompt();
11017
11219
  }
11018
11220
  async function init(options) {
@@ -11114,7 +11316,7 @@ async function init(options) {
11114
11316
  authSpin.fail(`Authentication failed: ${e.message}`);
11115
11317
  process.exit(1);
11116
11318
  }
11117
- const defaultLocalPath = path37.join(teamaiHome, "team-repo");
11319
+ const defaultLocalPath = path38.join(teamaiHome, "team-repo");
11118
11320
  const localPath = expandHome(defaultLocalPath);
11119
11321
  if (await pathExists(localPath)) {
11120
11322
  if (await isGitRepo(localPath)) {
@@ -11195,16 +11397,16 @@ async function init(options) {
11195
11397
  env: { injectShellProfile: true }
11196
11398
  }
11197
11399
  });
11198
- await writeFile(path37.join(localPath, "teamai.yaml"), defaultConfig);
11400
+ await writeFile(path38.join(localPath, "teamai.yaml"), defaultConfig);
11199
11401
  for (const dir of ["members", "skills", "rules", "docs", "env"]) {
11200
- await ensureDir(path37.join(localPath, dir));
11201
- const gitkeep = path37.join(localPath, dir, ".gitkeep");
11402
+ await ensureDir(path38.join(localPath, dir));
11403
+ const gitkeep = path38.join(localPath, dir, ".gitkeep");
11202
11404
  if (!await pathExists(gitkeep)) {
11203
11405
  await writeFile(gitkeep, "");
11204
11406
  }
11205
11407
  }
11206
11408
  }
11207
- const memberPath = path37.join(localPath, "members", `${username}.yaml`);
11409
+ const memberPath = path38.join(localPath, "members", `${username}.yaml`);
11208
11410
  const isNewMember = !await pathExists(memberPath);
11209
11411
  if (isNewMember) {
11210
11412
  const memberYaml = YAML10.stringify({
@@ -11242,7 +11444,7 @@ async function init(options) {
11242
11444
  const reviewerInput = await askQuestion("Reviewers (comma-separated usernames): ", "");
11243
11445
  const reviewers = reviewerInput.split(",").map((s) => s.trim()).filter(Boolean);
11244
11446
  if (reviewers.length > 0) {
11245
- const configPath = path37.join(localPath, "teamai.yaml");
11447
+ const configPath = path38.join(localPath, "teamai.yaml");
11246
11448
  const configContent = await readFileSafe(configPath);
11247
11449
  if (configContent) {
11248
11450
  const configData = YAML10.parse(configContent);
@@ -11292,7 +11494,7 @@ async function init(options) {
11292
11494
  if (scope === "project") {
11293
11495
  await saveLocalConfigForScope(localConfig, scope, projectRoot);
11294
11496
  log.success(`Local config saved to ${teamaiHome}/config.yaml`);
11295
- const gitignorePath = path37.join(teamaiHome, ".gitignore");
11497
+ const gitignorePath = path38.join(teamaiHome, ".gitignore");
11296
11498
  if (!await pathExists(gitignorePath)) {
11297
11499
  const gitignoreContent = [
11298
11500
  "# teamai local config (do not commit)",
@@ -11352,10 +11554,10 @@ var init_init = __esm({
11352
11554
  });
11353
11555
 
11354
11556
  // src/utils/tags.ts
11355
- import path38 from "path";
11557
+ import path39 from "path";
11356
11558
  import YAML11 from "yaml";
11357
11559
  async function loadTagsConfig(repoPath) {
11358
- const content = await readFileSafe(path38.join(repoPath, TAGS_FILE));
11560
+ const content = await readFileSafe(path39.join(repoPath, TAGS_FILE));
11359
11561
  if (!content) {
11360
11562
  return null;
11361
11563
  }
@@ -11410,7 +11612,7 @@ function filterByTags(items, tagsConfig, subscribedTags, resourceType) {
11410
11612
  return { included, skipped };
11411
11613
  }
11412
11614
  async function saveTagsConfig(repoPath, config) {
11413
- const filePath = path38.join(repoPath, TAGS_FILE);
11615
+ const filePath = path39.join(repoPath, TAGS_FILE);
11414
11616
  const content = YAML11.stringify({
11415
11617
  skills: config.skills,
11416
11618
  rules: config.rules
@@ -11515,7 +11717,7 @@ __export(votes_exports, {
11515
11717
  saveUserVotes: () => saveUserVotes,
11516
11718
  syncVotesToTeam: () => syncVotesToTeam
11517
11719
  });
11518
- import path39 from "path";
11720
+ import path40 from "path";
11519
11721
  import YAML12 from "yaml";
11520
11722
  function migrateV1ToV2(v1) {
11521
11723
  const votes = {};
@@ -11554,7 +11756,7 @@ async function loadUserVotes(votePath) {
11554
11756
  return { version: 2, votes: {}, deltas: {} };
11555
11757
  }
11556
11758
  async function saveUserVotes(votePath, votes) {
11557
- await ensureDir(path39.dirname(votePath));
11759
+ await ensureDir(path40.dirname(votePath));
11558
11760
  await writeFile(votePath, YAML12.stringify(votes));
11559
11761
  }
11560
11762
  async function incrementRecalled(votePath, docIds) {
@@ -11615,8 +11817,8 @@ function mergeDeltas(local, remote) {
11615
11817
  return { version: 2, votes, deltas: {} };
11616
11818
  }
11617
11819
  async function syncVotesToTeam(repoPath, username, localVotesDir) {
11618
- const localVotePath = path39.join(localVotesDir, `${username}.yaml`);
11619
- const remoteVotePath = path39.join(repoPath, "votes", `${username}.yaml`);
11820
+ const localVotePath = path40.join(localVotesDir, `${username}.yaml`);
11821
+ const remoteVotePath = path40.join(repoPath, "votes", `${username}.yaml`);
11620
11822
  const local = await loadUserVotes(localVotePath);
11621
11823
  if (Object.keys(local.deltas).length === 0) {
11622
11824
  return false;
@@ -11632,7 +11834,7 @@ async function recallFeedback(opts) {
11632
11834
  const { localConfig } = await requireInit3();
11633
11835
  const { username } = localConfig;
11634
11836
  const { VOTES_LOCAL_DIR: VOTES_LOCAL_DIR2 } = await Promise.resolve().then(() => (init_types(), types_exports));
11635
- const votePath = path39.join(VOTES_LOCAL_DIR2, `${username}.yaml`);
11837
+ const votePath = path40.join(VOTES_LOCAL_DIR2, `${username}.yaml`);
11636
11838
  if (opts.positive) {
11637
11839
  await incrementUpvoted(votePath, [opts.positive]);
11638
11840
  log.success(`Upvoted: ${opts.positive}`);
@@ -11682,7 +11884,7 @@ __export(confidence_exports, {
11682
11884
  computeConfidence: () => computeConfidence,
11683
11885
  writeBackConfidence: () => writeBackConfidence
11684
11886
  });
11685
- import path40 from "path";
11887
+ import path41 from "path";
11686
11888
  import matter2 from "gray-matter";
11687
11889
  function computeConfidence(factors) {
11688
11890
  const { recalledCount, upvotedCount, lastRecalledAt } = factors;
@@ -11705,7 +11907,7 @@ async function computeAllConfidence(votesDir) {
11705
11907
  for (const file of files) {
11706
11908
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
11707
11909
  try {
11708
- const data = await loadUserVotes2(path40.join(votesDir, file));
11910
+ const data = await loadUserVotes2(path41.join(votesDir, file));
11709
11911
  for (const [docId, entry] of Object.entries(data.votes)) {
11710
11912
  const existing = aggregated.get(docId) ?? { recalled: 0, upvoted: 0, lastRecalled: "" };
11711
11913
  existing.recalled += entry.recalled_count ?? 0;
@@ -11741,7 +11943,7 @@ async function writeBackConfidence(learningsDir, confidenceMap) {
11741
11943
  const docId = file.replace(/\.md$/i, "");
11742
11944
  const newConf = confidenceMap.get(docId);
11743
11945
  if (newConf === void 0) continue;
11744
- const absPath = path40.join(learningsDir, file);
11946
+ const absPath = path41.join(learningsDir, file);
11745
11947
  const content = await readFileSafe(absPath);
11746
11948
  if (!content) continue;
11747
11949
  try {
@@ -11810,7 +12012,7 @@ __export(search_index_exports, {
11810
12012
  titleFromFilename: () => titleFromFilename,
11811
12013
  tokenize: () => tokenize
11812
12014
  });
11813
- import path41 from "path";
12015
+ import path42 from "path";
11814
12016
  import matter3 from "gray-matter";
11815
12017
  function getSearchIndexPath() {
11816
12018
  return `${process.env.HOME ?? ""}/.teamai/search-index.json`;
@@ -11891,7 +12093,7 @@ async function aggregateVotes(votesDir) {
11891
12093
  const files = await listFiles(votesDir);
11892
12094
  for (const file of files) {
11893
12095
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
11894
- const content = await readFileSafe(path41.join(votesDir, file));
12096
+ const content = await readFileSafe(path42.join(votesDir, file));
11895
12097
  if (!content) continue;
11896
12098
  try {
11897
12099
  const YAML20 = (await import("yaml")).default;
@@ -11937,10 +12139,10 @@ async function aggregateVotes(votesDir) {
11937
12139
  return { scores, confidenceMap };
11938
12140
  }
11939
12141
  async function entryFromMdFile(absPath, filenameForId, type, voteCounts) {
11940
- const basename = path41.basename(absPath);
12142
+ const basename = path42.basename(absPath);
11941
12143
  if (basename === CODEBASE_FULL_FILENAME) {
11942
- const dir = path41.dirname(absPath);
11943
- const indexPath = path41.join(dir, CODEBASE_INDEX_FILENAME);
12144
+ const dir = path42.dirname(absPath);
12145
+ const indexPath = path42.join(dir, CODEBASE_INDEX_FILENAME);
11944
12146
  if (await pathExists(indexPath)) {
11945
12147
  log.debug(`Skipping ${absPath}: codebase-index.md exists in same directory`);
11946
12148
  return null;
@@ -11997,7 +12199,7 @@ async function collectFlatMdEntries(dir, type, voteCounts) {
11997
12199
  const out = [];
11998
12200
  for (const filename of files) {
11999
12201
  if (!filename.endsWith(".md")) continue;
12000
- const e = await entryFromMdFile(path41.join(dir, filename), filename, type, voteCounts);
12202
+ const e = await entryFromMdFile(path42.join(dir, filename), filename, type, voteCounts);
12001
12203
  if (e) out.push(e);
12002
12204
  }
12003
12205
  return out;
@@ -12008,7 +12210,7 @@ async function collectRecursiveMdEntries(dir, type, voteCounts) {
12008
12210
  const out = [];
12009
12211
  for (const rel of files) {
12010
12212
  if (!rel.endsWith(".md")) continue;
12011
- const e = await entryFromMdFile(path41.join(dir, rel), rel, type, voteCounts);
12213
+ const e = await entryFromMdFile(path42.join(dir, rel), rel, type, voteCounts);
12012
12214
  if (e) out.push(e);
12013
12215
  }
12014
12216
  return out;
@@ -12020,8 +12222,8 @@ async function collectSkillEntries(dir, voteCounts) {
12020
12222
  const subdirs = await listDirs(current);
12021
12223
  for (const sub of subdirs) {
12022
12224
  if (sub.startsWith(".")) continue;
12023
- const subPath = path41.join(current, sub);
12024
- const skillMd = path41.join(subPath, "SKILL.md");
12225
+ const subPath = path42.join(current, sub);
12226
+ const skillMd = path42.join(subPath, "SKILL.md");
12025
12227
  if (await pathExists(skillMd)) {
12026
12228
  const e = await entryFromMdFile(skillMd, `${sub}.md`, "skills", voteCounts);
12027
12229
  if (e) out.push(e);
@@ -12138,7 +12340,7 @@ function search(query, index, limit = 5) {
12138
12340
  const domainMultiplier = domainWeightRow[entry.domain ?? "neutral"];
12139
12341
  const typeMultiplier = TYPE_BONUS[entry.type];
12140
12342
  score *= domainMultiplier * typeMultiplier;
12141
- if (path41.basename(entry.path ?? "") === CODEBASE_INDEX_FILENAME) {
12343
+ if (path42.basename(entry.path ?? "") === CODEBASE_INDEX_FILENAME) {
12142
12344
  score *= CODEBASE_INDEX_WEIGHT_BOOST;
12143
12345
  }
12144
12346
  if (entry.hotness !== void 0 && entry.hotness < 1) {
@@ -12400,12 +12602,12 @@ __export(usage_tracker_exports, {
12400
12602
  updateKnownSkills: () => updateKnownSkills
12401
12603
  });
12402
12604
  import fs15 from "fs";
12403
- import path42 from "path";
12605
+ import path43 from "path";
12404
12606
  function getUsagePath() {
12405
- return path42.join(process.env.HOME ?? "", ".teamai", "usage.jsonl");
12607
+ return path43.join(process.env.HOME ?? "", ".teamai", "usage.jsonl");
12406
12608
  }
12407
12609
  function getKnownSkillsPath() {
12408
- return path42.join(process.env.HOME ?? "", ".teamai", "known-skills.json");
12610
+ return path43.join(process.env.HOME ?? "", ".teamai", "known-skills.json");
12409
12611
  }
12410
12612
  function extractSkillName(toolInput) {
12411
12613
  try {
@@ -12431,13 +12633,13 @@ function isValidSkillName(name) {
12431
12633
  async function skillExistsOnDisk(skillName) {
12432
12634
  const home = process.env.HOME ?? "";
12433
12635
  for (const dir of SKILL_DIRS) {
12434
- const skillMd = path42.join(home, dir, skillName, "SKILL.md");
12636
+ const skillMd = path43.join(home, dir, skillName, "SKILL.md");
12435
12637
  if (await pathExists(skillMd)) return true;
12436
12638
  }
12437
12639
  const cwd = process.cwd();
12438
- if (path42.resolve(cwd) !== path42.resolve(home)) {
12640
+ if (path43.resolve(cwd) !== path43.resolve(home)) {
12439
12641
  for (const dir of SKILL_DIRS) {
12440
- const skillMd = path42.join(cwd, dir, skillName, "SKILL.md");
12642
+ const skillMd = path43.join(cwd, dir, skillName, "SKILL.md");
12441
12643
  if (await pathExists(skillMd)) return true;
12442
12644
  }
12443
12645
  }
@@ -12445,7 +12647,7 @@ async function skillExistsOnDisk(skillName) {
12445
12647
  }
12446
12648
  async function appendUsageEvent(event) {
12447
12649
  try {
12448
- await ensureDir(path42.dirname(getUsagePath()));
12650
+ await ensureDir(path43.dirname(getUsagePath()));
12449
12651
  const line = JSON.stringify(event) + "\n";
12450
12652
  await fs15.promises.appendFile(getUsagePath(), line, "utf-8");
12451
12653
  log.debug(`Tracked skill: ${event.skill}`);
@@ -12919,16 +13121,16 @@ __export(digest_exports, {
12919
13121
  summarizeInterventions: () => summarizeInterventions
12920
13122
  });
12921
13123
  import YAML13 from "yaml";
12922
- import path43 from "path";
13124
+ import path44 from "path";
12923
13125
  import fs16 from "fs";
12924
13126
  async function loadTeamStats(repoPath) {
12925
- const statsDir = path43.join(repoPath, "stats");
13127
+ const statsDir = path44.join(repoPath, "stats");
12926
13128
  const stats = [];
12927
13129
  try {
12928
13130
  const files = await listFiles(statsDir);
12929
13131
  for (const file of files) {
12930
13132
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
12931
- const content = await readFileSafe(path43.join(statsDir, file));
13133
+ const content = await readFileSafe(path44.join(statsDir, file));
12932
13134
  if (!content) continue;
12933
13135
  try {
12934
13136
  const parsed = YAML13.parse(content);
@@ -13025,17 +13227,17 @@ async function getRecentSkillChanges(repoPath) {
13025
13227
  return changes;
13026
13228
  }
13027
13229
  async function getRecentSessions(repoPath) {
13028
- const sessionsDir = path43.join(repoPath, "sessions");
13230
+ const sessionsDir = path44.join(repoPath, "sessions");
13029
13231
  const summaries = [];
13030
13232
  try {
13031
13233
  const userDirs = await fs16.promises.readdir(sessionsDir, { withFileTypes: true });
13032
13234
  for (const userDir of userDirs) {
13033
13235
  if (!userDir.isDirectory()) continue;
13034
- const userSessionsDir = path43.join(sessionsDir, userDir.name);
13236
+ const userSessionsDir = path44.join(sessionsDir, userDir.name);
13035
13237
  const files = await listFiles(userSessionsDir);
13036
13238
  for (const file of files) {
13037
13239
  if (!file.endsWith(".md")) continue;
13038
- const content = await readFileSafe(path43.join(userSessionsDir, file));
13240
+ const content = await readFileSafe(path44.join(userSessionsDir, file));
13039
13241
  if (content) {
13040
13242
  summaries.push(`[${userDir.name}] ${file}:
13041
13243
  ${content.slice(0, 500)}`);
@@ -13047,7 +13249,7 @@ ${content.slice(0, 500)}`);
13047
13249
  return summaries;
13048
13250
  }
13049
13251
  async function getRecentLearnings(repoPath) {
13050
- const learningsDir = path43.join(repoPath, "learnings");
13252
+ const learningsDir = path44.join(repoPath, "learnings");
13051
13253
  const recent = [];
13052
13254
  let total = 0;
13053
13255
  try {
@@ -13060,7 +13262,7 @@ async function getRecentLearnings(repoPath) {
13060
13262
  if (!dateMatch) continue;
13061
13263
  const fileDate = dateMatch[1];
13062
13264
  if (fileDate < cutoff) continue;
13063
- const content = await readFileSafe(path43.join(learningsDir, filename));
13265
+ const content = await readFileSafe(path44.join(learningsDir, filename));
13064
13266
  if (!content) continue;
13065
13267
  const parsed = parseLearningDoc(content, filename);
13066
13268
  const title = parsed?.meta.title ?? titleFromFilename(filename);
@@ -13251,7 +13453,7 @@ __export(stats_exports, {
13251
13453
  showStats: () => showStats
13252
13454
  });
13253
13455
  import YAML14 from "yaml";
13254
- import path44 from "path";
13456
+ import path45 from "path";
13255
13457
  function aggregateUsage(events) {
13256
13458
  const map = /* @__PURE__ */ new Map();
13257
13459
  for (const event of events) {
@@ -13281,7 +13483,7 @@ async function loadReportedStats() {
13281
13483
  const { ensureReportsWorktree: ensureReportsWorktree2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
13282
13484
  statsRoot = await ensureReportsWorktree2(config);
13283
13485
  }
13284
- const statsPath = path44.join(statsRoot, "stats", `${config.username}.yaml`);
13486
+ const statsPath = path45.join(statsRoot, "stats", `${config.username}.yaml`);
13285
13487
  const content = await readFileSafe(statsPath);
13286
13488
  if (!content) return null;
13287
13489
  const parsed = YAML14.parse(content);
@@ -13490,7 +13692,7 @@ __export(team_push_exports, {
13490
13692
  reportUsageToTeam: () => reportUsageToTeam
13491
13693
  });
13492
13694
  import YAML15 from "yaml";
13493
- import path45 from "path";
13695
+ import path46 from "path";
13494
13696
  async function readExistingStats(statsPath) {
13495
13697
  try {
13496
13698
  const content = await readFileSafe(statsPath);
@@ -13528,7 +13730,7 @@ function mergeStats(existing, username, newEvents) {
13528
13730
  };
13529
13731
  }
13530
13732
  function getReportedInterventionsPath() {
13531
- return path45.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-interventions.json");
13733
+ return path46.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-interventions.json");
13532
13734
  }
13533
13735
  async function readReportedInterventions() {
13534
13736
  const parsed = await readJson(getReportedInterventionsPath());
@@ -13566,7 +13768,7 @@ function hasInterventionDelta(d) {
13566
13768
  return d.sessions > 0 || d.interrupt > 0 || d.toolReject > 0 || d.correction > 0;
13567
13769
  }
13568
13770
  function getReportedPromptTokensPath() {
13569
- return path45.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-prompt-tokens.json");
13771
+ return path46.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-prompt-tokens.json");
13570
13772
  }
13571
13773
  async function readReportedPromptTokens() {
13572
13774
  try {
@@ -13581,7 +13783,7 @@ async function readReportedPromptTokens() {
13581
13783
  async function writeReportedPromptTokens(data) {
13582
13784
  try {
13583
13785
  const p = getReportedPromptTokensPath();
13584
- await ensureDir(path45.dirname(p));
13786
+ await ensureDir(path46.dirname(p));
13585
13787
  await writeFile(p, JSON.stringify(data));
13586
13788
  } catch (e) {
13587
13789
  log.error(`Failed to persist reported prompt/token snapshot: ${e.message}`);
@@ -13667,9 +13869,9 @@ async function reportUsageToTeam(repoPath, username, options) {
13667
13869
  await pullRepo(repoPath);
13668
13870
  }
13669
13871
  if (hasUsage || hasInterventions || hasPromptTokens) {
13670
- const statsDir = path45.join(writeRoot, "stats");
13872
+ const statsDir = path46.join(writeRoot, "stats");
13671
13873
  await ensureDir(statsDir);
13672
- const statsPath = path45.join(statsDir, `${username}.yaml`);
13874
+ const statsPath = path46.join(statsDir, `${username}.yaml`);
13673
13875
  const existing = await readExistingStats(statsPath);
13674
13876
  const newStats = hasUsage ? aggregateUsage(events) : [];
13675
13877
  const merged = mergeStats(existing, username, newStats);
@@ -13935,7 +14137,7 @@ __export(mcp_reconcile_exports, {
13935
14137
  resolveMcpTargets: () => resolveMcpTargets,
13936
14138
  spliceCodexBlock: () => spliceCodexBlock
13937
14139
  });
13938
- import path46 from "path";
14140
+ import path47 from "path";
13939
14141
  import fse9 from "fs-extra";
13940
14142
  async function readManifest2(manifestPath) {
13941
14143
  const data = await readJson(expandHome(manifestPath));
@@ -13943,7 +14145,7 @@ async function readManifest2(manifestPath) {
13943
14145
  }
13944
14146
  async function buildVarTable(localConfig) {
13945
14147
  const table = {};
13946
- const envFile = path46.join(getTeamaiHome(localConfig.scope, localConfig.projectRoot), "env");
14148
+ const envFile = path47.join(getTeamaiHome(localConfig.scope, localConfig.projectRoot), "env");
13947
14149
  const content = await readFileSafe(envFile);
13948
14150
  if (content) {
13949
14151
  for (const line of content.split("\n")) {
@@ -14010,12 +14212,12 @@ async function resolveMcpTargets(teamConfig, localConfig) {
14010
14212
  if (!rel) continue;
14011
14213
  const probe = paths.skills ?? paths.settings ?? paths.agents;
14012
14214
  if (!probe) continue;
14013
- const toolRoot = path46.join(baseDir, probe.split("/")[0]);
14215
+ const toolRoot = path47.join(baseDir, probe.split("/")[0]);
14014
14216
  if (!await pathExists(toolRoot)) {
14015
14217
  log.debug(`Skipping MCP sync for ${tool}: tool not installed`);
14016
14218
  continue;
14017
14219
  }
14018
- targets.push({ tool, format, file: path46.join(baseDir, rel), projectScope });
14220
+ targets.push({ tool, format, file: path47.join(baseDir, rel), projectScope });
14019
14221
  }
14020
14222
  return targets;
14021
14223
  }
@@ -14213,7 +14415,7 @@ async function applyCodex(target, desired, ownedNames, nextRecords, changes, opt
14213
14415
  changes.push({ tool: target.tool, server: name, action: "removed" });
14214
14416
  }
14215
14417
  if (!dirty || options.dryRun) return false;
14216
- await fse9.ensureDir(path46.dirname(target.file));
14418
+ await fse9.ensureDir(path47.dirname(target.file));
14217
14419
  const tmp = `${target.file}.${process.pid}.tmp`;
14218
14420
  await fse9.writeFile(tmp, source, "utf-8");
14219
14421
  await fse9.chmod(tmp, 384);
@@ -14245,7 +14447,7 @@ __export(pull_exports, {
14245
14447
  pull: () => pull,
14246
14448
  scanRoleAwareSkills: () => scanRoleAwareSkills
14247
14449
  });
14248
- import path47 from "path";
14450
+ import path48 from "path";
14249
14451
  import fse10 from "fs-extra";
14250
14452
  import matter4 from "gray-matter";
14251
14453
  async function refreshTeamRepo(localConfig) {
@@ -14304,14 +14506,14 @@ async function buildRolePullContext(localConfig) {
14304
14506
  const activeSkillNames = /* @__PURE__ */ new Set();
14305
14507
  const inactiveSkillNames = /* @__PURE__ */ new Set();
14306
14508
  for (const namespace of activeNamespaces.skills) {
14307
- const namespaceDir = path47.join(localConfig.repo.localPath, "skills", namespace);
14509
+ const namespaceDir = path48.join(localConfig.repo.localPath, "skills", namespace);
14308
14510
  const names = await listDirs(namespaceDir);
14309
14511
  for (const name of names) {
14310
14512
  activeSkillNames.add(name);
14311
14513
  }
14312
14514
  }
14313
14515
  for (const namespace of inactiveSkillNamespaces) {
14314
- const namespaceDir = path47.join(localConfig.repo.localPath, "skills", namespace);
14516
+ const namespaceDir = path48.join(localConfig.repo.localPath, "skills", namespace);
14315
14517
  const names = await listDirs(namespaceDir);
14316
14518
  for (const name of names) {
14317
14519
  inactiveSkillNames.add(name);
@@ -14331,7 +14533,7 @@ function filterRulesByKnowledgeNamespaces(rules, knowledgeNamespaces) {
14331
14533
  async function scanRoleAwareSkills(localConfig, namespaces) {
14332
14534
  const items = /* @__PURE__ */ new Map();
14333
14535
  for (const namespace of namespaces.skills) {
14334
- const namespaceDir = path47.join(localConfig.repo.localPath, "skills", namespace);
14536
+ const namespaceDir = path48.join(localConfig.repo.localPath, "skills", namespace);
14335
14537
  const dirs = await listDirs(namespaceDir);
14336
14538
  for (const dir of dirs) {
14337
14539
  const existing = items.get(dir);
@@ -14341,7 +14543,7 @@ async function scanRoleAwareSkills(localConfig, namespaces) {
14341
14543
  items.set(dir, {
14342
14544
  name: dir,
14343
14545
  type: "skills",
14344
- sourcePath: path47.join(namespaceDir, dir),
14546
+ sourcePath: path48.join(namespaceDir, dir),
14345
14547
  relativePath: `skills/${namespace}/${dir}`,
14346
14548
  namespace
14347
14549
  });
@@ -14355,13 +14557,13 @@ async function cleanupInactiveNamespaceSkills(teamConfig, localConfig, activeSki
14355
14557
  if (isAgentDisabled(localConfig, tool)) continue;
14356
14558
  if (!toolPath.skills) continue;
14357
14559
  if (!await ResourceHandler.isToolInstalled(toolPath.skills, baseDir)) continue;
14358
- if (!await pathExists(path47.join(baseDir, toolPath.skills))) continue;
14359
- const localSkillNames = await listDirs(path47.join(baseDir, toolPath.skills));
14560
+ if (!await pathExists(path48.join(baseDir, toolPath.skills))) continue;
14561
+ const localSkillNames = await listDirs(path48.join(baseDir, toolPath.skills));
14360
14562
  for (const skillName of localSkillNames) {
14361
14563
  if (BUILTIN_SKILL_NAMES.has(skillName)) continue;
14362
14564
  if (activeSkillNames.has(skillName)) continue;
14363
14565
  if (!inactiveSkillNames.has(skillName)) continue;
14364
- const localSkillDir = path47.join(baseDir, toolPath.skills, skillName);
14566
+ const localSkillDir = path48.join(baseDir, toolPath.skills, skillName);
14365
14567
  await remove(localSkillDir);
14366
14568
  log.debug(`[${localConfig.scope}] Removed inactive role-scoped skill ${skillName} from ${tool}`);
14367
14569
  }
@@ -14373,10 +14575,10 @@ async function getExistingLocalNames(type, items, teamConfig, localConfig) {
14373
14575
  if (type === "skills") {
14374
14576
  for (const [_tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
14375
14577
  if (!toolPath.skills) continue;
14376
- const skillsDir = path47.join(baseDir, toolPath.skills);
14578
+ const skillsDir = path48.join(baseDir, toolPath.skills);
14377
14579
  if (!await pathExists(skillsDir)) continue;
14378
14580
  for (const item of items) {
14379
- const skillDir = path47.join(skillsDir, item.name);
14581
+ const skillDir = path48.join(skillsDir, item.name);
14380
14582
  if (await pathExists(skillDir)) {
14381
14583
  existing.add(item.name);
14382
14584
  }
@@ -14593,7 +14795,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14593
14795
  if (!await ResourceHandler.isToolInstalled(dir, baseDir)) continue;
14594
14796
  if (isAgentDisabled(localConfig, tool)) continue;
14595
14797
  for (const name of tombstones) {
14596
- const localPath = path47.join(baseDir, dir, ext ? `${name}${ext}` : name);
14798
+ const localPath = path48.join(baseDir, dir, ext ? `${name}${ext}` : name);
14597
14799
  if (await pathExists(localPath)) {
14598
14800
  await remove(localPath);
14599
14801
  log.debug(`[${scopeLabel}] Cleaned up tombstoned ${type} ${name} from ${dir}`);
@@ -14616,25 +14818,25 @@ async function pullForScope(localConfig, options, policy = {}) {
14616
14818
  if (isAgentDisabled(localConfig, tool)) continue;
14617
14819
  if (!toolPath.skills) continue;
14618
14820
  if (!await ResourceHandler.isToolInstalled(toolPath.skills, baseDir)) continue;
14619
- const skillsDir = path47.join(baseDir, toolPath.skills);
14821
+ const skillsDir = path48.join(baseDir, toolPath.skills);
14620
14822
  if (!await pathExists(skillsDir)) continue;
14621
14823
  const localDirs = await listDirs(skillsDir);
14622
14824
  for (const dir of localDirs) {
14623
14825
  if (BUILTIN_SKILL_NAMES.has(dir)) continue;
14624
14826
  if (desiredSkillNames.has(dir)) continue;
14625
14827
  if (!knownRepoSkillNames.has(dir)) continue;
14626
- const skillDir = path47.join(skillsDir, dir);
14828
+ const skillDir = path48.join(skillsDir, dir);
14627
14829
  await remove(skillDir);
14628
14830
  log.debug(`Removed excluded skill ${dir} from ${tool}`);
14629
14831
  }
14630
14832
  if (excludedSkills.size > 0) {
14631
14833
  for (const namespace of localDirs) {
14632
- const namespaceDir = path47.join(skillsDir, namespace);
14633
- if (await pathExists(path47.join(namespaceDir, "SKILL.md"))) continue;
14834
+ const namespaceDir = path48.join(skillsDir, namespace);
14835
+ if (await pathExists(path48.join(namespaceDir, "SKILL.md"))) continue;
14634
14836
  for (const skillName of await listDirs(namespaceDir)) {
14635
14837
  if (!excludedSkills.has(skillName) || BUILTIN_SKILL_NAMES.has(skillName)) continue;
14636
- const nestedSkillDir = path47.join(namespaceDir, skillName);
14637
- if (!await pathExists(path47.join(nestedSkillDir, "SKILL.md"))) continue;
14838
+ const nestedSkillDir = path48.join(namespaceDir, skillName);
14839
+ if (!await pathExists(path48.join(nestedSkillDir, "SKILL.md"))) continue;
14638
14840
  await remove(nestedSkillDir);
14639
14841
  log.debug(`Removed excluded skill ${namespace}/${skillName} from ${tool}`);
14640
14842
  }
@@ -14647,18 +14849,18 @@ async function pullForScope(localConfig, options, policy = {}) {
14647
14849
  }
14648
14850
  if (!options.dryRun) {
14649
14851
  try {
14650
- const learningsRepoDir = path47.join(localConfig.repo.localPath, "learnings");
14651
- const docsRepoDir = path47.join(localConfig.repo.localPath, "docs");
14652
- const rulesRepoDir = path47.join(localConfig.repo.localPath, "rules");
14653
- const skillsRepoDir = path47.join(localConfig.repo.localPath, "skills");
14654
- const votesDir = path47.join(localConfig.repo.localPath, "votes");
14852
+ const learningsRepoDir = path48.join(localConfig.repo.localPath, "learnings");
14853
+ const docsRepoDir = path48.join(localConfig.repo.localPath, "docs");
14854
+ const rulesRepoDir = path48.join(localConfig.repo.localPath, "rules");
14855
+ const skillsRepoDir = path48.join(localConfig.repo.localPath, "skills");
14856
+ const votesDir = path48.join(localConfig.repo.localPath, "votes");
14655
14857
  let learningsCount = 0;
14656
14858
  let effectiveLearningsDir;
14657
14859
  if (localConfig.scope === "user") {
14658
14860
  if (await pathExists(learningsRepoDir)) {
14659
14861
  await fse10.copy(learningsRepoDir, LEARNINGS_LOCAL_DIR, {
14660
14862
  overwrite: true,
14661
- filter: (src) => !path47.basename(src).startsWith(".")
14863
+ filter: (src) => !path48.basename(src).startsWith(".")
14662
14864
  });
14663
14865
  const allFiles = await listFiles(learningsRepoDir);
14664
14866
  learningsCount = allFiles.filter((f) => f.endsWith(".md")).length;
@@ -14672,12 +14874,12 @@ async function pullForScope(localConfig, options, policy = {}) {
14672
14874
  }
14673
14875
  }
14674
14876
  const hasAnySource = effectiveLearningsDir || await pathExists(docsRepoDir) || await pathExists(rulesRepoDir) || await pathExists(skillsRepoDir);
14675
- const repoCodebaseDir = path47.join(localConfig.repo.localPath, "docs", "team-codebase");
14877
+ const repoCodebaseDir = path48.join(localConfig.repo.localPath, "docs", "team-codebase");
14676
14878
  const effectiveCodebaseDir = await pathExists(repoCodebaseDir) ? repoCodebaseDir : void 0;
14677
14879
  if (hasAnySource || effectiveCodebaseDir) {
14678
14880
  const votesExist = await pathExists(votesDir);
14679
14881
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
14680
- const indexPath = path47.join(teamaiHome, "search-index.json");
14882
+ const indexPath = path48.join(teamaiHome, "search-index.json");
14681
14883
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
14682
14884
  const elapsed = await buildIndex2({
14683
14885
  learningsDir: effectiveLearningsDir,
@@ -14701,7 +14903,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14701
14903
  }
14702
14904
  if (!options.dryRun) {
14703
14905
  try {
14704
- const culturePath = path47.join(localConfig.repo.localPath, "culture.md");
14906
+ const culturePath = path48.join(localConfig.repo.localPath, "culture.md");
14705
14907
  if (await pathExists(culturePath)) {
14706
14908
  const cultureContent = await readFileSafe(culturePath);
14707
14909
  if (cultureContent) {
@@ -14712,7 +14914,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14712
14914
  if (isAgentDisabled(localConfig, tool)) continue;
14713
14915
  if (!toolPath.claudemd) continue;
14714
14916
  if (toolPath.rules && !await ResourceHandler.isToolInstalled(toolPath.rules, baseDir)) continue;
14715
- const claudeMdPath = path47.join(baseDir, toolPath.claudemd);
14917
+ const claudeMdPath = path48.join(baseDir, toolPath.claudemd);
14716
14918
  try {
14717
14919
  await injectClaudeMdSection(claudeMdPath, TEAMAI_CULTURE_START, TEAMAI_CULTURE_END, compiled);
14718
14920
  log.debug(`Injected culture into ${tool} CLAUDE.md`);
@@ -14742,7 +14944,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14742
14944
  if (isAgentDisabled(localConfig, tool)) continue;
14743
14945
  if (!toolPath.claudemd) continue;
14744
14946
  if (toolPath.rules && !await ResourceHandler.isToolInstalled(toolPath.rules, baseDir)) continue;
14745
- const claudeMdPath = path47.join(baseDir, toolPath.claudemd);
14947
+ const claudeMdPath = path48.join(baseDir, toolPath.claudemd);
14746
14948
  try {
14747
14949
  await injectClaudeMdSection(claudeMdPath, TEAMAI_CLAUDEMD_START, TEAMAI_CLAUDEMD_END, compiled);
14748
14950
  log.debug(`Injected shared instructions into ${tool} CLAUDE.md`);
@@ -14817,12 +15019,12 @@ async function pullForScope(localConfig, options, policy = {}) {
14817
15019
  const YAML20 = (await import("yaml")).default;
14818
15020
  const { listFiles: listFiles2, readFileSafe: readFileSafe5 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
14819
15021
  const { getRecommendations: getRecommendations2, displayRecommendations: displayRecommendations2 } = await Promise.resolve().then(() => (init_skill_recommend(), skill_recommend_exports));
14820
- const statsDir = path47.join(localConfig.repo.localPath, "stats");
15022
+ const statsDir = path48.join(localConfig.repo.localPath, "stats");
14821
15023
  const files = await listFiles2(statsDir);
14822
15024
  const teamStats = [];
14823
15025
  for (const file of files) {
14824
15026
  if (!file.endsWith(".yaml")) continue;
14825
- const content = await readFileSafe5(path47.join(statsDir, file));
15027
+ const content = await readFileSafe5(path48.join(statsDir, file));
14826
15028
  if (!content) continue;
14827
15029
  try {
14828
15030
  const parsed = YAML20.parse(content);
@@ -14910,7 +15112,7 @@ async function injectRecallBlockIntoTools(config, localConfig, scopeLabel) {
14910
15112
  if (isAgentDisabled(localConfig, tool)) continue;
14911
15113
  if (!toolPath.claudemd || !toolPath.agents) continue;
14912
15114
  if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) continue;
14913
- const claudeMdPath = path47.join(baseDir, toolPath.claudemd);
15115
+ const claudeMdPath = path48.join(baseDir, toolPath.claudemd);
14914
15116
  try {
14915
15117
  await injectClaudeMdSection(
14916
15118
  claudeMdPath,
@@ -14994,7 +15196,7 @@ function compileRecallRulesBlock() {
14994
15196
  return lines.join("\n");
14995
15197
  }
14996
15198
  async function collectClaudemdFiles(repoPath, roleContext) {
14997
- const claudemdDir = path47.join(repoPath, "claudemd");
15199
+ const claudemdDir = path48.join(repoPath, "claudemd");
14998
15200
  if (!await pathExists(claudemdDir)) return [];
14999
15201
  let namespaceDirs;
15000
15202
  if (roleContext) {
@@ -15004,11 +15206,11 @@ async function collectClaudemdFiles(repoPath, roleContext) {
15004
15206
  }
15005
15207
  const contents = [];
15006
15208
  for (const ns of namespaceDirs) {
15007
- const nsDir = path47.join(claudemdDir, ns);
15209
+ const nsDir = path48.join(claudemdDir, ns);
15008
15210
  if (!await pathExists(nsDir)) continue;
15009
15211
  const files = (await listFiles(nsDir)).filter((f) => f.endsWith(".md")).sort();
15010
15212
  for (const file of files) {
15011
- const content = await readFileSafe(path47.join(nsDir, file));
15213
+ const content = await readFileSafe(path48.join(nsDir, file));
15012
15214
  if (content) contents.push(content);
15013
15215
  }
15014
15216
  }
@@ -15016,7 +15218,7 @@ async function collectClaudemdFiles(repoPath, roleContext) {
15016
15218
  }
15017
15219
  async function autoMigrateHooksIfNeeded() {
15018
15220
  const home = process.env.HOME ?? "";
15019
- const primarySettings = path47.join(home, ".claude", "settings.json");
15221
+ const primarySettings = path48.join(home, ".claude", "settings.json");
15020
15222
  if (!await pathExists(primarySettings)) return;
15021
15223
  const content = await readFileSafe(primarySettings);
15022
15224
  if (!content) return;
@@ -15195,108 +15397,18 @@ var init_pull = __esm({
15195
15397
  }
15196
15398
  });
15197
15399
 
15198
- // src/known-agents.ts
15199
- function getEffectiveAgents(teamConfig) {
15200
- const byId = /* @__PURE__ */ new Map();
15201
- for (const agent of KNOWN_AGENTS) {
15202
- byId.set(agent.id, { ...agent });
15203
- }
15204
- for (const [id, paths] of Object.entries(teamConfig.toolPaths)) {
15205
- if (!paths.skills) continue;
15206
- const existing = byId.get(id);
15207
- if (existing) {
15208
- byId.set(id, { ...existing, skillsPath: paths.skills, fromTeamConfig: true });
15209
- } else {
15210
- byId.set(id, {
15211
- id,
15212
- displayName: id,
15213
- category: "coding",
15214
- skillsPath: paths.skills,
15215
- fromTeamConfig: true
15216
- });
15217
- }
15218
- }
15219
- return [...byId.values()];
15220
- }
15221
- async function detectInstalledAgents(localConfig, teamConfig) {
15222
- const baseDir = resolveBaseDir(localConfig);
15223
- const agents = getEffectiveAgents(teamConfig);
15224
- const fromTeamConfig = new Set(
15225
- Object.entries(teamConfig.toolPaths).filter(([, paths]) => paths.skills).map(([id]) => id)
15226
- );
15227
- const results = [];
15228
- for (const agent of agents) {
15229
- const segments = agent.skillsPath.split("/");
15230
- const rootSegment = segments[0] ?? "";
15231
- const rootPath = `${baseDir}/${rootSegment}`;
15232
- const installed = rootSegment ? await pathExists(rootPath) : false;
15233
- results.push({
15234
- ...agent,
15235
- absoluteSkillsPath: `${baseDir}/${agent.skillsPath}`,
15236
- installed,
15237
- fromTeamConfig: fromTeamConfig.has(agent.id)
15238
- });
15239
- }
15240
- return results;
15241
- }
15242
- var KNOWN_AGENTS;
15243
- var init_known_agents = __esm({
15244
- "src/known-agents.ts"() {
15245
- "use strict";
15246
- init_fs();
15247
- init_types();
15248
- KNOWN_AGENTS = [
15249
- // Coding agents already wired through teamConfig.toolPaths defaults
15250
- { id: "claude", displayName: "Claude Code", category: "coding", skillsPath: ".claude/skills" },
15251
- { id: "claude-internal", displayName: "Claude Code Internal", category: "coding", skillsPath: ".claude-internal/skills" },
15252
- { id: "tclaude", displayName: "TClaude", category: "coding", skillsPath: ".tclaude/skills" },
15253
- { id: "codex", displayName: "Codex CLI", category: "coding", skillsPath: ".codex/skills" },
15254
- { id: "codex-internal", displayName: "Codex CLI Internal", category: "coding", skillsPath: ".codex-internal/skills" },
15255
- { id: "tcodex", displayName: "TCodex", category: "coding", skillsPath: ".tcodex/skills" },
15256
- { id: "cursor", displayName: "Cursor", category: "coding", skillsPath: ".cursor/skills" },
15257
- { id: "codebuddy", displayName: "CodeBuddy", category: "coding", skillsPath: ".codebuddy/skills" },
15258
- // Additional coding agents from skills-manage
15259
- { id: "gemini", displayName: "Gemini CLI", category: "coding", skillsPath: ".gemini/skills" },
15260
- { id: "aider", displayName: "Aider", category: "coding", skillsPath: ".aider/skills" },
15261
- { id: "amp", displayName: "Amp", category: "coding", skillsPath: ".amp/skills" },
15262
- { id: "augment", displayName: "Augment", category: "coding", skillsPath: ".augment/skills" },
15263
- { id: "copilot", displayName: "Copilot", category: "coding", skillsPath: ".copilot/skills" },
15264
- { id: "factory", displayName: "Factory Droid", category: "coding", skillsPath: ".factory/skills" },
15265
- { id: "hermes", displayName: "Hermes", category: "coding", skillsPath: ".hermes/skills" },
15266
- { id: "junie", displayName: "Junie", category: "coding", skillsPath: ".junie/skills" },
15267
- { id: "kilocode", displayName: "KiloCode", category: "coding", skillsPath: ".kilocode/skills" },
15268
- { id: "kiro", displayName: "Kiro", category: "coding", skillsPath: ".kiro/skills" },
15269
- { id: "ob1", displayName: "OB1", category: "coding", skillsPath: ".ob1/skills" },
15270
- { id: "opencode", displayName: "OpenCode", category: "coding", skillsPath: ".opencode/skills" },
15271
- { id: "qoder", displayName: "Qoder", category: "coding", skillsPath: ".qoder/skills" },
15272
- { id: "qwen", displayName: "Qwen", category: "coding", skillsPath: ".qwen/skills" },
15273
- { id: "trae", displayName: "Trae", category: "coding", skillsPath: ".trae/skills" },
15274
- { id: "trae-cn", displayName: "Trae CN", category: "coding", skillsPath: ".trae-cn/skills" },
15275
- { id: "windsurf", displayName: "Windsurf", category: "coding", skillsPath: ".windsurf/skills" },
15276
- // Lobster family
15277
- { id: "openclaw", displayName: "OpenClaw", category: "lobster", skillsPath: ".openclaw/skills" },
15278
- { id: "qclaw", displayName: "QClaw", category: "lobster", skillsPath: ".qclaw/skills" },
15279
- { id: "easyclaw", displayName: "EasyClaw", category: "lobster", skillsPath: ".easyclaw/skills" },
15280
- { id: "autoclaw", displayName: "AutoClaw", category: "lobster", skillsPath: ".openclaw-autoclaw/skills" },
15281
- { id: "workbuddy", displayName: "WorkBuddy", category: "lobster", skillsPath: ".workbuddy/skills" },
15282
- // Central agent skills directory (codex / generic)
15283
- { id: "agents", displayName: "Central (Agent Skills)", category: "central", skillsPath: ".agents/skills" }
15284
- ];
15285
- }
15286
- });
15287
-
15288
15400
  // src/agent-skills.ts
15289
- import path48 from "path";
15401
+ import path49 from "path";
15290
15402
  import YAML16 from "yaml";
15291
15403
  async function buildClassifyContext(localConfig) {
15292
15404
  const teamSkills = await collectTeamRepoSkills(localConfig.repo.localPath);
15293
15405
  const sourceSkills = /* @__PURE__ */ new Map();
15294
15406
  try {
15295
- const sourcesDir = path48.join(process.env.HOME ?? "", ".teamai", "sources");
15407
+ const sourcesDir = path49.join(process.env.HOME ?? "", ".teamai", "sources");
15296
15408
  if (await pathExists(sourcesDir)) {
15297
15409
  const sourceNames = await listDirs(sourcesDir);
15298
15410
  for (const sourceName of sourceNames) {
15299
- const manifestPath = path48.join(sourcesDir, sourceName, "installed.json");
15411
+ const manifestPath = path49.join(sourcesDir, sourceName, "installed.json");
15300
15412
  const raw = await readFileSafe(manifestPath);
15301
15413
  if (!raw) continue;
15302
15414
  try {
@@ -15313,13 +15425,13 @@ async function buildClassifyContext(localConfig) {
15313
15425
  return { teamSkills, sourceSkills };
15314
15426
  }
15315
15427
  async function collectTeamRepoSkills(repoPath) {
15316
- const teamSkillsDir = path48.join(repoPath, "skills");
15428
+ const teamSkillsDir = path49.join(repoPath, "skills");
15317
15429
  const result = /* @__PURE__ */ new Map();
15318
15430
  if (!await pathExists(teamSkillsDir)) return result;
15319
15431
  const topDirs = await listDirs(teamSkillsDir);
15320
15432
  for (const dir of topDirs) {
15321
- const dirPath = path48.join(teamSkillsDir, dir);
15322
- const hasSkillMd = await pathExists(path48.join(dirPath, "SKILL.md"));
15433
+ const dirPath = path49.join(teamSkillsDir, dir);
15434
+ const hasSkillMd = await pathExists(path49.join(dirPath, "SKILL.md"));
15323
15435
  if (hasSkillMd) {
15324
15436
  result.set(dir, {});
15325
15437
  } else {
@@ -15366,8 +15478,8 @@ async function scanAgentSkills(agent, ctx) {
15366
15478
  const dirs = await listDirs(agent.absoluteSkillsPath);
15367
15479
  for (const name of dirs) {
15368
15480
  if (name.startsWith(".") || name.endsWith("-workspace")) continue;
15369
- const skillDir = path48.join(agent.absoluteSkillsPath, name);
15370
- const skillMd = path48.join(skillDir, "SKILL.md");
15481
+ const skillDir = path49.join(agent.absoluteSkillsPath, name);
15482
+ const skillMd = path49.join(skillDir, "SKILL.md");
15371
15483
  if (!await pathExists(skillMd)) continue;
15372
15484
  const description = await readSkillDescription(skillMd);
15373
15485
  skills.push({
@@ -15417,7 +15529,7 @@ __export(status_exports, {
15417
15529
  list: () => list,
15418
15530
  status: () => status
15419
15531
  });
15420
- import path49 from "path";
15532
+ import path50 from "path";
15421
15533
  import YAML17 from "yaml";
15422
15534
  async function status(options) {
15423
15535
  const { localConfig, teamConfig } = await autoDetectInit();
@@ -15450,14 +15562,14 @@ async function status(options) {
15450
15562
  log.info("Team resources:");
15451
15563
  const repoPath = localConfig.repo.localPath;
15452
15564
  const counts = {};
15453
- const skillsDirs = await listDirs(path49.join(repoPath, "skills"));
15565
+ const skillsDirs = await listDirs(path50.join(repoPath, "skills"));
15454
15566
  counts.skills = skillsDirs.length;
15455
- const rulesFiles = (await listFiles(path49.join(repoPath, "rules"))).filter((f) => f.endsWith(".md"));
15567
+ const rulesFiles = (await listFiles(path50.join(repoPath, "rules"))).filter((f) => f.endsWith(".md"));
15456
15568
  counts.rules = rulesFiles.length;
15457
- const docsExists = await pathExists(path49.join(repoPath, "docs"));
15458
- const docFiles = docsExists ? (await listFiles(path49.join(repoPath, "docs"))).filter((f) => !f.startsWith(".")) : [];
15569
+ const docsExists = await pathExists(path50.join(repoPath, "docs"));
15570
+ const docFiles = docsExists ? (await listFiles(path50.join(repoPath, "docs"))).filter((f) => !f.startsWith(".")) : [];
15459
15571
  counts.docs = docFiles.length;
15460
- const envYamlPath = path49.join(repoPath, "env", "env.yaml");
15572
+ const envYamlPath = path50.join(repoPath, "env", "env.yaml");
15461
15573
  let envCount = 0;
15462
15574
  if (await pathExists(envYamlPath)) {
15463
15575
  const envContent = await readFileSafe(envYamlPath);
@@ -15545,7 +15657,7 @@ async function printRepoSection(t, options, ctx) {
15545
15657
  console.log("");
15546
15658
  console.log(`=== REPO ${t.toUpperCase()} ===`);
15547
15659
  if (t === "env") {
15548
- const envYamlPath = path49.join(repoPath, "env", "env.yaml");
15660
+ const envYamlPath = path50.join(repoPath, "env", "env.yaml");
15549
15661
  if (await pathExists(envYamlPath)) {
15550
15662
  const envContent = await readFileSafe(envYamlPath);
15551
15663
  if (envContent) {
@@ -15705,7 +15817,7 @@ var skill_cmd_exports = {};
15705
15817
  __export(skill_cmd_exports, {
15706
15818
  skillShow: () => skillShow
15707
15819
  });
15708
- import path50 from "path";
15820
+ import path51 from "path";
15709
15821
  async function skillShow(name, options) {
15710
15822
  const { localConfig, teamConfig } = await autoDetectInit();
15711
15823
  const agents = await detectInstalledAgents(localConfig, teamConfig);
@@ -15718,7 +15830,7 @@ async function skillShow(name, options) {
15718
15830
  }
15719
15831
  const ctx = await buildClassifyContext(localConfig);
15720
15832
  const source = classifySkill(name, ctx);
15721
- const description = truncate(await readSkillDescription(path50.join(resolved.primaryPath, "SKILL.md")), DESCRIPTION_MAX);
15833
+ const description = truncate(await readSkillDescription(path51.join(resolved.primaryPath, "SKILL.md")), DESCRIPTION_MAX);
15722
15834
  const contributors = await SkillsHandler.readContributors(resolved.primaryPath);
15723
15835
  const tagsConfig = await loadTagsConfig(localConfig.repo.localPath);
15724
15836
  const tags = tagsConfig?.skills?.[name] ?? [];
@@ -15736,28 +15848,28 @@ async function skillShow(name, options) {
15736
15848
  });
15737
15849
  if (options.verbose) {
15738
15850
  console.log("");
15739
- console.log(` Verbose: SKILL.md path is ${path50.join(resolved.primaryPath, "SKILL.md")}`);
15851
+ console.log(` Verbose: SKILL.md path is ${path51.join(resolved.primaryPath, "SKILL.md")}`);
15740
15852
  }
15741
15853
  }
15742
15854
  async function locateSkill(name, localConfig, agents) {
15743
- const teamSkillsDir = path50.join(localConfig.repo.localPath, "skills");
15744
- const flat = path50.join(teamSkillsDir, name);
15745
- if (await pathExists(path50.join(flat, "SKILL.md"))) {
15855
+ const teamSkillsDir = path51.join(localConfig.repo.localPath, "skills");
15856
+ const flat = path51.join(teamSkillsDir, name);
15857
+ if (await pathExists(path51.join(flat, "SKILL.md"))) {
15746
15858
  return { name, primaryPath: flat, primaryOrigin: "team" };
15747
15859
  }
15748
15860
  if (await pathExists(teamSkillsDir)) {
15749
15861
  const namespaces = await listDirs(teamSkillsDir);
15750
15862
  for (const ns of namespaces) {
15751
- const candidate = path50.join(teamSkillsDir, ns, name);
15752
- if (await pathExists(path50.join(candidate, "SKILL.md"))) {
15863
+ const candidate = path51.join(teamSkillsDir, ns, name);
15864
+ if (await pathExists(path51.join(candidate, "SKILL.md"))) {
15753
15865
  return { name, primaryPath: candidate, primaryOrigin: "team", namespace: ns };
15754
15866
  }
15755
15867
  }
15756
15868
  }
15757
15869
  for (const agent of agents) {
15758
15870
  if (!agent.installed) continue;
15759
- const candidate = path50.join(agent.absoluteSkillsPath, name);
15760
- if (await pathExists(path50.join(candidate, "SKILL.md"))) {
15871
+ const candidate = path51.join(agent.absoluteSkillsPath, name);
15872
+ if (await pathExists(path51.join(candidate, "SKILL.md"))) {
15761
15873
  return { name, primaryPath: candidate, primaryOrigin: "agent" };
15762
15874
  }
15763
15875
  }
@@ -15767,8 +15879,8 @@ async function collectInstalledAgents(name, agents) {
15767
15879
  const matches = [];
15768
15880
  for (const agent of agents) {
15769
15881
  if (!agent.installed) continue;
15770
- const skillDir = path50.join(agent.absoluteSkillsPath, name);
15771
- if (await pathExists(path50.join(skillDir, "SKILL.md"))) {
15882
+ const skillDir = path51.join(agent.absoluteSkillsPath, name);
15883
+ if (await pathExists(path51.join(skillDir, "SKILL.md"))) {
15772
15884
  matches.push({ agent, path: skillDir });
15773
15885
  }
15774
15886
  }
@@ -15896,9 +16008,9 @@ __export(members_exports, {
15896
16008
  listMembers: () => listMembers
15897
16009
  });
15898
16010
  import YAML18 from "yaml";
15899
- import path51 from "path";
16011
+ import path52 from "path";
15900
16012
  async function getMemberConfig(repoPath, username) {
15901
- const memberPath = path51.join(repoPath, "members", `${username}.yaml`);
16013
+ const memberPath = path52.join(repoPath, "members", `${username}.yaml`);
15902
16014
  const content = await readFileSafe(memberPath);
15903
16015
  if (!content) return null;
15904
16016
  try {
@@ -15920,7 +16032,7 @@ async function listMembers(options) {
15920
16032
  repoPath = localConfig.repo.localPath;
15921
16033
  await pullRepo(repoPath);
15922
16034
  }
15923
- const membersDir = path51.join(repoPath, "members");
16035
+ const membersDir = path52.join(repoPath, "members");
15924
16036
  const files = await listFiles(membersDir);
15925
16037
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
15926
16038
  if (yamlFiles.length === 0) {
@@ -15931,7 +16043,7 @@ async function listMembers(options) {
15931
16043
  console.log(`Team members (${yamlFiles.length}):`);
15932
16044
  console.log("");
15933
16045
  for (const file of yamlFiles) {
15934
- const content = await readFileSafe(path51.join(membersDir, file));
16046
+ const content = await readFileSafe(path52.join(membersDir, file));
15935
16047
  if (!content) continue;
15936
16048
  try {
15937
16049
  const raw = YAML18.parse(content);
@@ -15977,8 +16089,16 @@ async function remove2(type, names, options) {
15977
16089
  const { localConfig, teamConfig } = await autoDetectInit();
15978
16090
  assertNotReadOnly(localConfig, "teamai remove");
15979
16091
  if (localConfig.repo.kind === "self") {
15980
- const { withKnowledgeWorktree: withKnowledgeWorktree2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
15981
- await withKnowledgeWorktree2(localConfig, (wtConfig) => removeCore(type, names, options, wtConfig, teamConfig));
16092
+ const { withKnowledgeWorktree: withKnowledgeWorktree2, EmptyRepoError: EmptyRepoError2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
16093
+ try {
16094
+ await withKnowledgeWorktree2(localConfig, (wtConfig) => removeCore(type, names, options, wtConfig, teamConfig));
16095
+ } catch (e) {
16096
+ if (e instanceof EmptyRepoError2) {
16097
+ log.error(e.message);
16098
+ } else {
16099
+ log.error(`Remove failed: ${e.message}`);
16100
+ }
16101
+ }
15982
16102
  return;
15983
16103
  }
15984
16104
  await removeCore(type, names, options, localConfig, teamConfig);
@@ -16114,13 +16234,13 @@ var doctor_exports = {};
16114
16234
  __export(doctor_exports, {
16115
16235
  doctor: () => doctor
16116
16236
  });
16117
- import path52 from "path";
16237
+ import path53 from "path";
16118
16238
  async function buildHookChecks(toolPaths, baseDir) {
16119
16239
  const checks = [];
16120
16240
  for (const [tool, paths] of Object.entries(toolPaths)) {
16121
16241
  if (!paths.settings) continue;
16122
- const settingsPath = path52.join(baseDir, paths.settings);
16123
- const parentDir = path52.dirname(settingsPath);
16242
+ const settingsPath = path53.join(baseDir, paths.settings);
16243
+ const parentDir = path53.dirname(settingsPath);
16124
16244
  if (!await pathExists(parentDir)) continue;
16125
16245
  checks.push({
16126
16246
  name: `teamai hooks in ${tool} settings`,
@@ -16212,13 +16332,13 @@ async function doctor(options) {
16212
16332
  check: async () => {
16213
16333
  if (teamConfig?.sharing?.env?.injectShellProfile === false) return true;
16214
16334
  if (!localConfig) return true;
16215
- const envYamlPath = path52.join(localConfig.repo.localPath, "env", "env.yaml");
16335
+ const envYamlPath = path53.join(localConfig.repo.localPath, "env", "env.yaml");
16216
16336
  if (!await pathExists(envYamlPath)) return true;
16217
16337
  const home = process.env.HOME ?? "";
16218
- const envShPath = path52.join(home, ".teamai", "env.sh");
16338
+ const envShPath = path53.join(home, ".teamai", "env.sh");
16219
16339
  if (!await pathExists(envShPath)) return false;
16220
16340
  const shell = process.env.SHELL ?? "";
16221
- const profilePath = shell.includes("zsh") ? path52.join(home, ".zshrc") : path52.join(home, ".bashrc");
16341
+ const profilePath = shell.includes("zsh") ? path53.join(home, ".zshrc") : path53.join(home, ".bashrc");
16222
16342
  if (!await pathExists(profilePath)) return false;
16223
16343
  const content = await readFileSafe(profilePath);
16224
16344
  return content?.includes(TEAMAI_ENV_START) ?? false;
@@ -16265,7 +16385,7 @@ __export(roles_cmd_exports, {
16265
16385
  rolesSet: () => rolesSet,
16266
16386
  rolesUpdate: () => rolesUpdate
16267
16387
  });
16268
- import path53 from "path";
16388
+ import path54 from "path";
16269
16389
  import YAML19 from "yaml";
16270
16390
  function parseNamespaces(input) {
16271
16391
  return input.split(",").map((s) => s.trim()).filter(Boolean);
@@ -16281,8 +16401,16 @@ async function pullLatest(repoPath) {
16281
16401
  }
16282
16402
  async function runRolesEdit(localConfig, fn) {
16283
16403
  if (localConfig.repo.kind === "self") {
16284
- const { withKnowledgeWorktree: withKnowledgeWorktree2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
16285
- await withKnowledgeWorktree2(localConfig, (wtConfig) => fn(wtConfig.repo.localPath, wtConfig));
16404
+ const { withKnowledgeWorktree: withKnowledgeWorktree2, EmptyRepoError: EmptyRepoError2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
16405
+ try {
16406
+ await withKnowledgeWorktree2(localConfig, (wtConfig) => fn(wtConfig.repo.localPath, wtConfig));
16407
+ } catch (e) {
16408
+ if (e instanceof EmptyRepoError2) {
16409
+ log.error(e.message);
16410
+ } else {
16411
+ log.error(`Roles update failed: ${e.message}`);
16412
+ }
16413
+ }
16286
16414
  return;
16287
16415
  }
16288
16416
  await fn(localConfig.repo.localPath, localConfig);
@@ -16319,7 +16447,7 @@ async function rolesInit(options) {
16319
16447
  const repoPath = localConfig.repo.localPath;
16320
16448
  const selfMode = localConfig.repo.kind === "self";
16321
16449
  if (!selfMode) await pullLatest(repoPath);
16322
- const manifestPath = path53.join(repoPath, "manifest", "roles.yaml");
16450
+ const manifestPath = path54.join(repoPath, "manifest", "roles.yaml");
16323
16451
  if (await pathExists(manifestPath)) {
16324
16452
  log.warn(`Roles manifest already exists at ${manifestPath}`);
16325
16453
  const overwrite = await askConfirmation("Overwrite existing manifest? [y/N] ");
@@ -16389,7 +16517,7 @@ async function rolesInit(options) {
16389
16517
  const commitMsg = `[teamai] Initialize roles manifest with ${roles.length} role(s)`;
16390
16518
  await runRolesEdit(localConfig, async (editRepoPath, editConfig) => {
16391
16519
  await saveRolesManifest(editRepoPath, manifest);
16392
- log.success(`Manifest written to ${path53.join(editRepoPath, "manifest", "roles.yaml")}`);
16520
+ log.success(`Manifest written to ${path54.join(editRepoPath, "manifest", "roles.yaml")}`);
16393
16521
  await pushManifestChange({
16394
16522
  repoPath: editRepoPath,
16395
16523
  teamConfig,
@@ -16667,7 +16795,7 @@ __export(tags_exports, {
16667
16795
  tagsSubscribe: () => tagsSubscribe,
16668
16796
  tagsUnsubscribe: () => tagsUnsubscribe
16669
16797
  });
16670
- import path54 from "path";
16798
+ import path55 from "path";
16671
16799
  async function resolveTagsScope() {
16672
16800
  const projectConfig = await detectProjectConfig();
16673
16801
  return projectConfig ?? (await requireInit()).localConfig;
@@ -16832,7 +16960,7 @@ async function tagsRemove(resourceType, name, tags, options) {
16832
16960
  async function getTeamSkillCount(repoPath) {
16833
16961
  try {
16834
16962
  const { listDirs: listDirs2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
16835
- const skillsDir = path54.join(repoPath, "skills");
16963
+ const skillsDir = path55.join(repoPath, "skills");
16836
16964
  const dirs = await listDirs2(skillsDir);
16837
16965
  return dirs.length;
16838
16966
  } catch {
@@ -16853,7 +16981,7 @@ var uninstall_exports = {};
16853
16981
  __export(uninstall_exports, {
16854
16982
  uninstall: () => uninstall
16855
16983
  });
16856
- import path55 from "path";
16984
+ import path56 from "path";
16857
16985
  function hasToolResources(r) {
16858
16986
  return r.hookFiles.length > 0 || r.openclawHookDirs.length > 0 || r.claudeMdFiles.length > 0 || r.skillDirs.length > 0 || r.ruleFiles.length > 0 || r.agentFiles.length > 0;
16859
16987
  }
@@ -16862,18 +16990,18 @@ function detectShellProfile() {
16862
16990
  if (!home) return null;
16863
16991
  const shell = process.env.SHELL ?? "";
16864
16992
  if (shell.includes("zsh")) {
16865
- return path55.join(home, ".zshrc");
16993
+ return path56.join(home, ".zshrc");
16866
16994
  }
16867
- return path55.join(home, ".bashrc");
16995
+ return path56.join(home, ".bashrc");
16868
16996
  }
16869
16997
  async function collectTeamSkillNames(repoPath) {
16870
- const teamSkillsDir = path55.join(repoPath, "skills");
16998
+ const teamSkillsDir = path56.join(repoPath, "skills");
16871
16999
  if (!await pathExists(teamSkillsDir)) return /* @__PURE__ */ new Set();
16872
17000
  const names = /* @__PURE__ */ new Set();
16873
17001
  const topDirs = await listDirs(teamSkillsDir);
16874
17002
  for (const dir of topDirs) {
16875
- const dirPath = path55.join(teamSkillsDir, dir);
16876
- const hasSkillMd = await pathExists(path55.join(dirPath, "SKILL.md"));
17003
+ const dirPath = path56.join(teamSkillsDir, dir);
17004
+ const hasSkillMd = await pathExists(path56.join(dirPath, "SKILL.md"));
16877
17005
  if (hasSkillMd) {
16878
17006
  names.add(dir);
16879
17007
  } else {
@@ -16886,7 +17014,7 @@ async function collectTeamSkillNames(repoPath) {
16886
17014
  return names;
16887
17015
  }
16888
17016
  async function collectTeamRuleNames(repoPath) {
16889
- const teamRulesDir = path55.join(repoPath, "rules");
17017
+ const teamRulesDir = path56.join(repoPath, "rules");
16890
17018
  if (!await pathExists(teamRulesDir)) return /* @__PURE__ */ new Set();
16891
17019
  const files = await listFilesRecursive(teamRulesDir);
16892
17020
  return new Set(
@@ -16908,52 +17036,52 @@ async function discoverToolResources(tool, toolPath, baseDir, teamSkillNames, te
16908
17036
  agentFiles: []
16909
17037
  };
16910
17038
  if (toolPath.settings) {
16911
- const settingsPath = path55.join(baseDir, toolPath.settings);
17039
+ const settingsPath = path56.join(baseDir, toolPath.settings);
16912
17040
  if (await pathExists(settingsPath) && (await hasTeamaiHooks(settingsPath, tool, managedHooksPath) || isEmptyHooksResidue(await readJson(settingsPath)))) {
16913
17041
  res.hookFiles.push({ path: settingsPath, tool });
16914
17042
  }
16915
17043
  } else {
16916
- const hooksDir = path55.join(baseDir, `.${tool}`, "hooks");
16917
- if (await pathExists(path55.join(hooksDir, OPENCLAW_HOOK_DIR))) {
17044
+ const hooksDir = path56.join(baseDir, `.${tool}`, "hooks");
17045
+ if (await pathExists(path56.join(hooksDir, OPENCLAW_HOOK_DIR))) {
16918
17046
  res.openclawHookDirs.push({ hooksDir, tool });
16919
17047
  }
16920
17048
  }
16921
17049
  if (toolPath.claudemd) {
16922
- const claudeMdPath = path55.join(baseDir, toolPath.claudemd);
17050
+ const claudeMdPath = path56.join(baseDir, toolPath.claudemd);
16923
17051
  const content = await readFileSafe(claudeMdPath);
16924
17052
  if (content && CLAUDEMD_MARKER_PAIRS.some(([start]) => content.includes(start))) {
16925
17053
  res.claudeMdFiles.push(claudeMdPath);
16926
17054
  }
16927
17055
  }
16928
17056
  if (toolPath.skills) {
16929
- const skillsDir = path55.join(baseDir, toolPath.skills);
17057
+ const skillsDir = path56.join(baseDir, toolPath.skills);
16930
17058
  if (await pathExists(skillsDir)) {
16931
17059
  const dirs = await listDirs(skillsDir);
16932
17060
  for (const dir of dirs) {
16933
17061
  if (teamSkillNames.has(dir)) {
16934
- res.skillDirs.push(path55.join(skillsDir, dir));
17062
+ res.skillDirs.push(path56.join(skillsDir, dir));
16935
17063
  }
16936
17064
  }
16937
17065
  }
16938
17066
  }
16939
17067
  if (toolPath.rules) {
16940
- const rulesDir = path55.join(baseDir, toolPath.rules);
17068
+ const rulesDir = path56.join(baseDir, toolPath.rules);
16941
17069
  if (await pathExists(rulesDir)) {
16942
17070
  const files = await listFilesRecursive(rulesDir);
16943
17071
  for (const file of files) {
16944
17072
  if (!file.endsWith(".md")) continue;
16945
17073
  const ruleName = file.replace(/\.md$/, "");
16946
17074
  if (teamRuleNames.has(ruleName)) {
16947
- res.ruleFiles.push(path55.join(rulesDir, file));
17075
+ res.ruleFiles.push(path56.join(rulesDir, file));
16948
17076
  }
16949
17077
  }
16950
17078
  }
16951
17079
  }
16952
17080
  if (toolPath.agents) {
16953
- const agentsDir = path55.join(baseDir, toolPath.agents);
17081
+ const agentsDir = path56.join(baseDir, toolPath.agents);
16954
17082
  if (await pathExists(agentsDir)) {
16955
17083
  for (const name of BUILTIN_AGENT_NAMES) {
16956
- const agentFile = path55.join(agentsDir, `${name}.md`);
17084
+ const agentFile = path56.join(agentsDir, `${name}.md`);
16957
17085
  if (await pathExists(agentFile)) {
16958
17086
  res.agentFiles.push(agentFile);
16959
17087
  }
@@ -16970,7 +17098,7 @@ async function buildRemovalPlan(localConfig, teamConfig, agentFilter) {
16970
17098
  for (const name of BUILTIN_SKILL_NAMES) teamSkillNames.add(name);
16971
17099
  const teamRuleNames = await collectTeamRuleNames(repoPath);
16972
17100
  for (const name of BUILTIN_RULE_NAMES) teamRuleNames.add(name);
16973
- const localAgentManifestPath = path55.join(
17101
+ const localAgentManifestPath = path56.join(
16974
17102
  process.env.HOME ?? "",
16975
17103
  ".teamai",
16976
17104
  "local-agent",
@@ -17057,7 +17185,7 @@ async function buildRemovalPlan(localConfig, teamConfig, agentFilter) {
17057
17185
  const docsLocalDir = teamConfig.sharing.docs.localDir;
17058
17186
  let docsDir;
17059
17187
  if (localConfig.scope === "project" && localConfig.projectRoot) {
17060
- docsDir = docsLocalDir.startsWith("~/") ? path55.join(localConfig.projectRoot, docsLocalDir.substring(2)) : expandHome(docsLocalDir);
17188
+ docsDir = docsLocalDir.startsWith("~/") ? path56.join(localConfig.projectRoot, docsLocalDir.substring(2)) : expandHome(docsLocalDir);
17061
17189
  } else {
17062
17190
  docsDir = expandHome(docsLocalDir);
17063
17191
  }
@@ -17090,7 +17218,7 @@ function printSummary(plan, agentFilter) {
17090
17218
  if (plan.openclawHookDirs.length > 0) {
17091
17219
  console.log(` OpenClaw Hooks (${plan.openclawHookDirs.length} \u4E2A\u76EE\u5F55):`);
17092
17220
  for (const { hooksDir } of plan.openclawHookDirs) {
17093
- console.log(` ${path55.join(hooksDir, OPENCLAW_HOOK_DIR)}/`);
17221
+ console.log(` ${path56.join(hooksDir, OPENCLAW_HOOK_DIR)}/`);
17094
17222
  }
17095
17223
  console.log("");
17096
17224
  }
@@ -17338,7 +17466,7 @@ async function uninstall(opts) {
17338
17466
  log.error("\u65E0\u6CD5\u786E\u5B9A\u7528\u6237\u4E3B\u76EE\u5F55\uFF08HOME \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E\uFF09");
17339
17467
  return;
17340
17468
  }
17341
- const home = path55.join(homeDir, ".teamai");
17469
+ const home = path56.join(homeDir, ".teamai");
17342
17470
  if (!await pathExists(home)) {
17343
17471
  log.info("\u6CA1\u6709\u9700\u8981\u5378\u8F7D\u7684\u5185\u5BB9");
17344
17472
  return;
@@ -17399,11 +17527,11 @@ __export(env_commands_exports, {
17399
17527
  envList: () => envList,
17400
17528
  envRemove: () => envRemove
17401
17529
  });
17402
- import path56 from "path";
17530
+ import path57 from "path";
17403
17531
  async function envList(options) {
17404
17532
  const projectConfig = await detectProjectConfig();
17405
17533
  const localConfig = projectConfig ?? (await requireInit()).localConfig;
17406
- const envYamlPath = path56.join(localConfig.repo.localPath, "env", "env.yaml");
17534
+ const envYamlPath = path57.join(localConfig.repo.localPath, "env", "env.yaml");
17407
17535
  if (!await pathExists(envYamlPath)) {
17408
17536
  log.info("No env variables defined (env/env.yaml not found)");
17409
17537
  return;
@@ -17432,7 +17560,7 @@ async function envAdd(key, value, options) {
17432
17560
  const projectConfig = await detectProjectConfig();
17433
17561
  const localConfig = projectConfig ?? (await requireInit()).localConfig;
17434
17562
  const repoPath = localConfig.repo.localPath;
17435
- const envYamlPath = path56.join(repoPath, "env", "env.yaml");
17563
+ const envYamlPath = path57.join(repoPath, "env", "env.yaml");
17436
17564
  const pullSpin = spinner("Pulling latest...").start();
17437
17565
  try {
17438
17566
  await pullRepo(repoPath);
@@ -17459,7 +17587,7 @@ async function envAdd(key, value, options) {
17459
17587
  log.info(`[dry-run] Would ${isUpdate ? "update" : "add"} env variable: ${key}=${value}`);
17460
17588
  return;
17461
17589
  }
17462
- await ensureDir(path56.join(repoPath, "env"));
17590
+ await ensureDir(path57.join(repoPath, "env"));
17463
17591
  await envHandler.writeEnvYaml(envYamlPath, envConfig);
17464
17592
  const action = isUpdate ? "Updated" : "Added";
17465
17593
  log.success(`${action} env variable: ${key}=${value}`);
@@ -17469,7 +17597,7 @@ async function envRemove(key, options) {
17469
17597
  const projectConfig = await detectProjectConfig();
17470
17598
  const localConfig = projectConfig ?? (await requireInit()).localConfig;
17471
17599
  const repoPath = localConfig.repo.localPath;
17472
- const envYamlPath = path56.join(repoPath, "env", "env.yaml");
17600
+ const envYamlPath = path57.join(repoPath, "env", "env.yaml");
17473
17601
  const pullSpin = spinner("Pulling latest...").start();
17474
17602
  try {
17475
17603
  await pullRepo(repoPath);
@@ -17516,7 +17644,7 @@ __export(hooks_cmd_exports, {
17516
17644
  hooksList: () => hooksList,
17517
17645
  hooksRemove: () => hooksRemove
17518
17646
  });
17519
- import path57 from "path";
17647
+ import path58 from "path";
17520
17648
  function resolveHookScopeTargets(localConfig) {
17521
17649
  if (localConfig.scope !== "project") {
17522
17650
  return [{
@@ -17533,7 +17661,7 @@ function formatDisplayPath(settingsPath) {
17533
17661
  const home = process.env.HOME;
17534
17662
  if (!home) return settingsPath;
17535
17663
  if (settingsPath === home) return "~";
17536
- if (settingsPath.startsWith(home + path57.sep) || settingsPath.startsWith(home + "/")) {
17664
+ if (settingsPath.startsWith(home + path58.sep) || settingsPath.startsWith(home + "/")) {
17537
17665
  return `~${settingsPath.slice(home.length)}`;
17538
17666
  }
17539
17667
  return settingsPath;
@@ -17575,7 +17703,7 @@ async function hooksList(_options) {
17575
17703
  continue;
17576
17704
  }
17577
17705
  for (const baseDir of baseDirs) {
17578
- const settingsPath = path57.join(baseDir, paths.settings);
17706
+ const settingsPath = path58.join(baseDir, paths.settings);
17579
17707
  rows.push({
17580
17708
  tool,
17581
17709
  status: await getHookStatus(settingsPath, tool),
@@ -17634,10 +17762,10 @@ __export(mcp_cmd_exports, {
17634
17762
  mcpList: () => mcpList,
17635
17763
  mcpRemove: () => mcpRemove
17636
17764
  });
17637
- import path58 from "path";
17765
+ import path59 from "path";
17638
17766
  function displayPath(p) {
17639
17767
  const home = process.env.HOME;
17640
- if (home && (p === home || p.startsWith(home + path58.sep))) return `~${p.slice(home.length)}`;
17768
+ if (home && (p === home || p.startsWith(home + path59.sep))) return `~${p.slice(home.length)}`;
17641
17769
  return p;
17642
17770
  }
17643
17771
  async function mcpList(_options) {
@@ -17717,7 +17845,7 @@ var init_mcp_cmd = __esm({
17717
17845
 
17718
17846
  // src/session-collector.ts
17719
17847
  import fs17 from "fs";
17720
- import path59 from "path";
17848
+ import path60 from "path";
17721
17849
  function isValuable(summary) {
17722
17850
  return summary.interventionCount > 0 || summary.distinctTools >= SUBSTANTIAL_TOOL_COUNT;
17723
17851
  }
@@ -17797,7 +17925,7 @@ function monthKey(summary) {
17797
17925
  async function appendMonthlyLog(dir, summary, options = {}) {
17798
17926
  await ensureDir(dir);
17799
17927
  const month = monthKey(summary);
17800
- const file = path59.join(dir, `${month}.md`);
17928
+ const file = path60.join(dir, `${month}.md`);
17801
17929
  const block = renderSessionMarkdown(summary, options);
17802
17930
  const marker = `<!-- teamai:session ${summary.sessionId} -->`;
17803
17931
  let existing = "";
@@ -17827,7 +17955,7 @@ async function pruneMonthlyLogs(dir, now, retentionDays = 90) {
17827
17955
  const monthEnd = new Date(Date.UTC(Number(m[1]), Number(m[2]), 0, 23, 59, 59));
17828
17956
  if (monthEnd.getTime() < cutoff) {
17829
17957
  try {
17830
- await fs17.promises.unlink(path59.join(dir, entry));
17958
+ await fs17.promises.unlink(path60.join(dir, entry));
17831
17959
  removed.push(entry);
17832
17960
  } catch {
17833
17961
  }
@@ -17853,7 +17981,7 @@ var save_session_exports = {};
17853
17981
  __export(save_session_exports, {
17854
17982
  saveSession: () => saveSession
17855
17983
  });
17856
- import path60 from "path";
17984
+ import path61 from "path";
17857
17985
  function mostRecentSessionId(events) {
17858
17986
  let best;
17859
17987
  for (const e of events) {
@@ -17933,13 +18061,13 @@ async function saveSession(options) {
17933
18061
  try {
17934
18062
  const { ensureReportsWorktree: ensureReportsWorktree2, commitAndPushReports: commitAndPushReports2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
17935
18063
  const wt = await ensureReportsWorktree2(localConfig);
17936
- const teamDir2 = path60.join(wt, "sessions", username);
18064
+ const teamDir2 = path61.join(wt, "sessions", username);
17937
18065
  const written = await appendMonthlyLog(teamDir2, summary, { includePrompt: options.includePrompt });
17938
18066
  if (!written) {
17939
18067
  spin2.info("Session already present in the team log \u2014 nothing to push.");
17940
18068
  return;
17941
18069
  }
17942
- const rel = path60.relative(wt, written);
18070
+ const rel = path61.relative(wt, written);
17943
18071
  const pushed = await withTimeout(
17944
18072
  commitAndPushReports2(localConfig, commitMsg, [rel]),
17945
18073
  1e4,
@@ -17954,7 +18082,7 @@ async function saveSession(options) {
17954
18082
  return;
17955
18083
  }
17956
18084
  const repoPath = localConfig.repo.localPath;
17957
- const teamDir = path60.join(repoPath, "sessions", username);
18085
+ const teamDir = path61.join(repoPath, "sessions", username);
17958
18086
  const spin = spinner("Pushing session summary to team...").start();
17959
18087
  try {
17960
18088
  try {
@@ -17967,7 +18095,7 @@ async function saveSession(options) {
17967
18095
  spin.info("Session already present in the team log \u2014 nothing to push.");
17968
18096
  return;
17969
18097
  }
17970
- const rel = path60.relative(repoPath, written);
18098
+ const rel = path61.relative(repoPath, written);
17971
18099
  await withTimeout(pushRepoDirectly(repoPath, commitMsg, [rel]), 1e4, "Push timeout (10s)");
17972
18100
  spin.succeed(`Pushed: ${rel}`);
17973
18101
  } catch (e) {
@@ -18737,11 +18865,11 @@ __export(dashboard_exports, {
18737
18865
  });
18738
18866
  import http from "http";
18739
18867
  import fs18 from "fs";
18740
- import path61 from "path";
18868
+ import path62 from "path";
18741
18869
  async function startDashboard(port) {
18742
18870
  const serverPort = port ?? DASHBOARD_DEFAULT_PORT;
18743
- const eventsPath = path61.join(process.env.HOME ?? "", ".teamai", "dashboard", "events.jsonl");
18744
- await ensureDir(path61.dirname(eventsPath));
18871
+ const eventsPath = path62.join(process.env.HOME ?? "", ".teamai", "dashboard", "events.jsonl");
18872
+ await ensureDir(path62.dirname(eventsPath));
18745
18873
  try {
18746
18874
  await fs18.promises.access(eventsPath);
18747
18875
  } catch {
@@ -18943,14 +19071,14 @@ var init_hook_dispatch = __esm({
18943
19071
  });
18944
19072
 
18945
19073
  // src/recall-quality.ts
18946
- import path62 from "path";
19074
+ import path63 from "path";
18947
19075
  import fs19 from "fs";
18948
19076
  function sanitizeSessionId(sessionId) {
18949
19077
  return sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
18950
19078
  }
18951
19079
  function getCachePath(sessionId) {
18952
19080
  const safeName = sanitizeSessionId(sessionId);
18953
- return path62.join(
19081
+ return path63.join(
18954
19082
  process.env.HOME ?? "",
18955
19083
  ".teamai",
18956
19084
  "sessions",
@@ -18981,7 +19109,7 @@ function readCache(sessionId) {
18981
19109
  function writeCache(sessionId, cache) {
18982
19110
  try {
18983
19111
  const cachePath = getCachePath(sessionId);
18984
- const dir = path62.dirname(cachePath);
19112
+ const dir = path63.dirname(cachePath);
18985
19113
  if (!fs19.existsSync(dir)) {
18986
19114
  fs19.mkdirSync(dir, { recursive: true });
18987
19115
  }
@@ -19067,7 +19195,7 @@ __export(contribute_check_exports, {
19067
19195
  writeContributeState: () => writeContributeState
19068
19196
  });
19069
19197
  import fs20 from "fs";
19070
- import path63 from "path";
19198
+ import path64 from "path";
19071
19199
  import { execFileSync as execFileSync2 } from "child_process";
19072
19200
  function sanitizeSessionId2(sessionId) {
19073
19201
  return sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -19093,7 +19221,7 @@ function normalizePromptSummary(raw) {
19093
19221
  return `${truncated}\u2026`;
19094
19222
  }
19095
19223
  function getSessionPath(sessionId) {
19096
- return path63.join(
19224
+ return path64.join(
19097
19225
  process.env.HOME ?? "",
19098
19226
  ".teamai",
19099
19227
  "sessions",
@@ -19131,14 +19259,14 @@ async function readContributeState(sessionId) {
19131
19259
  async function writeContributeState(sessionId, state) {
19132
19260
  try {
19133
19261
  const filePath = getSessionPath(sessionId);
19134
- await ensureDir(path63.dirname(filePath));
19262
+ await ensureDir(path64.dirname(filePath));
19135
19263
  const persistedState = {
19136
19264
  ...state,
19137
19265
  friction: parseSessionFriction(state.friction),
19138
19266
  promptSummary: normalizePromptSummary(state.promptSummary)
19139
19267
  };
19140
19268
  await writeJson(filePath, persistedState);
19141
- await cleanupStaleSessions(path63.dirname(filePath), sessionId);
19269
+ await cleanupStaleSessions(path64.dirname(filePath), sessionId);
19142
19270
  } catch (e) {
19143
19271
  log.error(`Failed to write contribute state: ${e.message}`);
19144
19272
  }
@@ -19151,7 +19279,7 @@ async function cleanupStaleSessions(dir, currentSessionId) {
19151
19279
  if (!entry.endsWith(".json")) continue;
19152
19280
  const name = entry.replace(".json", "");
19153
19281
  if (name === currentBasename) continue;
19154
- const filePath = path63.join(dir, entry);
19282
+ const filePath = path64.join(dir, entry);
19155
19283
  try {
19156
19284
  const stat6 = await fs20.promises.stat(filePath);
19157
19285
  if (now - stat6.mtimeMs > STALE_SESSION_MS) {
@@ -19443,7 +19571,7 @@ __export(transcript_parser_exports, {
19443
19571
  parseTranscriptForVotes: () => parseTranscriptForVotes
19444
19572
  });
19445
19573
  import fs21 from "fs";
19446
- import path64 from "path";
19574
+ import path65 from "path";
19447
19575
  import readline4 from "readline";
19448
19576
  async function parseTranscriptForVotes(transcriptPath) {
19449
19577
  const recalledSet = /* @__PURE__ */ new Set();
@@ -19513,7 +19641,7 @@ function extractRecalledDocIds(text, out) {
19513
19641
  let match;
19514
19642
  while ((match = filePattern.exec(region)) !== null) {
19515
19643
  const filePath = match[1].trim();
19516
- const docId = path64.basename(filePath).replace(/\.md$/i, "");
19644
+ const docId = path65.basename(filePath).replace(/\.md$/i, "");
19517
19645
  if (isValidDocId(docId)) out.add(docId);
19518
19646
  }
19519
19647
  searchFrom = endIdx + END.length;
@@ -19545,10 +19673,10 @@ __export(todowrite_hint_exports, {
19545
19673
  shouldSkipTodoWriteHint: () => shouldSkipTodoWriteHint,
19546
19674
  todoWriteHint: () => todoWriteHint
19547
19675
  });
19548
- import path65 from "path";
19676
+ import path66 from "path";
19549
19677
  import fs22 from "fs";
19550
19678
  function getTodoWriteHintCachePath(sessionId) {
19551
- return path65.join(
19679
+ return path66.join(
19552
19680
  process.env.HOME ?? "",
19553
19681
  ".teamai",
19554
19682
  "sessions",
@@ -19571,7 +19699,7 @@ function readCache2(sessionId) {
19571
19699
  function writeCache2(sessionId, cache) {
19572
19700
  try {
19573
19701
  const cachePath = getTodoWriteHintCachePath(sessionId);
19574
- const dir = path65.dirname(cachePath);
19702
+ const dir = path66.dirname(cachePath);
19575
19703
  if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
19576
19704
  fs22.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
19577
19705
  } catch {
@@ -19653,12 +19781,12 @@ __export(mr_hint_exports, {
19653
19781
  });
19654
19782
  import { spawnSync as spawnSync4 } from "child_process";
19655
19783
  import fs23 from "fs";
19656
- import path66 from "path";
19784
+ import path67 from "path";
19657
19785
  function repoSlug(owner, repo) {
19658
19786
  return `${owner}/${repo}`.replace(/[^a-zA-Z0-9_-]/g, "_");
19659
19787
  }
19660
19788
  function getCachePath2(owner, repo) {
19661
- return path66.join(
19789
+ return path67.join(
19662
19790
  process.env.HOME ?? "",
19663
19791
  ".teamai",
19664
19792
  "sessions",
@@ -19681,7 +19809,7 @@ function loadCache(owner, repo) {
19681
19809
  function saveCache(owner, repo, cache) {
19682
19810
  try {
19683
19811
  const cachePath = getCachePath2(owner, repo);
19684
- const dir = path66.dirname(cachePath);
19812
+ const dir = path67.dirname(cachePath);
19685
19813
  if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
19686
19814
  fs23.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
19687
19815
  } catch {
@@ -19828,7 +19956,7 @@ function buildHintMessage2(mrs) {
19828
19956
  async function computeMrHintOutput() {
19829
19957
  if (process.env.TEAMAI_MR_HINT_DISABLED === "1") return null;
19830
19958
  const rawCwd = process.env.TEAMAI_MR_HINT_CWD ?? process.cwd();
19831
- const cwd = path66.resolve(rawCwd);
19959
+ const cwd = path67.resolve(rawCwd);
19832
19960
  try {
19833
19961
  if (!fs23.statSync(cwd).isDirectory()) {
19834
19962
  return null;
@@ -19896,7 +20024,7 @@ var init_mr_hint = __esm({
19896
20024
  });
19897
20025
 
19898
20026
  // src/hook-handlers.ts
19899
- import path67 from "path";
20027
+ import path68 from "path";
19900
20028
  function buildHandlerRegistry() {
19901
20029
  return [
19902
20030
  // ─── SessionStart ─────────────────────────────────
@@ -20048,7 +20176,7 @@ var init_hook_handlers = __esm({
20048
20176
  const { localConfig } = await autoDetectInit2();
20049
20177
  const { VOTES_LOCAL_DIR: VOTES_LOCAL_DIR2, TEAMAI_SESSIONS_DIR: TEAMAI_SESSIONS_DIR2 } = await Promise.resolve().then(() => (init_types(), types_exports));
20050
20178
  const votesDir = VOTES_LOCAL_DIR2;
20051
- const votePath = path67.join(votesDir, `${localConfig.username}.yaml`);
20179
+ const votePath = path68.join(votesDir, `${localConfig.username}.yaml`);
20052
20180
  if (voteData.referencedDocIds.length > 0) {
20053
20181
  await incrementUpvoted2(votePath, voteData.referencedDocIds);
20054
20182
  }
@@ -20073,7 +20201,7 @@ var init_hook_handlers = __esm({
20073
20201
  if (recalled.length > 0 && declared.length === 0) {
20074
20202
  const fsp = await import("fs/promises");
20075
20203
  const safeId = sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
20076
- const marker = path67.join(TEAMAI_SESSIONS_DIR2, `${safeId}-adoption-nudged`);
20204
+ const marker = path68.join(TEAMAI_SESSIONS_DIR2, `${safeId}-adoption-nudged`);
20077
20205
  let already = false;
20078
20206
  try {
20079
20207
  await fsp.access(marker);
@@ -20277,21 +20405,21 @@ __export(contribute_exports, {
20277
20405
  contribute: () => contribute
20278
20406
  });
20279
20407
  import fs24 from "fs";
20280
- import path68 from "path";
20408
+ import path69 from "path";
20281
20409
  import fse11 from "fs-extra";
20282
20410
  async function rebuildIndexAfterContribute(localConfig) {
20283
20411
  const repoPath = localConfig.repo.localPath;
20284
- const learningsRepoDir = path68.join(repoPath, "learnings");
20285
- const docsRepoDir = path68.join(repoPath, "docs");
20286
- const rulesRepoDir = path68.join(repoPath, "rules");
20287
- const skillsRepoDir = path68.join(repoPath, "skills");
20288
- const votesDir = path68.join(repoPath, "votes");
20412
+ const learningsRepoDir = path69.join(repoPath, "learnings");
20413
+ const docsRepoDir = path69.join(repoPath, "docs");
20414
+ const rulesRepoDir = path69.join(repoPath, "rules");
20415
+ const skillsRepoDir = path69.join(repoPath, "skills");
20416
+ const votesDir = path69.join(repoPath, "votes");
20289
20417
  let effectiveLearningsDir;
20290
20418
  if (localConfig.scope === "user") {
20291
20419
  if (await pathExists(learningsRepoDir)) {
20292
20420
  await fse11.copy(learningsRepoDir, LEARNINGS_LOCAL_DIR, {
20293
20421
  overwrite: true,
20294
- filter: (src) => !path68.basename(src).startsWith(".")
20422
+ filter: (src) => !path69.basename(src).startsWith(".")
20295
20423
  });
20296
20424
  }
20297
20425
  effectiveLearningsDir = await pathExists(LEARNINGS_LOCAL_DIR) ? LEARNINGS_LOCAL_DIR : void 0;
@@ -20299,7 +20427,7 @@ async function rebuildIndexAfterContribute(localConfig) {
20299
20427
  effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
20300
20428
  }
20301
20429
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
20302
- const indexPath = path68.join(teamaiHome, "search-index.json");
20430
+ const indexPath = path69.join(teamaiHome, "search-index.json");
20303
20431
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
20304
20432
  await buildIndex2({
20305
20433
  learningsDir: effectiveLearningsDir,
@@ -20362,9 +20490,9 @@ async function contribute(options) {
20362
20490
  const pushSpin = spinner("Contributing session knowledge...").start();
20363
20491
  const filename = generateFilename(options.title);
20364
20492
  try {
20365
- const aiDocsDir = path68.join(repoPath, "learnings");
20493
+ const aiDocsDir = path69.join(repoPath, "learnings");
20366
20494
  await ensureDir(aiDocsDir);
20367
- const destPath = path68.join(aiDocsDir, filename);
20495
+ const destPath = path69.join(aiDocsDir, filename);
20368
20496
  await fs24.promises.writeFile(destPath, content, "utf-8");
20369
20497
  try {
20370
20498
  await pullRepo(repoPath);
@@ -20414,19 +20542,19 @@ async function contributeSelf(localConfig, content, options) {
20414
20542
  const teamConfig = await loadTeamConfig(localConfig.repo.localPath);
20415
20543
  await withKnowledgeWorktree2(localConfig, async (wtConfig) => {
20416
20544
  const wtRepo = wtConfig.repo.localPath;
20417
- await ensureDir(path68.join(wtRepo, "learnings"));
20418
- await fs24.promises.writeFile(path68.join(wtRepo, relPath), content, "utf-8");
20545
+ await ensureDir(path69.join(wtRepo, "learnings"));
20546
+ await fs24.promises.writeFile(path69.join(wtRepo, relPath), content, "utf-8");
20419
20547
  try {
20420
- const wtLearnings = path68.join(wtRepo, "learnings");
20548
+ const wtLearnings = path69.join(wtRepo, "learnings");
20421
20549
  await fse11.copy(wtLearnings, LEARNINGS_LOCAL_DIR, {
20422
20550
  overwrite: true,
20423
- filter: (src) => !path68.basename(src).startsWith(".")
20551
+ filter: (src) => !path69.basename(src).startsWith(".")
20424
20552
  });
20425
20553
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
20426
20554
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
20427
20555
  await buildIndex2({
20428
20556
  learningsDir: LEARNINGS_LOCAL_DIR,
20429
- indexPath: path68.join(teamaiHome, "search-index.json")
20557
+ indexPath: path69.join(teamaiHome, "search-index.json")
20430
20558
  });
20431
20559
  } catch (e) {
20432
20560
  log.debug(`contribute(self): local index refresh skipped: ${e.message}`);
@@ -20472,7 +20600,7 @@ var init_contribute = __esm({
20472
20600
  });
20473
20601
 
20474
20602
  // src/wiki-engine/core/wiki-protocol.ts
20475
- import path69 from "path";
20603
+ import path70 from "path";
20476
20604
  function safeIgnore(filePath) {
20477
20605
  const normalized = toPosix(filePath);
20478
20606
  const parts = normalized.split("/").filter(Boolean);
@@ -20486,7 +20614,7 @@ function safeIgnore(filePath) {
20486
20614
  return /\.(pem|key|p12|pfx)$/i.test(base);
20487
20615
  }
20488
20616
  function toPosix(value) {
20489
- return value.split(path69.sep).join("/");
20617
+ return value.split(path70.sep).join("/");
20490
20618
  }
20491
20619
  var CONFIDENCE_SCORE_DEFAULTS, SAFE_IGNORE_SEGMENTS, SENSITIVE_FILE_NAMES;
20492
20620
  var init_wiki_protocol = __esm({
@@ -20533,7 +20661,7 @@ __export(graph_index_schema_exports, {
20533
20661
  validateGraph: () => validateGraph
20534
20662
  });
20535
20663
  import { readFile as readFile2, writeFile as writeFile4, mkdir } from "fs/promises";
20536
- import path70 from "path";
20664
+ import path71 from "path";
20537
20665
  function toPageSlug(relativePath) {
20538
20666
  return relativePath.replace(/\.md$/u, "").replace(/\\/g, "/");
20539
20667
  }
@@ -20704,7 +20832,7 @@ function computeGraphHealth(graph) {
20704
20832
  };
20705
20833
  }
20706
20834
  async function loadGraphIndex(wikiRoot) {
20707
- const graphPath = path70.join(wikiRoot, ".indices", "graph-index.json");
20835
+ const graphPath = path71.join(wikiRoot, ".indices", "graph-index.json");
20708
20836
  try {
20709
20837
  const raw = await readFile2(graphPath, "utf8");
20710
20838
  const parsed = JSON.parse(raw);
@@ -20717,9 +20845,9 @@ async function loadGraphIndex(wikiRoot) {
20717
20845
  }
20718
20846
  }
20719
20847
  async function saveGraphIndex(wikiRoot, graph) {
20720
- const dir = path70.join(wikiRoot, ".indices");
20848
+ const dir = path71.join(wikiRoot, ".indices");
20721
20849
  await mkdir(dir, { recursive: true });
20722
- const outPath = path70.join(dir, "graph-index.json");
20850
+ const outPath = path71.join(dir, "graph-index.json");
20723
20851
  await writeFile4(outPath, JSON.stringify(graph, null, 2), "utf8");
20724
20852
  return outPath;
20725
20853
  }
@@ -20772,7 +20900,7 @@ var init_graph_index_schema = __esm({
20772
20900
 
20773
20901
  // src/code-knowledge-recall.ts
20774
20902
  import { readFile as readFile3, readdir } from "fs/promises";
20775
- import path71 from "path";
20903
+ import path72 from "path";
20776
20904
  import matter5 from "gray-matter";
20777
20905
  function countOccurrences(text, token) {
20778
20906
  let count = 0;
@@ -20907,7 +21035,7 @@ function extractSnippet(content, queryTokens, maxLen = 300) {
20907
21035
  async function loadWikiPages(wikiRoot, depth) {
20908
21036
  const pages = [];
20909
21037
  if (depth === "route") {
20910
- const routerPath = path71.join(wikiRoot, "router.md");
21038
+ const routerPath = path72.join(wikiRoot, "router.md");
20911
21039
  try {
20912
21040
  const content = await readFile3(routerPath, "utf-8");
20913
21041
  const titleMatch = content.match(/^title:\s*(.+)$/m);
@@ -20923,7 +21051,7 @@ async function loadWikiPages(wikiRoot, depth) {
20923
21051
  }
20924
21052
  return pages;
20925
21053
  }
20926
- const evidenceDir = path71.join(wikiRoot, "evidence", "code");
21054
+ const evidenceDir = path72.join(wikiRoot, "evidence", "code");
20927
21055
  let projectDirs;
20928
21056
  try {
20929
21057
  const entries = await readdir(evidenceDir, { withFileTypes: true });
@@ -20932,7 +21060,7 @@ async function loadWikiPages(wikiRoot, depth) {
20932
21060
  return pages;
20933
21061
  }
20934
21062
  for (const project of projectDirs) {
20935
- const projectDir = path71.join(evidenceDir, project);
21063
+ const projectDir = path72.join(evidenceDir, project);
20936
21064
  await loadPagesRecursive(projectDir, `evidence/code/${project}`, pages, depth);
20937
21065
  }
20938
21066
  return pages;
@@ -21003,7 +21131,7 @@ async function loadPagesRecursive(dir, relativePath, pages, depth, currentDepth
21003
21131
  if (currentDepth >= MAX_RECURSION_DEPTH) return;
21004
21132
  const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
21005
21133
  for (const entry of entries) {
21006
- const fullPath = path71.join(dir, entry.name);
21134
+ const fullPath = path72.join(dir, entry.name);
21007
21135
  if (entry.isDirectory()) {
21008
21136
  await loadPagesRecursive(
21009
21137
  fullPath,
@@ -21178,7 +21306,7 @@ __export(recall_exports, {
21178
21306
  isRelevantScore: () => isRelevantScore,
21179
21307
  recall: () => recall
21180
21308
  });
21181
- import path72 from "path";
21309
+ import path73 from "path";
21182
21310
  function isRelevantScore(score, isCodebaseHit, idfBaseline) {
21183
21311
  if (isCodebaseHit) return score >= CODEBASE_RELEVANCE_THRESHOLD;
21184
21312
  const baseline = idfBaseline > 0 ? idfBaseline : 1;
@@ -21249,7 +21377,7 @@ async function autoUpvote(results, username, _repoPath) {
21249
21377
  try {
21250
21378
  const { incrementRecalled: incrementRecalled2 } = await Promise.resolve().then(() => (init_votes(), votes_exports));
21251
21379
  const votesDir = getVotesLocalDir();
21252
- const localVotePath = path72.join(votesDir, `${username}.yaml`);
21380
+ const localVotePath = path73.join(votesDir, `${username}.yaml`);
21253
21381
  await ensureDir(votesDir);
21254
21382
  const docIds = results.map((r) => r.entry.filename.replace(/\.md$/i, ""));
21255
21383
  await incrementRecalled2(localVotePath, docIds);
@@ -21260,9 +21388,9 @@ async function autoUpvote(results, username, _repoPath) {
21260
21388
  }
21261
21389
  async function loadOrBuildScopeIndex(localConfig, scopeLabel) {
21262
21390
  const teamaiHome = localConfig.scope === "project" && localConfig.projectRoot ? getTeamaiHome("project", localConfig.projectRoot) : getTeamaiHome("user");
21263
- const indexPath = path72.join(teamaiHome, "search-index.json");
21264
- const localLearningsDir = path72.join(teamaiHome, "learnings");
21265
- const repoLearningsDir = path72.join(localConfig.repo.localPath, "learnings");
21391
+ const indexPath = path73.join(teamaiHome, "search-index.json");
21392
+ const localLearningsDir = path73.join(teamaiHome, "learnings");
21393
+ const repoLearningsDir = path73.join(localConfig.repo.localPath, "learnings");
21266
21394
  let effectiveLearningsDir = null;
21267
21395
  if (scopeLabel === "user" && await pathExists(localLearningsDir)) {
21268
21396
  effectiveLearningsDir = localLearningsDir;
@@ -21271,14 +21399,14 @@ async function loadOrBuildScopeIndex(localConfig, scopeLabel) {
21271
21399
  }
21272
21400
  let index = await loadIndex(indexPath);
21273
21401
  const needsRebuild = !index || isLegacyIndex(index);
21274
- if (needsRebuild && (effectiveLearningsDir || await pathExists(path72.join(localConfig.repo.localPath, "docs")) || await pathExists(path72.join(localConfig.repo.localPath, "rules")) || await pathExists(path72.join(localConfig.repo.localPath, "skills")))) {
21402
+ if (needsRebuild && (effectiveLearningsDir || await pathExists(path73.join(localConfig.repo.localPath, "docs")) || await pathExists(path73.join(localConfig.repo.localPath, "rules")) || await pathExists(path73.join(localConfig.repo.localPath, "skills")))) {
21275
21403
  const { getReportsDir: getReportsDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
21276
- const votesDir = path72.join(getReportsDir2(localConfig), "votes");
21404
+ const votesDir = path73.join(getReportsDir2(localConfig), "votes");
21277
21405
  const votesExist = await pathExists(votesDir);
21278
- const docsDir = path72.join(localConfig.repo.localPath, "docs");
21279
- const rulesDir = path72.join(localConfig.repo.localPath, "rules");
21280
- const skillsDir = path72.join(localConfig.repo.localPath, "skills");
21281
- const repoCodebaseDir = path72.join(localConfig.repo.localPath, "docs", "team-codebase");
21406
+ const docsDir = path73.join(localConfig.repo.localPath, "docs");
21407
+ const rulesDir = path73.join(localConfig.repo.localPath, "rules");
21408
+ const skillsDir = path73.join(localConfig.repo.localPath, "skills");
21409
+ const repoCodebaseDir = path73.join(localConfig.repo.localPath, "docs", "team-codebase");
21282
21410
  const codebaseDir = await pathExists(repoCodebaseDir) ? repoCodebaseDir : void 0;
21283
21411
  try {
21284
21412
  await buildIndex({
@@ -21369,7 +21497,7 @@ async function recall(query, options) {
21369
21497
  }
21370
21498
  }
21371
21499
  const wikiConfig = projectConfig ?? scopeIndexes[0]?.config;
21372
- const wikiRoot = wikiConfig ? path72.join(wikiConfig.repo.localPath, "teamwiki") : path72.join(process.cwd(), ".teamai", "team-repo", "teamwiki");
21500
+ const wikiRoot = wikiConfig ? path73.join(wikiConfig.repo.localPath, "teamwiki") : path73.join(process.cwd(), ".teamai", "team-repo", "teamwiki");
21373
21501
  const hasWiki = await pathExists(wikiRoot);
21374
21502
  if (scopeIndexes.length === 0 && !hasWiki) {
21375
21503
  if (options.check) {
@@ -21410,7 +21538,7 @@ async function recall(query, options) {
21410
21538
  votes: 0,
21411
21539
  type: "docs",
21412
21540
  domain: "technical",
21413
- path: path72.join(wikiRoot, cr.page),
21541
+ path: path73.join(wikiRoot, cr.page),
21414
21542
  snippet: cr.snippet
21415
21543
  },
21416
21544
  score: Math.min(10, Math.log2(cr.score + 1) * 2),
@@ -21482,19 +21610,19 @@ __export(recall_toggle_exports, {
21482
21610
  recallEnable: () => recallEnable,
21483
21611
  recallStatus: () => recallStatus
21484
21612
  });
21485
- import path73 from "path";
21613
+ import path74 from "path";
21486
21614
  async function removeRecallArtifacts(teamConfig, localConfig) {
21487
21615
  const baseDir = resolveBaseDir(localConfig);
21488
21616
  for (const [tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
21489
21617
  if (toolPath.rules) {
21490
- const ruleFile = path73.join(baseDir, toolPath.rules, "teamai-recall.md");
21618
+ const ruleFile = path74.join(baseDir, toolPath.rules, "teamai-recall.md");
21491
21619
  if (await pathExists(ruleFile)) {
21492
21620
  await remove(ruleFile);
21493
21621
  log.debug(`Removed recall rule from ${tool}`);
21494
21622
  }
21495
21623
  }
21496
21624
  if (toolPath.agents) {
21497
- const agentFile = path73.join(baseDir, toolPath.agents, "teamai-recall.md");
21625
+ const agentFile = path74.join(baseDir, toolPath.agents, "teamai-recall.md");
21498
21626
  if (await pathExists(agentFile)) {
21499
21627
  await remove(agentFile);
21500
21628
  log.debug(`Removed recall agent from ${tool}`);
@@ -21502,7 +21630,7 @@ async function removeRecallArtifacts(teamConfig, localConfig) {
21502
21630
  }
21503
21631
  if (toolPath.skills) {
21504
21632
  for (const skillName of RECALL_DEPENDENT_SKILLS) {
21505
- const skillDir = path73.join(baseDir, toolPath.skills, skillName);
21633
+ const skillDir = path74.join(baseDir, toolPath.skills, skillName);
21506
21634
  if (await pathExists(skillDir)) {
21507
21635
  await remove(skillDir);
21508
21636
  log.debug(`Removed recall skill ${skillName} from ${tool}`);
@@ -21510,7 +21638,7 @@ async function removeRecallArtifacts(teamConfig, localConfig) {
21510
21638
  }
21511
21639
  }
21512
21640
  if (toolPath.claudemd) {
21513
- const claudeMdPath = path73.join(baseDir, toolPath.claudemd);
21641
+ const claudeMdPath = path74.join(baseDir, toolPath.claudemd);
21514
21642
  const content = await readFileSafe(claudeMdPath);
21515
21643
  if (content && content.includes(TEAMAI_RECALL_RULES_START)) {
21516
21644
  const startIdx = content.indexOf(TEAMAI_RECALL_RULES_START);
@@ -21544,7 +21672,7 @@ async function deployRecallArtifacts(teamConfig, localConfig) {
21544
21672
  for (const [tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
21545
21673
  if (!toolPath.claudemd || !toolPath.agents) continue;
21546
21674
  if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) continue;
21547
- const claudeMdPath = path73.join(baseDir, toolPath.claudemd);
21675
+ const claudeMdPath = path74.join(baseDir, toolPath.claudemd);
21548
21676
  try {
21549
21677
  await injectClaudeMdSection2(
21550
21678
  claudeMdPath,
@@ -21596,20 +21724,20 @@ var init_recall_toggle = __esm({
21596
21724
  });
21597
21725
 
21598
21726
  // src/utils/cache-index.ts
21599
- import path74 from "path";
21727
+ import path75 from "path";
21600
21728
  import os4 from "os";
21601
21729
  import fs25 from "fs-extra";
21602
21730
  function getCacheRoot() {
21603
- return process.env.TEAMAI_CACHE_DIR ?? path74.join(os4.homedir(), ".teamai", "cache", "repos");
21731
+ return process.env.TEAMAI_CACHE_DIR ?? path75.join(os4.homedir(), ".teamai", "cache", "repos");
21604
21732
  }
21605
21733
  function buildKey(provider, owner, repo) {
21606
21734
  return `${provider}/${owner}/${repo}`;
21607
21735
  }
21608
21736
  function keyToAbsPath(key) {
21609
- return path74.join(getCacheRoot(), key);
21737
+ return path75.join(getCacheRoot(), key);
21610
21738
  }
21611
21739
  async function loadCacheIndex() {
21612
- const indexPath = path74.join(getCacheRoot(), INDEX_FILENAME);
21740
+ const indexPath = path75.join(getCacheRoot(), INDEX_FILENAME);
21613
21741
  try {
21614
21742
  const stat6 = await fs25.stat(indexPath);
21615
21743
  if (stat6.size > MAX_CONFIG_FILE_BYTES) {
@@ -21632,7 +21760,7 @@ async function loadCacheIndex() {
21632
21760
  async function saveCacheIndex(idx) {
21633
21761
  const root = getCacheRoot();
21634
21762
  await fs25.ensureDir(root);
21635
- const indexPath = path74.join(root, INDEX_FILENAME);
21763
+ const indexPath = path75.join(root, INDEX_FILENAME);
21636
21764
  const updated = { ...idx, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
21637
21765
  await fs25.writeFile(indexPath, JSON.stringify(updated, null, 2), "utf8");
21638
21766
  }
@@ -21665,7 +21793,7 @@ async function statDirSize(absPath) {
21665
21793
  return 0;
21666
21794
  }
21667
21795
  for (const entry of entries) {
21668
- const childPath = path74.join(absPath, entry.name);
21796
+ const childPath = path75.join(absPath, entry.name);
21669
21797
  if (entry.isSymbolicLink()) {
21670
21798
  continue;
21671
21799
  }
@@ -22153,7 +22281,7 @@ var init_ai_client = __esm({
22153
22281
 
22154
22282
  // src/import-local.ts
22155
22283
  import fs26 from "fs";
22156
- import path75 from "path";
22284
+ import path76 from "path";
22157
22285
  import readline5 from "readline";
22158
22286
  function toSlug(title) {
22159
22287
  return title.toLowerCase().replace(/[^a-z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
@@ -22189,7 +22317,7 @@ function parseClassifyOutput(sourcePath, rawContent, output) {
22189
22317
  sourcePath,
22190
22318
  rawContent,
22191
22319
  type: knownType,
22192
- title: typeof parsed.title === "string" ? parsed.title : path75.basename(sourcePath),
22320
+ title: typeof parsed.title === "string" ? parsed.title : path76.basename(sourcePath),
22193
22321
  summary: typeof parsed.summary === "string" ? parsed.summary : "",
22194
22322
  tags: Array.isArray(parsed.tags) ? parsed.tags.filter((t) => typeof t === "string") : [],
22195
22323
  confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0,
@@ -22201,7 +22329,7 @@ function parseClassifyOutput(sourcePath, rawContent, output) {
22201
22329
  sourcePath,
22202
22330
  rawContent,
22203
22331
  type: "learning",
22204
- title: path75.basename(sourcePath),
22332
+ title: path76.basename(sourcePath),
22205
22333
  summary: "",
22206
22334
  tags: [],
22207
22335
  confidence: 0,
@@ -22247,9 +22375,9 @@ async function scanCandidates(opts) {
22247
22375
  const relPaths = await listFilesRecursive(expandedDir);
22248
22376
  for (const relPath of relPaths) {
22249
22377
  if (relPath.split("/").some((seg) => seg.startsWith("."))) continue;
22250
- const ext = path75.extname(relPath).toLowerCase();
22378
+ const ext = path76.extname(relPath).toLowerCase();
22251
22379
  if (ext !== ".md" && ext !== ".txt") continue;
22252
- const absPath = path75.join(expandedDir, relPath);
22380
+ const absPath = path76.join(expandedDir, relPath);
22253
22381
  try {
22254
22382
  const stat6 = fs26.statSync(absPath);
22255
22383
  if (stat6.size > MAX_FILE_SIZE_BYTES) continue;
@@ -22271,8 +22399,8 @@ async function scanCandidates(opts) {
22271
22399
  if (!fs26.existsSync(baseDir)) continue;
22272
22400
  const relPaths = await listFilesRecursive(baseDir);
22273
22401
  for (const relPath of relPaths) {
22274
- if (path75.extname(relPath).toLowerCase() !== ".md") continue;
22275
- const absPath = path75.join(baseDir, relPath);
22402
+ if (path76.extname(relPath).toLowerCase() !== ".md") continue;
22403
+ const absPath = path76.join(baseDir, relPath);
22276
22404
  try {
22277
22405
  const stat6 = fs26.statSync(absPath);
22278
22406
  if (stat6.size > MAX_FILE_SIZE_BYTES) continue;
@@ -22303,7 +22431,7 @@ async function classifyWithAI(candidates) {
22303
22431
  sourcePath: c.path,
22304
22432
  rawContent: c.rawContent,
22305
22433
  type: "learning",
22306
- title: path75.basename(c.path),
22434
+ title: path76.basename(c.path),
22307
22435
  summary: "",
22308
22436
  tags: [],
22309
22437
  confidence: 0,
@@ -22383,7 +22511,7 @@ async function interactiveReview(items, opts) {
22383
22511
  for (const sessionItem of pendingItems) {
22384
22512
  const currentIndex = session.items.indexOf(sessionItem) + 1;
22385
22513
  const classified = classifiedMap.get(sessionItem.sourcePath ?? "");
22386
- const title = sessionItem.learningDraft?.title ?? classified?.title ?? path75.basename(sessionItem.sourcePath ?? "");
22514
+ const title = sessionItem.learningDraft?.title ?? classified?.title ?? path76.basename(sessionItem.sourcePath ?? "");
22387
22515
  const itemType = classified?.type ?? "learning";
22388
22516
  const summary = classified?.summary ?? "";
22389
22517
  const tags = classified?.tags ?? [];
@@ -22450,9 +22578,9 @@ async function pushAccepted(session, repoPath, opts) {
22450
22578
  } else {
22451
22579
  const typeInContent = detectTypeFromContent(draft.content);
22452
22580
  const subDir = typeInContent === "rule" ? "rules" : typeInContent === "doc" ? "docs" : "learnings";
22453
- destDir = path75.join(expandHome(repoPath), subDir);
22581
+ destDir = path76.join(expandHome(repoPath), subDir);
22454
22582
  }
22455
- const destPath = path75.join(destDir, filename);
22583
+ const destPath = path76.join(destDir, filename);
22456
22584
  if (opts.dryRun) {
22457
22585
  log.info(`[dry-run] would write: ${destPath}`);
22458
22586
  pushed++;
@@ -22717,7 +22845,7 @@ var init_iwiki_client = __esm({
22717
22845
  });
22718
22846
 
22719
22847
  // src/import-iwiki.ts
22720
- import path76 from "path";
22848
+ import path77 from "path";
22721
22849
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
22722
22850
  function parseIWikiInput(input) {
22723
22851
  const trimmed = input.trim();
@@ -22806,8 +22934,8 @@ async function importFromIWiki(opts) {
22806
22934
  dryRun: opts.dryRun,
22807
22935
  outputDir: opts.outputDir
22808
22936
  });
22809
- const teamwikiRoot = path76.join(repoPath, "teamwiki");
22810
- if (await pathExists(path76.join(teamwikiRoot, ".indices", "graph-index.json"))) {
22937
+ const teamwikiRoot = path77.join(repoPath, "teamwiki");
22938
+ if (await pathExists(path77.join(teamwikiRoot, ".indices", "graph-index.json"))) {
22811
22939
  try {
22812
22940
  const mapsToEdges = await reconcileIwikiWithCodebase(documents, teamwikiRoot);
22813
22941
  if (mapsToEdges.length > 0) {
@@ -22826,7 +22954,7 @@ async function importFromIWiki(opts) {
22826
22954
  log.success("iWiki import complete");
22827
22955
  }
22828
22956
  async function reconcileIwikiWithCodebase(documents, teamwikiRoot) {
22829
- const graphPath = path76.join(teamwikiRoot, ".indices", "graph-index.json");
22957
+ const graphPath = path77.join(teamwikiRoot, ".indices", "graph-index.json");
22830
22958
  const graphRaw = await readFile4(graphPath, "utf-8");
22831
22959
  const graph = JSON.parse(graphRaw);
22832
22960
  const codeLabels = /* @__PURE__ */ new Map();
@@ -22835,17 +22963,17 @@ async function reconcileIwikiWithCodebase(documents, teamwikiRoot) {
22835
22963
  const words = node.label.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
22836
22964
  codeLabels.set(words, node.id);
22837
22965
  }
22838
- const evidenceDir = path76.join(teamwikiRoot, "evidence", "code");
22966
+ const evidenceDir = path77.join(teamwikiRoot, "evidence", "code");
22839
22967
  const codePageContents = /* @__PURE__ */ new Map();
22840
22968
  if (await pathExists(evidenceDir)) {
22841
22969
  const { readdir: readdir9 } = await import("fs/promises");
22842
22970
  const projects = await readdir9(evidenceDir);
22843
22971
  for (const project of projects) {
22844
- const projectDir = path76.join(evidenceDir, project);
22972
+ const projectDir = path77.join(evidenceDir, project);
22845
22973
  const files = await readdir9(projectDir).catch(() => []);
22846
22974
  for (const file of files) {
22847
22975
  if (!file.endsWith(".md")) continue;
22848
- const content = await readFile4(path76.join(projectDir, file), "utf-8").catch(() => "");
22976
+ const content = await readFile4(path77.join(projectDir, file), "utf-8").catch(() => "");
22849
22977
  codePageContents.set(`evidence/code/${project}/${file}`, content);
22850
22978
  }
22851
22979
  }
@@ -22934,7 +23062,7 @@ function parseGitHubPRUrl(url) {
22934
23062
  }
22935
23063
  return { owner: match[1], repo: match[2], number: match[3] };
22936
23064
  }
22937
- async function githubApiGet(path106) {
23065
+ async function githubApiGet(path107) {
22938
23066
  return new Promise((resolve, reject) => {
22939
23067
  const token = process.env["GITHUB_TOKEN"];
22940
23068
  const headers = {
@@ -22943,7 +23071,7 @@ async function githubApiGet(path106) {
22943
23071
  };
22944
23072
  if (token) headers["Authorization"] = `Bearer ${token}`;
22945
23073
  const req = https2.request(
22946
- { hostname: "api.github.com", path: path106, headers },
23074
+ { hostname: "api.github.com", path: path107, headers },
22947
23075
  (res) => {
22948
23076
  const chunks = [];
22949
23077
  res.on("data", (c) => chunks.push(c));
@@ -23102,7 +23230,7 @@ var init_mr_fetch2 = __esm({
23102
23230
 
23103
23231
  // src/utils/dedup.ts
23104
23232
  import fs27 from "fs/promises";
23105
- import path77 from "path";
23233
+ import path78 from "path";
23106
23234
  import matter6 from "gray-matter";
23107
23235
  function extractKeywords(text) {
23108
23236
  const keywords = /* @__PURE__ */ new Set();
@@ -23160,7 +23288,7 @@ async function findSupersededLearnings(draftKeywords, learningsDir, withinDays =
23160
23288
  const cutoffDate = new Date(Date.now() - withinDays * 24 * 60 * 60 * 1e3);
23161
23289
  const results = [];
23162
23290
  for (const filename of mdFiles) {
23163
- const filePath = path77.join(learningsDir, filename);
23291
+ const filePath = path78.join(learningsDir, filename);
23164
23292
  try {
23165
23293
  const docDate = await resolveDocDate(filePath, filename);
23166
23294
  if (docDate < cutoffDate) {
@@ -23242,7 +23370,7 @@ var init_dedup = __esm({
23242
23370
 
23243
23371
  // src/import-mr.ts
23244
23372
  import fs28 from "fs/promises";
23245
- import path78 from "path";
23373
+ import path79 from "path";
23246
23374
  import readline6 from "readline/promises";
23247
23375
  import matter7 from "gray-matter";
23248
23376
  async function fetchMR(url) {
@@ -23391,18 +23519,18 @@ async function importFromMR(opts) {
23391
23519
  async function writeLearning(draft, outputDir, repoPath) {
23392
23520
  if (outputDir) {
23393
23521
  await fs28.mkdir(outputDir, { recursive: true });
23394
- const filePath = path78.join(outputDir, "learning.md");
23522
+ const filePath = path79.join(outputDir, "learning.md");
23395
23523
  await fs28.writeFile(filePath, draft.content, "utf-8");
23396
23524
  log.info(`Learning written: ${filePath}`);
23397
23525
  return;
23398
23526
  }
23399
23527
  if (repoPath) {
23400
- const learningsDir = path78.join(repoPath, "learnings");
23528
+ const learningsDir = path79.join(repoPath, "learnings");
23401
23529
  await fs28.mkdir(learningsDir, { recursive: true });
23402
23530
  const datePrefix = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
23403
23531
  const safeTitle = draft.title.slice(0, 40).replace(/[^a-zA-Z0-9一-鿿_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
23404
23532
  const filename = `${datePrefix}-${safeTitle}.md`;
23405
- const filePath = path78.join(learningsDir, filename);
23533
+ const filePath = path79.join(learningsDir, filename);
23406
23534
  await fs28.writeFile(filePath, draft.content, "utf-8");
23407
23535
  log.info(`Learning written: ${filePath}`);
23408
23536
  return;
@@ -23418,7 +23546,7 @@ var init_import_mr = __esm({
23418
23546
  init_ai_client();
23419
23547
  init_dedup();
23420
23548
  init_logger();
23421
- DEFAULT_LEARNINGS_DIR = path78.join(process.env.HOME ?? "/tmp", ".teamai", "learnings");
23549
+ DEFAULT_LEARNINGS_DIR = path79.join(process.env.HOME ?? "/tmp", ".teamai", "learnings");
23422
23550
  SUPERSEDE_THRESHOLD = 0.6;
23423
23551
  }
23424
23552
  });
@@ -23426,7 +23554,7 @@ var init_import_mr = __esm({
23426
23554
  // src/codebase.ts
23427
23555
  import { execSync as execSync6 } from "child_process";
23428
23556
  import fs29 from "fs";
23429
- import path79 from "path";
23557
+ import path80 from "path";
23430
23558
  import matter8 from "gray-matter";
23431
23559
  async function gatherRepoContext(repoPath) {
23432
23560
  const parts = [];
@@ -23450,7 +23578,7 @@ ${truncated}`);
23450
23578
  } catch (err) {
23451
23579
  log.debug(`gatherRepoContext: find \u5931\u8D25 \u2014 ${String(err)}`);
23452
23580
  }
23453
- const pkgPath = path79.join(repoPath, "package.json");
23581
+ const pkgPath = path80.join(repoPath, "package.json");
23454
23582
  if (fs29.existsSync(pkgPath)) {
23455
23583
  try {
23456
23584
  const raw = fs29.readFileSync(pkgPath, "utf-8");
@@ -23464,7 +23592,7 @@ ${excerpt}
23464
23592
  }
23465
23593
  }
23466
23594
  for (const candidate of ["src/index.ts", "src/main.ts", "index.ts", "main.py"]) {
23467
- const entryPath = path79.join(repoPath, candidate);
23595
+ const entryPath = path80.join(repoPath, candidate);
23468
23596
  if (fs29.existsSync(entryPath)) {
23469
23597
  try {
23470
23598
  const raw = fs29.readFileSync(entryPath, "utf-8");
@@ -23480,7 +23608,7 @@ ${excerpt}
23480
23608
  }
23481
23609
  }
23482
23610
  for (const candidate of ["src/types.ts", "src/types/index.ts", "types.py"]) {
23483
- const typesPath = path79.join(repoPath, candidate);
23611
+ const typesPath = path80.join(repoPath, candidate);
23484
23612
  if (fs29.existsSync(typesPath)) {
23485
23613
  try {
23486
23614
  const raw = fs29.readFileSync(typesPath, "utf-8");
@@ -23496,10 +23624,10 @@ ${excerpt}
23496
23624
  }
23497
23625
  }
23498
23626
  const docCandidates = [
23499
- path79.join(repoPath, "README.md"),
23500
- path79.join(repoPath, "ARCHITECTURE.md")
23627
+ path80.join(repoPath, "README.md"),
23628
+ path80.join(repoPath, "ARCHITECTURE.md")
23501
23629
  ];
23502
- const docsDir = path79.join(repoPath, "docs");
23630
+ const docsDir = path80.join(repoPath, "docs");
23503
23631
  if (fs29.existsSync(docsDir)) {
23504
23632
  try {
23505
23633
  const entries = fs29.readdirSync(docsDir);
@@ -23507,7 +23635,7 @@ ${excerpt}
23507
23635
  for (const entry of entries) {
23508
23636
  if (count >= DOCS_MAX_FILES) break;
23509
23637
  if (entry.endsWith(".md")) {
23510
- docCandidates.push(path79.join(docsDir, entry));
23638
+ docCandidates.push(path80.join(docsDir, entry));
23511
23639
  count++;
23512
23640
  }
23513
23641
  }
@@ -23520,7 +23648,7 @@ ${excerpt}
23520
23648
  try {
23521
23649
  const raw = fs29.readFileSync(docPath, "utf-8");
23522
23650
  const excerpt = raw.length > DOC_MAX_CHARS ? raw.slice(0, DOC_MAX_CHARS) + "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : raw;
23523
- const relPath = path79.relative(repoPath, docPath);
23651
+ const relPath = path80.relative(repoPath, docPath);
23524
23652
  parts.push(`## \u6587\u6863\u6458\u8981\uFF1A${relPath}
23525
23653
  ${excerpt}`);
23526
23654
  } catch (err) {
@@ -23551,7 +23679,7 @@ ${lines.join("\n")}`);
23551
23679
  if (fileCount >= LEARNINGS_MAX_FILES) break;
23552
23680
  if (!entry.endsWith(".md")) continue;
23553
23681
  try {
23554
- const filePath = path79.join(learningsDir, entry);
23682
+ const filePath = path80.join(learningsDir, entry);
23555
23683
  const raw = fs29.readFileSync(filePath, "utf-8");
23556
23684
  const parsed = matter8(raw);
23557
23685
  const tags = parsed.data["tags"];
@@ -23746,7 +23874,7 @@ var init_codebase = __esm({
23746
23874
  import { createHash as createHash2 } from "crypto";
23747
23875
  import { execFile as execFile4 } from "child_process";
23748
23876
  import { readFile as readFile5, readdir as readdir2, stat } from "fs/promises";
23749
- import path80 from "path";
23877
+ import path81 from "path";
23750
23878
  import { promisify as promisify3 } from "util";
23751
23879
  function isKeyFile(relativePath, language) {
23752
23880
  const patterns = KEY_FILE_PATTERNS[language];
@@ -23754,12 +23882,12 @@ function isKeyFile(relativePath, language) {
23754
23882
  return patterns.some((pattern) => pattern.test(relativePath));
23755
23883
  }
23756
23884
  async function collectCode(options) {
23757
- const root = path80.resolve(options.root);
23885
+ const root = path81.resolve(options.root);
23758
23886
  const filePaths = [];
23759
23887
  await walk(root, filePaths, options.includeTests ?? false);
23760
23888
  let filtered = filePaths.sort((a, b) => {
23761
- const relA = toPosix(path80.relative(root, a));
23762
- const relB = toPosix(path80.relative(root, b));
23889
+ const relA = toPosix(path81.relative(root, a));
23890
+ const relB = toPosix(path81.relative(root, b));
23763
23891
  const langA = languageFor(a);
23764
23892
  const langB = languageFor(b);
23765
23893
  const keyA = isKeyFile(relA, langA) ? 0 : 1;
@@ -23773,7 +23901,7 @@ async function collectCode(options) {
23773
23901
  if (options.changedFiles && options.changedFiles.length > 0) {
23774
23902
  const changedSet = new Set(options.changedFiles.map((f) => toPosix(f)));
23775
23903
  filtered = filtered.filter((fp) => {
23776
- const relativePath = toPosix(path80.relative(root, fp));
23904
+ const relativePath = toPosix(path81.relative(root, fp));
23777
23905
  return changedSet.has(relativePath);
23778
23906
  });
23779
23907
  }
@@ -23781,7 +23909,7 @@ async function collectCode(options) {
23781
23909
  const files = [];
23782
23910
  for (const filePath of limited) {
23783
23911
  const content = await readFile5(filePath, "utf8");
23784
- const relativePath = toPosix(path80.relative(root, filePath));
23912
+ const relativePath = toPosix(path81.relative(root, filePath));
23785
23913
  const language = languageFor(filePath);
23786
23914
  files.push({
23787
23915
  path: filePath,
@@ -23808,7 +23936,7 @@ async function walk(directory, results, includeTests) {
23808
23936
  return;
23809
23937
  }
23810
23938
  for (const entry of await readdir2(directory, { withFileTypes: true })) {
23811
- const fullPath = path80.join(directory, entry.name);
23939
+ const fullPath = path81.join(directory, entry.name);
23812
23940
  if (safeIgnore(fullPath) || !includeTests && isTestPath(fullPath)) {
23813
23941
  continue;
23814
23942
  }
@@ -23821,14 +23949,14 @@ async function walk(directory, results, includeTests) {
23821
23949
  }
23822
23950
  function isCodeFile(filePath) {
23823
23951
  return [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".java", ".json", ".yaml", ".yml", ".toml", ".sql", ".conf", ".ini"].includes(
23824
- path80.extname(filePath).toLowerCase()
23952
+ path81.extname(filePath).toLowerCase()
23825
23953
  );
23826
23954
  }
23827
23955
  function isTestPath(filePath) {
23828
23956
  return /(^|\/|\\)(test|tests|__tests__|fixtures)(\/|\\)|\.test\.|\.spec\./u.test(filePath);
23829
23957
  }
23830
23958
  function languageFor(filePath) {
23831
- const ext = path80.extname(filePath).toLowerCase();
23959
+ const ext = path81.extname(filePath).toLowerCase();
23832
23960
  const map = {
23833
23961
  ".ts": "typescript",
23834
23962
  ".tsx": "typescript",
@@ -24511,14 +24639,14 @@ var init_code_extractors = __esm({
24511
24639
  });
24512
24640
 
24513
24641
  // src/wiki-engine/code-knowledge/code-graph.ts
24514
- import path81 from "path";
24642
+ import path82 from "path";
24515
24643
  function buildCodeGraph(facts) {
24516
24644
  const nodes = facts.filter((fact) => fact.kind !== "relation").map((fact) => ({
24517
24645
  slug: `${fact.kind}/${fact.name}`,
24518
24646
  type: mapFactKindToCategory(fact.kind),
24519
24647
  confidence: fact.confidence === "EXTRACTED" ? "EXTRACTED" : "INFERRED",
24520
24648
  title: fact.name,
24521
- domain: path81.dirname(fact.file).split("/")[0] || void 0
24649
+ domain: path82.dirname(fact.file).split("/")[0] || void 0
24522
24650
  }));
24523
24651
  const nodeFiles = new Set(facts.filter((f) => f.kind !== "relation").map((f) => f.file));
24524
24652
  const edges = facts.filter((fact) => fact.kind === "relation").flatMap((fact) => {
@@ -24561,7 +24689,7 @@ var init_code_graph = __esm({
24561
24689
 
24562
24690
  // src/wiki-engine/code-knowledge/code-incremental.ts
24563
24691
  import { readFile as readFile6, writeFile as writeFile6, stat as stat2, mkdir as mkdir3 } from "fs/promises";
24564
- import path82 from "path";
24692
+ import path83 from "path";
24565
24693
  async function detectCodeIncrementalChanges(root, manifestPath, project) {
24566
24694
  const previous = await exists(manifestPath) ? JSON.parse(await readFile6(manifestPath, "utf8")) : { files: [] };
24567
24695
  const oldSha = previous.headSha;
@@ -24601,14 +24729,14 @@ function affectedPages(project, files) {
24601
24729
  }
24602
24730
  async function exists(filePath) {
24603
24731
  try {
24604
- await stat2(path82.resolve(filePath));
24732
+ await stat2(path83.resolve(filePath));
24605
24733
  return true;
24606
24734
  } catch {
24607
24735
  return false;
24608
24736
  }
24609
24737
  }
24610
24738
  async function loadFactsCache(indicesDir) {
24611
- const cachePath = path82.join(indicesDir, FACTS_CACHE_FILENAME);
24739
+ const cachePath = path83.join(indicesDir, FACTS_CACHE_FILENAME);
24612
24740
  try {
24613
24741
  const raw = await readFile6(cachePath, "utf-8");
24614
24742
  const parsed = JSON.parse(raw);
@@ -24619,10 +24747,10 @@ async function loadFactsCache(indicesDir) {
24619
24747
  }
24620
24748
  async function saveFactsCache(indicesDir, facts) {
24621
24749
  await mkdir3(indicesDir, { recursive: true });
24622
- await writeFile6(path82.join(indicesDir, FACTS_CACHE_FILENAME), JSON.stringify(facts), "utf-8");
24750
+ await writeFile6(path83.join(indicesDir, FACTS_CACHE_FILENAME), JSON.stringify(facts), "utf-8");
24623
24751
  }
24624
24752
  async function loadInterfacesCache(indicesDir) {
24625
- const cachePath = path82.join(indicesDir, INTERFACES_CACHE_FILENAME);
24753
+ const cachePath = path83.join(indicesDir, INTERFACES_CACHE_FILENAME);
24626
24754
  try {
24627
24755
  const raw = await readFile6(cachePath, "utf-8");
24628
24756
  const parsed = JSON.parse(raw);
@@ -24634,7 +24762,7 @@ async function loadInterfacesCache(indicesDir) {
24634
24762
  async function saveInterfacesCache(indicesDir, inventory) {
24635
24763
  await mkdir3(indicesDir, { recursive: true });
24636
24764
  await writeFile6(
24637
- path82.join(indicesDir, INTERFACES_CACHE_FILENAME),
24765
+ path83.join(indicesDir, INTERFACES_CACHE_FILENAME),
24638
24766
  JSON.stringify(inventory, null, 2),
24639
24767
  "utf-8"
24640
24768
  );
@@ -24660,7 +24788,7 @@ var init_code_incremental = __esm({
24660
24788
  });
24661
24789
 
24662
24790
  // src/wiki-engine/interface-scanner.ts
24663
- import path83 from "path";
24791
+ import path84 from "path";
24664
24792
  async function scanInterfaces(files) {
24665
24793
  const componentMap = groupByComponent(files);
24666
24794
  const entries = [];
@@ -24728,7 +24856,7 @@ function groupByComponent(files) {
24728
24856
  if (file.repo) {
24729
24857
  component = parts.length > 1 ? `${file.repo}/${parts[0]}` : file.repo;
24730
24858
  } else {
24731
- component = parts.length > 1 ? parts[0] : path83.basename(path83.dirname(file.path));
24859
+ component = parts.length > 1 ? parts[0] : path84.basename(path84.dirname(file.path));
24732
24860
  }
24733
24861
  const group = map.get(component) ?? [];
24734
24862
  group.push(file);
@@ -25014,7 +25142,7 @@ var init_reconciler_v2_types = __esm({
25014
25142
 
25015
25143
  // src/wiki-engine/knowledge-reconciler.ts
25016
25144
  import { readFile as readFile7, readdir as readdir3, stat as stat3 } from "fs/promises";
25017
- import path84 from "path";
25145
+ import path85 from "path";
25018
25146
  async function exists2(p) {
25019
25147
  return stat3(p).then(() => true).catch(() => false);
25020
25148
  }
@@ -25023,7 +25151,7 @@ async function readPages(dirPath) {
25023
25151
  const entries = await readdir3(dirPath, { withFileTypes: true });
25024
25152
  const pages = [];
25025
25153
  for (const entry of entries) {
25026
- const full = path84.join(dirPath, entry.name);
25154
+ const full = path85.join(dirPath, entry.name);
25027
25155
  if (entry.isDirectory()) {
25028
25156
  pages.push(...await readPages(full));
25029
25157
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -25116,17 +25244,17 @@ async function reconcileKnowledge(options) {
25116
25244
  const productDirNames = options.productDirs ?? ["product", "docs"];
25117
25245
  const codeDirNames = options.codeDirs ?? ["evidence/code"];
25118
25246
  for (const dir of [...productDirNames, ...codeDirNames]) {
25119
- if (dir.includes("..") || path84.isAbsolute(dir)) {
25247
+ if (dir.includes("..") || path85.isAbsolute(dir)) {
25120
25248
  throw new Error(`Unsafe directory path rejected: ${dir}`);
25121
25249
  }
25122
25250
  }
25123
25251
  const productPages = [];
25124
25252
  for (const dir of productDirNames) {
25125
- productPages.push(...await readPages(path84.join(wikiRoot, dir)));
25253
+ productPages.push(...await readPages(path85.join(wikiRoot, dir)));
25126
25254
  }
25127
25255
  const codePages = [];
25128
25256
  for (const dir of codeDirNames) {
25129
- codePages.push(...await readPages(path84.join(wikiRoot, dir)));
25257
+ codePages.push(...await readPages(path85.join(wikiRoot, dir)));
25130
25258
  }
25131
25259
  const graphEdges = [];
25132
25260
  const gaps = [];
@@ -25153,8 +25281,8 @@ async function reconcileKnowledge(options) {
25153
25281
  ];
25154
25282
  const nc = buildConfidence(factors);
25155
25283
  graphEdges.push({
25156
- from: toPageSlug(path84.relative(wikiRoot, productPage.path)),
25157
- to: toPageSlug(path84.relative(wikiRoot, codePage.path)),
25284
+ from: toPageSlug(path85.relative(wikiRoot, productPage.path)),
25285
+ to: toPageSlug(path85.relative(wikiRoot, codePage.path)),
25158
25286
  relation: "MAPS_TO",
25159
25287
  term,
25160
25288
  confidence: nc.label,
@@ -25235,10 +25363,10 @@ async function reconcileKnowledge(options) {
25235
25363
  const MS_PER_DAY = 864e5;
25236
25364
  for (const edge of graphEdges) {
25237
25365
  const fromPage = productPages.find(
25238
- (p) => toPageSlug(path84.relative(wikiRoot, p.path)) === edge.from
25366
+ (p) => toPageSlug(path85.relative(wikiRoot, p.path)) === edge.from
25239
25367
  );
25240
25368
  const toPage = codePages.find(
25241
- (p) => toPageSlug(path84.relative(wikiRoot, p.path)) === edge.to
25369
+ (p) => toPageSlug(path85.relative(wikiRoot, p.path)) === edge.to
25242
25370
  );
25243
25371
  if (!fromPage?.updated || !toPage?.updated) continue;
25244
25372
  const fromMs = new Date(fromPage.updated).getTime();
@@ -25497,7 +25625,7 @@ __export(enrich_with_ai_exports, {
25497
25625
  enrichWithAI: () => enrichWithAI,
25498
25626
  writeManifest: () => writeManifest
25499
25627
  });
25500
- import path85 from "path";
25628
+ import path86 from "path";
25501
25629
  import { writeFile as writeFile8, mkdir as mkdir5 } from "fs/promises";
25502
25630
  function sanitizeForPrompt(text) {
25503
25631
  return text.replace(/[\n\r]/g, " ").replace(/[<>]/g, "").slice(0, 200);
@@ -25638,7 +25766,7 @@ async function enrichWithAI(ctx) {
25638
25766
  }
25639
25767
  async function writeManifest(manifest, outputDir) {
25640
25768
  await mkdir5(outputDir, { recursive: true });
25641
- const manifestPath = path85.join(outputDir, "_manifest.json");
25769
+ const manifestPath = path86.join(outputDir, "_manifest.json");
25642
25770
  await writeFile8(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
25643
25771
  return manifestPath;
25644
25772
  }
@@ -25656,7 +25784,7 @@ __export(codebase_extract_exports, {
25656
25784
  extractCodebase: () => extractCodebase
25657
25785
  });
25658
25786
  import { mkdir as mkdir6, writeFile as writeFile9, readFile as readFile8 } from "fs/promises";
25659
- import path86 from "path";
25787
+ import path87 from "path";
25660
25788
  import chalk3 from "chalk";
25661
25789
  function detectKnowledgeGaps(facts, graph, files) {
25662
25790
  const gaps = [];
@@ -25673,7 +25801,7 @@ function detectKnowledgeGaps(facts, graph, files) {
25673
25801
  const target = rel.name;
25674
25802
  if (target.startsWith(".")) continue;
25675
25803
  if (target.startsWith("node:")) continue;
25676
- const matchesAnyFile = [...scannedFiles].some((f) => f.includes(target.replace(/\//g, path86.sep)));
25804
+ const matchesAnyFile = [...scannedFiles].some((f) => f.includes(target.replace(/\//g, path87.sep)));
25677
25805
  if (!matchesAnyFile) {
25678
25806
  unresolvedImports.add(target);
25679
25807
  }
@@ -26017,21 +26145,21 @@ function buildOverview(facts, graph, project, interfaceInventory, callChains) {
26017
26145
  lines.push("## Key Dependency Paths");
26018
26146
  lines.push("");
26019
26147
  for (const chain of callChains.slice(0, 5)) {
26020
- const path106 = chain.steps.map((s) => s.symbol).join(" \u2192 ");
26021
- lines.push(`- ${chain.entryPoint}: ${path106}`);
26148
+ const path107 = chain.steps.map((s) => s.symbol).join(" \u2192 ");
26149
+ lines.push(`- ${chain.entryPoint}: ${path107}`);
26022
26150
  }
26023
26151
  }
26024
26152
  lines.push("");
26025
26153
  return lines.join("\n");
26026
26154
  }
26027
26155
  async function extractCodebase(opts) {
26028
- const root = path86.resolve(opts.path || ".");
26029
- const project = opts.project || path86.basename(root);
26156
+ const root = path87.resolve(opts.path || ".");
26157
+ const project = opts.project || path87.basename(root);
26030
26158
  const maxFiles = opts.maxFiles || 200;
26031
- const outputBase = opts.outputRoot ? path86.resolve(opts.outputRoot) : root;
26032
- const wikiRoot = path86.join(outputBase, "teamwiki");
26033
- const evidenceDir = path86.join(wikiRoot, "evidence", "code", project);
26034
- const manifestPath = path86.join(wikiRoot, "source-manifest.json");
26159
+ const outputBase = opts.outputRoot ? path87.resolve(opts.outputRoot) : root;
26160
+ const wikiRoot = path87.join(outputBase, "teamwiki");
26161
+ const evidenceDir = path87.join(wikiRoot, "evidence", "code", project);
26162
+ const manifestPath = path87.join(wikiRoot, "source-manifest.json");
26035
26163
  let changedFiles;
26036
26164
  let deletedFiles = [];
26037
26165
  if (opts.incremental) {
@@ -26068,7 +26196,7 @@ async function extractCodebase(opts) {
26068
26196
  const newFacts = files.length > 0 ? extractCodeFacts(files) : [];
26069
26197
  let facts;
26070
26198
  let interfaceInventory;
26071
- const indicesDir = path86.join(wikiRoot, ".indices");
26199
+ const indicesDir = path87.join(wikiRoot, ".indices");
26072
26200
  if (changedFiles !== void 0) {
26073
26201
  const oldFacts = await loadFactsCache(indicesDir);
26074
26202
  const oldInterfaces = await loadInterfacesCache(indicesDir);
@@ -26096,7 +26224,7 @@ async function extractCodebase(opts) {
26096
26224
  }
26097
26225
  const graph = buildCodeGraph(facts);
26098
26226
  let callChains;
26099
- const depPathsFile = path86.join(evidenceDir, "dependency-paths.md");
26227
+ const depPathsFile = path87.join(evidenceDir, "dependency-paths.md");
26100
26228
  if (changedFiles) {
26101
26229
  callChains = [];
26102
26230
  } else {
@@ -26112,7 +26240,7 @@ async function extractCodebase(opts) {
26112
26240
  }
26113
26241
  }
26114
26242
  for (const [filename, content] of pages) {
26115
- await writeIfChanged(path86.join(evidenceDir, filename), content);
26243
+ await writeIfChanged(path87.join(evidenceDir, filename), content);
26116
26244
  }
26117
26245
  const pageSlugs = [...pages.keys()].map((p) => `evidence/code/${project}/${p.replace(".md", "")}`);
26118
26246
  const overlay = buildIndexHubOverlay(project, "evidence/code", pageSlugs);
@@ -26141,7 +26269,7 @@ async function extractCodebase(opts) {
26141
26269
  keywords: enrichResult.repoKeywords || [],
26142
26270
  components: enrichResult.domains[0]?.components ?? []
26143
26271
  };
26144
- await writeFile9(path86.join(evidenceDir, "_domains.json"), JSON.stringify(domainMeta, null, 2), "utf-8");
26272
+ await writeFile9(path87.join(evidenceDir, "_domains.json"), JSON.stringify(domainMeta, null, 2), "utf-8");
26145
26273
  if (!opts.json) {
26146
26274
  const domainLabel = domainMeta.domain || "uncategorized";
26147
26275
  console.log(` AI enrich: ${enrichResult.manifest.components.length} modules, domain=${domainLabel}`);
@@ -26154,14 +26282,14 @@ async function extractCodebase(opts) {
26154
26282
  }
26155
26283
  const moduleSummaries = buildModuleSummaries(facts, graph, project);
26156
26284
  if (moduleSummaries.size > 0) {
26157
- const modulesDir = path86.join(evidenceDir, "modules");
26285
+ const modulesDir = path87.join(evidenceDir, "modules");
26158
26286
  await mkdir6(modulesDir, { recursive: true });
26159
26287
  for (const [filename, content] of moduleSummaries) {
26160
- await writeIfChanged(path86.join(modulesDir, filename), content);
26288
+ await writeIfChanged(path87.join(modulesDir, filename), content);
26161
26289
  }
26162
26290
  }
26163
26291
  const overview = buildOverview(facts, repoGraph, project, interfaceInventory, callChains);
26164
- await writeIfChanged(path86.join(evidenceDir, "overview.md"), overview);
26292
+ await writeIfChanged(path87.join(evidenceDir, "overview.md"), overview);
26165
26293
  const proj = [{ slug: project, label: project }];
26166
26294
  const ifByType = {};
26167
26295
  for (const e of interfaceInventory.entries) {
@@ -26174,11 +26302,11 @@ async function extractCodebase(opts) {
26174
26302
  interfaces: Object.keys(ifByType).length > 0 ? ifByType : void 0,
26175
26303
  callChains: callChains.length > 0 ? callChains.length : void 0
26176
26304
  };
26177
- await writeIfChanged(path86.join(wikiRoot, "router.md"), routerTemplate(proj, aiDomains.length > 0 ? aiDomains : void 0));
26178
- await writeIfChanged(path86.join(wikiRoot, "hot.md"), HOT_TEMPLATE);
26179
- await writeIfChanged(path86.join(wikiRoot, "index.md"), indexTemplate(proj, indexStats));
26305
+ await writeIfChanged(path87.join(wikiRoot, "router.md"), routerTemplate(proj, aiDomains.length > 0 ? aiDomains : void 0));
26306
+ await writeIfChanged(path87.join(wikiRoot, "hot.md"), HOT_TEMPLATE);
26307
+ await writeIfChanged(path87.join(wikiRoot, "index.md"), indexTemplate(proj, indexStats));
26180
26308
  const gaps = detectKnowledgeGaps(facts, graph, files);
26181
- const gapsDir = path86.join(wikiRoot, "gaps");
26309
+ const gapsDir = path87.join(wikiRoot, "gaps");
26182
26310
  await mkdir6(gapsDir, { recursive: true });
26183
26311
  const gapLines = [
26184
26312
  "---",
@@ -26201,7 +26329,7 @@ async function extractCodebase(opts) {
26201
26329
  gapLines.push("| \u2014 | \u2014 | \u2014 | \u672A\u53D1\u73B0\u660E\u663E\u77E5\u8BC6\u7F3A\u53E3 | \u2014 |");
26202
26330
  }
26203
26331
  gapLines.push("");
26204
- await writeIfChanged(path86.join(gapsDir, "detected.md"), gapLines.join("\n"));
26332
+ await writeIfChanged(path87.join(gapsDir, "detected.md"), gapLines.join("\n"));
26205
26333
  await saveFactsCache(indicesDir, facts);
26206
26334
  await saveInterfacesCache(indicesDir, interfaceInventory);
26207
26335
  let allManifestFiles = collectionManifest.files.map((f) => ({
@@ -26458,14 +26586,14 @@ __export(repo_cache_exports, {
26458
26586
  readLastSync: () => readLastSync,
26459
26587
  writeLastSync: () => writeLastSync
26460
26588
  });
26461
- import path87 from "path";
26589
+ import path88 from "path";
26462
26590
  import os5 from "os";
26463
26591
  import fs31 from "fs-extra";
26464
26592
  function getCacheRoot2() {
26465
- return process.env.TEAMAI_CACHE_DIR ?? path87.join(os5.homedir(), ".teamai", "cache", "repos");
26593
+ return process.env.TEAMAI_CACHE_DIR ?? path88.join(os5.homedir(), ".teamai", "cache", "repos");
26466
26594
  }
26467
26595
  function getRepoCacheDir(provider, owner, repo) {
26468
- return path87.join(getCacheRoot2(), provider, owner, repo);
26596
+ return path88.join(getCacheRoot2(), provider, owner, repo);
26469
26597
  }
26470
26598
  function getRepoSlug(provider, owner, repo) {
26471
26599
  const safeOwner = owner.replace(/\//g, "-");
@@ -26476,10 +26604,10 @@ async function writeLastSync(cacheDir, sha) {
26476
26604
  const content = `${sha}
26477
26605
  ${isoTs}
26478
26606
  `;
26479
- await fs31.writeFile(path87.join(cacheDir, LAST_SYNC_FILE), content, "utf8");
26607
+ await fs31.writeFile(path88.join(cacheDir, LAST_SYNC_FILE), content, "utf8");
26480
26608
  }
26481
26609
  async function readLastSync(cacheDir) {
26482
- const filePath = path87.join(cacheDir, LAST_SYNC_FILE);
26610
+ const filePath = path88.join(cacheDir, LAST_SYNC_FILE);
26483
26611
  const exists3 = await fs31.pathExists(filePath);
26484
26612
  if (!exists3) {
26485
26613
  return null;
@@ -26510,7 +26638,7 @@ __export(deep_enrich_exports, {
26510
26638
  deepEnrich: () => deepEnrich
26511
26639
  });
26512
26640
  import { readFile as readFile9, writeFile as writeFile10, readdir as readdir4, mkdir as mkdir7 } from "fs/promises";
26513
- import path88 from "path";
26641
+ import path89 from "path";
26514
26642
  async function readFileSafe4(filePath) {
26515
26643
  try {
26516
26644
  return await readFile9(filePath, "utf-8");
@@ -26519,7 +26647,7 @@ async function readFileSafe4(filePath) {
26519
26647
  }
26520
26648
  }
26521
26649
  async function loadContext(evidenceDir) {
26522
- const manifestRaw = await readFileSafe4(path88.join(evidenceDir, "_manifest.json"));
26650
+ const manifestRaw = await readFileSafe4(path89.join(evidenceDir, "_manifest.json"));
26523
26651
  let manifest = {};
26524
26652
  try {
26525
26653
  manifest = JSON.parse(manifestRaw);
@@ -26527,18 +26655,18 @@ async function loadContext(evidenceDir) {
26527
26655
  log.debug("deep-enrich: failed to parse _manifest.json");
26528
26656
  }
26529
26657
  const [indexMd, callChains, overview] = await Promise.all([
26530
- readFileSafe4(path88.join(evidenceDir, "index.md")),
26531
- readFileSafe4(path88.join(evidenceDir, "dependency-paths.md")),
26532
- readFileSafe4(path88.join(evidenceDir, "overview.md"))
26658
+ readFileSafe4(path89.join(evidenceDir, "index.md")),
26659
+ readFileSafe4(path89.join(evidenceDir, "dependency-paths.md")),
26660
+ readFileSafe4(path89.join(evidenceDir, "overview.md"))
26533
26661
  ]);
26534
- const modulesDir = path88.join(evidenceDir, "modules");
26662
+ const modulesDir = path89.join(evidenceDir, "modules");
26535
26663
  const moduleDocs = /* @__PURE__ */ new Map();
26536
26664
  if (await pathExists(modulesDir)) {
26537
26665
  try {
26538
26666
  const entries = await readdir4(modulesDir);
26539
26667
  await Promise.all(
26540
26668
  entries.filter((e) => e.endsWith(".md")).map(async (e) => {
26541
- const content = await readFileSafe4(path88.join(modulesDir, e));
26669
+ const content = await readFileSafe4(path89.join(modulesDir, e));
26542
26670
  moduleDocs.set(e.replace(/\.md$/, ""), content);
26543
26671
  })
26544
26672
  );
@@ -26549,7 +26677,7 @@ async function loadContext(evidenceDir) {
26549
26677
  return { manifest, indexMd, callChains, overview, moduleDocs };
26550
26678
  }
26551
26679
  function progressPath(evidenceDir) {
26552
- return path88.join(evidenceDir, PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME);
26680
+ return path89.join(evidenceDir, PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME);
26553
26681
  }
26554
26682
  function isValidProgressState(v, project) {
26555
26683
  if (typeof v !== "object" || v === null) return false;
@@ -26575,7 +26703,7 @@ async function loadProgress(evidenceDir, project, allComponents) {
26575
26703
  }
26576
26704
  async function saveProgress(evidenceDir, state) {
26577
26705
  const p = progressPath(evidenceDir);
26578
- await mkdir7(path88.dirname(p), { recursive: true });
26706
+ await mkdir7(path89.dirname(p), { recursive: true });
26579
26707
  const updated = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
26580
26708
  await writeFile10(p, JSON.stringify(updated, null, 2), "utf-8");
26581
26709
  }
@@ -26814,7 +26942,7 @@ async function runPhaseComponents(opts, ctx, progress, docsDir) {
26814
26942
  log.warn(`deep-enrich[${project}]: Skipping unsafe component slug "${comp.slug}": ${e.message}`);
26815
26943
  continue;
26816
26944
  }
26817
- const outPath = path88.join(docsDir, `${comp.slug}.md`);
26945
+ const outPath = path89.join(docsDir, `${comp.slug}.md`);
26818
26946
  await mkdir7(docsDir, { recursive: true });
26819
26947
  await writeFile10(outPath, content, "utf-8");
26820
26948
  progress.componentsDone.push(comp.slug);
@@ -26842,7 +26970,7 @@ async function runPhaseArchitecture(opts, ctx, docsDir) {
26842
26970
  log.warn(`deep-enrich[${project}]: Architecture overview: AI returned empty, skipping write`);
26843
26971
  return;
26844
26972
  }
26845
- const outPath = path88.join(docsDir, "architecture.md");
26973
+ const outPath = path89.join(docsDir, "architecture.md");
26846
26974
  await mkdir7(docsDir, { recursive: true });
26847
26975
  await writeFile10(outPath, content, "utf-8");
26848
26976
  log.debug(`deep-enrich[${project}]: Architecture overview written: ${outPath}`);
@@ -26850,15 +26978,15 @@ async function runPhaseArchitecture(opts, ctx, docsDir) {
26850
26978
  async function runPhaseGraph(opts, ctx, docsDir) {
26851
26979
  const { project, evidenceDir } = opts;
26852
26980
  log.info(`deep-enrich[${project}]: Phase 3 \u2014 Generating deterministic graph docs`);
26853
- const interfacesMd = await readFileSafe4(path88.join(evidenceDir, "interfaces.md"));
26981
+ const interfacesMd = await readFileSafe4(path89.join(evidenceDir, "interfaces.md"));
26854
26982
  const g1 = buildG1RelationsDoc(ctx.manifest);
26855
26983
  const g2 = buildG2DataflowDoc(ctx.callChains);
26856
26984
  const g3 = buildG3InterfacesDoc(interfacesMd);
26857
26985
  await mkdir7(docsDir, { recursive: true });
26858
26986
  await Promise.all([
26859
- writeFile10(path88.join(docsDir, "graph-g1-relations.md"), g1, "utf-8"),
26860
- writeFile10(path88.join(docsDir, "graph-g2-dataflow.md"), g2, "utf-8"),
26861
- writeFile10(path88.join(docsDir, "graph-g3-interfaces.md"), g3, "utf-8")
26987
+ writeFile10(path89.join(docsDir, "graph-g1-relations.md"), g1, "utf-8"),
26988
+ writeFile10(path89.join(docsDir, "graph-g2-dataflow.md"), g2, "utf-8"),
26989
+ writeFile10(path89.join(docsDir, "graph-g3-interfaces.md"), g3, "utf-8")
26862
26990
  ]);
26863
26991
  log.debug(`deep-enrich[${project}]: Graph docs written: ${docsDir}`);
26864
26992
  }
@@ -26964,14 +27092,14 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
26964
27092
  await mkdir7(docsDir, { recursive: true });
26965
27093
  const g6HasEdges = (ctx.manifest.edges ?? []).length > 0;
26966
27094
  const g6 = buildG6Content(project, ctx.manifest);
26967
- await writeFile10(path88.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
27095
+ await writeFile10(path89.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
26968
27096
  log.debug(`deep-enrich[${project}]: G6 multi-hop analysis written`);
26969
27097
  let g5Generated = false;
26970
27098
  if (ctx.moduleDocs.size < 2) {
26971
27099
  log.warn(`deep-enrich[${project}]: Insufficient modules (${ctx.moduleDocs.size} < 2), skipping G5`);
26972
27100
  return { g5Generated, g6Generated: g6HasEdges };
26973
27101
  }
26974
- const architectureMd = await readFileSafe4(path88.join(docsDir, "architecture.md"));
27102
+ const architectureMd = await readFileSafe4(path89.join(docsDir, "architecture.md"));
26975
27103
  if (!architectureMd.trim()) {
26976
27104
  log.warn(`deep-enrich[${project}]: No architecture doc, skipping G5 scenarios`);
26977
27105
  return { g5Generated, g6Generated: g6HasEdges };
@@ -26981,7 +27109,7 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
26981
27109
  try {
26982
27110
  const g5Content = await callClaude(prompt);
26983
27111
  if (g5Content.trim()) {
26984
- await writeFile10(path88.join(docsDir, "graph-g5-scenarios.md"), g5Content, "utf-8");
27112
+ await writeFile10(path89.join(docsDir, "graph-g5-scenarios.md"), g5Content, "utf-8");
26985
27113
  log.debug(`deep-enrich[${project}]: G5 scenario diagrams written`);
26986
27114
  g5Generated = true;
26987
27115
  }
@@ -26999,10 +27127,10 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
26999
27127
  hasG5: graphFlags?.g5Generated ?? false,
27000
27128
  hasG6: graphFlags?.g6Generated ?? true
27001
27129
  });
27002
- await writeFile10(path88.join(docsDir, "README.md"), graphReadme, "utf-8");
27130
+ await writeFile10(path89.join(docsDir, "README.md"), graphReadme, "utf-8");
27003
27131
  log.debug(`deep-enrich[${project}]: graph/README.md routing table written`);
27004
27132
  const { wikiRoot } = opts;
27005
- const domainsJson = await readFileSafe4(path88.join(evidenceDir, "_domains.json"));
27133
+ const domainsJson = await readFileSafe4(path89.join(evidenceDir, "_domains.json"));
27006
27134
  let keywords = [];
27007
27135
  let description = "";
27008
27136
  try {
@@ -27011,7 +27139,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
27011
27139
  description = domains.description ?? "";
27012
27140
  } catch {
27013
27141
  }
27014
- const routerPath = path88.join(wikiRoot, "router.md");
27142
+ const routerPath = path89.join(wikiRoot, "router.md");
27015
27143
  const routerContent = await readFileSafe4(routerPath);
27016
27144
  const projectLink = `[[evidence/code/${project}/index]]`;
27017
27145
  if (routerContent && !routerContent.includes(projectLink)) {
@@ -27021,7 +27149,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
27021
27149
  `;
27022
27150
  await writeFile10(routerPath, routerContent.trimEnd() + "\n" + line, "utf-8");
27023
27151
  }
27024
- const indexPath = path88.join(wikiRoot, "index.md");
27152
+ const indexPath = path89.join(wikiRoot, "index.md");
27025
27153
  const indexContent = await readFileSafe4(indexPath);
27026
27154
  if (indexContent && !indexContent.includes(`evidence/code/${project}/`)) {
27027
27155
  const navBlock = [
@@ -27046,7 +27174,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
27046
27174
  }
27047
27175
  async function deepEnrich(opts) {
27048
27176
  const { project, evidenceDir } = opts;
27049
- const docsDir = path88.join(evidenceDir, "docs");
27177
+ const docsDir = path89.join(evidenceDir, "docs");
27050
27178
  log.info(`deep-enrich[${project}]: Starting deep knowledge generation, evidenceDir=${evidenceDir}`);
27051
27179
  const ctx = await loadContext(evidenceDir);
27052
27180
  let components = ctx.manifest.components ?? [];
@@ -27135,11 +27263,11 @@ var graph_aggregate_exports = {};
27135
27263
  __export(graph_aggregate_exports, {
27136
27264
  aggregateGlobalGraph: () => aggregateGlobalGraph
27137
27265
  });
27138
- import path89 from "path";
27266
+ import path90 from "path";
27139
27267
  import { readdir as readdir5 } from "fs/promises";
27140
27268
  import fs32 from "fs-extra";
27141
27269
  async function aggregateGlobalGraph(teamwikiRoot) {
27142
- const evidenceBase = path89.join(teamwikiRoot, "evidence", "code");
27270
+ const evidenceBase = path90.join(teamwikiRoot, "evidence", "code");
27143
27271
  if (!await fs32.pathExists(evidenceBase)) return null;
27144
27272
  const { mergeGraphs: mergeGraphs2 } = await Promise.resolve().then(() => (init_adapters(), adapters_exports));
27145
27273
  const { detectCrossRepoEdges: detectCrossRepoEdges2 } = await Promise.resolve().then(() => (init_import_repo(), import_repo_exports));
@@ -27147,7 +27275,7 @@ async function aggregateGlobalGraph(teamwikiRoot) {
27147
27275
  const projectDirs = await readdir5(evidenceBase, { withFileTypes: true });
27148
27276
  for (const dir of projectDirs) {
27149
27277
  if (!dir.isDirectory()) continue;
27150
- const graphPath = path89.join(evidenceBase, dir.name, ".indices", "graph-index.json");
27278
+ const graphPath = path90.join(evidenceBase, dir.name, ".indices", "graph-index.json");
27151
27279
  if (!await fs32.pathExists(graphPath)) continue;
27152
27280
  try {
27153
27281
  const overlay = JSON.parse(await fs32.readFile(graphPath, "utf8"));
@@ -27165,8 +27293,8 @@ async function aggregateGlobalGraph(teamwikiRoot) {
27165
27293
  }
27166
27294
  }
27167
27295
  if (globalGraph) {
27168
- const destPath = path89.join(teamwikiRoot, ".indices", "graph-index.json");
27169
- await fs32.ensureDir(path89.dirname(destPath));
27296
+ const destPath = path90.join(teamwikiRoot, ".indices", "graph-index.json");
27297
+ await fs32.ensureDir(path90.dirname(destPath));
27170
27298
  await fs32.writeFile(destPath, JSON.stringify(globalGraph, null, 2), "utf8");
27171
27299
  log.info(`global graph-index.json aggregated (${globalGraph.nodes.length} nodes, ${globalGraph.edges.length} edges)`);
27172
27300
  return { nodes: globalGraph.nodes.length, edges: globalGraph.edges.length };
@@ -27186,7 +27314,7 @@ __export(import_repo_exports, {
27186
27314
  detectCrossRepoEdges: () => detectCrossRepoEdges,
27187
27315
  importFromRepo: () => importFromRepo
27188
27316
  });
27189
- import path90 from "path";
27317
+ import path91 from "path";
27190
27318
  import fs33 from "fs-extra";
27191
27319
  import chalk4 from "chalk";
27192
27320
  function detectCrossRepoEdges(overlay, existing) {
@@ -27308,7 +27436,7 @@ async function importFromRepo(opts) {
27308
27436
  const cacheDir = getRepoCacheDir(providerName, owner, repoName);
27309
27437
  const slug = getRepoSlug(providerName, owner, repoName);
27310
27438
  const lastSync = await readLastSync(cacheDir);
27311
- const cacheExists = await fs33.pathExists(path90.join(cacheDir, ".git"));
27439
+ const cacheExists = await fs33.pathExists(path91.join(cacheDir, ".git"));
27312
27440
  const useIncremental = incremental && cacheExists && lastSync !== null;
27313
27441
  let cloneSha;
27314
27442
  let cloneBranch;
@@ -27386,25 +27514,25 @@ async function importFromRepo(opts) {
27386
27514
  mrTeamConfig = { repo: tc.repo, provider: tc.provider, reviewers: tc.reviewers };
27387
27515
  mrLocalConfig = { repo: lc.repo, username: lc.username };
27388
27516
  } catch {
27389
- teamRepoDir = path90.join(process.cwd(), ".teamai", "team-repo");
27517
+ teamRepoDir = path91.join(process.cwd(), ".teamai", "team-repo");
27390
27518
  }
27391
- const teamwikiRoot = output ? path90.resolve(output, "..", "teamwiki") : path90.join(teamRepoDir, "teamwiki");
27519
+ const teamwikiRoot = output ? path91.resolve(output, "..", "teamwiki") : path91.join(teamRepoDir, "teamwiki");
27392
27520
  if (!dryRun) {
27393
- const cacheWiki = path90.join(cacheDir, "teamwiki");
27521
+ const cacheWiki = path91.join(cacheDir, "teamwiki");
27394
27522
  try {
27395
27523
  if (incremental) {
27396
- const destIndices = path90.join(teamwikiRoot, ".indices");
27397
- const cacheIndices = path90.join(cacheDir, "teamwiki", ".indices");
27524
+ const destIndices = path91.join(teamwikiRoot, ".indices");
27525
+ const cacheIndices = path91.join(cacheDir, "teamwiki", ".indices");
27398
27526
  await fs33.ensureDir(cacheIndices);
27399
27527
  for (const f of ["facts-cache.json", "interfaces-cache.json"]) {
27400
- const src = path90.join(destIndices, f);
27528
+ const src = path91.join(destIndices, f);
27401
27529
  if (await fs33.pathExists(src)) {
27402
- await fs33.copy(src, path90.join(cacheIndices, f));
27530
+ await fs33.copy(src, path91.join(cacheIndices, f));
27403
27531
  }
27404
27532
  }
27405
- const existingManifest = path90.join(teamwikiRoot, "source-manifest.json");
27533
+ const existingManifest = path91.join(teamwikiRoot, "source-manifest.json");
27406
27534
  if (await fs33.pathExists(existingManifest)) {
27407
- await fs33.copy(existingManifest, path90.join(cacheDir, "teamwiki", "source-manifest.json"));
27535
+ await fs33.copy(existingManifest, path91.join(cacheDir, "teamwiki", "source-manifest.json"));
27408
27536
  }
27409
27537
  }
27410
27538
  await extractCodebase({
@@ -27418,19 +27546,19 @@ async function importFromRepo(opts) {
27418
27546
  sourceMrUrl
27419
27547
  });
27420
27548
  if (await fs33.pathExists(cacheWiki)) {
27421
- const evidenceSrc = path90.join(cacheWiki, "evidence", "code", slug);
27422
- const evidenceDest = path90.join(teamwikiRoot, "evidence", "code", slug);
27549
+ const evidenceSrc = path91.join(cacheWiki, "evidence", "code", slug);
27550
+ const evidenceDest = path91.join(teamwikiRoot, "evidence", "code", slug);
27423
27551
  if (await fs33.pathExists(evidenceDest)) {
27424
27552
  const entries = await fs33.readdir(evidenceDest);
27425
27553
  for (const entry of entries) {
27426
27554
  if (entry === ".indices") continue;
27427
- await fs33.remove(path90.join(evidenceDest, entry));
27555
+ await fs33.remove(path91.join(evidenceDest, entry));
27428
27556
  }
27429
27557
  }
27430
27558
  await fs33.ensureDir(evidenceDest);
27431
27559
  await fs33.copy(evidenceSrc, evidenceDest, { overwrite: true });
27432
27560
  if (codebaseMd) {
27433
- const overviewPath = path90.join(evidenceDest, "overview.md");
27561
+ const overviewPath = path91.join(evidenceDest, "overview.md");
27434
27562
  const existing = await fs33.readFile(overviewPath, "utf8").catch(() => "");
27435
27563
  const aiNarrative = codebaseMd.replace(/^---[\s\S]*?---\n*/m, "");
27436
27564
  const marker = "## AI Architecture Narrative";
@@ -27453,31 +27581,31 @@ ${aiNarrative}`;
27453
27581
  }
27454
27582
  await fs33.writeFile(overviewPath, combined, "utf8");
27455
27583
  }
27456
- const srcGraph = path90.join(cacheWiki, ".indices", "graph-index.json");
27584
+ const srcGraph = path91.join(cacheWiki, ".indices", "graph-index.json");
27457
27585
  if (await fs33.pathExists(srcGraph)) {
27458
- const evidenceGraphDir = path90.join(teamwikiRoot, "evidence", "code", slug, ".indices");
27586
+ const evidenceGraphDir = path91.join(teamwikiRoot, "evidence", "code", slug, ".indices");
27459
27587
  await fs33.ensureDir(evidenceGraphDir);
27460
- await fs33.copy(srcGraph, path90.join(evidenceGraphDir, "graph-index.json"));
27588
+ await fs33.copy(srcGraph, path91.join(evidenceGraphDir, "graph-index.json"));
27461
27589
  } else {
27462
27590
  log.debug(`[graph] per-repo graph-index.json not found, skipping copy`);
27463
27591
  }
27464
- const cacheIndices = path90.join(cacheWiki, ".indices");
27465
- const destIndices = path90.join(teamwikiRoot, ".indices");
27592
+ const cacheIndices = path91.join(cacheWiki, ".indices");
27593
+ const destIndices = path91.join(teamwikiRoot, ".indices");
27466
27594
  for (const cacheFile of ["facts-cache.json", "interfaces-cache.json"]) {
27467
- const src = path90.join(cacheIndices, cacheFile);
27595
+ const src = path91.join(cacheIndices, cacheFile);
27468
27596
  if (await fs33.pathExists(src)) {
27469
27597
  await fs33.ensureDir(destIndices);
27470
- await fs33.copy(src, path90.join(destIndices, cacheFile), { overwrite: true });
27598
+ await fs33.copy(src, path91.join(destIndices, cacheFile), { overwrite: true });
27471
27599
  }
27472
27600
  }
27473
- const srcManifest = path90.join(cacheWiki, "source-manifest.json");
27601
+ const srcManifest = path91.join(cacheWiki, "source-manifest.json");
27474
27602
  if (await fs33.pathExists(srcManifest)) {
27475
- await fs33.copy(srcManifest, path90.join(teamwikiRoot, "source-manifest.json"), { overwrite: true });
27603
+ await fs33.copy(srcManifest, path91.join(teamwikiRoot, "source-manifest.json"), { overwrite: true });
27476
27604
  }
27477
27605
  await fs33.remove(cacheWiki);
27478
27606
  }
27479
27607
  if (explicitDomain) {
27480
- const domainsJsonPath = path90.join(teamwikiRoot, "evidence", "code", slug, "_domains.json");
27608
+ const domainsJsonPath = path91.join(teamwikiRoot, "evidence", "code", slug, "_domains.json");
27481
27609
  if (await fs33.pathExists(domainsJsonPath)) {
27482
27610
  try {
27483
27611
  const existing = JSON.parse(await fs33.readFile(domainsJsonPath, "utf8"));
@@ -27490,8 +27618,8 @@ ${aiNarrative}`;
27490
27618
  }
27491
27619
  }
27492
27620
  const { routerTemplate: routerTemplate2, indexTemplate: indexTemplate2, HOT_TEMPLATE: HOT_TEMPLATE2 } = await Promise.resolve().then(() => (init_templates(), templates_exports));
27493
- const routerPath = path90.join(teamwikiRoot, "router.md");
27494
- const indexPath = path90.join(teamwikiRoot, "index.md");
27621
+ const routerPath = path91.join(teamwikiRoot, "router.md");
27622
+ const indexPath = path91.join(teamwikiRoot, "index.md");
27495
27623
  const projectLink = `[[evidence/code/${slug}/index]]`;
27496
27624
  if (await fs33.pathExists(routerPath)) {
27497
27625
  const router = await fs33.readFile(routerPath, "utf8");
@@ -27517,8 +27645,8 @@ ${aiNarrative}`;
27517
27645
  } else {
27518
27646
  await fs33.writeFile(indexPath, indexTemplate2([{ slug, label: slug }]), "utf8");
27519
27647
  }
27520
- if (!await fs33.pathExists(path90.join(teamwikiRoot, "hot.md"))) {
27521
- await fs33.writeFile(path90.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE2, "utf8");
27648
+ if (!await fs33.pathExists(path91.join(teamwikiRoot, "hot.md"))) {
27649
+ await fs33.writeFile(path91.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE2, "utf8");
27522
27650
  }
27523
27651
  log.info(chalk4.green(`\u2713 teamwiki/ knowledge graph updated: ${slug}`));
27524
27652
  } catch (err) {
@@ -27540,8 +27668,8 @@ ${aiNarrative}`;
27540
27668
  }
27541
27669
  }
27542
27670
  if (!dryRun && !skipEnrich && teamwikiRoot) {
27543
- const evidenceDir = path90.join(teamwikiRoot, "evidence", "code", slug);
27544
- if (await fs33.pathExists(path90.join(evidenceDir, "_manifest.json"))) {
27671
+ const evidenceDir = path91.join(teamwikiRoot, "evidence", "code", slug);
27672
+ if (await fs33.pathExists(path91.join(evidenceDir, "_manifest.json"))) {
27545
27673
  try {
27546
27674
  const { deepEnrich: deepEnrich2 } = await Promise.resolve().then(() => (init_deep_enrich(), deep_enrich_exports));
27547
27675
  await deepEnrich2({ project: slug, evidenceDir, wikiRoot: teamwikiRoot, cacheDir });
@@ -27657,7 +27785,7 @@ var init_store = __esm({
27657
27785
  });
27658
27786
 
27659
27787
  // src/import-repo-list.ts
27660
- import path91 from "path";
27788
+ import path92 from "path";
27661
27789
  function sortByPriority(entries) {
27662
27790
  const order = { high: 0, normal: 1, low: 2 };
27663
27791
  return [...entries].sort((a, b) => {
@@ -27734,7 +27862,7 @@ async function importFromRepoList(opts) {
27734
27862
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
27735
27863
  const { localConfig: lc } = await autoDetectInit2();
27736
27864
  const teamRepoPath = lc.repo.localPath;
27737
- const teamwikiRoot = path91.join(teamRepoPath, "teamwiki");
27865
+ const teamwikiRoot = path92.join(teamRepoPath, "teamwiki");
27738
27866
  const { aggregateGlobalGraph: aggregateGlobalGraph2 } = await Promise.resolve().then(() => (init_graph_aggregate(), graph_aggregate_exports));
27739
27867
  await aggregateGlobalGraph2(teamwikiRoot);
27740
27868
  } catch (e) {
@@ -27784,9 +27912,9 @@ __export(rebuild_wiki_index_exports, {
27784
27912
  rebuildWikiIndex: () => rebuildWikiIndex
27785
27913
  });
27786
27914
  import { readFile as readFile10, readdir as readdir6, stat as stat4, writeFile as writeFile11 } from "fs/promises";
27787
- import path92 from "path";
27915
+ import path93 from "path";
27788
27916
  async function rebuildWikiIndex(teamwikiRoot) {
27789
- const evidenceCodeDir = path92.join(teamwikiRoot, "evidence", "code");
27917
+ const evidenceCodeDir = path93.join(teamwikiRoot, "evidence", "code");
27790
27918
  if (!await pathExists(evidenceCodeDir)) return;
27791
27919
  const projects = [];
27792
27920
  let totalFacts = 0, totalNodes = 0, totalEdges = 0;
@@ -27794,7 +27922,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27794
27922
  let totalCallChains = 0;
27795
27923
  const dirs = await readdir6(evidenceCodeDir);
27796
27924
  for (const dir of dirs) {
27797
- const dirPath = path92.join(evidenceCodeDir, dir);
27925
+ const dirPath = path93.join(evidenceCodeDir, dir);
27798
27926
  const dirStat = await stat4(dirPath).catch(() => null);
27799
27927
  if (!dirStat?.isDirectory()) continue;
27800
27928
  const info = {
@@ -27807,7 +27935,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27807
27935
  keywords: [],
27808
27936
  domain: ""
27809
27937
  };
27810
- const overviewPath = path92.join(dirPath, "overview.md");
27938
+ const overviewPath = path93.join(dirPath, "overview.md");
27811
27939
  if (await pathExists(overviewPath)) {
27812
27940
  const content = await readFile10(overviewPath, "utf-8");
27813
27941
  const bodyStart = content.indexOf("\n\n", content.indexOf("---", 3));
@@ -27820,7 +27948,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27820
27948
  }
27821
27949
  }
27822
27950
  }
27823
- const projectIndex = path92.join(dirPath, "index.md");
27951
+ const projectIndex = path93.join(dirPath, "index.md");
27824
27952
  if (await pathExists(projectIndex)) {
27825
27953
  const content = await readFile10(projectIndex, "utf-8");
27826
27954
  const factsMatch = content.match(/Facts:\s*(\d+)/);
@@ -27830,7 +27958,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27830
27958
  info.interfaces[m[1]] = (info.interfaces[m[1]] ?? 0) + parseInt(m[2], 10);
27831
27959
  }
27832
27960
  }
27833
- const manifestPath = path92.join(dirPath, "_manifest.json");
27961
+ const manifestPath = path93.join(dirPath, "_manifest.json");
27834
27962
  if (await pathExists(manifestPath)) {
27835
27963
  try {
27836
27964
  const raw = await readFile10(manifestPath, "utf-8");
@@ -27842,7 +27970,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27842
27970
  } catch {
27843
27971
  }
27844
27972
  }
27845
- const domainsPath = path92.join(dirPath, "_domains.json");
27973
+ const domainsPath = path93.join(dirPath, "_domains.json");
27846
27974
  if (await pathExists(domainsPath)) {
27847
27975
  try {
27848
27976
  const raw = await readFile10(domainsPath, "utf-8");
@@ -27859,7 +27987,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27859
27987
  } catch {
27860
27988
  }
27861
27989
  }
27862
- const chainsPath = path92.join(dirPath, "dependency-paths.md");
27990
+ const chainsPath = path93.join(dirPath, "dependency-paths.md");
27863
27991
  if (await pathExists(chainsPath)) {
27864
27992
  const content = await readFile10(chainsPath, "utf-8");
27865
27993
  const chainMatch = content.match(/(\d+)\s*call chain/);
@@ -27875,7 +28003,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27875
28003
  }
27876
28004
  projects.push(info);
27877
28005
  }
27878
- const graphPath = path92.join(teamwikiRoot, ".indices", "graph-index.json");
28006
+ const graphPath = path93.join(teamwikiRoot, ".indices", "graph-index.json");
27879
28007
  if (await pathExists(graphPath)) {
27880
28008
  try {
27881
28009
  const raw = await readFile10(graphPath, "utf-8");
@@ -27916,7 +28044,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27916
28044
  routerLines.push("4. **\u8C03\u7528\u94FE/\u6392\u969C** \u2192 \u67E5\u5BF9\u5E94\u4ED3\u5E93\u7684 dependency-paths.md");
27917
28045
  routerLines.push("5. **\u6A21\u5757\u804C\u8D23\u6982\u8FF0** \u2192 \u67E5 overview.md \u6216 modules/*.md");
27918
28046
  routerLines.push("");
27919
- await writeFile11(path92.join(teamwikiRoot, "router.md"), routerLines.join("\n"), "utf-8");
28047
+ await writeFile11(path93.join(teamwikiRoot, "router.md"), routerLines.join("\n"), "utf-8");
27920
28048
  const indexLines = [
27921
28049
  "# Team Wiki Index",
27922
28050
  "",
@@ -27952,9 +28080,9 @@ async function rebuildWikiIndex(teamwikiRoot) {
27952
28080
  indexLines.push("- [router.md](./router.md) \u2014 \u4EA7\u54C1\u57DF\u8DEF\u7531\uFF08\u8868\u683C + \u8DEF\u7531\u89C4\u5219\uFF09");
27953
28081
  indexLines.push("- [hot.md](./hot.md) \u2014 \u6D3B\u8DC3\u5DE5\u4F5C\u8BB0\u5FC6");
27954
28082
  indexLines.push("");
27955
- await writeFile11(path92.join(teamwikiRoot, "index.md"), indexLines.join("\n"), "utf-8");
27956
- if (!await pathExists(path92.join(teamwikiRoot, "hot.md"))) {
27957
- await writeFile11(path92.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE, "utf-8");
28083
+ await writeFile11(path93.join(teamwikiRoot, "index.md"), indexLines.join("\n"), "utf-8");
28084
+ if (!await pathExists(path93.join(teamwikiRoot, "hot.md"))) {
28085
+ await writeFile11(path93.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE, "utf-8");
27958
28086
  }
27959
28087
  log.debug(`rebuildWikiIndex: ${projects.length} projects, ${totalNodes} nodes, ${totalEdges} edges`);
27960
28088
  }
@@ -27993,7 +28121,7 @@ var init_rebuild_wiki_index = __esm({
27993
28121
  });
27994
28122
 
27995
28123
  // src/import-org.ts
27996
- import path93 from "path";
28124
+ import path94 from "path";
27997
28125
  import fs35 from "fs-extra";
27998
28126
  function parseOrgInput(org) {
27999
28127
  const trimmed = org.trim();
@@ -28064,9 +28192,9 @@ async function importFromOrg(opts) {
28064
28192
  return;
28065
28193
  }
28066
28194
  log.info(`${filteredRepos.length} repos after filtering, generating whitelist...`);
28067
- const whitelistDraftPath = path93.join(cwd, WHITELIST_DRAFT_PATH);
28195
+ const whitelistDraftPath = path94.join(cwd, WHITELIST_DRAFT_PATH);
28068
28196
  if (!opts.dryRun) {
28069
- await fs35.ensureDir(path93.dirname(whitelistDraftPath));
28197
+ await fs35.ensureDir(path94.dirname(whitelistDraftPath));
28070
28198
  const lines = ["version: 1", "repos:"];
28071
28199
  for (const repo of filteredRepos) {
28072
28200
  lines.push(` - url: ${repo.url}`);
@@ -28095,8 +28223,8 @@ async function importFromOrg(opts) {
28095
28223
  );
28096
28224
  try {
28097
28225
  const { rebuildWikiIndex: rebuildWikiIndex2 } = await Promise.resolve().then(() => (init_rebuild_wiki_index(), rebuild_wiki_index_exports));
28098
- const teamRepoPath = path93.join(cwd, ".teamai", "team-repo");
28099
- const teamRepoWiki = path93.join(teamRepoPath, "teamwiki");
28226
+ const teamRepoPath = path94.join(cwd, ".teamai", "team-repo");
28227
+ const teamRepoWiki = path94.join(teamRepoPath, "teamwiki");
28100
28228
  if (await fs35.pathExists(teamRepoWiki)) {
28101
28229
  await rebuildWikiIndex2(teamRepoWiki);
28102
28230
  log.info("teamwiki router.md / index.md rebuilt");
@@ -28128,10 +28256,10 @@ var init_import_org = __esm({
28128
28256
 
28129
28257
  // src/review-store.ts
28130
28258
  import crypto4 from "crypto";
28131
- import path94 from "path";
28259
+ import path95 from "path";
28132
28260
  import fs36 from "fs-extra";
28133
28261
  function getPendingReviewPath(cwd) {
28134
- return path94.join(cwd, PENDING_REVIEW_PATH);
28262
+ return path95.join(cwd, PENDING_REVIEW_PATH);
28135
28263
  }
28136
28264
  function computeReviewId(file, section, ts) {
28137
28265
  return crypto4.createHash("sha1").update(`${file}|${section ?? ""}|${ts}`).digest("hex").slice(0, 12);
@@ -28207,7 +28335,7 @@ async function loadPendingReview(cwd) {
28207
28335
  async function savePendingReview(cwd, items) {
28208
28336
  const filePath = getPendingReviewPath(cwd);
28209
28337
  const tmpPath = `${filePath}.tmp`;
28210
- await fs36.ensureDir(path94.dirname(filePath));
28338
+ await fs36.ensureDir(path95.dirname(filePath));
28211
28339
  const content = items.map((item) => JSON.stringify(item)).join("\n") + (items.length > 0 ? "\n" : "");
28212
28340
  await fs36.writeFile(tmpPath, content, "utf8");
28213
28341
  await fs36.rename(tmpPath, filePath);
@@ -28227,7 +28355,7 @@ async function appendPendingReview(cwd, partial) {
28227
28355
  risk
28228
28356
  };
28229
28357
  const filePath = getPendingReviewPath(cwd);
28230
- await fs36.ensureDir(path94.dirname(filePath));
28358
+ await fs36.ensureDir(path95.dirname(filePath));
28231
28359
  await fs36.appendFile(filePath, JSON.stringify(item) + "\n", "utf8");
28232
28360
  return item;
28233
28361
  }
@@ -28262,14 +28390,14 @@ var init_review_store = __esm({
28262
28390
  });
28263
28391
 
28264
28392
  // src/utils/team-codebase-paths.ts
28265
- import path95 from "path";
28393
+ import path96 from "path";
28266
28394
  function getTeamCodebasePaths(cwd, output) {
28267
- const root = output ?? path95.join(cwd, "docs", TEAM_CODEBASE_DIR);
28395
+ const root = output ?? path96.join(cwd, "docs", TEAM_CODEBASE_DIR);
28268
28396
  return {
28269
28397
  root,
28270
- index: path95.join(root, "index.md"),
28271
- domainsDir: path95.join(root, "domains"),
28272
- reposDir: path95.join(root, "repos")
28398
+ index: path96.join(root, "index.md"),
28399
+ domainsDir: path96.join(root, "domains"),
28400
+ reposDir: path96.join(root, "repos")
28273
28401
  };
28274
28402
  }
28275
28403
  var TEAM_CODEBASE_DIR;
@@ -28281,7 +28409,7 @@ var init_team_codebase_paths = __esm({
28281
28409
  });
28282
28410
 
28283
28411
  // src/iwiki-dual.ts
28284
- import path96 from "path";
28412
+ import path97 from "path";
28285
28413
  import fs37 from "fs-extra";
28286
28414
  function parseIWikiInput2(input) {
28287
28415
  const trimmed = input.trim();
@@ -28446,10 +28574,10 @@ async function importFromIWikiDual(opts) {
28446
28574
  return { sectionsUpdated: [], pendingReview: false };
28447
28575
  }
28448
28576
  const paths = getTeamCodebasePaths(cwd, opts.output);
28449
- const filePath = path96.join(paths.root, "external-knowledge.md");
28577
+ const filePath = path97.join(paths.root, "external-knowledge.md");
28450
28578
  if (opts.requireReview) {
28451
28579
  if (!opts.dryRun) {
28452
- const relativeFilePath = path96.relative(cwd, filePath);
28580
+ const relativeFilePath = path97.relative(cwd, filePath);
28453
28581
  for (const sectionKey of sections) {
28454
28582
  const body = aiOutput[sectionKey] ?? "";
28455
28583
  if (!body) continue;
@@ -28516,7 +28644,7 @@ var import_exports = {};
28516
28644
  __export(import_exports, {
28517
28645
  importCmd: () => importCmd
28518
28646
  });
28519
- import path97 from "path";
28647
+ import path98 from "path";
28520
28648
  import os6 from "os";
28521
28649
  import fs38 from "fs-extra";
28522
28650
  import { Listr, PRESET_TIMER } from "listr2";
@@ -28632,7 +28760,7 @@ async function importCmd(opts) {
28632
28760
  task: async (ctx) => {
28633
28761
  const { learning, repoUrl } = await importFromMR({
28634
28762
  url: opts.fromMr,
28635
- learningsDir: path97.join(localConfig.repo.localPath, "learnings"),
28763
+ learningsDir: path98.join(localConfig.repo.localPath, "learnings"),
28636
28764
  all: opts.all,
28637
28765
  outputDir: opts.output,
28638
28766
  repoPath: opts.dryRun ? void 0 : localConfig.repo.localPath,
@@ -28646,7 +28774,7 @@ async function importCmd(opts) {
28646
28774
  title: "Incremental teamwiki update",
28647
28775
  skip: (ctx) => !ctx.repoUrl || !!opts.dryRun || !!opts.output,
28648
28776
  task: async (ctx, task) => {
28649
- const teamwikiRoot = path97.join(localConfig.repo.localPath, "teamwiki");
28777
+ const teamwikiRoot = path98.join(localConfig.repo.localPath, "teamwiki");
28650
28778
  try {
28651
28779
  const { detectProvider: detectProvider2, getProvider: getProvider2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
28652
28780
  const { getRepoSlug: getRepoSlug2 } = await Promise.resolve().then(() => (init_repo_cache(), repo_cache_exports));
@@ -28654,7 +28782,7 @@ async function importCmd(opts) {
28654
28782
  const provider = getProvider2(providerName);
28655
28783
  const repoInfo = provider.parseRepoInput(ctx.repoUrl);
28656
28784
  const slug = getRepoSlug2(providerName, repoInfo.owner, repoInfo.repo);
28657
- const evidenceDir = path97.join(teamwikiRoot, "evidence", "code", slug);
28785
+ const evidenceDir = path98.join(teamwikiRoot, "evidence", "code", slug);
28658
28786
  if (await fs38.pathExists(evidenceDir)) {
28659
28787
  task.output = `Updating ${slug}...`;
28660
28788
  await importFromRepo({
@@ -28700,18 +28828,18 @@ async function importCmd(opts) {
28700
28828
  setSilent(false);
28701
28829
  }
28702
28830
  } else if (opts.dir) {
28703
- const dirPath = path97.resolve(opts.dir);
28831
+ const dirPath = path98.resolve(opts.dir);
28704
28832
  if (!await fs38.pathExists(dirPath)) {
28705
28833
  throw new Error(`Directory not found: ${dirPath}`);
28706
28834
  }
28707
- const slug = path97.basename(dirPath);
28835
+ const slug = path98.basename(dirPath);
28708
28836
  log.info(`Scanning local directory: ${dirPath} (project: ${slug})`);
28709
28837
  if (opts.dryRun) {
28710
28838
  log.info(`[dry-run] skipping code extraction, no action taken`);
28711
28839
  log.success(`Local directory ${slug} import complete (dry-run)`);
28712
28840
  return;
28713
28841
  }
28714
- const tmpExtractDir = await fs38.mkdtemp(path97.join(os6.tmpdir(), "teamai-extract-"));
28842
+ const tmpExtractDir = await fs38.mkdtemp(path98.join(os6.tmpdir(), "teamai-extract-"));
28715
28843
  try {
28716
28844
  const { extractCodebase: extractCodebase2 } = await Promise.resolve().then(() => (init_codebase_extract(), codebase_extract_exports));
28717
28845
  await extractCodebase2({
@@ -28721,9 +28849,9 @@ async function importCmd(opts) {
28721
28849
  skipEnrich: opts.skipEnrich ?? false,
28722
28850
  outputRoot: tmpExtractDir
28723
28851
  });
28724
- const srcWiki = path97.join(tmpExtractDir, "teamwiki");
28852
+ const srcWiki = path98.join(tmpExtractDir, "teamwiki");
28725
28853
  if (opts.output) {
28726
- const outputWiki = path97.join(opts.output, "teamwiki");
28854
+ const outputWiki = path98.join(opts.output, "teamwiki");
28727
28855
  if (await fs38.pathExists(srcWiki)) {
28728
28856
  await fs38.copy(srcWiki, outputWiki, { overwrite: true });
28729
28857
  log.info(`Output written: ${outputWiki}`);
@@ -28731,19 +28859,19 @@ async function importCmd(opts) {
28731
28859
  } else {
28732
28860
  const { localConfig } = await autoDetectInit();
28733
28861
  const teamRepoPath = localConfig.repo.localPath;
28734
- const teamwikiRoot = path97.join(teamRepoPath, "teamwiki");
28862
+ const teamwikiRoot = path98.join(teamRepoPath, "teamwiki");
28735
28863
  if (await fs38.pathExists(srcWiki)) {
28736
- const evidenceSrc = path97.join(srcWiki, "evidence", "code", slug);
28737
- const evidenceDest = path97.join(teamwikiRoot, "evidence", "code", slug);
28864
+ const evidenceSrc = path98.join(srcWiki, "evidence", "code", slug);
28865
+ const evidenceDest = path98.join(teamwikiRoot, "evidence", "code", slug);
28738
28866
  if (await fs38.pathExists(evidenceSrc)) {
28739
- await fs38.ensureDir(path97.dirname(evidenceDest));
28867
+ await fs38.ensureDir(path98.dirname(evidenceDest));
28740
28868
  await fs38.copy(evidenceSrc, evidenceDest, { overwrite: true });
28741
28869
  }
28742
- const srcGraph = path97.join(srcWiki, ".indices", "graph-index.json");
28870
+ const srcGraph = path98.join(srcWiki, ".indices", "graph-index.json");
28743
28871
  if (await fs38.pathExists(srcGraph)) {
28744
- const destGraphDir = path97.join(evidenceDest, ".indices");
28872
+ const destGraphDir = path98.join(evidenceDest, ".indices");
28745
28873
  await fs38.ensureDir(destGraphDir);
28746
- await fs38.copy(srcGraph, path97.join(destGraphDir, "graph-index.json"), { overwrite: true });
28874
+ await fs38.copy(srcGraph, path98.join(destGraphDir, "graph-index.json"), { overwrite: true });
28747
28875
  }
28748
28876
  log.info(`teamwiki/ knowledge graph updated: ${slug}`);
28749
28877
  }
@@ -28804,11 +28932,11 @@ __export(codebase_upgrade_wiki_exports, {
28804
28932
  upgradeCodebaseWiki: () => upgradeCodebaseWiki
28805
28933
  });
28806
28934
  import { readdir as readdir7, readFile as readFile11 } from "fs/promises";
28807
- import path98 from "path";
28935
+ import path99 from "path";
28808
28936
  import chalk5 from "chalk";
28809
28937
  import matter9 from "gray-matter";
28810
28938
  async function upgradeCodebaseWiki(opts) {
28811
- const teamCodebaseDir = path98.join(opts.cwd, "docs", "team-codebase", "repos");
28939
+ const teamCodebaseDir = path99.join(opts.cwd, "docs", "team-codebase", "repos");
28812
28940
  if (!await pathExists(teamCodebaseDir)) {
28813
28941
  if (opts.json) {
28814
28942
  console.log(JSON.stringify({ status: "nothing-to-migrate", reason: "docs/team-codebase/repos/ not found" }));
@@ -28833,7 +28961,7 @@ async function upgradeCodebaseWiki(opts) {
28833
28961
  const result = { migrated: [], skipped: [], errors: [] };
28834
28962
  for (const file of mdFiles) {
28835
28963
  const slug = file.replace(".md", "");
28836
- const filePath = path98.join(teamCodebaseDir, file);
28964
+ const filePath = path99.join(teamCodebaseDir, file);
28837
28965
  try {
28838
28966
  const content = await readFile11(filePath, "utf-8");
28839
28967
  const parsed = matter9(content);
@@ -28846,9 +28974,9 @@ async function upgradeCodebaseWiki(opts) {
28846
28974
  result.migrated.push(`${slug} \u2192 teamwiki/evidence/code/${slug}/`);
28847
28975
  continue;
28848
28976
  }
28849
- const cacheBase = path98.join(process.env["HOME"] ?? "", ".teamai", "cache", "repos");
28977
+ const cacheBase = path99.join(process.env["HOME"] ?? "", ".teamai", "cache", "repos");
28850
28978
  const urlParts = String(source).replace(/^https?:\/\//, "").replace(/@.*$/, "").split("/");
28851
- const cachePath = path98.join(cacheBase, ...urlParts.slice(0, 3));
28979
+ const cachePath = path99.join(cacheBase, ...urlParts.slice(0, 3));
28852
28980
  if (await pathExists(cachePath)) {
28853
28981
  await extractCodebase({ path: cachePath, project: slug });
28854
28982
  result.migrated.push(slug);
@@ -28903,10 +29031,10 @@ __export(codebase_wiki_lint_exports, {
28903
29031
  lintTeamwiki: () => lintTeamwiki
28904
29032
  });
28905
29033
  import { readFile as readFile12, readdir as readdir8, stat as stat5 } from "fs/promises";
28906
- import path99 from "path";
29034
+ import path100 from "path";
28907
29035
  import chalk6 from "chalk";
28908
29036
  async function lintTeamwiki(opts) {
28909
- const wikiRoot = opts.wikiRoot ?? path99.join(opts.cwd ?? process.cwd(), "teamwiki");
29037
+ const wikiRoot = opts.wikiRoot ?? path100.join(opts.cwd ?? process.cwd(), "teamwiki");
28910
29038
  const issues = [];
28911
29039
  const minSeverity = opts.severity ?? "info";
28912
29040
  const severityOrder = ["info", "low", "medium", "high"];
@@ -28916,7 +29044,7 @@ async function lintTeamwiki(opts) {
28916
29044
  issues.push(issue);
28917
29045
  }
28918
29046
  }
28919
- const graphPath = path99.join(wikiRoot, ".indices", "graph-index.json");
29047
+ const graphPath = path100.join(wikiRoot, ".indices", "graph-index.json");
28920
29048
  let graph = null;
28921
29049
  if (!await pathExists(graphPath)) {
28922
29050
  addIssue({
@@ -28938,7 +29066,7 @@ async function lintTeamwiki(opts) {
28938
29066
  });
28939
29067
  }
28940
29068
  }
28941
- const evidenceDir = path99.join(wikiRoot, "evidence", "code");
29069
+ const evidenceDir = path100.join(wikiRoot, "evidence", "code");
28942
29070
  if (!await pathExists(evidenceDir)) {
28943
29071
  addIssue({
28944
29072
  severity: "high",
@@ -28957,7 +29085,7 @@ async function lintTeamwiki(opts) {
28957
29085
  });
28958
29086
  }
28959
29087
  for (const project of projects) {
28960
- const projectDir = path99.join(evidenceDir, project);
29088
+ const projectDir = path100.join(evidenceDir, project);
28961
29089
  const pStat = await stat5(projectDir).catch(() => null);
28962
29090
  if (!pStat?.isDirectory()) {
28963
29091
  if (!pStat) {
@@ -28977,7 +29105,7 @@ async function lintTeamwiki(opts) {
28977
29105
  }
28978
29106
  }
28979
29107
  for (const navFile of ["router.md", "index.md", "hot.md"]) {
28980
- if (!await pathExists(path99.join(wikiRoot, navFile))) {
29108
+ if (!await pathExists(path100.join(wikiRoot, navFile))) {
28981
29109
  addIssue({
28982
29110
  severity: "low",
28983
29111
  category: "nav-missing",
@@ -28986,7 +29114,7 @@ async function lintTeamwiki(opts) {
28986
29114
  });
28987
29115
  }
28988
29116
  }
28989
- const manifestPath = path99.join(wikiRoot, "source-manifest.json");
29117
+ const manifestPath = path100.join(wikiRoot, "source-manifest.json");
28990
29118
  if (!await pathExists(manifestPath)) {
28991
29119
  addIssue({
28992
29120
  severity: "low",
@@ -29102,7 +29230,7 @@ var codebase_cmd_exports = {};
29102
29230
  __export(codebase_cmd_exports, {
29103
29231
  codebaseCmd: () => codebaseCmd
29104
29232
  });
29105
- import path100 from "path";
29233
+ import path101 from "path";
29106
29234
  import { readFile as readFile13 } from "fs/promises";
29107
29235
  import chalk7 from "chalk";
29108
29236
  async function codebaseCmd(opts) {
@@ -29143,14 +29271,14 @@ async function codebaseCmd(opts) {
29143
29271
  const { pathExists: pathExists3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
29144
29272
  let teamwikiDir;
29145
29273
  if (opts.output) {
29146
- teamwikiDir = path100.resolve(opts.output, "teamwiki");
29274
+ teamwikiDir = path101.resolve(opts.output, "teamwiki");
29147
29275
  } else {
29148
29276
  try {
29149
29277
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
29150
29278
  const { localConfig: lc } = await autoDetectInit2();
29151
- teamwikiDir = path100.join(lc.repo.localPath, "teamwiki");
29279
+ teamwikiDir = path101.join(lc.repo.localPath, "teamwiki");
29152
29280
  } catch {
29153
- teamwikiDir = path100.join(cwd, ".teamai", "team-repo", "teamwiki");
29281
+ teamwikiDir = path101.join(cwd, ".teamai", "team-repo", "teamwiki");
29154
29282
  }
29155
29283
  }
29156
29284
  if (!await pathExists3(teamwikiDir)) {
@@ -29173,17 +29301,17 @@ async function printCodebaseStatus(opts) {
29173
29301
  const cwd = process.cwd();
29174
29302
  let teamwikiDir;
29175
29303
  if (opts.output) {
29176
- teamwikiDir = path100.resolve(opts.output, "teamwiki");
29304
+ teamwikiDir = path101.resolve(opts.output, "teamwiki");
29177
29305
  } else {
29178
29306
  try {
29179
29307
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
29180
29308
  const { localConfig: lc } = await autoDetectInit2();
29181
- teamwikiDir = path100.join(lc.repo.localPath, "teamwiki");
29309
+ teamwikiDir = path101.join(lc.repo.localPath, "teamwiki");
29182
29310
  } catch {
29183
- teamwikiDir = path100.join(cwd, ".teamai", "team-repo", "teamwiki");
29311
+ teamwikiDir = path101.join(cwd, ".teamai", "team-repo", "teamwiki");
29184
29312
  }
29185
29313
  }
29186
- const manifestPath = path100.join(teamwikiDir, "source-manifest.json");
29314
+ const manifestPath = path101.join(teamwikiDir, "source-manifest.json");
29187
29315
  let manifest;
29188
29316
  try {
29189
29317
  manifest = JSON.parse(await readFile13(manifestPath, "utf-8"));
@@ -29280,7 +29408,7 @@ var review_cmd_exports = {};
29280
29408
  __export(review_cmd_exports, {
29281
29409
  reviewCmd: () => reviewCmd
29282
29410
  });
29283
- import path101 from "path";
29411
+ import path102 from "path";
29284
29412
  import chalk8 from "chalk";
29285
29413
  import fs39 from "fs-extra";
29286
29414
  function riskAtMost(itemRisk, ceiling) {
@@ -29356,7 +29484,7 @@ async function applyOne(cwd, item) {
29356
29484
  if (!section) {
29357
29485
  return { ok: false, reason: "target.section \u7F3A\u5931" };
29358
29486
  }
29359
- const filePath = path101.isAbsolute(file) ? file : path101.join(cwd, file);
29487
+ const filePath = path102.isAbsolute(file) ? file : path102.join(cwd, file);
29360
29488
  if (!await fs39.pathExists(filePath)) {
29361
29489
  return { ok: false, reason: `\u76EE\u6807\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${filePath}` };
29362
29490
  }
@@ -29513,10 +29641,10 @@ function formatComment(learning, suggestions, marker) {
29513
29641
  lines.push("> _Auto-generated by `teamai ci extract-mr`_");
29514
29642
  return lines.join("\n");
29515
29643
  }
29516
- async function githubRequest(path106, method, body) {
29644
+ async function githubRequest(path107, method, body) {
29517
29645
  const token = process.env["GITHUB_TOKEN"];
29518
29646
  if (!token) throw new Error("\u672A\u8BBE\u7F6E GITHUB_TOKEN \u73AF\u5883\u53D8\u91CF");
29519
- const url = `https://api.github.com${path106}`;
29647
+ const url = `https://api.github.com${path107}`;
29520
29648
  const headers = {
29521
29649
  Authorization: `Bearer ${token}`,
29522
29650
  Accept: "application/vnd.github+json",
@@ -29565,8 +29693,8 @@ async function updateGitHubComment(owner, repo, commentId, body) {
29565
29693
  const data = await resp.json();
29566
29694
  return { created: false, url: data.html_url };
29567
29695
  }
29568
- async function tgitRequest(path106, method, body) {
29569
- return tgitFetch(path106, {
29696
+ async function tgitRequest(path107, method, body) {
29697
+ return tgitFetch(path107, {
29570
29698
  method,
29571
29699
  body: body ? JSON.stringify(body) : void 0
29572
29700
  });
@@ -29849,10 +29977,10 @@ function extractMarkerId(body) {
29849
29977
  const match = body.match(MARKER_REGEX);
29850
29978
  return match ? match[1] : null;
29851
29979
  }
29852
- async function githubRequest2(path106) {
29980
+ async function githubRequest2(path107) {
29853
29981
  const token = process.env["GITHUB_TOKEN"];
29854
29982
  if (!token) throw new Error("\u672A\u8BBE\u7F6E GITHUB_TOKEN");
29855
- return fetch(`https://api.github.com${path106}`, {
29983
+ return fetch(`https://api.github.com${path107}`, {
29856
29984
  headers: {
29857
29985
  Authorization: `Bearer ${token}`,
29858
29986
  Accept: "application/vnd.github+json",
@@ -29887,8 +30015,8 @@ async function readGitHubRejections(owner, repo, prNumber) {
29887
30015
  }
29888
30016
  return result;
29889
30017
  }
29890
- async function tgitRequest2(path106) {
29891
- return tgitFetch(path106);
30018
+ async function tgitRequest2(path107) {
30019
+ return tgitFetch(path107);
29892
30020
  }
29893
30021
  async function getMrGlobalId2(projectId, mrIid) {
29894
30022
  const resp = await tgitRequest2(`/projects/${projectId}/merge_requests?iid=${mrIid}`);
@@ -29949,7 +30077,7 @@ __export(extract_mr_exports, {
29949
30077
  ciExtractMr: () => ciExtractMr
29950
30078
  });
29951
30079
  import fs40 from "fs/promises";
29952
- import path102 from "path";
30080
+ import path103 from "path";
29953
30081
  async function configureGitUser2(repoPath, provider) {
29954
30082
  const { execFileSync: execFileSync4 } = await import("child_process");
29955
30083
  let name = "teamai-ci";
@@ -29996,8 +30124,8 @@ async function writeKnowledgeToRepo(teamRepo, learning, suggestions, writeMode,
29996
30124
  const safeTitle = learning.title.replace(/[^a-zA-Z0-9一-鿿_-]/g, "-").replace(/-+/g, "-").slice(0, 50);
29997
30125
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
29998
30126
  const filename = `${dateStr}-${safeTitle}.md`;
29999
- const learningsDir = path102.join(teamRepo, "learnings");
30000
- const learningPath = path102.join(learningsDir, filename);
30127
+ const learningsDir = path103.join(teamRepo, "learnings");
30128
+ const learningPath = path103.join(learningsDir, filename);
30001
30129
  if (!dryRun) {
30002
30130
  await fs40.mkdir(learningsDir, { recursive: true });
30003
30131
  await fs40.writeFile(learningPath, learning.content, "utf-8");
@@ -30037,11 +30165,11 @@ async function writeKnowledgeToRepo(teamRepo, learning, suggestions, writeMode,
30037
30165
  async function writeArtifacts(outputDir, learning, suggestions) {
30038
30166
  await fs40.mkdir(outputDir, { recursive: true });
30039
30167
  if (learning) {
30040
- await fs40.writeFile(path102.join(outputDir, "learning.md"), learning.content, "utf-8");
30168
+ await fs40.writeFile(path103.join(outputDir, "learning.md"), learning.content, "utf-8");
30041
30169
  }
30042
30170
  if (suggestions && suggestions.length > 0) {
30043
30171
  await fs40.writeFile(
30044
- path102.join(outputDir, "codebase-suggestions.json"),
30172
+ path103.join(outputDir, "codebase-suggestions.json"),
30045
30173
  JSON.stringify(suggestions, null, 2),
30046
30174
  "utf-8"
30047
30175
  );
@@ -30055,7 +30183,7 @@ async function ciExtractMr(opts) {
30055
30183
  const result = await importFromMR({
30056
30184
  url: opts.url,
30057
30185
  all: true,
30058
- learningsDir: opts.teamRepo ? path102.join(opts.teamRepo, "learnings") : void 0,
30186
+ learningsDir: opts.teamRepo ? path103.join(opts.teamRepo, "learnings") : void 0,
30059
30187
  dryRun: true
30060
30188
  // 不让 importFromMR 自己写文件,我们自己控制写入
30061
30189
  });
@@ -30164,21 +30292,21 @@ ${affectedModules.map((m) => `- \`${m}\` (evidence + G-document)`).join("\n")}`
30164
30292
  const projectName = parsed.repo;
30165
30293
  await extractCodebase2({ path: businessRepo, project: projectName });
30166
30294
  const fse12 = await import("fs-extra");
30167
- const srcWiki = path102.join(businessRepo, "teamwiki");
30168
- const teamWikiRoot = path102.join(path102.resolve(opts.teamRepo), "teamwiki");
30295
+ const srcWiki = path103.join(businessRepo, "teamwiki");
30296
+ const teamWikiRoot = path103.join(path103.resolve(opts.teamRepo), "teamwiki");
30169
30297
  try {
30170
30298
  if (await fse12.pathExists(srcWiki)) {
30171
- const evidenceSrc = path102.join(srcWiki, "evidence", "code", projectName);
30172
- const evidenceDest = path102.join(teamWikiRoot, "evidence", "code", projectName);
30299
+ const evidenceSrc = path103.join(srcWiki, "evidence", "code", projectName);
30300
+ const evidenceDest = path103.join(teamWikiRoot, "evidence", "code", projectName);
30173
30301
  if (await fse12.pathExists(evidenceSrc)) {
30174
30302
  await fse12.ensureDir(evidenceDest);
30175
30303
  await fse12.copy(evidenceSrc, evidenceDest, { overwrite: true });
30176
30304
  }
30177
- const srcGraph = path102.join(srcWiki, ".indices", "graph-index.json");
30305
+ const srcGraph = path103.join(srcWiki, ".indices", "graph-index.json");
30178
30306
  if (await fse12.pathExists(srcGraph)) {
30179
- const destGraphDir = path102.join(evidenceDest, ".indices");
30307
+ const destGraphDir = path103.join(evidenceDest, ".indices");
30180
30308
  await fse12.ensureDir(destGraphDir);
30181
- await fse12.copy(srcGraph, path102.join(destGraphDir, "graph-index.json"));
30309
+ await fse12.copy(srcGraph, path103.join(destGraphDir, "graph-index.json"));
30182
30310
  }
30183
30311
  const { aggregateGlobalGraph: aggregateGlobalGraph2 } = await Promise.resolve().then(() => (init_graph_aggregate(), graph_aggregate_exports));
30184
30312
  await aggregateGlobalGraph2(teamWikiRoot);
@@ -30235,7 +30363,7 @@ var init_extract_mr = __esm({
30235
30363
  });
30236
30364
 
30237
30365
  // src/maintenance/prune.ts
30238
- import path103 from "path";
30366
+ import path104 from "path";
30239
30367
  import matter10 from "gray-matter";
30240
30368
  async function findPruneCandidates(learningsDir, votesDir, options = {}) {
30241
30369
  const threshold = options.threshold ?? DEFAULT_THRESHOLD;
@@ -30246,7 +30374,7 @@ async function findPruneCandidates(learningsDir, votesDir, options = {}) {
30246
30374
  for (const file of files) {
30247
30375
  if (!file.endsWith(".md")) continue;
30248
30376
  const docId = file.replace(/\.md$/i, "");
30249
- const absPath = path103.join(learningsDir, file);
30377
+ const absPath = path104.join(learningsDir, file);
30250
30378
  const content = await readFileSafe(absPath);
30251
30379
  if (!content) continue;
30252
30380
  let date = "";
@@ -30288,9 +30416,9 @@ async function executePrune(repoPath, candidates, options = {}) {
30288
30416
  }
30289
30417
  for (const candidate of candidates) {
30290
30418
  if (options.archive) {
30291
- const archiveDir = path103.join(repoPath, "learnings", "_archive");
30419
+ const archiveDir = path104.join(repoPath, "learnings", "_archive");
30292
30420
  await ensureDir(archiveDir);
30293
- await copyFile(candidate.path, path103.join(archiveDir, candidate.filename));
30421
+ await copyFile(candidate.path, path104.join(archiveDir, candidate.filename));
30294
30422
  await remove(candidate.path);
30295
30423
  archived++;
30296
30424
  } else {
@@ -30315,7 +30443,7 @@ var init_prune = __esm({
30315
30443
  });
30316
30444
 
30317
30445
  // src/maintenance/quality-update.ts
30318
- import path104 from "path";
30446
+ import path105 from "path";
30319
30447
  async function findStaleEntries(votesDir, knowledgeDirs, options = {}) {
30320
30448
  const minRecalled = options.minRecalled ?? DEFAULT_MIN_RECALLED;
30321
30449
  const maxUpvoted = options.maxUpvoted ?? DEFAULT_MAX_UPVOTED;
@@ -30325,7 +30453,7 @@ async function findStaleEntries(votesDir, knowledgeDirs, options = {}) {
30325
30453
  for (const file of voteFiles) {
30326
30454
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
30327
30455
  const username = file.replace(/\.(yaml|yml)$/, "");
30328
- const filePath = path104.join(votesDir, file);
30456
+ const filePath = path105.join(votesDir, file);
30329
30457
  try {
30330
30458
  const data = await loadUserVotes(filePath);
30331
30459
  for (const [docId, entry] of Object.entries(data.votes)) {
@@ -30362,7 +30490,7 @@ async function resolveDocPath(docId, dirs) {
30362
30490
  const filename = docId.endsWith(".md") ? docId : `${docId}.md`;
30363
30491
  for (const dir of [dirs.docs, dirs.rules, dirs.skills]) {
30364
30492
  if (!dir) continue;
30365
- const candidate = path104.join(dir, filename);
30493
+ const candidate = path105.join(dir, filename);
30366
30494
  if (await pathExists(candidate)) return candidate;
30367
30495
  }
30368
30496
  return null;
@@ -30385,7 +30513,7 @@ async function findRelatedAdoptedLearnings(staleEntry, votesDir, learningsDir, l
30385
30513
  for (const file of voteFiles) {
30386
30514
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
30387
30515
  try {
30388
- const data = await loadUserVotes(path104.join(votesDir, file));
30516
+ const data = await loadUserVotes(path105.join(votesDir, file));
30389
30517
  for (const [docId, entry] of Object.entries(data.votes)) {
30390
30518
  if (docId === staleEntry.docId) continue;
30391
30519
  if ((entry.upvoted_count ?? 0) > 0) {
@@ -30400,7 +30528,7 @@ async function findRelatedAdoptedLearnings(staleEntry, votesDir, learningsDir, l
30400
30528
  const contents = [];
30401
30529
  for (const [docId] of sorted) {
30402
30530
  const filename = docId.endsWith(".md") ? docId : `${docId}.md`;
30403
- const filePath = path104.join(learningsDir, filename);
30531
+ const filePath = path105.join(learningsDir, filename);
30404
30532
  const content = await readFileSafe(filePath);
30405
30533
  if (content) contents.push(content);
30406
30534
  }
@@ -30456,7 +30584,7 @@ var init_quality_update = __esm({
30456
30584
  });
30457
30585
 
30458
30586
  // src/maintenance/promote.ts
30459
- import path105 from "path";
30587
+ import path106 from "path";
30460
30588
  import matter11 from "gray-matter";
30461
30589
  async function findPromotionCandidates(learningsDir, votesDir) {
30462
30590
  const confidenceMap = await computeAllConfidence(votesDir);
@@ -30473,7 +30601,7 @@ async function findPromotionCandidates(learningsDir, votesDir) {
30473
30601
  if (!docVotes) continue;
30474
30602
  if (docVotes.upvoted < MIN_UPVOTED) continue;
30475
30603
  if (docVotes.users.size < MIN_USERS) continue;
30476
- const absPath = path105.join(learningsDir, file);
30604
+ const absPath = path106.join(learningsDir, file);
30477
30605
  const content = await readFileSafe(absPath);
30478
30606
  if (!content) continue;
30479
30607
  let title = docId;
@@ -30545,9 +30673,9 @@ Output ONLY the transformed markdown content (including YAML frontmatter with ti
30545
30673
  }
30546
30674
  async function executePromotion(candidate, repoPath, options = {}) {
30547
30675
  const category = options.category ?? candidate.suggestedCategory;
30548
- const targetDir = path105.join(repoPath, category);
30676
+ const targetDir = path106.join(repoPath, category);
30549
30677
  await ensureDir(targetDir);
30550
- const targetPath = path105.join(targetDir, candidate.filename);
30678
+ const targetPath = path106.join(targetDir, candidate.filename);
30551
30679
  if (options.dryRun) {
30552
30680
  log.info(`[dry-run] Would promote ${candidate.docId} -> ${category}/${candidate.filename}`);
30553
30681
  return targetPath;
@@ -30609,7 +30737,7 @@ async function aggregatePerDocVotes(votesDir) {
30609
30737
  for (const file of voteFiles) {
30610
30738
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
30611
30739
  const username = file.replace(/\.(yaml|yml)$/, "");
30612
- const filePath = path105.join(votesDir, file);
30740
+ const filePath = path106.join(votesDir, file);
30613
30741
  try {
30614
30742
  const data = await loadUserVotes2(filePath);
30615
30743
  for (const [docId, entry] of Object.entries(data.votes)) {