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

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 +769 -632
  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);
@@ -9634,11 +9655,18 @@ async function pushCore(localConfig, teamConfig, options) {
9634
9655
  log.debug(`Pre-push sync skipped: ${e.message}`);
9635
9656
  }
9636
9657
  const spin = spinner("Scanning local resources...").start();
9658
+ const scanTeamConfig = selfMode ? {
9659
+ ...teamConfig,
9660
+ toolPaths: {
9661
+ ...teamConfig.toolPaths,
9662
+ [SELF_KNOWLEDGE_SCAN_KEY]: { skills: ".teamai/skills", rules: ".teamai/rules" }
9663
+ }
9664
+ } : teamConfig;
9637
9665
  const pushableTypes = ["skills", "rules", "env", "agents"];
9638
9666
  const allItems = [];
9639
9667
  for (const type of pushableTypes) {
9640
9668
  const handler = getHandler(type);
9641
- const items = await handler.scanLocalForPush(teamConfig, localConfig);
9669
+ const items = await handler.scanLocalForPush(scanTeamConfig, localConfig);
9642
9670
  allItems.push(...items);
9643
9671
  }
9644
9672
  spin.stop();
@@ -9912,6 +9940,7 @@ ${selectedItems.map((i) => `- [${i.type}] ${i.name}`).join("\n")}`
9912
9940
  }
9913
9941
  await saveStateForScope(state, localConfig.scope, localConfig.projectRoot);
9914
9942
  }
9943
+ var SELF_KNOWLEDGE_SCAN_KEY;
9915
9944
  var init_push = __esm({
9916
9945
  "src/push.ts"() {
9917
9946
  "use strict";
@@ -9927,6 +9956,7 @@ var init_push = __esm({
9927
9956
  init_roles();
9928
9957
  init_prompt();
9929
9958
  init_fs();
9959
+ SELF_KNOWLEDGE_SCAN_KEY = "__teamai_self_knowledge__";
9930
9960
  }
9931
9961
  });
9932
9962
 
@@ -9936,6 +9966,7 @@ __export(git_exports, {
9936
9966
  autoPushTeamRepo: () => autoPushTeamRepo,
9937
9967
  autoPushViaMR: () => autoPushViaMR,
9938
9968
  checkoutMaster: () => checkoutMaster,
9969
+ commitPaths: () => commitPaths,
9939
9970
  configureGitUser: () => configureGitUser,
9940
9971
  createGit: () => createGit2,
9941
9972
  generateBranchName: () => generateBranchName,
@@ -9944,6 +9975,7 @@ __export(git_exports, {
9944
9975
  getHeadRev: () => getHeadRev,
9945
9976
  getRemoteUrl: () => getRemoteUrl,
9946
9977
  getRepoStatus: () => getRepoStatus,
9978
+ hasCommits: () => hasCommits,
9947
9979
  initRepo: () => initRepo,
9948
9980
  isGitRepo: () => isGitRepo,
9949
9981
  isMetadataOnlyDiff: () => isMetadataOnlyDiff,
@@ -9999,6 +10031,33 @@ async function getRemoteUrl(localPath, remoteName = "origin") {
9999
10031
  return null;
10000
10032
  }
10001
10033
  }
10034
+ async function hasCommits(localPath) {
10035
+ const git = createGit2(localPath);
10036
+ try {
10037
+ const out = (await git.raw(["rev-parse", "--verify", "HEAD^{commit}"])).trim();
10038
+ return /^[0-9a-f]{7,40}$/.test(out);
10039
+ } catch {
10040
+ return false;
10041
+ }
10042
+ }
10043
+ async function commitPaths(localPath, message, files) {
10044
+ const git = createGit2(localPath);
10045
+ const existing = files.filter((f) => fs12.existsSync(path33.join(localPath, f)));
10046
+ if (existing.length === 0) return false;
10047
+ let added = 0;
10048
+ for (const f of existing) {
10049
+ try {
10050
+ await git.add(["--", f]);
10051
+ added++;
10052
+ } catch {
10053
+ }
10054
+ }
10055
+ if (added === 0) return false;
10056
+ const status2 = await git.status();
10057
+ if (status2.staged.length === 0) return false;
10058
+ await git.commit(message);
10059
+ return true;
10060
+ }
10002
10061
  async function pullRepo(localPath) {
10003
10062
  const git = createGit2(localPath);
10004
10063
  const result = await git.pull();
@@ -10209,15 +10268,127 @@ var init_git = __esm({
10209
10268
  }
10210
10269
  });
10211
10270
 
10271
+ // src/known-agents.ts
10272
+ var known_agents_exports = {};
10273
+ __export(known_agents_exports, {
10274
+ KNOWN_AGENTS: () => KNOWN_AGENTS,
10275
+ detectInstalledAgents: () => detectInstalledAgents,
10276
+ getEffectiveAgents: () => getEffectiveAgents,
10277
+ seedSelfModeToolDirs: () => seedSelfModeToolDirs
10278
+ });
10279
+ import path34 from "path";
10280
+ async function seedSelfModeToolDirs(localConfig, teamConfig) {
10281
+ const baseDir = resolveBaseDir(localConfig);
10282
+ const configured = teamConfig.toolPaths ?? {};
10283
+ let targets = localConfig.enabledAgents && localConfig.enabledAgents.length > 0 ? localConfig.enabledAgents : ["claude"];
10284
+ targets = targets.filter((id) => !isAgentDisabled(localConfig, id));
10285
+ const seeded = [];
10286
+ for (const id of targets) {
10287
+ const skillsPath = configured[id]?.skills ?? KNOWN_AGENTS.find((a) => a.id === id)?.skillsPath;
10288
+ if (!skillsPath) continue;
10289
+ await ensureDir(path34.join(baseDir, skillsPath));
10290
+ seeded.push(id);
10291
+ }
10292
+ return seeded;
10293
+ }
10294
+ function getEffectiveAgents(teamConfig) {
10295
+ const byId = /* @__PURE__ */ new Map();
10296
+ for (const agent of KNOWN_AGENTS) {
10297
+ byId.set(agent.id, { ...agent });
10298
+ }
10299
+ for (const [id, paths] of Object.entries(teamConfig.toolPaths)) {
10300
+ if (!paths.skills) continue;
10301
+ const existing = byId.get(id);
10302
+ if (existing) {
10303
+ byId.set(id, { ...existing, skillsPath: paths.skills, fromTeamConfig: true });
10304
+ } else {
10305
+ byId.set(id, {
10306
+ id,
10307
+ displayName: id,
10308
+ category: "coding",
10309
+ skillsPath: paths.skills,
10310
+ fromTeamConfig: true
10311
+ });
10312
+ }
10313
+ }
10314
+ return [...byId.values()];
10315
+ }
10316
+ async function detectInstalledAgents(localConfig, teamConfig) {
10317
+ const baseDir = resolveBaseDir(localConfig);
10318
+ const agents = getEffectiveAgents(teamConfig);
10319
+ const fromTeamConfig = new Set(
10320
+ Object.entries(teamConfig.toolPaths).filter(([, paths]) => paths.skills).map(([id]) => id)
10321
+ );
10322
+ const results = [];
10323
+ for (const agent of agents) {
10324
+ const segments = agent.skillsPath.split("/");
10325
+ const rootSegment = segments[0] ?? "";
10326
+ const rootPath = `${baseDir}/${rootSegment}`;
10327
+ const installed = rootSegment ? await pathExists(rootPath) : false;
10328
+ results.push({
10329
+ ...agent,
10330
+ absoluteSkillsPath: `${baseDir}/${agent.skillsPath}`,
10331
+ installed,
10332
+ fromTeamConfig: fromTeamConfig.has(agent.id)
10333
+ });
10334
+ }
10335
+ return results;
10336
+ }
10337
+ var KNOWN_AGENTS;
10338
+ var init_known_agents = __esm({
10339
+ "src/known-agents.ts"() {
10340
+ "use strict";
10341
+ init_fs();
10342
+ init_types();
10343
+ KNOWN_AGENTS = [
10344
+ // Coding agents already wired through teamConfig.toolPaths defaults
10345
+ { id: "claude", displayName: "Claude Code", category: "coding", skillsPath: ".claude/skills" },
10346
+ { id: "claude-internal", displayName: "Claude Code Internal", category: "coding", skillsPath: ".claude-internal/skills" },
10347
+ { id: "tclaude", displayName: "TClaude", category: "coding", skillsPath: ".tclaude/skills" },
10348
+ { id: "codex", displayName: "Codex CLI", category: "coding", skillsPath: ".codex/skills" },
10349
+ { id: "codex-internal", displayName: "Codex CLI Internal", category: "coding", skillsPath: ".codex-internal/skills" },
10350
+ { id: "tcodex", displayName: "TCodex", category: "coding", skillsPath: ".tcodex/skills" },
10351
+ { id: "cursor", displayName: "Cursor", category: "coding", skillsPath: ".cursor/skills" },
10352
+ { id: "codebuddy", displayName: "CodeBuddy", category: "coding", skillsPath: ".codebuddy/skills" },
10353
+ // Additional coding agents from skills-manage
10354
+ { id: "gemini", displayName: "Gemini CLI", category: "coding", skillsPath: ".gemini/skills" },
10355
+ { id: "aider", displayName: "Aider", category: "coding", skillsPath: ".aider/skills" },
10356
+ { id: "amp", displayName: "Amp", category: "coding", skillsPath: ".amp/skills" },
10357
+ { id: "augment", displayName: "Augment", category: "coding", skillsPath: ".augment/skills" },
10358
+ { id: "copilot", displayName: "Copilot", category: "coding", skillsPath: ".copilot/skills" },
10359
+ { id: "factory", displayName: "Factory Droid", category: "coding", skillsPath: ".factory/skills" },
10360
+ { id: "hermes", displayName: "Hermes", category: "coding", skillsPath: ".hermes/skills" },
10361
+ { id: "junie", displayName: "Junie", category: "coding", skillsPath: ".junie/skills" },
10362
+ { id: "kilocode", displayName: "KiloCode", category: "coding", skillsPath: ".kilocode/skills" },
10363
+ { id: "kiro", displayName: "Kiro", category: "coding", skillsPath: ".kiro/skills" },
10364
+ { id: "ob1", displayName: "OB1", category: "coding", skillsPath: ".ob1/skills" },
10365
+ { id: "opencode", displayName: "OpenCode", category: "coding", skillsPath: ".opencode/skills" },
10366
+ { id: "qoder", displayName: "Qoder", category: "coding", skillsPath: ".qoder/skills" },
10367
+ { id: "qwen", displayName: "Qwen", category: "coding", skillsPath: ".qwen/skills" },
10368
+ { id: "trae", displayName: "Trae", category: "coding", skillsPath: ".trae/skills" },
10369
+ { id: "trae-cn", displayName: "Trae CN", category: "coding", skillsPath: ".trae-cn/skills" },
10370
+ { id: "windsurf", displayName: "Windsurf", category: "coding", skillsPath: ".windsurf/skills" },
10371
+ // Lobster family
10372
+ { id: "openclaw", displayName: "OpenClaw", category: "lobster", skillsPath: ".openclaw/skills" },
10373
+ { id: "qclaw", displayName: "QClaw", category: "lobster", skillsPath: ".qclaw/skills" },
10374
+ { id: "easyclaw", displayName: "EasyClaw", category: "lobster", skillsPath: ".easyclaw/skills" },
10375
+ { id: "autoclaw", displayName: "AutoClaw", category: "lobster", skillsPath: ".openclaw-autoclaw/skills" },
10376
+ { id: "workbuddy", displayName: "WorkBuddy", category: "lobster", skillsPath: ".workbuddy/skills" },
10377
+ // Central agent skills directory (codex / generic)
10378
+ { id: "agents", displayName: "Central (Agent Skills)", category: "central", skillsPath: ".agents/skills" }
10379
+ ];
10380
+ }
10381
+ });
10382
+
10212
10383
  // src/bootstrap.ts
10213
10384
  var bootstrap_exports = {};
10214
10385
  __export(bootstrap_exports, {
10215
10386
  bootstrapSelfRepo: () => bootstrapSelfRepo
10216
10387
  });
10217
- import path34 from "path";
10388
+ import path35 from "path";
10218
10389
  import YAML8 from "yaml";
10219
10390
  async function readSelfModeMarker(dir) {
10220
- const yamlPath = path34.join(dir, ".teamai", "teamai.yaml");
10391
+ const yamlPath = path35.join(dir, ".teamai", "teamai.yaml");
10221
10392
  const content = await readFileSafe(yamlPath);
10222
10393
  if (!content) return null;
10223
10394
  try {
@@ -10239,7 +10410,7 @@ async function bootstrapSelfRepo(dir, opts) {
10239
10410
  if (await pathExists(configPath)) return "already";
10240
10411
  const marker = await readSelfModeMarker(businessRepoRoot);
10241
10412
  if (!marker) return "skip";
10242
- const lockPath = path34.join(businessRepoRoot, ".teamai", BOOTSTRAP_LOCK_FILENAME);
10413
+ const lockPath = path35.join(businessRepoRoot, ".teamai", BOOTSTRAP_LOCK_FILENAME);
10243
10414
  const locked = await acquireLock(lockPath);
10244
10415
  if (!locked) {
10245
10416
  log.debug("[bootstrap] another bootstrap is in progress; skipping");
@@ -10247,7 +10418,7 @@ async function bootstrapSelfRepo(dir, opts) {
10247
10418
  }
10248
10419
  try {
10249
10420
  if (await pathExists(configPath)) return "already";
10250
- const localPath = path34.join(businessRepoRoot, ".teamai");
10421
+ const localPath = path35.join(businessRepoRoot, ".teamai");
10251
10422
  const remoteUrl = await getRemoteUrl(businessRepoRoot) ?? marker.repo ?? "";
10252
10423
  if (!remoteUrl) {
10253
10424
  log.debug("[bootstrap] no remote/repo to derive provider from; skipping");
@@ -10308,6 +10479,12 @@ async function bootstrapSelfRepo(dir, opts) {
10308
10479
  await saveStateForScope2(state, "project", businessRepoRoot);
10309
10480
  } catch {
10310
10481
  }
10482
+ try {
10483
+ const { seedSelfModeToolDirs: seedSelfModeToolDirs2 } = await Promise.resolve().then(() => (init_known_agents(), known_agents_exports));
10484
+ await seedSelfModeToolDirs2(localConfig, teamConfig);
10485
+ } catch (e) {
10486
+ log.debug(`[bootstrap] tool-dir seeding skipped: ${e.message}`);
10487
+ }
10311
10488
  try {
10312
10489
  const { reconcileTeamHooksForConfig: reconcileTeamHooksForConfig2 } = await Promise.resolve().then(() => (init_hooks2(), hooks_exports));
10313
10490
  await reconcileTeamHooksForConfig2(teamConfig, localConfig, {});
@@ -10317,9 +10494,9 @@ async function bootstrapSelfRepo(dir, opts) {
10317
10494
  try {
10318
10495
  const { ensureReportsWorktree: ensureReportsWorktree2, commitAndPushReports: commitAndPushReports2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
10319
10496
  const wt = await ensureReportsWorktree2(localConfig);
10320
- const memberDir = path34.join(wt, "members");
10497
+ const memberDir = path35.join(wt, "members");
10321
10498
  await ensureDir(memberDir);
10322
- const memberPath = path34.join(memberDir, `${username}.yaml`);
10499
+ const memberPath = path35.join(memberDir, `${username}.yaml`);
10323
10500
  if (!await pathExists(memberPath)) {
10324
10501
  await writeFile(memberPath, YAML8.stringify({
10325
10502
  username,
@@ -10369,7 +10546,7 @@ __export(config_exports, {
10369
10546
  saveStateForScope: () => saveStateForScope
10370
10547
  });
10371
10548
  import YAML9 from "yaml";
10372
- import path35 from "path";
10549
+ import path36 from "path";
10373
10550
  async function migrateLegacyRoleConfig(config, configPath) {
10374
10551
  if (config.primaryRole) {
10375
10552
  return config;
@@ -10395,7 +10572,7 @@ async function migrateLegacyRoleConfig(config, configPath) {
10395
10572
  return migrated;
10396
10573
  }
10397
10574
  async function loadTeamConfig(repoPath) {
10398
- const content = await readFileSafe(path35.join(repoPath, "teamai.yaml"));
10575
+ const content = await readFileSafe(path36.join(repoPath, "teamai.yaml"));
10399
10576
  if (!content) {
10400
10577
  log.debug("teamai.yaml not found in repo");
10401
10578
  return null;
@@ -10473,7 +10650,7 @@ async function saveStateForScope(state, scope, projectRoot) {
10473
10650
  }
10474
10651
  async function detectProjectConfig(cwd) {
10475
10652
  const dir = cwd ?? process.cwd();
10476
- const configPath = path35.join(dir, ".teamai", "config.yaml");
10653
+ const configPath = path36.join(dir, ".teamai", "config.yaml");
10477
10654
  if (!await pathExists(configPath)) {
10478
10655
  try {
10479
10656
  const { bootstrapSelfRepo: bootstrapSelfRepo2 } = await Promise.resolve().then(() => (init_bootstrap(), bootstrap_exports));
@@ -10537,9 +10714,9 @@ __export(api_key_exports, {
10537
10714
  saveApiKey: () => saveApiKey
10538
10715
  });
10539
10716
  import fs13 from "fs";
10540
- import path36 from "path";
10717
+ import path37 from "path";
10541
10718
  function getApiKeyPath() {
10542
- return path36.join(process.env.HOME ?? "", ".teamai", "apikey");
10719
+ return path37.join(process.env.HOME ?? "", ".teamai", "apikey");
10543
10720
  }
10544
10721
  function resolveApiKey() {
10545
10722
  const fromEnv = process.env.TEAMAI_API_TOKEN || process.env.TEAMAI_API_KEY;
@@ -10555,7 +10732,7 @@ async function saveApiKey(key) {
10555
10732
  const trimmed = key.trim();
10556
10733
  if (!trimmed) throw new Error("API key must not be empty");
10557
10734
  const keyPath = getApiKeyPath();
10558
- await ensureDir(path36.dirname(keyPath));
10735
+ await ensureDir(path37.dirname(keyPath));
10559
10736
  fs13.writeFileSync(keyPath, trimmed + "\n", { mode: 384 });
10560
10737
  fs13.chmodSync(keyPath, 384);
10561
10738
  }
@@ -10579,9 +10756,9 @@ __export(init_exports, {
10579
10756
  });
10580
10757
  import YAML10 from "yaml";
10581
10758
  import fs14 from "fs";
10582
- import path37 from "path";
10759
+ import path38 from "path";
10583
10760
  function resolveRealPath(p) {
10584
- const resolved = path37.resolve(p);
10761
+ const resolved = path38.resolve(p);
10585
10762
  try {
10586
10763
  return fs14.realpathSync(resolved);
10587
10764
  } catch {
@@ -10703,10 +10880,10 @@ function printScopeSummary(scope, projectRoot, explicit) {
10703
10880
  }
10704
10881
  }
10705
10882
  async function isInsideGitRepo(dir) {
10706
- let current = path37.resolve(dir);
10883
+ let current = path38.resolve(dir);
10707
10884
  for (; ; ) {
10708
- if (await pathExists(path37.join(current, ".git"))) return true;
10709
- const parent = path37.dirname(current);
10885
+ if (await pathExists(path38.join(current, ".git"))) return true;
10886
+ const parent = path38.dirname(current);
10710
10887
  if (parent === current) return false;
10711
10888
  current = parent;
10712
10889
  }
@@ -10767,9 +10944,9 @@ async function initHttp(url, options) {
10767
10944
  log.error("No API key found. Pass --token <key> to `teamai init --http`, or set TEAMAI_API_TOKEN.");
10768
10945
  process.exit(1);
10769
10946
  }
10770
- const localPath = expandHome(path37.join(teamaiHome, "team-repo"));
10947
+ const localPath = expandHome(path38.join(teamaiHome, "team-repo"));
10771
10948
  await ensureDir(localPath);
10772
- const stubPath = path37.join(localPath, "teamai.yaml");
10949
+ const stubPath = path38.join(localPath, "teamai.yaml");
10773
10950
  if (!await pathExists(stubPath)) {
10774
10951
  await writeFile(stubPath, YAML10.stringify({ team: "http-reporting", repo: url, sharing: {} }));
10775
10952
  }
@@ -10864,7 +11041,7 @@ async function initSelfRepo(options) {
10864
11041
  return;
10865
11042
  }
10866
11043
  const businessRepoRoot = cwd;
10867
- const teamaiHome = path37.join(businessRepoRoot, ".teamai");
11044
+ const teamaiHome = path38.join(businessRepoRoot, ".teamai");
10868
11045
  const localPath = teamaiHome;
10869
11046
  let inheritUserScope;
10870
11047
  try {
@@ -10921,13 +11098,13 @@ async function initSelfRepo(options) {
10921
11098
  }
10922
11099
  await ensureDir(localPath);
10923
11100
  for (const dir of ["skills", "rules", "docs", "learnings", "env"]) {
10924
- await ensureDir(path37.join(localPath, dir));
10925
- const gitkeep = path37.join(localPath, dir, ".gitkeep");
11101
+ await ensureDir(path38.join(localPath, dir));
11102
+ const gitkeep = path38.join(localPath, dir, ".gitkeep");
10926
11103
  if (!await pathExists(gitkeep)) {
10927
11104
  await writeFile(gitkeep, "");
10928
11105
  }
10929
11106
  }
10930
- const teamaiYamlPath = path37.join(localPath, "teamai.yaml");
11107
+ const teamaiYamlPath = path38.join(localPath, "teamai.yaml");
10931
11108
  if (!await pathExists(teamaiYamlPath)) {
10932
11109
  const defaultConfig = YAML10.stringify({
10933
11110
  team: repoInfo.repo,
@@ -10975,16 +11152,43 @@ async function initSelfRepo(options) {
10975
11152
  await ensureDir(teamaiHome);
10976
11153
  await saveLocalConfigForScope(localConfig, "project", businessRepoRoot);
10977
11154
  log.success(`Local config saved to ${teamaiHome}/config.yaml`);
10978
- const gitignorePath = path37.join(teamaiHome, ".gitignore");
11155
+ const gitignorePath = path38.join(teamaiHome, ".gitignore");
10979
11156
  await writeFile(gitignorePath, buildSelfModeGitignore());
10980
11157
  log.debug("Generated single-repo .teamai/.gitignore");
11158
+ if (!options.dryRun) {
11159
+ try {
11160
+ const { commitPaths: commitPaths2, hasCommits: hasCommits2 } = await Promise.resolve().then(() => (init_git(), git_exports));
11161
+ const hadCommits = await hasCommits2(businessRepoRoot);
11162
+ const skeletonPaths = [
11163
+ ".teamai/skills",
11164
+ ".teamai/rules",
11165
+ ".teamai/docs",
11166
+ ".teamai/learnings",
11167
+ ".teamai/teamai.yaml",
11168
+ ".teamai/.gitignore",
11169
+ ".claude/settings.json"
11170
+ ];
11171
+ const committed = await commitPaths2(
11172
+ businessRepoRoot,
11173
+ "[teamai] Initialize single-repo mode (skills/rules/docs/learnings skeleton)",
11174
+ skeletonPaths
11175
+ );
11176
+ if (committed) {
11177
+ log.success(
11178
+ hadCommits ? "Committed .teamai/ skeleton to the current branch" : "Created initial commit with the .teamai/ skeleton"
11179
+ );
11180
+ }
11181
+ } catch (e) {
11182
+ log.warn(`Could not commit the .teamai/ skeleton (do it manually before \`teamai push\`): ${e.message}`);
11183
+ }
11184
+ }
10981
11185
  if (!options.dryRun) {
10982
11186
  try {
10983
11187
  const { ensureReportsWorktree: ensureReportsWorktree2, commitAndPushReports: commitAndPushReports2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
10984
11188
  const wt = await ensureReportsWorktree2(localConfig);
10985
- const memberDir = path37.join(wt, "members");
11189
+ const memberDir = path38.join(wt, "members");
10986
11190
  await ensureDir(memberDir);
10987
- const memberPath = path37.join(memberDir, `${username}.yaml`);
11191
+ const memberPath = path38.join(memberDir, `${username}.yaml`);
10988
11192
  if (!await pathExists(memberPath)) {
10989
11193
  await writeFile(memberPath, YAML10.stringify({
10990
11194
  username,
@@ -11008,11 +11212,18 @@ async function initSelfRepo(options) {
11008
11212
  await saveStateForScope(state, "project", businessRepoRoot);
11009
11213
  } catch {
11010
11214
  }
11215
+ try {
11216
+ const { seedSelfModeToolDirs: seedSelfModeToolDirs2 } = await Promise.resolve().then(() => (init_known_agents(), known_agents_exports));
11217
+ const seeded = await seedSelfModeToolDirs2(localConfig, teamConfig);
11218
+ if (seeded.length > 0) log.debug(`Seeded tool dirs for: ${seeded.join(", ")}`);
11219
+ } catch (e) {
11220
+ log.debug(`Tool-dir seeding skipped: ${e.message}`);
11221
+ }
11011
11222
  const filterAgents2 = options.agent ? [options.agent] : void 0;
11012
11223
  await reconcileTeamHooksForConfig(teamConfig, localConfig, { filterAgents: filterAgents2 });
11013
11224
  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.");
11225
+ 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.");
11226
+ log.info("Add skills/rules later with `teamai push` \u2014 it opens a PR against your repo without touching your working tree.");
11016
11227
  closePrompt();
11017
11228
  }
11018
11229
  async function init(options) {
@@ -11114,7 +11325,7 @@ async function init(options) {
11114
11325
  authSpin.fail(`Authentication failed: ${e.message}`);
11115
11326
  process.exit(1);
11116
11327
  }
11117
- const defaultLocalPath = path37.join(teamaiHome, "team-repo");
11328
+ const defaultLocalPath = path38.join(teamaiHome, "team-repo");
11118
11329
  const localPath = expandHome(defaultLocalPath);
11119
11330
  if (await pathExists(localPath)) {
11120
11331
  if (await isGitRepo(localPath)) {
@@ -11195,16 +11406,16 @@ async function init(options) {
11195
11406
  env: { injectShellProfile: true }
11196
11407
  }
11197
11408
  });
11198
- await writeFile(path37.join(localPath, "teamai.yaml"), defaultConfig);
11409
+ await writeFile(path38.join(localPath, "teamai.yaml"), defaultConfig);
11199
11410
  for (const dir of ["members", "skills", "rules", "docs", "env"]) {
11200
- await ensureDir(path37.join(localPath, dir));
11201
- const gitkeep = path37.join(localPath, dir, ".gitkeep");
11411
+ await ensureDir(path38.join(localPath, dir));
11412
+ const gitkeep = path38.join(localPath, dir, ".gitkeep");
11202
11413
  if (!await pathExists(gitkeep)) {
11203
11414
  await writeFile(gitkeep, "");
11204
11415
  }
11205
11416
  }
11206
11417
  }
11207
- const memberPath = path37.join(localPath, "members", `${username}.yaml`);
11418
+ const memberPath = path38.join(localPath, "members", `${username}.yaml`);
11208
11419
  const isNewMember = !await pathExists(memberPath);
11209
11420
  if (isNewMember) {
11210
11421
  const memberYaml = YAML10.stringify({
@@ -11242,7 +11453,7 @@ async function init(options) {
11242
11453
  const reviewerInput = await askQuestion("Reviewers (comma-separated usernames): ", "");
11243
11454
  const reviewers = reviewerInput.split(",").map((s) => s.trim()).filter(Boolean);
11244
11455
  if (reviewers.length > 0) {
11245
- const configPath = path37.join(localPath, "teamai.yaml");
11456
+ const configPath = path38.join(localPath, "teamai.yaml");
11246
11457
  const configContent = await readFileSafe(configPath);
11247
11458
  if (configContent) {
11248
11459
  const configData = YAML10.parse(configContent);
@@ -11292,7 +11503,7 @@ async function init(options) {
11292
11503
  if (scope === "project") {
11293
11504
  await saveLocalConfigForScope(localConfig, scope, projectRoot);
11294
11505
  log.success(`Local config saved to ${teamaiHome}/config.yaml`);
11295
- const gitignorePath = path37.join(teamaiHome, ".gitignore");
11506
+ const gitignorePath = path38.join(teamaiHome, ".gitignore");
11296
11507
  if (!await pathExists(gitignorePath)) {
11297
11508
  const gitignoreContent = [
11298
11509
  "# teamai local config (do not commit)",
@@ -11352,10 +11563,10 @@ var init_init = __esm({
11352
11563
  });
11353
11564
 
11354
11565
  // src/utils/tags.ts
11355
- import path38 from "path";
11566
+ import path39 from "path";
11356
11567
  import YAML11 from "yaml";
11357
11568
  async function loadTagsConfig(repoPath) {
11358
- const content = await readFileSafe(path38.join(repoPath, TAGS_FILE));
11569
+ const content = await readFileSafe(path39.join(repoPath, TAGS_FILE));
11359
11570
  if (!content) {
11360
11571
  return null;
11361
11572
  }
@@ -11410,7 +11621,7 @@ function filterByTags(items, tagsConfig, subscribedTags, resourceType) {
11410
11621
  return { included, skipped };
11411
11622
  }
11412
11623
  async function saveTagsConfig(repoPath, config) {
11413
- const filePath = path38.join(repoPath, TAGS_FILE);
11624
+ const filePath = path39.join(repoPath, TAGS_FILE);
11414
11625
  const content = YAML11.stringify({
11415
11626
  skills: config.skills,
11416
11627
  rules: config.rules
@@ -11515,7 +11726,7 @@ __export(votes_exports, {
11515
11726
  saveUserVotes: () => saveUserVotes,
11516
11727
  syncVotesToTeam: () => syncVotesToTeam
11517
11728
  });
11518
- import path39 from "path";
11729
+ import path40 from "path";
11519
11730
  import YAML12 from "yaml";
11520
11731
  function migrateV1ToV2(v1) {
11521
11732
  const votes = {};
@@ -11554,7 +11765,7 @@ async function loadUserVotes(votePath) {
11554
11765
  return { version: 2, votes: {}, deltas: {} };
11555
11766
  }
11556
11767
  async function saveUserVotes(votePath, votes) {
11557
- await ensureDir(path39.dirname(votePath));
11768
+ await ensureDir(path40.dirname(votePath));
11558
11769
  await writeFile(votePath, YAML12.stringify(votes));
11559
11770
  }
11560
11771
  async function incrementRecalled(votePath, docIds) {
@@ -11615,8 +11826,8 @@ function mergeDeltas(local, remote) {
11615
11826
  return { version: 2, votes, deltas: {} };
11616
11827
  }
11617
11828
  async function syncVotesToTeam(repoPath, username, localVotesDir) {
11618
- const localVotePath = path39.join(localVotesDir, `${username}.yaml`);
11619
- const remoteVotePath = path39.join(repoPath, "votes", `${username}.yaml`);
11829
+ const localVotePath = path40.join(localVotesDir, `${username}.yaml`);
11830
+ const remoteVotePath = path40.join(repoPath, "votes", `${username}.yaml`);
11620
11831
  const local = await loadUserVotes(localVotePath);
11621
11832
  if (Object.keys(local.deltas).length === 0) {
11622
11833
  return false;
@@ -11632,7 +11843,7 @@ async function recallFeedback(opts) {
11632
11843
  const { localConfig } = await requireInit3();
11633
11844
  const { username } = localConfig;
11634
11845
  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`);
11846
+ const votePath = path40.join(VOTES_LOCAL_DIR2, `${username}.yaml`);
11636
11847
  if (opts.positive) {
11637
11848
  await incrementUpvoted(votePath, [opts.positive]);
11638
11849
  log.success(`Upvoted: ${opts.positive}`);
@@ -11682,7 +11893,7 @@ __export(confidence_exports, {
11682
11893
  computeConfidence: () => computeConfidence,
11683
11894
  writeBackConfidence: () => writeBackConfidence
11684
11895
  });
11685
- import path40 from "path";
11896
+ import path41 from "path";
11686
11897
  import matter2 from "gray-matter";
11687
11898
  function computeConfidence(factors) {
11688
11899
  const { recalledCount, upvotedCount, lastRecalledAt } = factors;
@@ -11705,7 +11916,7 @@ async function computeAllConfidence(votesDir) {
11705
11916
  for (const file of files) {
11706
11917
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
11707
11918
  try {
11708
- const data = await loadUserVotes2(path40.join(votesDir, file));
11919
+ const data = await loadUserVotes2(path41.join(votesDir, file));
11709
11920
  for (const [docId, entry] of Object.entries(data.votes)) {
11710
11921
  const existing = aggregated.get(docId) ?? { recalled: 0, upvoted: 0, lastRecalled: "" };
11711
11922
  existing.recalled += entry.recalled_count ?? 0;
@@ -11741,7 +11952,7 @@ async function writeBackConfidence(learningsDir, confidenceMap) {
11741
11952
  const docId = file.replace(/\.md$/i, "");
11742
11953
  const newConf = confidenceMap.get(docId);
11743
11954
  if (newConf === void 0) continue;
11744
- const absPath = path40.join(learningsDir, file);
11955
+ const absPath = path41.join(learningsDir, file);
11745
11956
  const content = await readFileSafe(absPath);
11746
11957
  if (!content) continue;
11747
11958
  try {
@@ -11810,7 +12021,7 @@ __export(search_index_exports, {
11810
12021
  titleFromFilename: () => titleFromFilename,
11811
12022
  tokenize: () => tokenize
11812
12023
  });
11813
- import path41 from "path";
12024
+ import path42 from "path";
11814
12025
  import matter3 from "gray-matter";
11815
12026
  function getSearchIndexPath() {
11816
12027
  return `${process.env.HOME ?? ""}/.teamai/search-index.json`;
@@ -11891,7 +12102,7 @@ async function aggregateVotes(votesDir) {
11891
12102
  const files = await listFiles(votesDir);
11892
12103
  for (const file of files) {
11893
12104
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
11894
- const content = await readFileSafe(path41.join(votesDir, file));
12105
+ const content = await readFileSafe(path42.join(votesDir, file));
11895
12106
  if (!content) continue;
11896
12107
  try {
11897
12108
  const YAML20 = (await import("yaml")).default;
@@ -11937,10 +12148,10 @@ async function aggregateVotes(votesDir) {
11937
12148
  return { scores, confidenceMap };
11938
12149
  }
11939
12150
  async function entryFromMdFile(absPath, filenameForId, type, voteCounts) {
11940
- const basename = path41.basename(absPath);
12151
+ const basename = path42.basename(absPath);
11941
12152
  if (basename === CODEBASE_FULL_FILENAME) {
11942
- const dir = path41.dirname(absPath);
11943
- const indexPath = path41.join(dir, CODEBASE_INDEX_FILENAME);
12153
+ const dir = path42.dirname(absPath);
12154
+ const indexPath = path42.join(dir, CODEBASE_INDEX_FILENAME);
11944
12155
  if (await pathExists(indexPath)) {
11945
12156
  log.debug(`Skipping ${absPath}: codebase-index.md exists in same directory`);
11946
12157
  return null;
@@ -11997,7 +12208,7 @@ async function collectFlatMdEntries(dir, type, voteCounts) {
11997
12208
  const out = [];
11998
12209
  for (const filename of files) {
11999
12210
  if (!filename.endsWith(".md")) continue;
12000
- const e = await entryFromMdFile(path41.join(dir, filename), filename, type, voteCounts);
12211
+ const e = await entryFromMdFile(path42.join(dir, filename), filename, type, voteCounts);
12001
12212
  if (e) out.push(e);
12002
12213
  }
12003
12214
  return out;
@@ -12008,7 +12219,7 @@ async function collectRecursiveMdEntries(dir, type, voteCounts) {
12008
12219
  const out = [];
12009
12220
  for (const rel of files) {
12010
12221
  if (!rel.endsWith(".md")) continue;
12011
- const e = await entryFromMdFile(path41.join(dir, rel), rel, type, voteCounts);
12222
+ const e = await entryFromMdFile(path42.join(dir, rel), rel, type, voteCounts);
12012
12223
  if (e) out.push(e);
12013
12224
  }
12014
12225
  return out;
@@ -12020,8 +12231,8 @@ async function collectSkillEntries(dir, voteCounts) {
12020
12231
  const subdirs = await listDirs(current);
12021
12232
  for (const sub of subdirs) {
12022
12233
  if (sub.startsWith(".")) continue;
12023
- const subPath = path41.join(current, sub);
12024
- const skillMd = path41.join(subPath, "SKILL.md");
12234
+ const subPath = path42.join(current, sub);
12235
+ const skillMd = path42.join(subPath, "SKILL.md");
12025
12236
  if (await pathExists(skillMd)) {
12026
12237
  const e = await entryFromMdFile(skillMd, `${sub}.md`, "skills", voteCounts);
12027
12238
  if (e) out.push(e);
@@ -12138,7 +12349,7 @@ function search(query, index, limit = 5) {
12138
12349
  const domainMultiplier = domainWeightRow[entry.domain ?? "neutral"];
12139
12350
  const typeMultiplier = TYPE_BONUS[entry.type];
12140
12351
  score *= domainMultiplier * typeMultiplier;
12141
- if (path41.basename(entry.path ?? "") === CODEBASE_INDEX_FILENAME) {
12352
+ if (path42.basename(entry.path ?? "") === CODEBASE_INDEX_FILENAME) {
12142
12353
  score *= CODEBASE_INDEX_WEIGHT_BOOST;
12143
12354
  }
12144
12355
  if (entry.hotness !== void 0 && entry.hotness < 1) {
@@ -12400,12 +12611,12 @@ __export(usage_tracker_exports, {
12400
12611
  updateKnownSkills: () => updateKnownSkills
12401
12612
  });
12402
12613
  import fs15 from "fs";
12403
- import path42 from "path";
12614
+ import path43 from "path";
12404
12615
  function getUsagePath() {
12405
- return path42.join(process.env.HOME ?? "", ".teamai", "usage.jsonl");
12616
+ return path43.join(process.env.HOME ?? "", ".teamai", "usage.jsonl");
12406
12617
  }
12407
12618
  function getKnownSkillsPath() {
12408
- return path42.join(process.env.HOME ?? "", ".teamai", "known-skills.json");
12619
+ return path43.join(process.env.HOME ?? "", ".teamai", "known-skills.json");
12409
12620
  }
12410
12621
  function extractSkillName(toolInput) {
12411
12622
  try {
@@ -12431,13 +12642,13 @@ function isValidSkillName(name) {
12431
12642
  async function skillExistsOnDisk(skillName) {
12432
12643
  const home = process.env.HOME ?? "";
12433
12644
  for (const dir of SKILL_DIRS) {
12434
- const skillMd = path42.join(home, dir, skillName, "SKILL.md");
12645
+ const skillMd = path43.join(home, dir, skillName, "SKILL.md");
12435
12646
  if (await pathExists(skillMd)) return true;
12436
12647
  }
12437
12648
  const cwd = process.cwd();
12438
- if (path42.resolve(cwd) !== path42.resolve(home)) {
12649
+ if (path43.resolve(cwd) !== path43.resolve(home)) {
12439
12650
  for (const dir of SKILL_DIRS) {
12440
- const skillMd = path42.join(cwd, dir, skillName, "SKILL.md");
12651
+ const skillMd = path43.join(cwd, dir, skillName, "SKILL.md");
12441
12652
  if (await pathExists(skillMd)) return true;
12442
12653
  }
12443
12654
  }
@@ -12445,7 +12656,7 @@ async function skillExistsOnDisk(skillName) {
12445
12656
  }
12446
12657
  async function appendUsageEvent(event) {
12447
12658
  try {
12448
- await ensureDir(path42.dirname(getUsagePath()));
12659
+ await ensureDir(path43.dirname(getUsagePath()));
12449
12660
  const line = JSON.stringify(event) + "\n";
12450
12661
  await fs15.promises.appendFile(getUsagePath(), line, "utf-8");
12451
12662
  log.debug(`Tracked skill: ${event.skill}`);
@@ -12919,16 +13130,16 @@ __export(digest_exports, {
12919
13130
  summarizeInterventions: () => summarizeInterventions
12920
13131
  });
12921
13132
  import YAML13 from "yaml";
12922
- import path43 from "path";
13133
+ import path44 from "path";
12923
13134
  import fs16 from "fs";
12924
13135
  async function loadTeamStats(repoPath) {
12925
- const statsDir = path43.join(repoPath, "stats");
13136
+ const statsDir = path44.join(repoPath, "stats");
12926
13137
  const stats = [];
12927
13138
  try {
12928
13139
  const files = await listFiles(statsDir);
12929
13140
  for (const file of files) {
12930
13141
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
12931
- const content = await readFileSafe(path43.join(statsDir, file));
13142
+ const content = await readFileSafe(path44.join(statsDir, file));
12932
13143
  if (!content) continue;
12933
13144
  try {
12934
13145
  const parsed = YAML13.parse(content);
@@ -13025,17 +13236,17 @@ async function getRecentSkillChanges(repoPath) {
13025
13236
  return changes;
13026
13237
  }
13027
13238
  async function getRecentSessions(repoPath) {
13028
- const sessionsDir = path43.join(repoPath, "sessions");
13239
+ const sessionsDir = path44.join(repoPath, "sessions");
13029
13240
  const summaries = [];
13030
13241
  try {
13031
13242
  const userDirs = await fs16.promises.readdir(sessionsDir, { withFileTypes: true });
13032
13243
  for (const userDir of userDirs) {
13033
13244
  if (!userDir.isDirectory()) continue;
13034
- const userSessionsDir = path43.join(sessionsDir, userDir.name);
13245
+ const userSessionsDir = path44.join(sessionsDir, userDir.name);
13035
13246
  const files = await listFiles(userSessionsDir);
13036
13247
  for (const file of files) {
13037
13248
  if (!file.endsWith(".md")) continue;
13038
- const content = await readFileSafe(path43.join(userSessionsDir, file));
13249
+ const content = await readFileSafe(path44.join(userSessionsDir, file));
13039
13250
  if (content) {
13040
13251
  summaries.push(`[${userDir.name}] ${file}:
13041
13252
  ${content.slice(0, 500)}`);
@@ -13047,7 +13258,7 @@ ${content.slice(0, 500)}`);
13047
13258
  return summaries;
13048
13259
  }
13049
13260
  async function getRecentLearnings(repoPath) {
13050
- const learningsDir = path43.join(repoPath, "learnings");
13261
+ const learningsDir = path44.join(repoPath, "learnings");
13051
13262
  const recent = [];
13052
13263
  let total = 0;
13053
13264
  try {
@@ -13060,7 +13271,7 @@ async function getRecentLearnings(repoPath) {
13060
13271
  if (!dateMatch) continue;
13061
13272
  const fileDate = dateMatch[1];
13062
13273
  if (fileDate < cutoff) continue;
13063
- const content = await readFileSafe(path43.join(learningsDir, filename));
13274
+ const content = await readFileSafe(path44.join(learningsDir, filename));
13064
13275
  if (!content) continue;
13065
13276
  const parsed = parseLearningDoc(content, filename);
13066
13277
  const title = parsed?.meta.title ?? titleFromFilename(filename);
@@ -13251,7 +13462,7 @@ __export(stats_exports, {
13251
13462
  showStats: () => showStats
13252
13463
  });
13253
13464
  import YAML14 from "yaml";
13254
- import path44 from "path";
13465
+ import path45 from "path";
13255
13466
  function aggregateUsage(events) {
13256
13467
  const map = /* @__PURE__ */ new Map();
13257
13468
  for (const event of events) {
@@ -13281,7 +13492,7 @@ async function loadReportedStats() {
13281
13492
  const { ensureReportsWorktree: ensureReportsWorktree2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
13282
13493
  statsRoot = await ensureReportsWorktree2(config);
13283
13494
  }
13284
- const statsPath = path44.join(statsRoot, "stats", `${config.username}.yaml`);
13495
+ const statsPath = path45.join(statsRoot, "stats", `${config.username}.yaml`);
13285
13496
  const content = await readFileSafe(statsPath);
13286
13497
  if (!content) return null;
13287
13498
  const parsed = YAML14.parse(content);
@@ -13490,7 +13701,7 @@ __export(team_push_exports, {
13490
13701
  reportUsageToTeam: () => reportUsageToTeam
13491
13702
  });
13492
13703
  import YAML15 from "yaml";
13493
- import path45 from "path";
13704
+ import path46 from "path";
13494
13705
  async function readExistingStats(statsPath) {
13495
13706
  try {
13496
13707
  const content = await readFileSafe(statsPath);
@@ -13528,7 +13739,7 @@ function mergeStats(existing, username, newEvents) {
13528
13739
  };
13529
13740
  }
13530
13741
  function getReportedInterventionsPath() {
13531
- return path45.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-interventions.json");
13742
+ return path46.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-interventions.json");
13532
13743
  }
13533
13744
  async function readReportedInterventions() {
13534
13745
  const parsed = await readJson(getReportedInterventionsPath());
@@ -13566,7 +13777,7 @@ function hasInterventionDelta(d) {
13566
13777
  return d.sessions > 0 || d.interrupt > 0 || d.toolReject > 0 || d.correction > 0;
13567
13778
  }
13568
13779
  function getReportedPromptTokensPath() {
13569
- return path45.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-prompt-tokens.json");
13780
+ return path46.join(process.env.HOME ?? "", ".teamai", "dashboard", "reported-prompt-tokens.json");
13570
13781
  }
13571
13782
  async function readReportedPromptTokens() {
13572
13783
  try {
@@ -13581,7 +13792,7 @@ async function readReportedPromptTokens() {
13581
13792
  async function writeReportedPromptTokens(data) {
13582
13793
  try {
13583
13794
  const p = getReportedPromptTokensPath();
13584
- await ensureDir(path45.dirname(p));
13795
+ await ensureDir(path46.dirname(p));
13585
13796
  await writeFile(p, JSON.stringify(data));
13586
13797
  } catch (e) {
13587
13798
  log.error(`Failed to persist reported prompt/token snapshot: ${e.message}`);
@@ -13667,9 +13878,9 @@ async function reportUsageToTeam(repoPath, username, options) {
13667
13878
  await pullRepo(repoPath);
13668
13879
  }
13669
13880
  if (hasUsage || hasInterventions || hasPromptTokens) {
13670
- const statsDir = path45.join(writeRoot, "stats");
13881
+ const statsDir = path46.join(writeRoot, "stats");
13671
13882
  await ensureDir(statsDir);
13672
- const statsPath = path45.join(statsDir, `${username}.yaml`);
13883
+ const statsPath = path46.join(statsDir, `${username}.yaml`);
13673
13884
  const existing = await readExistingStats(statsPath);
13674
13885
  const newStats = hasUsage ? aggregateUsage(events) : [];
13675
13886
  const merged = mergeStats(existing, username, newStats);
@@ -13935,7 +14146,7 @@ __export(mcp_reconcile_exports, {
13935
14146
  resolveMcpTargets: () => resolveMcpTargets,
13936
14147
  spliceCodexBlock: () => spliceCodexBlock
13937
14148
  });
13938
- import path46 from "path";
14149
+ import path47 from "path";
13939
14150
  import fse9 from "fs-extra";
13940
14151
  async function readManifest2(manifestPath) {
13941
14152
  const data = await readJson(expandHome(manifestPath));
@@ -13943,7 +14154,7 @@ async function readManifest2(manifestPath) {
13943
14154
  }
13944
14155
  async function buildVarTable(localConfig) {
13945
14156
  const table = {};
13946
- const envFile = path46.join(getTeamaiHome(localConfig.scope, localConfig.projectRoot), "env");
14157
+ const envFile = path47.join(getTeamaiHome(localConfig.scope, localConfig.projectRoot), "env");
13947
14158
  const content = await readFileSafe(envFile);
13948
14159
  if (content) {
13949
14160
  for (const line of content.split("\n")) {
@@ -14010,12 +14221,12 @@ async function resolveMcpTargets(teamConfig, localConfig) {
14010
14221
  if (!rel) continue;
14011
14222
  const probe = paths.skills ?? paths.settings ?? paths.agents;
14012
14223
  if (!probe) continue;
14013
- const toolRoot = path46.join(baseDir, probe.split("/")[0]);
14224
+ const toolRoot = path47.join(baseDir, probe.split("/")[0]);
14014
14225
  if (!await pathExists(toolRoot)) {
14015
14226
  log.debug(`Skipping MCP sync for ${tool}: tool not installed`);
14016
14227
  continue;
14017
14228
  }
14018
- targets.push({ tool, format, file: path46.join(baseDir, rel), projectScope });
14229
+ targets.push({ tool, format, file: path47.join(baseDir, rel), projectScope });
14019
14230
  }
14020
14231
  return targets;
14021
14232
  }
@@ -14213,7 +14424,7 @@ async function applyCodex(target, desired, ownedNames, nextRecords, changes, opt
14213
14424
  changes.push({ tool: target.tool, server: name, action: "removed" });
14214
14425
  }
14215
14426
  if (!dirty || options.dryRun) return false;
14216
- await fse9.ensureDir(path46.dirname(target.file));
14427
+ await fse9.ensureDir(path47.dirname(target.file));
14217
14428
  const tmp = `${target.file}.${process.pid}.tmp`;
14218
14429
  await fse9.writeFile(tmp, source, "utf-8");
14219
14430
  await fse9.chmod(tmp, 384);
@@ -14245,7 +14456,7 @@ __export(pull_exports, {
14245
14456
  pull: () => pull,
14246
14457
  scanRoleAwareSkills: () => scanRoleAwareSkills
14247
14458
  });
14248
- import path47 from "path";
14459
+ import path48 from "path";
14249
14460
  import fse10 from "fs-extra";
14250
14461
  import matter4 from "gray-matter";
14251
14462
  async function refreshTeamRepo(localConfig) {
@@ -14304,14 +14515,14 @@ async function buildRolePullContext(localConfig) {
14304
14515
  const activeSkillNames = /* @__PURE__ */ new Set();
14305
14516
  const inactiveSkillNames = /* @__PURE__ */ new Set();
14306
14517
  for (const namespace of activeNamespaces.skills) {
14307
- const namespaceDir = path47.join(localConfig.repo.localPath, "skills", namespace);
14518
+ const namespaceDir = path48.join(localConfig.repo.localPath, "skills", namespace);
14308
14519
  const names = await listDirs(namespaceDir);
14309
14520
  for (const name of names) {
14310
14521
  activeSkillNames.add(name);
14311
14522
  }
14312
14523
  }
14313
14524
  for (const namespace of inactiveSkillNamespaces) {
14314
- const namespaceDir = path47.join(localConfig.repo.localPath, "skills", namespace);
14525
+ const namespaceDir = path48.join(localConfig.repo.localPath, "skills", namespace);
14315
14526
  const names = await listDirs(namespaceDir);
14316
14527
  for (const name of names) {
14317
14528
  inactiveSkillNames.add(name);
@@ -14331,7 +14542,7 @@ function filterRulesByKnowledgeNamespaces(rules, knowledgeNamespaces) {
14331
14542
  async function scanRoleAwareSkills(localConfig, namespaces) {
14332
14543
  const items = /* @__PURE__ */ new Map();
14333
14544
  for (const namespace of namespaces.skills) {
14334
- const namespaceDir = path47.join(localConfig.repo.localPath, "skills", namespace);
14545
+ const namespaceDir = path48.join(localConfig.repo.localPath, "skills", namespace);
14335
14546
  const dirs = await listDirs(namespaceDir);
14336
14547
  for (const dir of dirs) {
14337
14548
  const existing = items.get(dir);
@@ -14341,7 +14552,7 @@ async function scanRoleAwareSkills(localConfig, namespaces) {
14341
14552
  items.set(dir, {
14342
14553
  name: dir,
14343
14554
  type: "skills",
14344
- sourcePath: path47.join(namespaceDir, dir),
14555
+ sourcePath: path48.join(namespaceDir, dir),
14345
14556
  relativePath: `skills/${namespace}/${dir}`,
14346
14557
  namespace
14347
14558
  });
@@ -14355,13 +14566,13 @@ async function cleanupInactiveNamespaceSkills(teamConfig, localConfig, activeSki
14355
14566
  if (isAgentDisabled(localConfig, tool)) continue;
14356
14567
  if (!toolPath.skills) continue;
14357
14568
  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));
14569
+ if (!await pathExists(path48.join(baseDir, toolPath.skills))) continue;
14570
+ const localSkillNames = await listDirs(path48.join(baseDir, toolPath.skills));
14360
14571
  for (const skillName of localSkillNames) {
14361
14572
  if (BUILTIN_SKILL_NAMES.has(skillName)) continue;
14362
14573
  if (activeSkillNames.has(skillName)) continue;
14363
14574
  if (!inactiveSkillNames.has(skillName)) continue;
14364
- const localSkillDir = path47.join(baseDir, toolPath.skills, skillName);
14575
+ const localSkillDir = path48.join(baseDir, toolPath.skills, skillName);
14365
14576
  await remove(localSkillDir);
14366
14577
  log.debug(`[${localConfig.scope}] Removed inactive role-scoped skill ${skillName} from ${tool}`);
14367
14578
  }
@@ -14373,10 +14584,10 @@ async function getExistingLocalNames(type, items, teamConfig, localConfig) {
14373
14584
  if (type === "skills") {
14374
14585
  for (const [_tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
14375
14586
  if (!toolPath.skills) continue;
14376
- const skillsDir = path47.join(baseDir, toolPath.skills);
14587
+ const skillsDir = path48.join(baseDir, toolPath.skills);
14377
14588
  if (!await pathExists(skillsDir)) continue;
14378
14589
  for (const item of items) {
14379
- const skillDir = path47.join(skillsDir, item.name);
14590
+ const skillDir = path48.join(skillsDir, item.name);
14380
14591
  if (await pathExists(skillDir)) {
14381
14592
  existing.add(item.name);
14382
14593
  }
@@ -14593,7 +14804,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14593
14804
  if (!await ResourceHandler.isToolInstalled(dir, baseDir)) continue;
14594
14805
  if (isAgentDisabled(localConfig, tool)) continue;
14595
14806
  for (const name of tombstones) {
14596
- const localPath = path47.join(baseDir, dir, ext ? `${name}${ext}` : name);
14807
+ const localPath = path48.join(baseDir, dir, ext ? `${name}${ext}` : name);
14597
14808
  if (await pathExists(localPath)) {
14598
14809
  await remove(localPath);
14599
14810
  log.debug(`[${scopeLabel}] Cleaned up tombstoned ${type} ${name} from ${dir}`);
@@ -14616,25 +14827,25 @@ async function pullForScope(localConfig, options, policy = {}) {
14616
14827
  if (isAgentDisabled(localConfig, tool)) continue;
14617
14828
  if (!toolPath.skills) continue;
14618
14829
  if (!await ResourceHandler.isToolInstalled(toolPath.skills, baseDir)) continue;
14619
- const skillsDir = path47.join(baseDir, toolPath.skills);
14830
+ const skillsDir = path48.join(baseDir, toolPath.skills);
14620
14831
  if (!await pathExists(skillsDir)) continue;
14621
14832
  const localDirs = await listDirs(skillsDir);
14622
14833
  for (const dir of localDirs) {
14623
14834
  if (BUILTIN_SKILL_NAMES.has(dir)) continue;
14624
14835
  if (desiredSkillNames.has(dir)) continue;
14625
14836
  if (!knownRepoSkillNames.has(dir)) continue;
14626
- const skillDir = path47.join(skillsDir, dir);
14837
+ const skillDir = path48.join(skillsDir, dir);
14627
14838
  await remove(skillDir);
14628
14839
  log.debug(`Removed excluded skill ${dir} from ${tool}`);
14629
14840
  }
14630
14841
  if (excludedSkills.size > 0) {
14631
14842
  for (const namespace of localDirs) {
14632
- const namespaceDir = path47.join(skillsDir, namespace);
14633
- if (await pathExists(path47.join(namespaceDir, "SKILL.md"))) continue;
14843
+ const namespaceDir = path48.join(skillsDir, namespace);
14844
+ if (await pathExists(path48.join(namespaceDir, "SKILL.md"))) continue;
14634
14845
  for (const skillName of await listDirs(namespaceDir)) {
14635
14846
  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;
14847
+ const nestedSkillDir = path48.join(namespaceDir, skillName);
14848
+ if (!await pathExists(path48.join(nestedSkillDir, "SKILL.md"))) continue;
14638
14849
  await remove(nestedSkillDir);
14639
14850
  log.debug(`Removed excluded skill ${namespace}/${skillName} from ${tool}`);
14640
14851
  }
@@ -14647,18 +14858,18 @@ async function pullForScope(localConfig, options, policy = {}) {
14647
14858
  }
14648
14859
  if (!options.dryRun) {
14649
14860
  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");
14861
+ const learningsRepoDir = path48.join(localConfig.repo.localPath, "learnings");
14862
+ const docsRepoDir = path48.join(localConfig.repo.localPath, "docs");
14863
+ const rulesRepoDir = path48.join(localConfig.repo.localPath, "rules");
14864
+ const skillsRepoDir = path48.join(localConfig.repo.localPath, "skills");
14865
+ const votesDir = path48.join(localConfig.repo.localPath, "votes");
14655
14866
  let learningsCount = 0;
14656
14867
  let effectiveLearningsDir;
14657
14868
  if (localConfig.scope === "user") {
14658
14869
  if (await pathExists(learningsRepoDir)) {
14659
14870
  await fse10.copy(learningsRepoDir, LEARNINGS_LOCAL_DIR, {
14660
14871
  overwrite: true,
14661
- filter: (src) => !path47.basename(src).startsWith(".")
14872
+ filter: (src) => !path48.basename(src).startsWith(".")
14662
14873
  });
14663
14874
  const allFiles = await listFiles(learningsRepoDir);
14664
14875
  learningsCount = allFiles.filter((f) => f.endsWith(".md")).length;
@@ -14672,12 +14883,12 @@ async function pullForScope(localConfig, options, policy = {}) {
14672
14883
  }
14673
14884
  }
14674
14885
  const hasAnySource = effectiveLearningsDir || await pathExists(docsRepoDir) || await pathExists(rulesRepoDir) || await pathExists(skillsRepoDir);
14675
- const repoCodebaseDir = path47.join(localConfig.repo.localPath, "docs", "team-codebase");
14886
+ const repoCodebaseDir = path48.join(localConfig.repo.localPath, "docs", "team-codebase");
14676
14887
  const effectiveCodebaseDir = await pathExists(repoCodebaseDir) ? repoCodebaseDir : void 0;
14677
14888
  if (hasAnySource || effectiveCodebaseDir) {
14678
14889
  const votesExist = await pathExists(votesDir);
14679
14890
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
14680
- const indexPath = path47.join(teamaiHome, "search-index.json");
14891
+ const indexPath = path48.join(teamaiHome, "search-index.json");
14681
14892
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
14682
14893
  const elapsed = await buildIndex2({
14683
14894
  learningsDir: effectiveLearningsDir,
@@ -14701,7 +14912,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14701
14912
  }
14702
14913
  if (!options.dryRun) {
14703
14914
  try {
14704
- const culturePath = path47.join(localConfig.repo.localPath, "culture.md");
14915
+ const culturePath = path48.join(localConfig.repo.localPath, "culture.md");
14705
14916
  if (await pathExists(culturePath)) {
14706
14917
  const cultureContent = await readFileSafe(culturePath);
14707
14918
  if (cultureContent) {
@@ -14712,7 +14923,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14712
14923
  if (isAgentDisabled(localConfig, tool)) continue;
14713
14924
  if (!toolPath.claudemd) continue;
14714
14925
  if (toolPath.rules && !await ResourceHandler.isToolInstalled(toolPath.rules, baseDir)) continue;
14715
- const claudeMdPath = path47.join(baseDir, toolPath.claudemd);
14926
+ const claudeMdPath = path48.join(baseDir, toolPath.claudemd);
14716
14927
  try {
14717
14928
  await injectClaudeMdSection(claudeMdPath, TEAMAI_CULTURE_START, TEAMAI_CULTURE_END, compiled);
14718
14929
  log.debug(`Injected culture into ${tool} CLAUDE.md`);
@@ -14742,7 +14953,7 @@ async function pullForScope(localConfig, options, policy = {}) {
14742
14953
  if (isAgentDisabled(localConfig, tool)) continue;
14743
14954
  if (!toolPath.claudemd) continue;
14744
14955
  if (toolPath.rules && !await ResourceHandler.isToolInstalled(toolPath.rules, baseDir)) continue;
14745
- const claudeMdPath = path47.join(baseDir, toolPath.claudemd);
14956
+ const claudeMdPath = path48.join(baseDir, toolPath.claudemd);
14746
14957
  try {
14747
14958
  await injectClaudeMdSection(claudeMdPath, TEAMAI_CLAUDEMD_START, TEAMAI_CLAUDEMD_END, compiled);
14748
14959
  log.debug(`Injected shared instructions into ${tool} CLAUDE.md`);
@@ -14817,12 +15028,12 @@ async function pullForScope(localConfig, options, policy = {}) {
14817
15028
  const YAML20 = (await import("yaml")).default;
14818
15029
  const { listFiles: listFiles2, readFileSafe: readFileSafe5 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
14819
15030
  const { getRecommendations: getRecommendations2, displayRecommendations: displayRecommendations2 } = await Promise.resolve().then(() => (init_skill_recommend(), skill_recommend_exports));
14820
- const statsDir = path47.join(localConfig.repo.localPath, "stats");
15031
+ const statsDir = path48.join(localConfig.repo.localPath, "stats");
14821
15032
  const files = await listFiles2(statsDir);
14822
15033
  const teamStats = [];
14823
15034
  for (const file of files) {
14824
15035
  if (!file.endsWith(".yaml")) continue;
14825
- const content = await readFileSafe5(path47.join(statsDir, file));
15036
+ const content = await readFileSafe5(path48.join(statsDir, file));
14826
15037
  if (!content) continue;
14827
15038
  try {
14828
15039
  const parsed = YAML20.parse(content);
@@ -14910,7 +15121,7 @@ async function injectRecallBlockIntoTools(config, localConfig, scopeLabel) {
14910
15121
  if (isAgentDisabled(localConfig, tool)) continue;
14911
15122
  if (!toolPath.claudemd || !toolPath.agents) continue;
14912
15123
  if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) continue;
14913
- const claudeMdPath = path47.join(baseDir, toolPath.claudemd);
15124
+ const claudeMdPath = path48.join(baseDir, toolPath.claudemd);
14914
15125
  try {
14915
15126
  await injectClaudeMdSection(
14916
15127
  claudeMdPath,
@@ -14994,7 +15205,7 @@ function compileRecallRulesBlock() {
14994
15205
  return lines.join("\n");
14995
15206
  }
14996
15207
  async function collectClaudemdFiles(repoPath, roleContext) {
14997
- const claudemdDir = path47.join(repoPath, "claudemd");
15208
+ const claudemdDir = path48.join(repoPath, "claudemd");
14998
15209
  if (!await pathExists(claudemdDir)) return [];
14999
15210
  let namespaceDirs;
15000
15211
  if (roleContext) {
@@ -15004,11 +15215,11 @@ async function collectClaudemdFiles(repoPath, roleContext) {
15004
15215
  }
15005
15216
  const contents = [];
15006
15217
  for (const ns of namespaceDirs) {
15007
- const nsDir = path47.join(claudemdDir, ns);
15218
+ const nsDir = path48.join(claudemdDir, ns);
15008
15219
  if (!await pathExists(nsDir)) continue;
15009
15220
  const files = (await listFiles(nsDir)).filter((f) => f.endsWith(".md")).sort();
15010
15221
  for (const file of files) {
15011
- const content = await readFileSafe(path47.join(nsDir, file));
15222
+ const content = await readFileSafe(path48.join(nsDir, file));
15012
15223
  if (content) contents.push(content);
15013
15224
  }
15014
15225
  }
@@ -15016,7 +15227,7 @@ async function collectClaudemdFiles(repoPath, roleContext) {
15016
15227
  }
15017
15228
  async function autoMigrateHooksIfNeeded() {
15018
15229
  const home = process.env.HOME ?? "";
15019
- const primarySettings = path47.join(home, ".claude", "settings.json");
15230
+ const primarySettings = path48.join(home, ".claude", "settings.json");
15020
15231
  if (!await pathExists(primarySettings)) return;
15021
15232
  const content = await readFileSafe(primarySettings);
15022
15233
  if (!content) return;
@@ -15195,108 +15406,18 @@ var init_pull = __esm({
15195
15406
  }
15196
15407
  });
15197
15408
 
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
15409
  // src/agent-skills.ts
15289
- import path48 from "path";
15410
+ import path49 from "path";
15290
15411
  import YAML16 from "yaml";
15291
15412
  async function buildClassifyContext(localConfig) {
15292
15413
  const teamSkills = await collectTeamRepoSkills(localConfig.repo.localPath);
15293
15414
  const sourceSkills = /* @__PURE__ */ new Map();
15294
15415
  try {
15295
- const sourcesDir = path48.join(process.env.HOME ?? "", ".teamai", "sources");
15416
+ const sourcesDir = path49.join(process.env.HOME ?? "", ".teamai", "sources");
15296
15417
  if (await pathExists(sourcesDir)) {
15297
15418
  const sourceNames = await listDirs(sourcesDir);
15298
15419
  for (const sourceName of sourceNames) {
15299
- const manifestPath = path48.join(sourcesDir, sourceName, "installed.json");
15420
+ const manifestPath = path49.join(sourcesDir, sourceName, "installed.json");
15300
15421
  const raw = await readFileSafe(manifestPath);
15301
15422
  if (!raw) continue;
15302
15423
  try {
@@ -15313,13 +15434,13 @@ async function buildClassifyContext(localConfig) {
15313
15434
  return { teamSkills, sourceSkills };
15314
15435
  }
15315
15436
  async function collectTeamRepoSkills(repoPath) {
15316
- const teamSkillsDir = path48.join(repoPath, "skills");
15437
+ const teamSkillsDir = path49.join(repoPath, "skills");
15317
15438
  const result = /* @__PURE__ */ new Map();
15318
15439
  if (!await pathExists(teamSkillsDir)) return result;
15319
15440
  const topDirs = await listDirs(teamSkillsDir);
15320
15441
  for (const dir of topDirs) {
15321
- const dirPath = path48.join(teamSkillsDir, dir);
15322
- const hasSkillMd = await pathExists(path48.join(dirPath, "SKILL.md"));
15442
+ const dirPath = path49.join(teamSkillsDir, dir);
15443
+ const hasSkillMd = await pathExists(path49.join(dirPath, "SKILL.md"));
15323
15444
  if (hasSkillMd) {
15324
15445
  result.set(dir, {});
15325
15446
  } else {
@@ -15366,8 +15487,8 @@ async function scanAgentSkills(agent, ctx) {
15366
15487
  const dirs = await listDirs(agent.absoluteSkillsPath);
15367
15488
  for (const name of dirs) {
15368
15489
  if (name.startsWith(".") || name.endsWith("-workspace")) continue;
15369
- const skillDir = path48.join(agent.absoluteSkillsPath, name);
15370
- const skillMd = path48.join(skillDir, "SKILL.md");
15490
+ const skillDir = path49.join(agent.absoluteSkillsPath, name);
15491
+ const skillMd = path49.join(skillDir, "SKILL.md");
15371
15492
  if (!await pathExists(skillMd)) continue;
15372
15493
  const description = await readSkillDescription(skillMd);
15373
15494
  skills.push({
@@ -15417,7 +15538,7 @@ __export(status_exports, {
15417
15538
  list: () => list,
15418
15539
  status: () => status
15419
15540
  });
15420
- import path49 from "path";
15541
+ import path50 from "path";
15421
15542
  import YAML17 from "yaml";
15422
15543
  async function status(options) {
15423
15544
  const { localConfig, teamConfig } = await autoDetectInit();
@@ -15450,14 +15571,14 @@ async function status(options) {
15450
15571
  log.info("Team resources:");
15451
15572
  const repoPath = localConfig.repo.localPath;
15452
15573
  const counts = {};
15453
- const skillsDirs = await listDirs(path49.join(repoPath, "skills"));
15574
+ const skillsDirs = await listDirs(path50.join(repoPath, "skills"));
15454
15575
  counts.skills = skillsDirs.length;
15455
- const rulesFiles = (await listFiles(path49.join(repoPath, "rules"))).filter((f) => f.endsWith(".md"));
15576
+ const rulesFiles = (await listFiles(path50.join(repoPath, "rules"))).filter((f) => f.endsWith(".md"));
15456
15577
  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(".")) : [];
15578
+ const docsExists = await pathExists(path50.join(repoPath, "docs"));
15579
+ const docFiles = docsExists ? (await listFiles(path50.join(repoPath, "docs"))).filter((f) => !f.startsWith(".")) : [];
15459
15580
  counts.docs = docFiles.length;
15460
- const envYamlPath = path49.join(repoPath, "env", "env.yaml");
15581
+ const envYamlPath = path50.join(repoPath, "env", "env.yaml");
15461
15582
  let envCount = 0;
15462
15583
  if (await pathExists(envYamlPath)) {
15463
15584
  const envContent = await readFileSafe(envYamlPath);
@@ -15545,7 +15666,7 @@ async function printRepoSection(t, options, ctx) {
15545
15666
  console.log("");
15546
15667
  console.log(`=== REPO ${t.toUpperCase()} ===`);
15547
15668
  if (t === "env") {
15548
- const envYamlPath = path49.join(repoPath, "env", "env.yaml");
15669
+ const envYamlPath = path50.join(repoPath, "env", "env.yaml");
15549
15670
  if (await pathExists(envYamlPath)) {
15550
15671
  const envContent = await readFileSafe(envYamlPath);
15551
15672
  if (envContent) {
@@ -15705,7 +15826,7 @@ var skill_cmd_exports = {};
15705
15826
  __export(skill_cmd_exports, {
15706
15827
  skillShow: () => skillShow
15707
15828
  });
15708
- import path50 from "path";
15829
+ import path51 from "path";
15709
15830
  async function skillShow(name, options) {
15710
15831
  const { localConfig, teamConfig } = await autoDetectInit();
15711
15832
  const agents = await detectInstalledAgents(localConfig, teamConfig);
@@ -15718,7 +15839,7 @@ async function skillShow(name, options) {
15718
15839
  }
15719
15840
  const ctx = await buildClassifyContext(localConfig);
15720
15841
  const source = classifySkill(name, ctx);
15721
- const description = truncate(await readSkillDescription(path50.join(resolved.primaryPath, "SKILL.md")), DESCRIPTION_MAX);
15842
+ const description = truncate(await readSkillDescription(path51.join(resolved.primaryPath, "SKILL.md")), DESCRIPTION_MAX);
15722
15843
  const contributors = await SkillsHandler.readContributors(resolved.primaryPath);
15723
15844
  const tagsConfig = await loadTagsConfig(localConfig.repo.localPath);
15724
15845
  const tags = tagsConfig?.skills?.[name] ?? [];
@@ -15736,28 +15857,28 @@ async function skillShow(name, options) {
15736
15857
  });
15737
15858
  if (options.verbose) {
15738
15859
  console.log("");
15739
- console.log(` Verbose: SKILL.md path is ${path50.join(resolved.primaryPath, "SKILL.md")}`);
15860
+ console.log(` Verbose: SKILL.md path is ${path51.join(resolved.primaryPath, "SKILL.md")}`);
15740
15861
  }
15741
15862
  }
15742
15863
  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"))) {
15864
+ const teamSkillsDir = path51.join(localConfig.repo.localPath, "skills");
15865
+ const flat = path51.join(teamSkillsDir, name);
15866
+ if (await pathExists(path51.join(flat, "SKILL.md"))) {
15746
15867
  return { name, primaryPath: flat, primaryOrigin: "team" };
15747
15868
  }
15748
15869
  if (await pathExists(teamSkillsDir)) {
15749
15870
  const namespaces = await listDirs(teamSkillsDir);
15750
15871
  for (const ns of namespaces) {
15751
- const candidate = path50.join(teamSkillsDir, ns, name);
15752
- if (await pathExists(path50.join(candidate, "SKILL.md"))) {
15872
+ const candidate = path51.join(teamSkillsDir, ns, name);
15873
+ if (await pathExists(path51.join(candidate, "SKILL.md"))) {
15753
15874
  return { name, primaryPath: candidate, primaryOrigin: "team", namespace: ns };
15754
15875
  }
15755
15876
  }
15756
15877
  }
15757
15878
  for (const agent of agents) {
15758
15879
  if (!agent.installed) continue;
15759
- const candidate = path50.join(agent.absoluteSkillsPath, name);
15760
- if (await pathExists(path50.join(candidate, "SKILL.md"))) {
15880
+ const candidate = path51.join(agent.absoluteSkillsPath, name);
15881
+ if (await pathExists(path51.join(candidate, "SKILL.md"))) {
15761
15882
  return { name, primaryPath: candidate, primaryOrigin: "agent" };
15762
15883
  }
15763
15884
  }
@@ -15767,8 +15888,8 @@ async function collectInstalledAgents(name, agents) {
15767
15888
  const matches = [];
15768
15889
  for (const agent of agents) {
15769
15890
  if (!agent.installed) continue;
15770
- const skillDir = path50.join(agent.absoluteSkillsPath, name);
15771
- if (await pathExists(path50.join(skillDir, "SKILL.md"))) {
15891
+ const skillDir = path51.join(agent.absoluteSkillsPath, name);
15892
+ if (await pathExists(path51.join(skillDir, "SKILL.md"))) {
15772
15893
  matches.push({ agent, path: skillDir });
15773
15894
  }
15774
15895
  }
@@ -15896,9 +16017,9 @@ __export(members_exports, {
15896
16017
  listMembers: () => listMembers
15897
16018
  });
15898
16019
  import YAML18 from "yaml";
15899
- import path51 from "path";
16020
+ import path52 from "path";
15900
16021
  async function getMemberConfig(repoPath, username) {
15901
- const memberPath = path51.join(repoPath, "members", `${username}.yaml`);
16022
+ const memberPath = path52.join(repoPath, "members", `${username}.yaml`);
15902
16023
  const content = await readFileSafe(memberPath);
15903
16024
  if (!content) return null;
15904
16025
  try {
@@ -15920,7 +16041,7 @@ async function listMembers(options) {
15920
16041
  repoPath = localConfig.repo.localPath;
15921
16042
  await pullRepo(repoPath);
15922
16043
  }
15923
- const membersDir = path51.join(repoPath, "members");
16044
+ const membersDir = path52.join(repoPath, "members");
15924
16045
  const files = await listFiles(membersDir);
15925
16046
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
15926
16047
  if (yamlFiles.length === 0) {
@@ -15931,7 +16052,7 @@ async function listMembers(options) {
15931
16052
  console.log(`Team members (${yamlFiles.length}):`);
15932
16053
  console.log("");
15933
16054
  for (const file of yamlFiles) {
15934
- const content = await readFileSafe(path51.join(membersDir, file));
16055
+ const content = await readFileSafe(path52.join(membersDir, file));
15935
16056
  if (!content) continue;
15936
16057
  try {
15937
16058
  const raw = YAML18.parse(content);
@@ -15977,8 +16098,16 @@ async function remove2(type, names, options) {
15977
16098
  const { localConfig, teamConfig } = await autoDetectInit();
15978
16099
  assertNotReadOnly(localConfig, "teamai remove");
15979
16100
  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));
16101
+ const { withKnowledgeWorktree: withKnowledgeWorktree2, EmptyRepoError: EmptyRepoError2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
16102
+ try {
16103
+ await withKnowledgeWorktree2(localConfig, (wtConfig) => removeCore(type, names, options, wtConfig, teamConfig));
16104
+ } catch (e) {
16105
+ if (e instanceof EmptyRepoError2) {
16106
+ log.error(e.message);
16107
+ } else {
16108
+ log.error(`Remove failed: ${e.message}`);
16109
+ }
16110
+ }
15982
16111
  return;
15983
16112
  }
15984
16113
  await removeCore(type, names, options, localConfig, teamConfig);
@@ -16114,13 +16243,13 @@ var doctor_exports = {};
16114
16243
  __export(doctor_exports, {
16115
16244
  doctor: () => doctor
16116
16245
  });
16117
- import path52 from "path";
16246
+ import path53 from "path";
16118
16247
  async function buildHookChecks(toolPaths, baseDir) {
16119
16248
  const checks = [];
16120
16249
  for (const [tool, paths] of Object.entries(toolPaths)) {
16121
16250
  if (!paths.settings) continue;
16122
- const settingsPath = path52.join(baseDir, paths.settings);
16123
- const parentDir = path52.dirname(settingsPath);
16251
+ const settingsPath = path53.join(baseDir, paths.settings);
16252
+ const parentDir = path53.dirname(settingsPath);
16124
16253
  if (!await pathExists(parentDir)) continue;
16125
16254
  checks.push({
16126
16255
  name: `teamai hooks in ${tool} settings`,
@@ -16212,13 +16341,13 @@ async function doctor(options) {
16212
16341
  check: async () => {
16213
16342
  if (teamConfig?.sharing?.env?.injectShellProfile === false) return true;
16214
16343
  if (!localConfig) return true;
16215
- const envYamlPath = path52.join(localConfig.repo.localPath, "env", "env.yaml");
16344
+ const envYamlPath = path53.join(localConfig.repo.localPath, "env", "env.yaml");
16216
16345
  if (!await pathExists(envYamlPath)) return true;
16217
16346
  const home = process.env.HOME ?? "";
16218
- const envShPath = path52.join(home, ".teamai", "env.sh");
16347
+ const envShPath = path53.join(home, ".teamai", "env.sh");
16219
16348
  if (!await pathExists(envShPath)) return false;
16220
16349
  const shell = process.env.SHELL ?? "";
16221
- const profilePath = shell.includes("zsh") ? path52.join(home, ".zshrc") : path52.join(home, ".bashrc");
16350
+ const profilePath = shell.includes("zsh") ? path53.join(home, ".zshrc") : path53.join(home, ".bashrc");
16222
16351
  if (!await pathExists(profilePath)) return false;
16223
16352
  const content = await readFileSafe(profilePath);
16224
16353
  return content?.includes(TEAMAI_ENV_START) ?? false;
@@ -16265,7 +16394,7 @@ __export(roles_cmd_exports, {
16265
16394
  rolesSet: () => rolesSet,
16266
16395
  rolesUpdate: () => rolesUpdate
16267
16396
  });
16268
- import path53 from "path";
16397
+ import path54 from "path";
16269
16398
  import YAML19 from "yaml";
16270
16399
  function parseNamespaces(input) {
16271
16400
  return input.split(",").map((s) => s.trim()).filter(Boolean);
@@ -16281,8 +16410,16 @@ async function pullLatest(repoPath) {
16281
16410
  }
16282
16411
  async function runRolesEdit(localConfig, fn) {
16283
16412
  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));
16413
+ const { withKnowledgeWorktree: withKnowledgeWorktree2, EmptyRepoError: EmptyRepoError2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
16414
+ try {
16415
+ await withKnowledgeWorktree2(localConfig, (wtConfig) => fn(wtConfig.repo.localPath, wtConfig));
16416
+ } catch (e) {
16417
+ if (e instanceof EmptyRepoError2) {
16418
+ log.error(e.message);
16419
+ } else {
16420
+ log.error(`Roles update failed: ${e.message}`);
16421
+ }
16422
+ }
16286
16423
  return;
16287
16424
  }
16288
16425
  await fn(localConfig.repo.localPath, localConfig);
@@ -16319,7 +16456,7 @@ async function rolesInit(options) {
16319
16456
  const repoPath = localConfig.repo.localPath;
16320
16457
  const selfMode = localConfig.repo.kind === "self";
16321
16458
  if (!selfMode) await pullLatest(repoPath);
16322
- const manifestPath = path53.join(repoPath, "manifest", "roles.yaml");
16459
+ const manifestPath = path54.join(repoPath, "manifest", "roles.yaml");
16323
16460
  if (await pathExists(manifestPath)) {
16324
16461
  log.warn(`Roles manifest already exists at ${manifestPath}`);
16325
16462
  const overwrite = await askConfirmation("Overwrite existing manifest? [y/N] ");
@@ -16389,7 +16526,7 @@ async function rolesInit(options) {
16389
16526
  const commitMsg = `[teamai] Initialize roles manifest with ${roles.length} role(s)`;
16390
16527
  await runRolesEdit(localConfig, async (editRepoPath, editConfig) => {
16391
16528
  await saveRolesManifest(editRepoPath, manifest);
16392
- log.success(`Manifest written to ${path53.join(editRepoPath, "manifest", "roles.yaml")}`);
16529
+ log.success(`Manifest written to ${path54.join(editRepoPath, "manifest", "roles.yaml")}`);
16393
16530
  await pushManifestChange({
16394
16531
  repoPath: editRepoPath,
16395
16532
  teamConfig,
@@ -16667,7 +16804,7 @@ __export(tags_exports, {
16667
16804
  tagsSubscribe: () => tagsSubscribe,
16668
16805
  tagsUnsubscribe: () => tagsUnsubscribe
16669
16806
  });
16670
- import path54 from "path";
16807
+ import path55 from "path";
16671
16808
  async function resolveTagsScope() {
16672
16809
  const projectConfig = await detectProjectConfig();
16673
16810
  return projectConfig ?? (await requireInit()).localConfig;
@@ -16832,7 +16969,7 @@ async function tagsRemove(resourceType, name, tags, options) {
16832
16969
  async function getTeamSkillCount(repoPath) {
16833
16970
  try {
16834
16971
  const { listDirs: listDirs2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
16835
- const skillsDir = path54.join(repoPath, "skills");
16972
+ const skillsDir = path55.join(repoPath, "skills");
16836
16973
  const dirs = await listDirs2(skillsDir);
16837
16974
  return dirs.length;
16838
16975
  } catch {
@@ -16853,7 +16990,7 @@ var uninstall_exports = {};
16853
16990
  __export(uninstall_exports, {
16854
16991
  uninstall: () => uninstall
16855
16992
  });
16856
- import path55 from "path";
16993
+ import path56 from "path";
16857
16994
  function hasToolResources(r) {
16858
16995
  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
16996
  }
@@ -16862,18 +16999,18 @@ function detectShellProfile() {
16862
16999
  if (!home) return null;
16863
17000
  const shell = process.env.SHELL ?? "";
16864
17001
  if (shell.includes("zsh")) {
16865
- return path55.join(home, ".zshrc");
17002
+ return path56.join(home, ".zshrc");
16866
17003
  }
16867
- return path55.join(home, ".bashrc");
17004
+ return path56.join(home, ".bashrc");
16868
17005
  }
16869
17006
  async function collectTeamSkillNames(repoPath) {
16870
- const teamSkillsDir = path55.join(repoPath, "skills");
17007
+ const teamSkillsDir = path56.join(repoPath, "skills");
16871
17008
  if (!await pathExists(teamSkillsDir)) return /* @__PURE__ */ new Set();
16872
17009
  const names = /* @__PURE__ */ new Set();
16873
17010
  const topDirs = await listDirs(teamSkillsDir);
16874
17011
  for (const dir of topDirs) {
16875
- const dirPath = path55.join(teamSkillsDir, dir);
16876
- const hasSkillMd = await pathExists(path55.join(dirPath, "SKILL.md"));
17012
+ const dirPath = path56.join(teamSkillsDir, dir);
17013
+ const hasSkillMd = await pathExists(path56.join(dirPath, "SKILL.md"));
16877
17014
  if (hasSkillMd) {
16878
17015
  names.add(dir);
16879
17016
  } else {
@@ -16886,7 +17023,7 @@ async function collectTeamSkillNames(repoPath) {
16886
17023
  return names;
16887
17024
  }
16888
17025
  async function collectTeamRuleNames(repoPath) {
16889
- const teamRulesDir = path55.join(repoPath, "rules");
17026
+ const teamRulesDir = path56.join(repoPath, "rules");
16890
17027
  if (!await pathExists(teamRulesDir)) return /* @__PURE__ */ new Set();
16891
17028
  const files = await listFilesRecursive(teamRulesDir);
16892
17029
  return new Set(
@@ -16908,52 +17045,52 @@ async function discoverToolResources(tool, toolPath, baseDir, teamSkillNames, te
16908
17045
  agentFiles: []
16909
17046
  };
16910
17047
  if (toolPath.settings) {
16911
- const settingsPath = path55.join(baseDir, toolPath.settings);
17048
+ const settingsPath = path56.join(baseDir, toolPath.settings);
16912
17049
  if (await pathExists(settingsPath) && (await hasTeamaiHooks(settingsPath, tool, managedHooksPath) || isEmptyHooksResidue(await readJson(settingsPath)))) {
16913
17050
  res.hookFiles.push({ path: settingsPath, tool });
16914
17051
  }
16915
17052
  } else {
16916
- const hooksDir = path55.join(baseDir, `.${tool}`, "hooks");
16917
- if (await pathExists(path55.join(hooksDir, OPENCLAW_HOOK_DIR))) {
17053
+ const hooksDir = path56.join(baseDir, `.${tool}`, "hooks");
17054
+ if (await pathExists(path56.join(hooksDir, OPENCLAW_HOOK_DIR))) {
16918
17055
  res.openclawHookDirs.push({ hooksDir, tool });
16919
17056
  }
16920
17057
  }
16921
17058
  if (toolPath.claudemd) {
16922
- const claudeMdPath = path55.join(baseDir, toolPath.claudemd);
17059
+ const claudeMdPath = path56.join(baseDir, toolPath.claudemd);
16923
17060
  const content = await readFileSafe(claudeMdPath);
16924
17061
  if (content && CLAUDEMD_MARKER_PAIRS.some(([start]) => content.includes(start))) {
16925
17062
  res.claudeMdFiles.push(claudeMdPath);
16926
17063
  }
16927
17064
  }
16928
17065
  if (toolPath.skills) {
16929
- const skillsDir = path55.join(baseDir, toolPath.skills);
17066
+ const skillsDir = path56.join(baseDir, toolPath.skills);
16930
17067
  if (await pathExists(skillsDir)) {
16931
17068
  const dirs = await listDirs(skillsDir);
16932
17069
  for (const dir of dirs) {
16933
17070
  if (teamSkillNames.has(dir)) {
16934
- res.skillDirs.push(path55.join(skillsDir, dir));
17071
+ res.skillDirs.push(path56.join(skillsDir, dir));
16935
17072
  }
16936
17073
  }
16937
17074
  }
16938
17075
  }
16939
17076
  if (toolPath.rules) {
16940
- const rulesDir = path55.join(baseDir, toolPath.rules);
17077
+ const rulesDir = path56.join(baseDir, toolPath.rules);
16941
17078
  if (await pathExists(rulesDir)) {
16942
17079
  const files = await listFilesRecursive(rulesDir);
16943
17080
  for (const file of files) {
16944
17081
  if (!file.endsWith(".md")) continue;
16945
17082
  const ruleName = file.replace(/\.md$/, "");
16946
17083
  if (teamRuleNames.has(ruleName)) {
16947
- res.ruleFiles.push(path55.join(rulesDir, file));
17084
+ res.ruleFiles.push(path56.join(rulesDir, file));
16948
17085
  }
16949
17086
  }
16950
17087
  }
16951
17088
  }
16952
17089
  if (toolPath.agents) {
16953
- const agentsDir = path55.join(baseDir, toolPath.agents);
17090
+ const agentsDir = path56.join(baseDir, toolPath.agents);
16954
17091
  if (await pathExists(agentsDir)) {
16955
17092
  for (const name of BUILTIN_AGENT_NAMES) {
16956
- const agentFile = path55.join(agentsDir, `${name}.md`);
17093
+ const agentFile = path56.join(agentsDir, `${name}.md`);
16957
17094
  if (await pathExists(agentFile)) {
16958
17095
  res.agentFiles.push(agentFile);
16959
17096
  }
@@ -16970,7 +17107,7 @@ async function buildRemovalPlan(localConfig, teamConfig, agentFilter) {
16970
17107
  for (const name of BUILTIN_SKILL_NAMES) teamSkillNames.add(name);
16971
17108
  const teamRuleNames = await collectTeamRuleNames(repoPath);
16972
17109
  for (const name of BUILTIN_RULE_NAMES) teamRuleNames.add(name);
16973
- const localAgentManifestPath = path55.join(
17110
+ const localAgentManifestPath = path56.join(
16974
17111
  process.env.HOME ?? "",
16975
17112
  ".teamai",
16976
17113
  "local-agent",
@@ -17057,7 +17194,7 @@ async function buildRemovalPlan(localConfig, teamConfig, agentFilter) {
17057
17194
  const docsLocalDir = teamConfig.sharing.docs.localDir;
17058
17195
  let docsDir;
17059
17196
  if (localConfig.scope === "project" && localConfig.projectRoot) {
17060
- docsDir = docsLocalDir.startsWith("~/") ? path55.join(localConfig.projectRoot, docsLocalDir.substring(2)) : expandHome(docsLocalDir);
17197
+ docsDir = docsLocalDir.startsWith("~/") ? path56.join(localConfig.projectRoot, docsLocalDir.substring(2)) : expandHome(docsLocalDir);
17061
17198
  } else {
17062
17199
  docsDir = expandHome(docsLocalDir);
17063
17200
  }
@@ -17090,7 +17227,7 @@ function printSummary(plan, agentFilter) {
17090
17227
  if (plan.openclawHookDirs.length > 0) {
17091
17228
  console.log(` OpenClaw Hooks (${plan.openclawHookDirs.length} \u4E2A\u76EE\u5F55):`);
17092
17229
  for (const { hooksDir } of plan.openclawHookDirs) {
17093
- console.log(` ${path55.join(hooksDir, OPENCLAW_HOOK_DIR)}/`);
17230
+ console.log(` ${path56.join(hooksDir, OPENCLAW_HOOK_DIR)}/`);
17094
17231
  }
17095
17232
  console.log("");
17096
17233
  }
@@ -17338,7 +17475,7 @@ async function uninstall(opts) {
17338
17475
  log.error("\u65E0\u6CD5\u786E\u5B9A\u7528\u6237\u4E3B\u76EE\u5F55\uFF08HOME \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E\uFF09");
17339
17476
  return;
17340
17477
  }
17341
- const home = path55.join(homeDir, ".teamai");
17478
+ const home = path56.join(homeDir, ".teamai");
17342
17479
  if (!await pathExists(home)) {
17343
17480
  log.info("\u6CA1\u6709\u9700\u8981\u5378\u8F7D\u7684\u5185\u5BB9");
17344
17481
  return;
@@ -17399,11 +17536,11 @@ __export(env_commands_exports, {
17399
17536
  envList: () => envList,
17400
17537
  envRemove: () => envRemove
17401
17538
  });
17402
- import path56 from "path";
17539
+ import path57 from "path";
17403
17540
  async function envList(options) {
17404
17541
  const projectConfig = await detectProjectConfig();
17405
17542
  const localConfig = projectConfig ?? (await requireInit()).localConfig;
17406
- const envYamlPath = path56.join(localConfig.repo.localPath, "env", "env.yaml");
17543
+ const envYamlPath = path57.join(localConfig.repo.localPath, "env", "env.yaml");
17407
17544
  if (!await pathExists(envYamlPath)) {
17408
17545
  log.info("No env variables defined (env/env.yaml not found)");
17409
17546
  return;
@@ -17432,7 +17569,7 @@ async function envAdd(key, value, options) {
17432
17569
  const projectConfig = await detectProjectConfig();
17433
17570
  const localConfig = projectConfig ?? (await requireInit()).localConfig;
17434
17571
  const repoPath = localConfig.repo.localPath;
17435
- const envYamlPath = path56.join(repoPath, "env", "env.yaml");
17572
+ const envYamlPath = path57.join(repoPath, "env", "env.yaml");
17436
17573
  const pullSpin = spinner("Pulling latest...").start();
17437
17574
  try {
17438
17575
  await pullRepo(repoPath);
@@ -17459,7 +17596,7 @@ async function envAdd(key, value, options) {
17459
17596
  log.info(`[dry-run] Would ${isUpdate ? "update" : "add"} env variable: ${key}=${value}`);
17460
17597
  return;
17461
17598
  }
17462
- await ensureDir(path56.join(repoPath, "env"));
17599
+ await ensureDir(path57.join(repoPath, "env"));
17463
17600
  await envHandler.writeEnvYaml(envYamlPath, envConfig);
17464
17601
  const action = isUpdate ? "Updated" : "Added";
17465
17602
  log.success(`${action} env variable: ${key}=${value}`);
@@ -17469,7 +17606,7 @@ async function envRemove(key, options) {
17469
17606
  const projectConfig = await detectProjectConfig();
17470
17607
  const localConfig = projectConfig ?? (await requireInit()).localConfig;
17471
17608
  const repoPath = localConfig.repo.localPath;
17472
- const envYamlPath = path56.join(repoPath, "env", "env.yaml");
17609
+ const envYamlPath = path57.join(repoPath, "env", "env.yaml");
17473
17610
  const pullSpin = spinner("Pulling latest...").start();
17474
17611
  try {
17475
17612
  await pullRepo(repoPath);
@@ -17516,7 +17653,7 @@ __export(hooks_cmd_exports, {
17516
17653
  hooksList: () => hooksList,
17517
17654
  hooksRemove: () => hooksRemove
17518
17655
  });
17519
- import path57 from "path";
17656
+ import path58 from "path";
17520
17657
  function resolveHookScopeTargets(localConfig) {
17521
17658
  if (localConfig.scope !== "project") {
17522
17659
  return [{
@@ -17533,7 +17670,7 @@ function formatDisplayPath(settingsPath) {
17533
17670
  const home = process.env.HOME;
17534
17671
  if (!home) return settingsPath;
17535
17672
  if (settingsPath === home) return "~";
17536
- if (settingsPath.startsWith(home + path57.sep) || settingsPath.startsWith(home + "/")) {
17673
+ if (settingsPath.startsWith(home + path58.sep) || settingsPath.startsWith(home + "/")) {
17537
17674
  return `~${settingsPath.slice(home.length)}`;
17538
17675
  }
17539
17676
  return settingsPath;
@@ -17575,7 +17712,7 @@ async function hooksList(_options) {
17575
17712
  continue;
17576
17713
  }
17577
17714
  for (const baseDir of baseDirs) {
17578
- const settingsPath = path57.join(baseDir, paths.settings);
17715
+ const settingsPath = path58.join(baseDir, paths.settings);
17579
17716
  rows.push({
17580
17717
  tool,
17581
17718
  status: await getHookStatus(settingsPath, tool),
@@ -17634,10 +17771,10 @@ __export(mcp_cmd_exports, {
17634
17771
  mcpList: () => mcpList,
17635
17772
  mcpRemove: () => mcpRemove
17636
17773
  });
17637
- import path58 from "path";
17774
+ import path59 from "path";
17638
17775
  function displayPath(p) {
17639
17776
  const home = process.env.HOME;
17640
- if (home && (p === home || p.startsWith(home + path58.sep))) return `~${p.slice(home.length)}`;
17777
+ if (home && (p === home || p.startsWith(home + path59.sep))) return `~${p.slice(home.length)}`;
17641
17778
  return p;
17642
17779
  }
17643
17780
  async function mcpList(_options) {
@@ -17717,7 +17854,7 @@ var init_mcp_cmd = __esm({
17717
17854
 
17718
17855
  // src/session-collector.ts
17719
17856
  import fs17 from "fs";
17720
- import path59 from "path";
17857
+ import path60 from "path";
17721
17858
  function isValuable(summary) {
17722
17859
  return summary.interventionCount > 0 || summary.distinctTools >= SUBSTANTIAL_TOOL_COUNT;
17723
17860
  }
@@ -17797,7 +17934,7 @@ function monthKey(summary) {
17797
17934
  async function appendMonthlyLog(dir, summary, options = {}) {
17798
17935
  await ensureDir(dir);
17799
17936
  const month = monthKey(summary);
17800
- const file = path59.join(dir, `${month}.md`);
17937
+ const file = path60.join(dir, `${month}.md`);
17801
17938
  const block = renderSessionMarkdown(summary, options);
17802
17939
  const marker = `<!-- teamai:session ${summary.sessionId} -->`;
17803
17940
  let existing = "";
@@ -17827,7 +17964,7 @@ async function pruneMonthlyLogs(dir, now, retentionDays = 90) {
17827
17964
  const monthEnd = new Date(Date.UTC(Number(m[1]), Number(m[2]), 0, 23, 59, 59));
17828
17965
  if (monthEnd.getTime() < cutoff) {
17829
17966
  try {
17830
- await fs17.promises.unlink(path59.join(dir, entry));
17967
+ await fs17.promises.unlink(path60.join(dir, entry));
17831
17968
  removed.push(entry);
17832
17969
  } catch {
17833
17970
  }
@@ -17853,7 +17990,7 @@ var save_session_exports = {};
17853
17990
  __export(save_session_exports, {
17854
17991
  saveSession: () => saveSession
17855
17992
  });
17856
- import path60 from "path";
17993
+ import path61 from "path";
17857
17994
  function mostRecentSessionId(events) {
17858
17995
  let best;
17859
17996
  for (const e of events) {
@@ -17933,13 +18070,13 @@ async function saveSession(options) {
17933
18070
  try {
17934
18071
  const { ensureReportsWorktree: ensureReportsWorktree2, commitAndPushReports: commitAndPushReports2 } = await Promise.resolve().then(() => (init_reports_branch(), reports_branch_exports));
17935
18072
  const wt = await ensureReportsWorktree2(localConfig);
17936
- const teamDir2 = path60.join(wt, "sessions", username);
18073
+ const teamDir2 = path61.join(wt, "sessions", username);
17937
18074
  const written = await appendMonthlyLog(teamDir2, summary, { includePrompt: options.includePrompt });
17938
18075
  if (!written) {
17939
18076
  spin2.info("Session already present in the team log \u2014 nothing to push.");
17940
18077
  return;
17941
18078
  }
17942
- const rel = path60.relative(wt, written);
18079
+ const rel = path61.relative(wt, written);
17943
18080
  const pushed = await withTimeout(
17944
18081
  commitAndPushReports2(localConfig, commitMsg, [rel]),
17945
18082
  1e4,
@@ -17954,7 +18091,7 @@ async function saveSession(options) {
17954
18091
  return;
17955
18092
  }
17956
18093
  const repoPath = localConfig.repo.localPath;
17957
- const teamDir = path60.join(repoPath, "sessions", username);
18094
+ const teamDir = path61.join(repoPath, "sessions", username);
17958
18095
  const spin = spinner("Pushing session summary to team...").start();
17959
18096
  try {
17960
18097
  try {
@@ -17967,7 +18104,7 @@ async function saveSession(options) {
17967
18104
  spin.info("Session already present in the team log \u2014 nothing to push.");
17968
18105
  return;
17969
18106
  }
17970
- const rel = path60.relative(repoPath, written);
18107
+ const rel = path61.relative(repoPath, written);
17971
18108
  await withTimeout(pushRepoDirectly(repoPath, commitMsg, [rel]), 1e4, "Push timeout (10s)");
17972
18109
  spin.succeed(`Pushed: ${rel}`);
17973
18110
  } catch (e) {
@@ -18737,11 +18874,11 @@ __export(dashboard_exports, {
18737
18874
  });
18738
18875
  import http from "http";
18739
18876
  import fs18 from "fs";
18740
- import path61 from "path";
18877
+ import path62 from "path";
18741
18878
  async function startDashboard(port) {
18742
18879
  const serverPort = port ?? DASHBOARD_DEFAULT_PORT;
18743
- const eventsPath = path61.join(process.env.HOME ?? "", ".teamai", "dashboard", "events.jsonl");
18744
- await ensureDir(path61.dirname(eventsPath));
18880
+ const eventsPath = path62.join(process.env.HOME ?? "", ".teamai", "dashboard", "events.jsonl");
18881
+ await ensureDir(path62.dirname(eventsPath));
18745
18882
  try {
18746
18883
  await fs18.promises.access(eventsPath);
18747
18884
  } catch {
@@ -18943,14 +19080,14 @@ var init_hook_dispatch = __esm({
18943
19080
  });
18944
19081
 
18945
19082
  // src/recall-quality.ts
18946
- import path62 from "path";
19083
+ import path63 from "path";
18947
19084
  import fs19 from "fs";
18948
19085
  function sanitizeSessionId(sessionId) {
18949
19086
  return sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
18950
19087
  }
18951
19088
  function getCachePath(sessionId) {
18952
19089
  const safeName = sanitizeSessionId(sessionId);
18953
- return path62.join(
19090
+ return path63.join(
18954
19091
  process.env.HOME ?? "",
18955
19092
  ".teamai",
18956
19093
  "sessions",
@@ -18981,7 +19118,7 @@ function readCache(sessionId) {
18981
19118
  function writeCache(sessionId, cache) {
18982
19119
  try {
18983
19120
  const cachePath = getCachePath(sessionId);
18984
- const dir = path62.dirname(cachePath);
19121
+ const dir = path63.dirname(cachePath);
18985
19122
  if (!fs19.existsSync(dir)) {
18986
19123
  fs19.mkdirSync(dir, { recursive: true });
18987
19124
  }
@@ -19067,7 +19204,7 @@ __export(contribute_check_exports, {
19067
19204
  writeContributeState: () => writeContributeState
19068
19205
  });
19069
19206
  import fs20 from "fs";
19070
- import path63 from "path";
19207
+ import path64 from "path";
19071
19208
  import { execFileSync as execFileSync2 } from "child_process";
19072
19209
  function sanitizeSessionId2(sessionId) {
19073
19210
  return sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
@@ -19093,7 +19230,7 @@ function normalizePromptSummary(raw) {
19093
19230
  return `${truncated}\u2026`;
19094
19231
  }
19095
19232
  function getSessionPath(sessionId) {
19096
- return path63.join(
19233
+ return path64.join(
19097
19234
  process.env.HOME ?? "",
19098
19235
  ".teamai",
19099
19236
  "sessions",
@@ -19131,14 +19268,14 @@ async function readContributeState(sessionId) {
19131
19268
  async function writeContributeState(sessionId, state) {
19132
19269
  try {
19133
19270
  const filePath = getSessionPath(sessionId);
19134
- await ensureDir(path63.dirname(filePath));
19271
+ await ensureDir(path64.dirname(filePath));
19135
19272
  const persistedState = {
19136
19273
  ...state,
19137
19274
  friction: parseSessionFriction(state.friction),
19138
19275
  promptSummary: normalizePromptSummary(state.promptSummary)
19139
19276
  };
19140
19277
  await writeJson(filePath, persistedState);
19141
- await cleanupStaleSessions(path63.dirname(filePath), sessionId);
19278
+ await cleanupStaleSessions(path64.dirname(filePath), sessionId);
19142
19279
  } catch (e) {
19143
19280
  log.error(`Failed to write contribute state: ${e.message}`);
19144
19281
  }
@@ -19151,7 +19288,7 @@ async function cleanupStaleSessions(dir, currentSessionId) {
19151
19288
  if (!entry.endsWith(".json")) continue;
19152
19289
  const name = entry.replace(".json", "");
19153
19290
  if (name === currentBasename) continue;
19154
- const filePath = path63.join(dir, entry);
19291
+ const filePath = path64.join(dir, entry);
19155
19292
  try {
19156
19293
  const stat6 = await fs20.promises.stat(filePath);
19157
19294
  if (now - stat6.mtimeMs > STALE_SESSION_MS) {
@@ -19443,7 +19580,7 @@ __export(transcript_parser_exports, {
19443
19580
  parseTranscriptForVotes: () => parseTranscriptForVotes
19444
19581
  });
19445
19582
  import fs21 from "fs";
19446
- import path64 from "path";
19583
+ import path65 from "path";
19447
19584
  import readline4 from "readline";
19448
19585
  async function parseTranscriptForVotes(transcriptPath) {
19449
19586
  const recalledSet = /* @__PURE__ */ new Set();
@@ -19513,7 +19650,7 @@ function extractRecalledDocIds(text, out) {
19513
19650
  let match;
19514
19651
  while ((match = filePattern.exec(region)) !== null) {
19515
19652
  const filePath = match[1].trim();
19516
- const docId = path64.basename(filePath).replace(/\.md$/i, "");
19653
+ const docId = path65.basename(filePath).replace(/\.md$/i, "");
19517
19654
  if (isValidDocId(docId)) out.add(docId);
19518
19655
  }
19519
19656
  searchFrom = endIdx + END.length;
@@ -19545,10 +19682,10 @@ __export(todowrite_hint_exports, {
19545
19682
  shouldSkipTodoWriteHint: () => shouldSkipTodoWriteHint,
19546
19683
  todoWriteHint: () => todoWriteHint
19547
19684
  });
19548
- import path65 from "path";
19685
+ import path66 from "path";
19549
19686
  import fs22 from "fs";
19550
19687
  function getTodoWriteHintCachePath(sessionId) {
19551
- return path65.join(
19688
+ return path66.join(
19552
19689
  process.env.HOME ?? "",
19553
19690
  ".teamai",
19554
19691
  "sessions",
@@ -19571,7 +19708,7 @@ function readCache2(sessionId) {
19571
19708
  function writeCache2(sessionId, cache) {
19572
19709
  try {
19573
19710
  const cachePath = getTodoWriteHintCachePath(sessionId);
19574
- const dir = path65.dirname(cachePath);
19711
+ const dir = path66.dirname(cachePath);
19575
19712
  if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
19576
19713
  fs22.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
19577
19714
  } catch {
@@ -19653,12 +19790,12 @@ __export(mr_hint_exports, {
19653
19790
  });
19654
19791
  import { spawnSync as spawnSync4 } from "child_process";
19655
19792
  import fs23 from "fs";
19656
- import path66 from "path";
19793
+ import path67 from "path";
19657
19794
  function repoSlug(owner, repo) {
19658
19795
  return `${owner}/${repo}`.replace(/[^a-zA-Z0-9_-]/g, "_");
19659
19796
  }
19660
19797
  function getCachePath2(owner, repo) {
19661
- return path66.join(
19798
+ return path67.join(
19662
19799
  process.env.HOME ?? "",
19663
19800
  ".teamai",
19664
19801
  "sessions",
@@ -19681,7 +19818,7 @@ function loadCache(owner, repo) {
19681
19818
  function saveCache(owner, repo, cache) {
19682
19819
  try {
19683
19820
  const cachePath = getCachePath2(owner, repo);
19684
- const dir = path66.dirname(cachePath);
19821
+ const dir = path67.dirname(cachePath);
19685
19822
  if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
19686
19823
  fs23.writeFileSync(cachePath, JSON.stringify(cache), "utf-8");
19687
19824
  } catch {
@@ -19828,7 +19965,7 @@ function buildHintMessage2(mrs) {
19828
19965
  async function computeMrHintOutput() {
19829
19966
  if (process.env.TEAMAI_MR_HINT_DISABLED === "1") return null;
19830
19967
  const rawCwd = process.env.TEAMAI_MR_HINT_CWD ?? process.cwd();
19831
- const cwd = path66.resolve(rawCwd);
19968
+ const cwd = path67.resolve(rawCwd);
19832
19969
  try {
19833
19970
  if (!fs23.statSync(cwd).isDirectory()) {
19834
19971
  return null;
@@ -19896,7 +20033,7 @@ var init_mr_hint = __esm({
19896
20033
  });
19897
20034
 
19898
20035
  // src/hook-handlers.ts
19899
- import path67 from "path";
20036
+ import path68 from "path";
19900
20037
  function buildHandlerRegistry() {
19901
20038
  return [
19902
20039
  // ─── SessionStart ─────────────────────────────────
@@ -20048,7 +20185,7 @@ var init_hook_handlers = __esm({
20048
20185
  const { localConfig } = await autoDetectInit2();
20049
20186
  const { VOTES_LOCAL_DIR: VOTES_LOCAL_DIR2, TEAMAI_SESSIONS_DIR: TEAMAI_SESSIONS_DIR2 } = await Promise.resolve().then(() => (init_types(), types_exports));
20050
20187
  const votesDir = VOTES_LOCAL_DIR2;
20051
- const votePath = path67.join(votesDir, `${localConfig.username}.yaml`);
20188
+ const votePath = path68.join(votesDir, `${localConfig.username}.yaml`);
20052
20189
  if (voteData.referencedDocIds.length > 0) {
20053
20190
  await incrementUpvoted2(votePath, voteData.referencedDocIds);
20054
20191
  }
@@ -20073,7 +20210,7 @@ var init_hook_handlers = __esm({
20073
20210
  if (recalled.length > 0 && declared.length === 0) {
20074
20211
  const fsp = await import("fs/promises");
20075
20212
  const safeId = sessionId.replace(/[^a-zA-Z0-9_.-]/g, "_");
20076
- const marker = path67.join(TEAMAI_SESSIONS_DIR2, `${safeId}-adoption-nudged`);
20213
+ const marker = path68.join(TEAMAI_SESSIONS_DIR2, `${safeId}-adoption-nudged`);
20077
20214
  let already = false;
20078
20215
  try {
20079
20216
  await fsp.access(marker);
@@ -20277,21 +20414,21 @@ __export(contribute_exports, {
20277
20414
  contribute: () => contribute
20278
20415
  });
20279
20416
  import fs24 from "fs";
20280
- import path68 from "path";
20417
+ import path69 from "path";
20281
20418
  import fse11 from "fs-extra";
20282
20419
  async function rebuildIndexAfterContribute(localConfig) {
20283
20420
  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");
20421
+ const learningsRepoDir = path69.join(repoPath, "learnings");
20422
+ const docsRepoDir = path69.join(repoPath, "docs");
20423
+ const rulesRepoDir = path69.join(repoPath, "rules");
20424
+ const skillsRepoDir = path69.join(repoPath, "skills");
20425
+ const votesDir = path69.join(repoPath, "votes");
20289
20426
  let effectiveLearningsDir;
20290
20427
  if (localConfig.scope === "user") {
20291
20428
  if (await pathExists(learningsRepoDir)) {
20292
20429
  await fse11.copy(learningsRepoDir, LEARNINGS_LOCAL_DIR, {
20293
20430
  overwrite: true,
20294
- filter: (src) => !path68.basename(src).startsWith(".")
20431
+ filter: (src) => !path69.basename(src).startsWith(".")
20295
20432
  });
20296
20433
  }
20297
20434
  effectiveLearningsDir = await pathExists(LEARNINGS_LOCAL_DIR) ? LEARNINGS_LOCAL_DIR : void 0;
@@ -20299,7 +20436,7 @@ async function rebuildIndexAfterContribute(localConfig) {
20299
20436
  effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
20300
20437
  }
20301
20438
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
20302
- const indexPath = path68.join(teamaiHome, "search-index.json");
20439
+ const indexPath = path69.join(teamaiHome, "search-index.json");
20303
20440
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
20304
20441
  await buildIndex2({
20305
20442
  learningsDir: effectiveLearningsDir,
@@ -20362,9 +20499,9 @@ async function contribute(options) {
20362
20499
  const pushSpin = spinner("Contributing session knowledge...").start();
20363
20500
  const filename = generateFilename(options.title);
20364
20501
  try {
20365
- const aiDocsDir = path68.join(repoPath, "learnings");
20502
+ const aiDocsDir = path69.join(repoPath, "learnings");
20366
20503
  await ensureDir(aiDocsDir);
20367
- const destPath = path68.join(aiDocsDir, filename);
20504
+ const destPath = path69.join(aiDocsDir, filename);
20368
20505
  await fs24.promises.writeFile(destPath, content, "utf-8");
20369
20506
  try {
20370
20507
  await pullRepo(repoPath);
@@ -20414,19 +20551,19 @@ async function contributeSelf(localConfig, content, options) {
20414
20551
  const teamConfig = await loadTeamConfig(localConfig.repo.localPath);
20415
20552
  await withKnowledgeWorktree2(localConfig, async (wtConfig) => {
20416
20553
  const wtRepo = wtConfig.repo.localPath;
20417
- await ensureDir(path68.join(wtRepo, "learnings"));
20418
- await fs24.promises.writeFile(path68.join(wtRepo, relPath), content, "utf-8");
20554
+ await ensureDir(path69.join(wtRepo, "learnings"));
20555
+ await fs24.promises.writeFile(path69.join(wtRepo, relPath), content, "utf-8");
20419
20556
  try {
20420
- const wtLearnings = path68.join(wtRepo, "learnings");
20557
+ const wtLearnings = path69.join(wtRepo, "learnings");
20421
20558
  await fse11.copy(wtLearnings, LEARNINGS_LOCAL_DIR, {
20422
20559
  overwrite: true,
20423
- filter: (src) => !path68.basename(src).startsWith(".")
20560
+ filter: (src) => !path69.basename(src).startsWith(".")
20424
20561
  });
20425
20562
  const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
20426
20563
  const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
20427
20564
  await buildIndex2({
20428
20565
  learningsDir: LEARNINGS_LOCAL_DIR,
20429
- indexPath: path68.join(teamaiHome, "search-index.json")
20566
+ indexPath: path69.join(teamaiHome, "search-index.json")
20430
20567
  });
20431
20568
  } catch (e) {
20432
20569
  log.debug(`contribute(self): local index refresh skipped: ${e.message}`);
@@ -20472,7 +20609,7 @@ var init_contribute = __esm({
20472
20609
  });
20473
20610
 
20474
20611
  // src/wiki-engine/core/wiki-protocol.ts
20475
- import path69 from "path";
20612
+ import path70 from "path";
20476
20613
  function safeIgnore(filePath) {
20477
20614
  const normalized = toPosix(filePath);
20478
20615
  const parts = normalized.split("/").filter(Boolean);
@@ -20486,7 +20623,7 @@ function safeIgnore(filePath) {
20486
20623
  return /\.(pem|key|p12|pfx)$/i.test(base);
20487
20624
  }
20488
20625
  function toPosix(value) {
20489
- return value.split(path69.sep).join("/");
20626
+ return value.split(path70.sep).join("/");
20490
20627
  }
20491
20628
  var CONFIDENCE_SCORE_DEFAULTS, SAFE_IGNORE_SEGMENTS, SENSITIVE_FILE_NAMES;
20492
20629
  var init_wiki_protocol = __esm({
@@ -20533,7 +20670,7 @@ __export(graph_index_schema_exports, {
20533
20670
  validateGraph: () => validateGraph
20534
20671
  });
20535
20672
  import { readFile as readFile2, writeFile as writeFile4, mkdir } from "fs/promises";
20536
- import path70 from "path";
20673
+ import path71 from "path";
20537
20674
  function toPageSlug(relativePath) {
20538
20675
  return relativePath.replace(/\.md$/u, "").replace(/\\/g, "/");
20539
20676
  }
@@ -20704,7 +20841,7 @@ function computeGraphHealth(graph) {
20704
20841
  };
20705
20842
  }
20706
20843
  async function loadGraphIndex(wikiRoot) {
20707
- const graphPath = path70.join(wikiRoot, ".indices", "graph-index.json");
20844
+ const graphPath = path71.join(wikiRoot, ".indices", "graph-index.json");
20708
20845
  try {
20709
20846
  const raw = await readFile2(graphPath, "utf8");
20710
20847
  const parsed = JSON.parse(raw);
@@ -20717,9 +20854,9 @@ async function loadGraphIndex(wikiRoot) {
20717
20854
  }
20718
20855
  }
20719
20856
  async function saveGraphIndex(wikiRoot, graph) {
20720
- const dir = path70.join(wikiRoot, ".indices");
20857
+ const dir = path71.join(wikiRoot, ".indices");
20721
20858
  await mkdir(dir, { recursive: true });
20722
- const outPath = path70.join(dir, "graph-index.json");
20859
+ const outPath = path71.join(dir, "graph-index.json");
20723
20860
  await writeFile4(outPath, JSON.stringify(graph, null, 2), "utf8");
20724
20861
  return outPath;
20725
20862
  }
@@ -20772,7 +20909,7 @@ var init_graph_index_schema = __esm({
20772
20909
 
20773
20910
  // src/code-knowledge-recall.ts
20774
20911
  import { readFile as readFile3, readdir } from "fs/promises";
20775
- import path71 from "path";
20912
+ import path72 from "path";
20776
20913
  import matter5 from "gray-matter";
20777
20914
  function countOccurrences(text, token) {
20778
20915
  let count = 0;
@@ -20907,7 +21044,7 @@ function extractSnippet(content, queryTokens, maxLen = 300) {
20907
21044
  async function loadWikiPages(wikiRoot, depth) {
20908
21045
  const pages = [];
20909
21046
  if (depth === "route") {
20910
- const routerPath = path71.join(wikiRoot, "router.md");
21047
+ const routerPath = path72.join(wikiRoot, "router.md");
20911
21048
  try {
20912
21049
  const content = await readFile3(routerPath, "utf-8");
20913
21050
  const titleMatch = content.match(/^title:\s*(.+)$/m);
@@ -20923,7 +21060,7 @@ async function loadWikiPages(wikiRoot, depth) {
20923
21060
  }
20924
21061
  return pages;
20925
21062
  }
20926
- const evidenceDir = path71.join(wikiRoot, "evidence", "code");
21063
+ const evidenceDir = path72.join(wikiRoot, "evidence", "code");
20927
21064
  let projectDirs;
20928
21065
  try {
20929
21066
  const entries = await readdir(evidenceDir, { withFileTypes: true });
@@ -20932,7 +21069,7 @@ async function loadWikiPages(wikiRoot, depth) {
20932
21069
  return pages;
20933
21070
  }
20934
21071
  for (const project of projectDirs) {
20935
- const projectDir = path71.join(evidenceDir, project);
21072
+ const projectDir = path72.join(evidenceDir, project);
20936
21073
  await loadPagesRecursive(projectDir, `evidence/code/${project}`, pages, depth);
20937
21074
  }
20938
21075
  return pages;
@@ -21003,7 +21140,7 @@ async function loadPagesRecursive(dir, relativePath, pages, depth, currentDepth
21003
21140
  if (currentDepth >= MAX_RECURSION_DEPTH) return;
21004
21141
  const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
21005
21142
  for (const entry of entries) {
21006
- const fullPath = path71.join(dir, entry.name);
21143
+ const fullPath = path72.join(dir, entry.name);
21007
21144
  if (entry.isDirectory()) {
21008
21145
  await loadPagesRecursive(
21009
21146
  fullPath,
@@ -21178,7 +21315,7 @@ __export(recall_exports, {
21178
21315
  isRelevantScore: () => isRelevantScore,
21179
21316
  recall: () => recall
21180
21317
  });
21181
- import path72 from "path";
21318
+ import path73 from "path";
21182
21319
  function isRelevantScore(score, isCodebaseHit, idfBaseline) {
21183
21320
  if (isCodebaseHit) return score >= CODEBASE_RELEVANCE_THRESHOLD;
21184
21321
  const baseline = idfBaseline > 0 ? idfBaseline : 1;
@@ -21249,7 +21386,7 @@ async function autoUpvote(results, username, _repoPath) {
21249
21386
  try {
21250
21387
  const { incrementRecalled: incrementRecalled2 } = await Promise.resolve().then(() => (init_votes(), votes_exports));
21251
21388
  const votesDir = getVotesLocalDir();
21252
- const localVotePath = path72.join(votesDir, `${username}.yaml`);
21389
+ const localVotePath = path73.join(votesDir, `${username}.yaml`);
21253
21390
  await ensureDir(votesDir);
21254
21391
  const docIds = results.map((r) => r.entry.filename.replace(/\.md$/i, ""));
21255
21392
  await incrementRecalled2(localVotePath, docIds);
@@ -21260,9 +21397,9 @@ async function autoUpvote(results, username, _repoPath) {
21260
21397
  }
21261
21398
  async function loadOrBuildScopeIndex(localConfig, scopeLabel) {
21262
21399
  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");
21400
+ const indexPath = path73.join(teamaiHome, "search-index.json");
21401
+ const localLearningsDir = path73.join(teamaiHome, "learnings");
21402
+ const repoLearningsDir = path73.join(localConfig.repo.localPath, "learnings");
21266
21403
  let effectiveLearningsDir = null;
21267
21404
  if (scopeLabel === "user" && await pathExists(localLearningsDir)) {
21268
21405
  effectiveLearningsDir = localLearningsDir;
@@ -21271,14 +21408,14 @@ async function loadOrBuildScopeIndex(localConfig, scopeLabel) {
21271
21408
  }
21272
21409
  let index = await loadIndex(indexPath);
21273
21410
  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")))) {
21411
+ 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
21412
  const { getReportsDir: getReportsDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
21276
- const votesDir = path72.join(getReportsDir2(localConfig), "votes");
21413
+ const votesDir = path73.join(getReportsDir2(localConfig), "votes");
21277
21414
  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");
21415
+ const docsDir = path73.join(localConfig.repo.localPath, "docs");
21416
+ const rulesDir = path73.join(localConfig.repo.localPath, "rules");
21417
+ const skillsDir = path73.join(localConfig.repo.localPath, "skills");
21418
+ const repoCodebaseDir = path73.join(localConfig.repo.localPath, "docs", "team-codebase");
21282
21419
  const codebaseDir = await pathExists(repoCodebaseDir) ? repoCodebaseDir : void 0;
21283
21420
  try {
21284
21421
  await buildIndex({
@@ -21369,7 +21506,7 @@ async function recall(query, options) {
21369
21506
  }
21370
21507
  }
21371
21508
  const wikiConfig = projectConfig ?? scopeIndexes[0]?.config;
21372
- const wikiRoot = wikiConfig ? path72.join(wikiConfig.repo.localPath, "teamwiki") : path72.join(process.cwd(), ".teamai", "team-repo", "teamwiki");
21509
+ const wikiRoot = wikiConfig ? path73.join(wikiConfig.repo.localPath, "teamwiki") : path73.join(process.cwd(), ".teamai", "team-repo", "teamwiki");
21373
21510
  const hasWiki = await pathExists(wikiRoot);
21374
21511
  if (scopeIndexes.length === 0 && !hasWiki) {
21375
21512
  if (options.check) {
@@ -21410,7 +21547,7 @@ async function recall(query, options) {
21410
21547
  votes: 0,
21411
21548
  type: "docs",
21412
21549
  domain: "technical",
21413
- path: path72.join(wikiRoot, cr.page),
21550
+ path: path73.join(wikiRoot, cr.page),
21414
21551
  snippet: cr.snippet
21415
21552
  },
21416
21553
  score: Math.min(10, Math.log2(cr.score + 1) * 2),
@@ -21482,19 +21619,19 @@ __export(recall_toggle_exports, {
21482
21619
  recallEnable: () => recallEnable,
21483
21620
  recallStatus: () => recallStatus
21484
21621
  });
21485
- import path73 from "path";
21622
+ import path74 from "path";
21486
21623
  async function removeRecallArtifacts(teamConfig, localConfig) {
21487
21624
  const baseDir = resolveBaseDir(localConfig);
21488
21625
  for (const [tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
21489
21626
  if (toolPath.rules) {
21490
- const ruleFile = path73.join(baseDir, toolPath.rules, "teamai-recall.md");
21627
+ const ruleFile = path74.join(baseDir, toolPath.rules, "teamai-recall.md");
21491
21628
  if (await pathExists(ruleFile)) {
21492
21629
  await remove(ruleFile);
21493
21630
  log.debug(`Removed recall rule from ${tool}`);
21494
21631
  }
21495
21632
  }
21496
21633
  if (toolPath.agents) {
21497
- const agentFile = path73.join(baseDir, toolPath.agents, "teamai-recall.md");
21634
+ const agentFile = path74.join(baseDir, toolPath.agents, "teamai-recall.md");
21498
21635
  if (await pathExists(agentFile)) {
21499
21636
  await remove(agentFile);
21500
21637
  log.debug(`Removed recall agent from ${tool}`);
@@ -21502,7 +21639,7 @@ async function removeRecallArtifacts(teamConfig, localConfig) {
21502
21639
  }
21503
21640
  if (toolPath.skills) {
21504
21641
  for (const skillName of RECALL_DEPENDENT_SKILLS) {
21505
- const skillDir = path73.join(baseDir, toolPath.skills, skillName);
21642
+ const skillDir = path74.join(baseDir, toolPath.skills, skillName);
21506
21643
  if (await pathExists(skillDir)) {
21507
21644
  await remove(skillDir);
21508
21645
  log.debug(`Removed recall skill ${skillName} from ${tool}`);
@@ -21510,7 +21647,7 @@ async function removeRecallArtifacts(teamConfig, localConfig) {
21510
21647
  }
21511
21648
  }
21512
21649
  if (toolPath.claudemd) {
21513
- const claudeMdPath = path73.join(baseDir, toolPath.claudemd);
21650
+ const claudeMdPath = path74.join(baseDir, toolPath.claudemd);
21514
21651
  const content = await readFileSafe(claudeMdPath);
21515
21652
  if (content && content.includes(TEAMAI_RECALL_RULES_START)) {
21516
21653
  const startIdx = content.indexOf(TEAMAI_RECALL_RULES_START);
@@ -21544,7 +21681,7 @@ async function deployRecallArtifacts(teamConfig, localConfig) {
21544
21681
  for (const [tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
21545
21682
  if (!toolPath.claudemd || !toolPath.agents) continue;
21546
21683
  if (!await ResourceHandler.isToolInstalled(toolPath.agents, baseDir)) continue;
21547
- const claudeMdPath = path73.join(baseDir, toolPath.claudemd);
21684
+ const claudeMdPath = path74.join(baseDir, toolPath.claudemd);
21548
21685
  try {
21549
21686
  await injectClaudeMdSection2(
21550
21687
  claudeMdPath,
@@ -21596,20 +21733,20 @@ var init_recall_toggle = __esm({
21596
21733
  });
21597
21734
 
21598
21735
  // src/utils/cache-index.ts
21599
- import path74 from "path";
21736
+ import path75 from "path";
21600
21737
  import os4 from "os";
21601
21738
  import fs25 from "fs-extra";
21602
21739
  function getCacheRoot() {
21603
- return process.env.TEAMAI_CACHE_DIR ?? path74.join(os4.homedir(), ".teamai", "cache", "repos");
21740
+ return process.env.TEAMAI_CACHE_DIR ?? path75.join(os4.homedir(), ".teamai", "cache", "repos");
21604
21741
  }
21605
21742
  function buildKey(provider, owner, repo) {
21606
21743
  return `${provider}/${owner}/${repo}`;
21607
21744
  }
21608
21745
  function keyToAbsPath(key) {
21609
- return path74.join(getCacheRoot(), key);
21746
+ return path75.join(getCacheRoot(), key);
21610
21747
  }
21611
21748
  async function loadCacheIndex() {
21612
- const indexPath = path74.join(getCacheRoot(), INDEX_FILENAME);
21749
+ const indexPath = path75.join(getCacheRoot(), INDEX_FILENAME);
21613
21750
  try {
21614
21751
  const stat6 = await fs25.stat(indexPath);
21615
21752
  if (stat6.size > MAX_CONFIG_FILE_BYTES) {
@@ -21632,7 +21769,7 @@ async function loadCacheIndex() {
21632
21769
  async function saveCacheIndex(idx) {
21633
21770
  const root = getCacheRoot();
21634
21771
  await fs25.ensureDir(root);
21635
- const indexPath = path74.join(root, INDEX_FILENAME);
21772
+ const indexPath = path75.join(root, INDEX_FILENAME);
21636
21773
  const updated = { ...idx, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
21637
21774
  await fs25.writeFile(indexPath, JSON.stringify(updated, null, 2), "utf8");
21638
21775
  }
@@ -21665,7 +21802,7 @@ async function statDirSize(absPath) {
21665
21802
  return 0;
21666
21803
  }
21667
21804
  for (const entry of entries) {
21668
- const childPath = path74.join(absPath, entry.name);
21805
+ const childPath = path75.join(absPath, entry.name);
21669
21806
  if (entry.isSymbolicLink()) {
21670
21807
  continue;
21671
21808
  }
@@ -22153,7 +22290,7 @@ var init_ai_client = __esm({
22153
22290
 
22154
22291
  // src/import-local.ts
22155
22292
  import fs26 from "fs";
22156
- import path75 from "path";
22293
+ import path76 from "path";
22157
22294
  import readline5 from "readline";
22158
22295
  function toSlug(title) {
22159
22296
  return title.toLowerCase().replace(/[^a-z0-9一-鿿]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
@@ -22189,7 +22326,7 @@ function parseClassifyOutput(sourcePath, rawContent, output) {
22189
22326
  sourcePath,
22190
22327
  rawContent,
22191
22328
  type: knownType,
22192
- title: typeof parsed.title === "string" ? parsed.title : path75.basename(sourcePath),
22329
+ title: typeof parsed.title === "string" ? parsed.title : path76.basename(sourcePath),
22193
22330
  summary: typeof parsed.summary === "string" ? parsed.summary : "",
22194
22331
  tags: Array.isArray(parsed.tags) ? parsed.tags.filter((t) => typeof t === "string") : [],
22195
22332
  confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0,
@@ -22201,7 +22338,7 @@ function parseClassifyOutput(sourcePath, rawContent, output) {
22201
22338
  sourcePath,
22202
22339
  rawContent,
22203
22340
  type: "learning",
22204
- title: path75.basename(sourcePath),
22341
+ title: path76.basename(sourcePath),
22205
22342
  summary: "",
22206
22343
  tags: [],
22207
22344
  confidence: 0,
@@ -22247,9 +22384,9 @@ async function scanCandidates(opts) {
22247
22384
  const relPaths = await listFilesRecursive(expandedDir);
22248
22385
  for (const relPath of relPaths) {
22249
22386
  if (relPath.split("/").some((seg) => seg.startsWith("."))) continue;
22250
- const ext = path75.extname(relPath).toLowerCase();
22387
+ const ext = path76.extname(relPath).toLowerCase();
22251
22388
  if (ext !== ".md" && ext !== ".txt") continue;
22252
- const absPath = path75.join(expandedDir, relPath);
22389
+ const absPath = path76.join(expandedDir, relPath);
22253
22390
  try {
22254
22391
  const stat6 = fs26.statSync(absPath);
22255
22392
  if (stat6.size > MAX_FILE_SIZE_BYTES) continue;
@@ -22271,8 +22408,8 @@ async function scanCandidates(opts) {
22271
22408
  if (!fs26.existsSync(baseDir)) continue;
22272
22409
  const relPaths = await listFilesRecursive(baseDir);
22273
22410
  for (const relPath of relPaths) {
22274
- if (path75.extname(relPath).toLowerCase() !== ".md") continue;
22275
- const absPath = path75.join(baseDir, relPath);
22411
+ if (path76.extname(relPath).toLowerCase() !== ".md") continue;
22412
+ const absPath = path76.join(baseDir, relPath);
22276
22413
  try {
22277
22414
  const stat6 = fs26.statSync(absPath);
22278
22415
  if (stat6.size > MAX_FILE_SIZE_BYTES) continue;
@@ -22303,7 +22440,7 @@ async function classifyWithAI(candidates) {
22303
22440
  sourcePath: c.path,
22304
22441
  rawContent: c.rawContent,
22305
22442
  type: "learning",
22306
- title: path75.basename(c.path),
22443
+ title: path76.basename(c.path),
22307
22444
  summary: "",
22308
22445
  tags: [],
22309
22446
  confidence: 0,
@@ -22383,7 +22520,7 @@ async function interactiveReview(items, opts) {
22383
22520
  for (const sessionItem of pendingItems) {
22384
22521
  const currentIndex = session.items.indexOf(sessionItem) + 1;
22385
22522
  const classified = classifiedMap.get(sessionItem.sourcePath ?? "");
22386
- const title = sessionItem.learningDraft?.title ?? classified?.title ?? path75.basename(sessionItem.sourcePath ?? "");
22523
+ const title = sessionItem.learningDraft?.title ?? classified?.title ?? path76.basename(sessionItem.sourcePath ?? "");
22387
22524
  const itemType = classified?.type ?? "learning";
22388
22525
  const summary = classified?.summary ?? "";
22389
22526
  const tags = classified?.tags ?? [];
@@ -22450,9 +22587,9 @@ async function pushAccepted(session, repoPath, opts) {
22450
22587
  } else {
22451
22588
  const typeInContent = detectTypeFromContent(draft.content);
22452
22589
  const subDir = typeInContent === "rule" ? "rules" : typeInContent === "doc" ? "docs" : "learnings";
22453
- destDir = path75.join(expandHome(repoPath), subDir);
22590
+ destDir = path76.join(expandHome(repoPath), subDir);
22454
22591
  }
22455
- const destPath = path75.join(destDir, filename);
22592
+ const destPath = path76.join(destDir, filename);
22456
22593
  if (opts.dryRun) {
22457
22594
  log.info(`[dry-run] would write: ${destPath}`);
22458
22595
  pushed++;
@@ -22717,7 +22854,7 @@ var init_iwiki_client = __esm({
22717
22854
  });
22718
22855
 
22719
22856
  // src/import-iwiki.ts
22720
- import path76 from "path";
22857
+ import path77 from "path";
22721
22858
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
22722
22859
  function parseIWikiInput(input) {
22723
22860
  const trimmed = input.trim();
@@ -22806,8 +22943,8 @@ async function importFromIWiki(opts) {
22806
22943
  dryRun: opts.dryRun,
22807
22944
  outputDir: opts.outputDir
22808
22945
  });
22809
- const teamwikiRoot = path76.join(repoPath, "teamwiki");
22810
- if (await pathExists(path76.join(teamwikiRoot, ".indices", "graph-index.json"))) {
22946
+ const teamwikiRoot = path77.join(repoPath, "teamwiki");
22947
+ if (await pathExists(path77.join(teamwikiRoot, ".indices", "graph-index.json"))) {
22811
22948
  try {
22812
22949
  const mapsToEdges = await reconcileIwikiWithCodebase(documents, teamwikiRoot);
22813
22950
  if (mapsToEdges.length > 0) {
@@ -22826,7 +22963,7 @@ async function importFromIWiki(opts) {
22826
22963
  log.success("iWiki import complete");
22827
22964
  }
22828
22965
  async function reconcileIwikiWithCodebase(documents, teamwikiRoot) {
22829
- const graphPath = path76.join(teamwikiRoot, ".indices", "graph-index.json");
22966
+ const graphPath = path77.join(teamwikiRoot, ".indices", "graph-index.json");
22830
22967
  const graphRaw = await readFile4(graphPath, "utf-8");
22831
22968
  const graph = JSON.parse(graphRaw);
22832
22969
  const codeLabels = /* @__PURE__ */ new Map();
@@ -22835,17 +22972,17 @@ async function reconcileIwikiWithCodebase(documents, teamwikiRoot) {
22835
22972
  const words = node.label.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
22836
22973
  codeLabels.set(words, node.id);
22837
22974
  }
22838
- const evidenceDir = path76.join(teamwikiRoot, "evidence", "code");
22975
+ const evidenceDir = path77.join(teamwikiRoot, "evidence", "code");
22839
22976
  const codePageContents = /* @__PURE__ */ new Map();
22840
22977
  if (await pathExists(evidenceDir)) {
22841
22978
  const { readdir: readdir9 } = await import("fs/promises");
22842
22979
  const projects = await readdir9(evidenceDir);
22843
22980
  for (const project of projects) {
22844
- const projectDir = path76.join(evidenceDir, project);
22981
+ const projectDir = path77.join(evidenceDir, project);
22845
22982
  const files = await readdir9(projectDir).catch(() => []);
22846
22983
  for (const file of files) {
22847
22984
  if (!file.endsWith(".md")) continue;
22848
- const content = await readFile4(path76.join(projectDir, file), "utf-8").catch(() => "");
22985
+ const content = await readFile4(path77.join(projectDir, file), "utf-8").catch(() => "");
22849
22986
  codePageContents.set(`evidence/code/${project}/${file}`, content);
22850
22987
  }
22851
22988
  }
@@ -22934,7 +23071,7 @@ function parseGitHubPRUrl(url) {
22934
23071
  }
22935
23072
  return { owner: match[1], repo: match[2], number: match[3] };
22936
23073
  }
22937
- async function githubApiGet(path106) {
23074
+ async function githubApiGet(path107) {
22938
23075
  return new Promise((resolve, reject) => {
22939
23076
  const token = process.env["GITHUB_TOKEN"];
22940
23077
  const headers = {
@@ -22943,7 +23080,7 @@ async function githubApiGet(path106) {
22943
23080
  };
22944
23081
  if (token) headers["Authorization"] = `Bearer ${token}`;
22945
23082
  const req = https2.request(
22946
- { hostname: "api.github.com", path: path106, headers },
23083
+ { hostname: "api.github.com", path: path107, headers },
22947
23084
  (res) => {
22948
23085
  const chunks = [];
22949
23086
  res.on("data", (c) => chunks.push(c));
@@ -23102,7 +23239,7 @@ var init_mr_fetch2 = __esm({
23102
23239
 
23103
23240
  // src/utils/dedup.ts
23104
23241
  import fs27 from "fs/promises";
23105
- import path77 from "path";
23242
+ import path78 from "path";
23106
23243
  import matter6 from "gray-matter";
23107
23244
  function extractKeywords(text) {
23108
23245
  const keywords = /* @__PURE__ */ new Set();
@@ -23160,7 +23297,7 @@ async function findSupersededLearnings(draftKeywords, learningsDir, withinDays =
23160
23297
  const cutoffDate = new Date(Date.now() - withinDays * 24 * 60 * 60 * 1e3);
23161
23298
  const results = [];
23162
23299
  for (const filename of mdFiles) {
23163
- const filePath = path77.join(learningsDir, filename);
23300
+ const filePath = path78.join(learningsDir, filename);
23164
23301
  try {
23165
23302
  const docDate = await resolveDocDate(filePath, filename);
23166
23303
  if (docDate < cutoffDate) {
@@ -23242,7 +23379,7 @@ var init_dedup = __esm({
23242
23379
 
23243
23380
  // src/import-mr.ts
23244
23381
  import fs28 from "fs/promises";
23245
- import path78 from "path";
23382
+ import path79 from "path";
23246
23383
  import readline6 from "readline/promises";
23247
23384
  import matter7 from "gray-matter";
23248
23385
  async function fetchMR(url) {
@@ -23391,18 +23528,18 @@ async function importFromMR(opts) {
23391
23528
  async function writeLearning(draft, outputDir, repoPath) {
23392
23529
  if (outputDir) {
23393
23530
  await fs28.mkdir(outputDir, { recursive: true });
23394
- const filePath = path78.join(outputDir, "learning.md");
23531
+ const filePath = path79.join(outputDir, "learning.md");
23395
23532
  await fs28.writeFile(filePath, draft.content, "utf-8");
23396
23533
  log.info(`Learning written: ${filePath}`);
23397
23534
  return;
23398
23535
  }
23399
23536
  if (repoPath) {
23400
- const learningsDir = path78.join(repoPath, "learnings");
23537
+ const learningsDir = path79.join(repoPath, "learnings");
23401
23538
  await fs28.mkdir(learningsDir, { recursive: true });
23402
23539
  const datePrefix = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
23403
23540
  const safeTitle = draft.title.slice(0, 40).replace(/[^a-zA-Z0-9一-鿿_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
23404
23541
  const filename = `${datePrefix}-${safeTitle}.md`;
23405
- const filePath = path78.join(learningsDir, filename);
23542
+ const filePath = path79.join(learningsDir, filename);
23406
23543
  await fs28.writeFile(filePath, draft.content, "utf-8");
23407
23544
  log.info(`Learning written: ${filePath}`);
23408
23545
  return;
@@ -23418,7 +23555,7 @@ var init_import_mr = __esm({
23418
23555
  init_ai_client();
23419
23556
  init_dedup();
23420
23557
  init_logger();
23421
- DEFAULT_LEARNINGS_DIR = path78.join(process.env.HOME ?? "/tmp", ".teamai", "learnings");
23558
+ DEFAULT_LEARNINGS_DIR = path79.join(process.env.HOME ?? "/tmp", ".teamai", "learnings");
23422
23559
  SUPERSEDE_THRESHOLD = 0.6;
23423
23560
  }
23424
23561
  });
@@ -23426,7 +23563,7 @@ var init_import_mr = __esm({
23426
23563
  // src/codebase.ts
23427
23564
  import { execSync as execSync6 } from "child_process";
23428
23565
  import fs29 from "fs";
23429
- import path79 from "path";
23566
+ import path80 from "path";
23430
23567
  import matter8 from "gray-matter";
23431
23568
  async function gatherRepoContext(repoPath) {
23432
23569
  const parts = [];
@@ -23450,7 +23587,7 @@ ${truncated}`);
23450
23587
  } catch (err) {
23451
23588
  log.debug(`gatherRepoContext: find \u5931\u8D25 \u2014 ${String(err)}`);
23452
23589
  }
23453
- const pkgPath = path79.join(repoPath, "package.json");
23590
+ const pkgPath = path80.join(repoPath, "package.json");
23454
23591
  if (fs29.existsSync(pkgPath)) {
23455
23592
  try {
23456
23593
  const raw = fs29.readFileSync(pkgPath, "utf-8");
@@ -23464,7 +23601,7 @@ ${excerpt}
23464
23601
  }
23465
23602
  }
23466
23603
  for (const candidate of ["src/index.ts", "src/main.ts", "index.ts", "main.py"]) {
23467
- const entryPath = path79.join(repoPath, candidate);
23604
+ const entryPath = path80.join(repoPath, candidate);
23468
23605
  if (fs29.existsSync(entryPath)) {
23469
23606
  try {
23470
23607
  const raw = fs29.readFileSync(entryPath, "utf-8");
@@ -23480,7 +23617,7 @@ ${excerpt}
23480
23617
  }
23481
23618
  }
23482
23619
  for (const candidate of ["src/types.ts", "src/types/index.ts", "types.py"]) {
23483
- const typesPath = path79.join(repoPath, candidate);
23620
+ const typesPath = path80.join(repoPath, candidate);
23484
23621
  if (fs29.existsSync(typesPath)) {
23485
23622
  try {
23486
23623
  const raw = fs29.readFileSync(typesPath, "utf-8");
@@ -23496,10 +23633,10 @@ ${excerpt}
23496
23633
  }
23497
23634
  }
23498
23635
  const docCandidates = [
23499
- path79.join(repoPath, "README.md"),
23500
- path79.join(repoPath, "ARCHITECTURE.md")
23636
+ path80.join(repoPath, "README.md"),
23637
+ path80.join(repoPath, "ARCHITECTURE.md")
23501
23638
  ];
23502
- const docsDir = path79.join(repoPath, "docs");
23639
+ const docsDir = path80.join(repoPath, "docs");
23503
23640
  if (fs29.existsSync(docsDir)) {
23504
23641
  try {
23505
23642
  const entries = fs29.readdirSync(docsDir);
@@ -23507,7 +23644,7 @@ ${excerpt}
23507
23644
  for (const entry of entries) {
23508
23645
  if (count >= DOCS_MAX_FILES) break;
23509
23646
  if (entry.endsWith(".md")) {
23510
- docCandidates.push(path79.join(docsDir, entry));
23647
+ docCandidates.push(path80.join(docsDir, entry));
23511
23648
  count++;
23512
23649
  }
23513
23650
  }
@@ -23520,7 +23657,7 @@ ${excerpt}
23520
23657
  try {
23521
23658
  const raw = fs29.readFileSync(docPath, "utf-8");
23522
23659
  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);
23660
+ const relPath = path80.relative(repoPath, docPath);
23524
23661
  parts.push(`## \u6587\u6863\u6458\u8981\uFF1A${relPath}
23525
23662
  ${excerpt}`);
23526
23663
  } catch (err) {
@@ -23551,7 +23688,7 @@ ${lines.join("\n")}`);
23551
23688
  if (fileCount >= LEARNINGS_MAX_FILES) break;
23552
23689
  if (!entry.endsWith(".md")) continue;
23553
23690
  try {
23554
- const filePath = path79.join(learningsDir, entry);
23691
+ const filePath = path80.join(learningsDir, entry);
23555
23692
  const raw = fs29.readFileSync(filePath, "utf-8");
23556
23693
  const parsed = matter8(raw);
23557
23694
  const tags = parsed.data["tags"];
@@ -23746,7 +23883,7 @@ var init_codebase = __esm({
23746
23883
  import { createHash as createHash2 } from "crypto";
23747
23884
  import { execFile as execFile4 } from "child_process";
23748
23885
  import { readFile as readFile5, readdir as readdir2, stat } from "fs/promises";
23749
- import path80 from "path";
23886
+ import path81 from "path";
23750
23887
  import { promisify as promisify3 } from "util";
23751
23888
  function isKeyFile(relativePath, language) {
23752
23889
  const patterns = KEY_FILE_PATTERNS[language];
@@ -23754,12 +23891,12 @@ function isKeyFile(relativePath, language) {
23754
23891
  return patterns.some((pattern) => pattern.test(relativePath));
23755
23892
  }
23756
23893
  async function collectCode(options) {
23757
- const root = path80.resolve(options.root);
23894
+ const root = path81.resolve(options.root);
23758
23895
  const filePaths = [];
23759
23896
  await walk(root, filePaths, options.includeTests ?? false);
23760
23897
  let filtered = filePaths.sort((a, b) => {
23761
- const relA = toPosix(path80.relative(root, a));
23762
- const relB = toPosix(path80.relative(root, b));
23898
+ const relA = toPosix(path81.relative(root, a));
23899
+ const relB = toPosix(path81.relative(root, b));
23763
23900
  const langA = languageFor(a);
23764
23901
  const langB = languageFor(b);
23765
23902
  const keyA = isKeyFile(relA, langA) ? 0 : 1;
@@ -23773,7 +23910,7 @@ async function collectCode(options) {
23773
23910
  if (options.changedFiles && options.changedFiles.length > 0) {
23774
23911
  const changedSet = new Set(options.changedFiles.map((f) => toPosix(f)));
23775
23912
  filtered = filtered.filter((fp) => {
23776
- const relativePath = toPosix(path80.relative(root, fp));
23913
+ const relativePath = toPosix(path81.relative(root, fp));
23777
23914
  return changedSet.has(relativePath);
23778
23915
  });
23779
23916
  }
@@ -23781,7 +23918,7 @@ async function collectCode(options) {
23781
23918
  const files = [];
23782
23919
  for (const filePath of limited) {
23783
23920
  const content = await readFile5(filePath, "utf8");
23784
- const relativePath = toPosix(path80.relative(root, filePath));
23921
+ const relativePath = toPosix(path81.relative(root, filePath));
23785
23922
  const language = languageFor(filePath);
23786
23923
  files.push({
23787
23924
  path: filePath,
@@ -23808,7 +23945,7 @@ async function walk(directory, results, includeTests) {
23808
23945
  return;
23809
23946
  }
23810
23947
  for (const entry of await readdir2(directory, { withFileTypes: true })) {
23811
- const fullPath = path80.join(directory, entry.name);
23948
+ const fullPath = path81.join(directory, entry.name);
23812
23949
  if (safeIgnore(fullPath) || !includeTests && isTestPath(fullPath)) {
23813
23950
  continue;
23814
23951
  }
@@ -23821,14 +23958,14 @@ async function walk(directory, results, includeTests) {
23821
23958
  }
23822
23959
  function isCodeFile(filePath) {
23823
23960
  return [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".go", ".rs", ".java", ".json", ".yaml", ".yml", ".toml", ".sql", ".conf", ".ini"].includes(
23824
- path80.extname(filePath).toLowerCase()
23961
+ path81.extname(filePath).toLowerCase()
23825
23962
  );
23826
23963
  }
23827
23964
  function isTestPath(filePath) {
23828
23965
  return /(^|\/|\\)(test|tests|__tests__|fixtures)(\/|\\)|\.test\.|\.spec\./u.test(filePath);
23829
23966
  }
23830
23967
  function languageFor(filePath) {
23831
- const ext = path80.extname(filePath).toLowerCase();
23968
+ const ext = path81.extname(filePath).toLowerCase();
23832
23969
  const map = {
23833
23970
  ".ts": "typescript",
23834
23971
  ".tsx": "typescript",
@@ -24511,14 +24648,14 @@ var init_code_extractors = __esm({
24511
24648
  });
24512
24649
 
24513
24650
  // src/wiki-engine/code-knowledge/code-graph.ts
24514
- import path81 from "path";
24651
+ import path82 from "path";
24515
24652
  function buildCodeGraph(facts) {
24516
24653
  const nodes = facts.filter((fact) => fact.kind !== "relation").map((fact) => ({
24517
24654
  slug: `${fact.kind}/${fact.name}`,
24518
24655
  type: mapFactKindToCategory(fact.kind),
24519
24656
  confidence: fact.confidence === "EXTRACTED" ? "EXTRACTED" : "INFERRED",
24520
24657
  title: fact.name,
24521
- domain: path81.dirname(fact.file).split("/")[0] || void 0
24658
+ domain: path82.dirname(fact.file).split("/")[0] || void 0
24522
24659
  }));
24523
24660
  const nodeFiles = new Set(facts.filter((f) => f.kind !== "relation").map((f) => f.file));
24524
24661
  const edges = facts.filter((fact) => fact.kind === "relation").flatMap((fact) => {
@@ -24561,7 +24698,7 @@ var init_code_graph = __esm({
24561
24698
 
24562
24699
  // src/wiki-engine/code-knowledge/code-incremental.ts
24563
24700
  import { readFile as readFile6, writeFile as writeFile6, stat as stat2, mkdir as mkdir3 } from "fs/promises";
24564
- import path82 from "path";
24701
+ import path83 from "path";
24565
24702
  async function detectCodeIncrementalChanges(root, manifestPath, project) {
24566
24703
  const previous = await exists(manifestPath) ? JSON.parse(await readFile6(manifestPath, "utf8")) : { files: [] };
24567
24704
  const oldSha = previous.headSha;
@@ -24601,14 +24738,14 @@ function affectedPages(project, files) {
24601
24738
  }
24602
24739
  async function exists(filePath) {
24603
24740
  try {
24604
- await stat2(path82.resolve(filePath));
24741
+ await stat2(path83.resolve(filePath));
24605
24742
  return true;
24606
24743
  } catch {
24607
24744
  return false;
24608
24745
  }
24609
24746
  }
24610
24747
  async function loadFactsCache(indicesDir) {
24611
- const cachePath = path82.join(indicesDir, FACTS_CACHE_FILENAME);
24748
+ const cachePath = path83.join(indicesDir, FACTS_CACHE_FILENAME);
24612
24749
  try {
24613
24750
  const raw = await readFile6(cachePath, "utf-8");
24614
24751
  const parsed = JSON.parse(raw);
@@ -24619,10 +24756,10 @@ async function loadFactsCache(indicesDir) {
24619
24756
  }
24620
24757
  async function saveFactsCache(indicesDir, facts) {
24621
24758
  await mkdir3(indicesDir, { recursive: true });
24622
- await writeFile6(path82.join(indicesDir, FACTS_CACHE_FILENAME), JSON.stringify(facts), "utf-8");
24759
+ await writeFile6(path83.join(indicesDir, FACTS_CACHE_FILENAME), JSON.stringify(facts), "utf-8");
24623
24760
  }
24624
24761
  async function loadInterfacesCache(indicesDir) {
24625
- const cachePath = path82.join(indicesDir, INTERFACES_CACHE_FILENAME);
24762
+ const cachePath = path83.join(indicesDir, INTERFACES_CACHE_FILENAME);
24626
24763
  try {
24627
24764
  const raw = await readFile6(cachePath, "utf-8");
24628
24765
  const parsed = JSON.parse(raw);
@@ -24634,7 +24771,7 @@ async function loadInterfacesCache(indicesDir) {
24634
24771
  async function saveInterfacesCache(indicesDir, inventory) {
24635
24772
  await mkdir3(indicesDir, { recursive: true });
24636
24773
  await writeFile6(
24637
- path82.join(indicesDir, INTERFACES_CACHE_FILENAME),
24774
+ path83.join(indicesDir, INTERFACES_CACHE_FILENAME),
24638
24775
  JSON.stringify(inventory, null, 2),
24639
24776
  "utf-8"
24640
24777
  );
@@ -24660,7 +24797,7 @@ var init_code_incremental = __esm({
24660
24797
  });
24661
24798
 
24662
24799
  // src/wiki-engine/interface-scanner.ts
24663
- import path83 from "path";
24800
+ import path84 from "path";
24664
24801
  async function scanInterfaces(files) {
24665
24802
  const componentMap = groupByComponent(files);
24666
24803
  const entries = [];
@@ -24728,7 +24865,7 @@ function groupByComponent(files) {
24728
24865
  if (file.repo) {
24729
24866
  component = parts.length > 1 ? `${file.repo}/${parts[0]}` : file.repo;
24730
24867
  } else {
24731
- component = parts.length > 1 ? parts[0] : path83.basename(path83.dirname(file.path));
24868
+ component = parts.length > 1 ? parts[0] : path84.basename(path84.dirname(file.path));
24732
24869
  }
24733
24870
  const group = map.get(component) ?? [];
24734
24871
  group.push(file);
@@ -25014,7 +25151,7 @@ var init_reconciler_v2_types = __esm({
25014
25151
 
25015
25152
  // src/wiki-engine/knowledge-reconciler.ts
25016
25153
  import { readFile as readFile7, readdir as readdir3, stat as stat3 } from "fs/promises";
25017
- import path84 from "path";
25154
+ import path85 from "path";
25018
25155
  async function exists2(p) {
25019
25156
  return stat3(p).then(() => true).catch(() => false);
25020
25157
  }
@@ -25023,7 +25160,7 @@ async function readPages(dirPath) {
25023
25160
  const entries = await readdir3(dirPath, { withFileTypes: true });
25024
25161
  const pages = [];
25025
25162
  for (const entry of entries) {
25026
- const full = path84.join(dirPath, entry.name);
25163
+ const full = path85.join(dirPath, entry.name);
25027
25164
  if (entry.isDirectory()) {
25028
25165
  pages.push(...await readPages(full));
25029
25166
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -25116,17 +25253,17 @@ async function reconcileKnowledge(options) {
25116
25253
  const productDirNames = options.productDirs ?? ["product", "docs"];
25117
25254
  const codeDirNames = options.codeDirs ?? ["evidence/code"];
25118
25255
  for (const dir of [...productDirNames, ...codeDirNames]) {
25119
- if (dir.includes("..") || path84.isAbsolute(dir)) {
25256
+ if (dir.includes("..") || path85.isAbsolute(dir)) {
25120
25257
  throw new Error(`Unsafe directory path rejected: ${dir}`);
25121
25258
  }
25122
25259
  }
25123
25260
  const productPages = [];
25124
25261
  for (const dir of productDirNames) {
25125
- productPages.push(...await readPages(path84.join(wikiRoot, dir)));
25262
+ productPages.push(...await readPages(path85.join(wikiRoot, dir)));
25126
25263
  }
25127
25264
  const codePages = [];
25128
25265
  for (const dir of codeDirNames) {
25129
- codePages.push(...await readPages(path84.join(wikiRoot, dir)));
25266
+ codePages.push(...await readPages(path85.join(wikiRoot, dir)));
25130
25267
  }
25131
25268
  const graphEdges = [];
25132
25269
  const gaps = [];
@@ -25153,8 +25290,8 @@ async function reconcileKnowledge(options) {
25153
25290
  ];
25154
25291
  const nc = buildConfidence(factors);
25155
25292
  graphEdges.push({
25156
- from: toPageSlug(path84.relative(wikiRoot, productPage.path)),
25157
- to: toPageSlug(path84.relative(wikiRoot, codePage.path)),
25293
+ from: toPageSlug(path85.relative(wikiRoot, productPage.path)),
25294
+ to: toPageSlug(path85.relative(wikiRoot, codePage.path)),
25158
25295
  relation: "MAPS_TO",
25159
25296
  term,
25160
25297
  confidence: nc.label,
@@ -25235,10 +25372,10 @@ async function reconcileKnowledge(options) {
25235
25372
  const MS_PER_DAY = 864e5;
25236
25373
  for (const edge of graphEdges) {
25237
25374
  const fromPage = productPages.find(
25238
- (p) => toPageSlug(path84.relative(wikiRoot, p.path)) === edge.from
25375
+ (p) => toPageSlug(path85.relative(wikiRoot, p.path)) === edge.from
25239
25376
  );
25240
25377
  const toPage = codePages.find(
25241
- (p) => toPageSlug(path84.relative(wikiRoot, p.path)) === edge.to
25378
+ (p) => toPageSlug(path85.relative(wikiRoot, p.path)) === edge.to
25242
25379
  );
25243
25380
  if (!fromPage?.updated || !toPage?.updated) continue;
25244
25381
  const fromMs = new Date(fromPage.updated).getTime();
@@ -25497,7 +25634,7 @@ __export(enrich_with_ai_exports, {
25497
25634
  enrichWithAI: () => enrichWithAI,
25498
25635
  writeManifest: () => writeManifest
25499
25636
  });
25500
- import path85 from "path";
25637
+ import path86 from "path";
25501
25638
  import { writeFile as writeFile8, mkdir as mkdir5 } from "fs/promises";
25502
25639
  function sanitizeForPrompt(text) {
25503
25640
  return text.replace(/[\n\r]/g, " ").replace(/[<>]/g, "").slice(0, 200);
@@ -25638,7 +25775,7 @@ async function enrichWithAI(ctx) {
25638
25775
  }
25639
25776
  async function writeManifest(manifest, outputDir) {
25640
25777
  await mkdir5(outputDir, { recursive: true });
25641
- const manifestPath = path85.join(outputDir, "_manifest.json");
25778
+ const manifestPath = path86.join(outputDir, "_manifest.json");
25642
25779
  await writeFile8(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
25643
25780
  return manifestPath;
25644
25781
  }
@@ -25656,7 +25793,7 @@ __export(codebase_extract_exports, {
25656
25793
  extractCodebase: () => extractCodebase
25657
25794
  });
25658
25795
  import { mkdir as mkdir6, writeFile as writeFile9, readFile as readFile8 } from "fs/promises";
25659
- import path86 from "path";
25796
+ import path87 from "path";
25660
25797
  import chalk3 from "chalk";
25661
25798
  function detectKnowledgeGaps(facts, graph, files) {
25662
25799
  const gaps = [];
@@ -25673,7 +25810,7 @@ function detectKnowledgeGaps(facts, graph, files) {
25673
25810
  const target = rel.name;
25674
25811
  if (target.startsWith(".")) continue;
25675
25812
  if (target.startsWith("node:")) continue;
25676
- const matchesAnyFile = [...scannedFiles].some((f) => f.includes(target.replace(/\//g, path86.sep)));
25813
+ const matchesAnyFile = [...scannedFiles].some((f) => f.includes(target.replace(/\//g, path87.sep)));
25677
25814
  if (!matchesAnyFile) {
25678
25815
  unresolvedImports.add(target);
25679
25816
  }
@@ -26017,21 +26154,21 @@ function buildOverview(facts, graph, project, interfaceInventory, callChains) {
26017
26154
  lines.push("## Key Dependency Paths");
26018
26155
  lines.push("");
26019
26156
  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}`);
26157
+ const path107 = chain.steps.map((s) => s.symbol).join(" \u2192 ");
26158
+ lines.push(`- ${chain.entryPoint}: ${path107}`);
26022
26159
  }
26023
26160
  }
26024
26161
  lines.push("");
26025
26162
  return lines.join("\n");
26026
26163
  }
26027
26164
  async function extractCodebase(opts) {
26028
- const root = path86.resolve(opts.path || ".");
26029
- const project = opts.project || path86.basename(root);
26165
+ const root = path87.resolve(opts.path || ".");
26166
+ const project = opts.project || path87.basename(root);
26030
26167
  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");
26168
+ const outputBase = opts.outputRoot ? path87.resolve(opts.outputRoot) : root;
26169
+ const wikiRoot = path87.join(outputBase, "teamwiki");
26170
+ const evidenceDir = path87.join(wikiRoot, "evidence", "code", project);
26171
+ const manifestPath = path87.join(wikiRoot, "source-manifest.json");
26035
26172
  let changedFiles;
26036
26173
  let deletedFiles = [];
26037
26174
  if (opts.incremental) {
@@ -26068,7 +26205,7 @@ async function extractCodebase(opts) {
26068
26205
  const newFacts = files.length > 0 ? extractCodeFacts(files) : [];
26069
26206
  let facts;
26070
26207
  let interfaceInventory;
26071
- const indicesDir = path86.join(wikiRoot, ".indices");
26208
+ const indicesDir = path87.join(wikiRoot, ".indices");
26072
26209
  if (changedFiles !== void 0) {
26073
26210
  const oldFacts = await loadFactsCache(indicesDir);
26074
26211
  const oldInterfaces = await loadInterfacesCache(indicesDir);
@@ -26096,7 +26233,7 @@ async function extractCodebase(opts) {
26096
26233
  }
26097
26234
  const graph = buildCodeGraph(facts);
26098
26235
  let callChains;
26099
- const depPathsFile = path86.join(evidenceDir, "dependency-paths.md");
26236
+ const depPathsFile = path87.join(evidenceDir, "dependency-paths.md");
26100
26237
  if (changedFiles) {
26101
26238
  callChains = [];
26102
26239
  } else {
@@ -26112,7 +26249,7 @@ async function extractCodebase(opts) {
26112
26249
  }
26113
26250
  }
26114
26251
  for (const [filename, content] of pages) {
26115
- await writeIfChanged(path86.join(evidenceDir, filename), content);
26252
+ await writeIfChanged(path87.join(evidenceDir, filename), content);
26116
26253
  }
26117
26254
  const pageSlugs = [...pages.keys()].map((p) => `evidence/code/${project}/${p.replace(".md", "")}`);
26118
26255
  const overlay = buildIndexHubOverlay(project, "evidence/code", pageSlugs);
@@ -26141,7 +26278,7 @@ async function extractCodebase(opts) {
26141
26278
  keywords: enrichResult.repoKeywords || [],
26142
26279
  components: enrichResult.domains[0]?.components ?? []
26143
26280
  };
26144
- await writeFile9(path86.join(evidenceDir, "_domains.json"), JSON.stringify(domainMeta, null, 2), "utf-8");
26281
+ await writeFile9(path87.join(evidenceDir, "_domains.json"), JSON.stringify(domainMeta, null, 2), "utf-8");
26145
26282
  if (!opts.json) {
26146
26283
  const domainLabel = domainMeta.domain || "uncategorized";
26147
26284
  console.log(` AI enrich: ${enrichResult.manifest.components.length} modules, domain=${domainLabel}`);
@@ -26154,14 +26291,14 @@ async function extractCodebase(opts) {
26154
26291
  }
26155
26292
  const moduleSummaries = buildModuleSummaries(facts, graph, project);
26156
26293
  if (moduleSummaries.size > 0) {
26157
- const modulesDir = path86.join(evidenceDir, "modules");
26294
+ const modulesDir = path87.join(evidenceDir, "modules");
26158
26295
  await mkdir6(modulesDir, { recursive: true });
26159
26296
  for (const [filename, content] of moduleSummaries) {
26160
- await writeIfChanged(path86.join(modulesDir, filename), content);
26297
+ await writeIfChanged(path87.join(modulesDir, filename), content);
26161
26298
  }
26162
26299
  }
26163
26300
  const overview = buildOverview(facts, repoGraph, project, interfaceInventory, callChains);
26164
- await writeIfChanged(path86.join(evidenceDir, "overview.md"), overview);
26301
+ await writeIfChanged(path87.join(evidenceDir, "overview.md"), overview);
26165
26302
  const proj = [{ slug: project, label: project }];
26166
26303
  const ifByType = {};
26167
26304
  for (const e of interfaceInventory.entries) {
@@ -26174,11 +26311,11 @@ async function extractCodebase(opts) {
26174
26311
  interfaces: Object.keys(ifByType).length > 0 ? ifByType : void 0,
26175
26312
  callChains: callChains.length > 0 ? callChains.length : void 0
26176
26313
  };
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));
26314
+ await writeIfChanged(path87.join(wikiRoot, "router.md"), routerTemplate(proj, aiDomains.length > 0 ? aiDomains : void 0));
26315
+ await writeIfChanged(path87.join(wikiRoot, "hot.md"), HOT_TEMPLATE);
26316
+ await writeIfChanged(path87.join(wikiRoot, "index.md"), indexTemplate(proj, indexStats));
26180
26317
  const gaps = detectKnowledgeGaps(facts, graph, files);
26181
- const gapsDir = path86.join(wikiRoot, "gaps");
26318
+ const gapsDir = path87.join(wikiRoot, "gaps");
26182
26319
  await mkdir6(gapsDir, { recursive: true });
26183
26320
  const gapLines = [
26184
26321
  "---",
@@ -26201,7 +26338,7 @@ async function extractCodebase(opts) {
26201
26338
  gapLines.push("| \u2014 | \u2014 | \u2014 | \u672A\u53D1\u73B0\u660E\u663E\u77E5\u8BC6\u7F3A\u53E3 | \u2014 |");
26202
26339
  }
26203
26340
  gapLines.push("");
26204
- await writeIfChanged(path86.join(gapsDir, "detected.md"), gapLines.join("\n"));
26341
+ await writeIfChanged(path87.join(gapsDir, "detected.md"), gapLines.join("\n"));
26205
26342
  await saveFactsCache(indicesDir, facts);
26206
26343
  await saveInterfacesCache(indicesDir, interfaceInventory);
26207
26344
  let allManifestFiles = collectionManifest.files.map((f) => ({
@@ -26458,14 +26595,14 @@ __export(repo_cache_exports, {
26458
26595
  readLastSync: () => readLastSync,
26459
26596
  writeLastSync: () => writeLastSync
26460
26597
  });
26461
- import path87 from "path";
26598
+ import path88 from "path";
26462
26599
  import os5 from "os";
26463
26600
  import fs31 from "fs-extra";
26464
26601
  function getCacheRoot2() {
26465
- return process.env.TEAMAI_CACHE_DIR ?? path87.join(os5.homedir(), ".teamai", "cache", "repos");
26602
+ return process.env.TEAMAI_CACHE_DIR ?? path88.join(os5.homedir(), ".teamai", "cache", "repos");
26466
26603
  }
26467
26604
  function getRepoCacheDir(provider, owner, repo) {
26468
- return path87.join(getCacheRoot2(), provider, owner, repo);
26605
+ return path88.join(getCacheRoot2(), provider, owner, repo);
26469
26606
  }
26470
26607
  function getRepoSlug(provider, owner, repo) {
26471
26608
  const safeOwner = owner.replace(/\//g, "-");
@@ -26476,10 +26613,10 @@ async function writeLastSync(cacheDir, sha) {
26476
26613
  const content = `${sha}
26477
26614
  ${isoTs}
26478
26615
  `;
26479
- await fs31.writeFile(path87.join(cacheDir, LAST_SYNC_FILE), content, "utf8");
26616
+ await fs31.writeFile(path88.join(cacheDir, LAST_SYNC_FILE), content, "utf8");
26480
26617
  }
26481
26618
  async function readLastSync(cacheDir) {
26482
- const filePath = path87.join(cacheDir, LAST_SYNC_FILE);
26619
+ const filePath = path88.join(cacheDir, LAST_SYNC_FILE);
26483
26620
  const exists3 = await fs31.pathExists(filePath);
26484
26621
  if (!exists3) {
26485
26622
  return null;
@@ -26510,7 +26647,7 @@ __export(deep_enrich_exports, {
26510
26647
  deepEnrich: () => deepEnrich
26511
26648
  });
26512
26649
  import { readFile as readFile9, writeFile as writeFile10, readdir as readdir4, mkdir as mkdir7 } from "fs/promises";
26513
- import path88 from "path";
26650
+ import path89 from "path";
26514
26651
  async function readFileSafe4(filePath) {
26515
26652
  try {
26516
26653
  return await readFile9(filePath, "utf-8");
@@ -26519,7 +26656,7 @@ async function readFileSafe4(filePath) {
26519
26656
  }
26520
26657
  }
26521
26658
  async function loadContext(evidenceDir) {
26522
- const manifestRaw = await readFileSafe4(path88.join(evidenceDir, "_manifest.json"));
26659
+ const manifestRaw = await readFileSafe4(path89.join(evidenceDir, "_manifest.json"));
26523
26660
  let manifest = {};
26524
26661
  try {
26525
26662
  manifest = JSON.parse(manifestRaw);
@@ -26527,18 +26664,18 @@ async function loadContext(evidenceDir) {
26527
26664
  log.debug("deep-enrich: failed to parse _manifest.json");
26528
26665
  }
26529
26666
  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"))
26667
+ readFileSafe4(path89.join(evidenceDir, "index.md")),
26668
+ readFileSafe4(path89.join(evidenceDir, "dependency-paths.md")),
26669
+ readFileSafe4(path89.join(evidenceDir, "overview.md"))
26533
26670
  ]);
26534
- const modulesDir = path88.join(evidenceDir, "modules");
26671
+ const modulesDir = path89.join(evidenceDir, "modules");
26535
26672
  const moduleDocs = /* @__PURE__ */ new Map();
26536
26673
  if (await pathExists(modulesDir)) {
26537
26674
  try {
26538
26675
  const entries = await readdir4(modulesDir);
26539
26676
  await Promise.all(
26540
26677
  entries.filter((e) => e.endsWith(".md")).map(async (e) => {
26541
- const content = await readFileSafe4(path88.join(modulesDir, e));
26678
+ const content = await readFileSafe4(path89.join(modulesDir, e));
26542
26679
  moduleDocs.set(e.replace(/\.md$/, ""), content);
26543
26680
  })
26544
26681
  );
@@ -26549,7 +26686,7 @@ async function loadContext(evidenceDir) {
26549
26686
  return { manifest, indexMd, callChains, overview, moduleDocs };
26550
26687
  }
26551
26688
  function progressPath(evidenceDir) {
26552
- return path88.join(evidenceDir, PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME);
26689
+ return path89.join(evidenceDir, PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME);
26553
26690
  }
26554
26691
  function isValidProgressState(v, project) {
26555
26692
  if (typeof v !== "object" || v === null) return false;
@@ -26575,7 +26712,7 @@ async function loadProgress(evidenceDir, project, allComponents) {
26575
26712
  }
26576
26713
  async function saveProgress(evidenceDir, state) {
26577
26714
  const p = progressPath(evidenceDir);
26578
- await mkdir7(path88.dirname(p), { recursive: true });
26715
+ await mkdir7(path89.dirname(p), { recursive: true });
26579
26716
  const updated = { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
26580
26717
  await writeFile10(p, JSON.stringify(updated, null, 2), "utf-8");
26581
26718
  }
@@ -26814,7 +26951,7 @@ async function runPhaseComponents(opts, ctx, progress, docsDir) {
26814
26951
  log.warn(`deep-enrich[${project}]: Skipping unsafe component slug "${comp.slug}": ${e.message}`);
26815
26952
  continue;
26816
26953
  }
26817
- const outPath = path88.join(docsDir, `${comp.slug}.md`);
26954
+ const outPath = path89.join(docsDir, `${comp.slug}.md`);
26818
26955
  await mkdir7(docsDir, { recursive: true });
26819
26956
  await writeFile10(outPath, content, "utf-8");
26820
26957
  progress.componentsDone.push(comp.slug);
@@ -26842,7 +26979,7 @@ async function runPhaseArchitecture(opts, ctx, docsDir) {
26842
26979
  log.warn(`deep-enrich[${project}]: Architecture overview: AI returned empty, skipping write`);
26843
26980
  return;
26844
26981
  }
26845
- const outPath = path88.join(docsDir, "architecture.md");
26982
+ const outPath = path89.join(docsDir, "architecture.md");
26846
26983
  await mkdir7(docsDir, { recursive: true });
26847
26984
  await writeFile10(outPath, content, "utf-8");
26848
26985
  log.debug(`deep-enrich[${project}]: Architecture overview written: ${outPath}`);
@@ -26850,15 +26987,15 @@ async function runPhaseArchitecture(opts, ctx, docsDir) {
26850
26987
  async function runPhaseGraph(opts, ctx, docsDir) {
26851
26988
  const { project, evidenceDir } = opts;
26852
26989
  log.info(`deep-enrich[${project}]: Phase 3 \u2014 Generating deterministic graph docs`);
26853
- const interfacesMd = await readFileSafe4(path88.join(evidenceDir, "interfaces.md"));
26990
+ const interfacesMd = await readFileSafe4(path89.join(evidenceDir, "interfaces.md"));
26854
26991
  const g1 = buildG1RelationsDoc(ctx.manifest);
26855
26992
  const g2 = buildG2DataflowDoc(ctx.callChains);
26856
26993
  const g3 = buildG3InterfacesDoc(interfacesMd);
26857
26994
  await mkdir7(docsDir, { recursive: true });
26858
26995
  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")
26996
+ writeFile10(path89.join(docsDir, "graph-g1-relations.md"), g1, "utf-8"),
26997
+ writeFile10(path89.join(docsDir, "graph-g2-dataflow.md"), g2, "utf-8"),
26998
+ writeFile10(path89.join(docsDir, "graph-g3-interfaces.md"), g3, "utf-8")
26862
26999
  ]);
26863
27000
  log.debug(`deep-enrich[${project}]: Graph docs written: ${docsDir}`);
26864
27001
  }
@@ -26964,14 +27101,14 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
26964
27101
  await mkdir7(docsDir, { recursive: true });
26965
27102
  const g6HasEdges = (ctx.manifest.edges ?? []).length > 0;
26966
27103
  const g6 = buildG6Content(project, ctx.manifest);
26967
- await writeFile10(path88.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
27104
+ await writeFile10(path89.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
26968
27105
  log.debug(`deep-enrich[${project}]: G6 multi-hop analysis written`);
26969
27106
  let g5Generated = false;
26970
27107
  if (ctx.moduleDocs.size < 2) {
26971
27108
  log.warn(`deep-enrich[${project}]: Insufficient modules (${ctx.moduleDocs.size} < 2), skipping G5`);
26972
27109
  return { g5Generated, g6Generated: g6HasEdges };
26973
27110
  }
26974
- const architectureMd = await readFileSafe4(path88.join(docsDir, "architecture.md"));
27111
+ const architectureMd = await readFileSafe4(path89.join(docsDir, "architecture.md"));
26975
27112
  if (!architectureMd.trim()) {
26976
27113
  log.warn(`deep-enrich[${project}]: No architecture doc, skipping G5 scenarios`);
26977
27114
  return { g5Generated, g6Generated: g6HasEdges };
@@ -26981,7 +27118,7 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
26981
27118
  try {
26982
27119
  const g5Content = await callClaude(prompt);
26983
27120
  if (g5Content.trim()) {
26984
- await writeFile10(path88.join(docsDir, "graph-g5-scenarios.md"), g5Content, "utf-8");
27121
+ await writeFile10(path89.join(docsDir, "graph-g5-scenarios.md"), g5Content, "utf-8");
26985
27122
  log.debug(`deep-enrich[${project}]: G5 scenario diagrams written`);
26986
27123
  g5Generated = true;
26987
27124
  }
@@ -26999,10 +27136,10 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
26999
27136
  hasG5: graphFlags?.g5Generated ?? false,
27000
27137
  hasG6: graphFlags?.g6Generated ?? true
27001
27138
  });
27002
- await writeFile10(path88.join(docsDir, "README.md"), graphReadme, "utf-8");
27139
+ await writeFile10(path89.join(docsDir, "README.md"), graphReadme, "utf-8");
27003
27140
  log.debug(`deep-enrich[${project}]: graph/README.md routing table written`);
27004
27141
  const { wikiRoot } = opts;
27005
- const domainsJson = await readFileSafe4(path88.join(evidenceDir, "_domains.json"));
27142
+ const domainsJson = await readFileSafe4(path89.join(evidenceDir, "_domains.json"));
27006
27143
  let keywords = [];
27007
27144
  let description = "";
27008
27145
  try {
@@ -27011,7 +27148,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
27011
27148
  description = domains.description ?? "";
27012
27149
  } catch {
27013
27150
  }
27014
- const routerPath = path88.join(wikiRoot, "router.md");
27151
+ const routerPath = path89.join(wikiRoot, "router.md");
27015
27152
  const routerContent = await readFileSafe4(routerPath);
27016
27153
  const projectLink = `[[evidence/code/${project}/index]]`;
27017
27154
  if (routerContent && !routerContent.includes(projectLink)) {
@@ -27021,7 +27158,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
27021
27158
  `;
27022
27159
  await writeFile10(routerPath, routerContent.trimEnd() + "\n" + line, "utf-8");
27023
27160
  }
27024
- const indexPath = path88.join(wikiRoot, "index.md");
27161
+ const indexPath = path89.join(wikiRoot, "index.md");
27025
27162
  const indexContent = await readFileSafe4(indexPath);
27026
27163
  if (indexContent && !indexContent.includes(`evidence/code/${project}/`)) {
27027
27164
  const navBlock = [
@@ -27046,7 +27183,7 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
27046
27183
  }
27047
27184
  async function deepEnrich(opts) {
27048
27185
  const { project, evidenceDir } = opts;
27049
- const docsDir = path88.join(evidenceDir, "docs");
27186
+ const docsDir = path89.join(evidenceDir, "docs");
27050
27187
  log.info(`deep-enrich[${project}]: Starting deep knowledge generation, evidenceDir=${evidenceDir}`);
27051
27188
  const ctx = await loadContext(evidenceDir);
27052
27189
  let components = ctx.manifest.components ?? [];
@@ -27135,11 +27272,11 @@ var graph_aggregate_exports = {};
27135
27272
  __export(graph_aggregate_exports, {
27136
27273
  aggregateGlobalGraph: () => aggregateGlobalGraph
27137
27274
  });
27138
- import path89 from "path";
27275
+ import path90 from "path";
27139
27276
  import { readdir as readdir5 } from "fs/promises";
27140
27277
  import fs32 from "fs-extra";
27141
27278
  async function aggregateGlobalGraph(teamwikiRoot) {
27142
- const evidenceBase = path89.join(teamwikiRoot, "evidence", "code");
27279
+ const evidenceBase = path90.join(teamwikiRoot, "evidence", "code");
27143
27280
  if (!await fs32.pathExists(evidenceBase)) return null;
27144
27281
  const { mergeGraphs: mergeGraphs2 } = await Promise.resolve().then(() => (init_adapters(), adapters_exports));
27145
27282
  const { detectCrossRepoEdges: detectCrossRepoEdges2 } = await Promise.resolve().then(() => (init_import_repo(), import_repo_exports));
@@ -27147,7 +27284,7 @@ async function aggregateGlobalGraph(teamwikiRoot) {
27147
27284
  const projectDirs = await readdir5(evidenceBase, { withFileTypes: true });
27148
27285
  for (const dir of projectDirs) {
27149
27286
  if (!dir.isDirectory()) continue;
27150
- const graphPath = path89.join(evidenceBase, dir.name, ".indices", "graph-index.json");
27287
+ const graphPath = path90.join(evidenceBase, dir.name, ".indices", "graph-index.json");
27151
27288
  if (!await fs32.pathExists(graphPath)) continue;
27152
27289
  try {
27153
27290
  const overlay = JSON.parse(await fs32.readFile(graphPath, "utf8"));
@@ -27165,8 +27302,8 @@ async function aggregateGlobalGraph(teamwikiRoot) {
27165
27302
  }
27166
27303
  }
27167
27304
  if (globalGraph) {
27168
- const destPath = path89.join(teamwikiRoot, ".indices", "graph-index.json");
27169
- await fs32.ensureDir(path89.dirname(destPath));
27305
+ const destPath = path90.join(teamwikiRoot, ".indices", "graph-index.json");
27306
+ await fs32.ensureDir(path90.dirname(destPath));
27170
27307
  await fs32.writeFile(destPath, JSON.stringify(globalGraph, null, 2), "utf8");
27171
27308
  log.info(`global graph-index.json aggregated (${globalGraph.nodes.length} nodes, ${globalGraph.edges.length} edges)`);
27172
27309
  return { nodes: globalGraph.nodes.length, edges: globalGraph.edges.length };
@@ -27186,7 +27323,7 @@ __export(import_repo_exports, {
27186
27323
  detectCrossRepoEdges: () => detectCrossRepoEdges,
27187
27324
  importFromRepo: () => importFromRepo
27188
27325
  });
27189
- import path90 from "path";
27326
+ import path91 from "path";
27190
27327
  import fs33 from "fs-extra";
27191
27328
  import chalk4 from "chalk";
27192
27329
  function detectCrossRepoEdges(overlay, existing) {
@@ -27308,7 +27445,7 @@ async function importFromRepo(opts) {
27308
27445
  const cacheDir = getRepoCacheDir(providerName, owner, repoName);
27309
27446
  const slug = getRepoSlug(providerName, owner, repoName);
27310
27447
  const lastSync = await readLastSync(cacheDir);
27311
- const cacheExists = await fs33.pathExists(path90.join(cacheDir, ".git"));
27448
+ const cacheExists = await fs33.pathExists(path91.join(cacheDir, ".git"));
27312
27449
  const useIncremental = incremental && cacheExists && lastSync !== null;
27313
27450
  let cloneSha;
27314
27451
  let cloneBranch;
@@ -27386,25 +27523,25 @@ async function importFromRepo(opts) {
27386
27523
  mrTeamConfig = { repo: tc.repo, provider: tc.provider, reviewers: tc.reviewers };
27387
27524
  mrLocalConfig = { repo: lc.repo, username: lc.username };
27388
27525
  } catch {
27389
- teamRepoDir = path90.join(process.cwd(), ".teamai", "team-repo");
27526
+ teamRepoDir = path91.join(process.cwd(), ".teamai", "team-repo");
27390
27527
  }
27391
- const teamwikiRoot = output ? path90.resolve(output, "..", "teamwiki") : path90.join(teamRepoDir, "teamwiki");
27528
+ const teamwikiRoot = output ? path91.resolve(output, "..", "teamwiki") : path91.join(teamRepoDir, "teamwiki");
27392
27529
  if (!dryRun) {
27393
- const cacheWiki = path90.join(cacheDir, "teamwiki");
27530
+ const cacheWiki = path91.join(cacheDir, "teamwiki");
27394
27531
  try {
27395
27532
  if (incremental) {
27396
- const destIndices = path90.join(teamwikiRoot, ".indices");
27397
- const cacheIndices = path90.join(cacheDir, "teamwiki", ".indices");
27533
+ const destIndices = path91.join(teamwikiRoot, ".indices");
27534
+ const cacheIndices = path91.join(cacheDir, "teamwiki", ".indices");
27398
27535
  await fs33.ensureDir(cacheIndices);
27399
27536
  for (const f of ["facts-cache.json", "interfaces-cache.json"]) {
27400
- const src = path90.join(destIndices, f);
27537
+ const src = path91.join(destIndices, f);
27401
27538
  if (await fs33.pathExists(src)) {
27402
- await fs33.copy(src, path90.join(cacheIndices, f));
27539
+ await fs33.copy(src, path91.join(cacheIndices, f));
27403
27540
  }
27404
27541
  }
27405
- const existingManifest = path90.join(teamwikiRoot, "source-manifest.json");
27542
+ const existingManifest = path91.join(teamwikiRoot, "source-manifest.json");
27406
27543
  if (await fs33.pathExists(existingManifest)) {
27407
- await fs33.copy(existingManifest, path90.join(cacheDir, "teamwiki", "source-manifest.json"));
27544
+ await fs33.copy(existingManifest, path91.join(cacheDir, "teamwiki", "source-manifest.json"));
27408
27545
  }
27409
27546
  }
27410
27547
  await extractCodebase({
@@ -27418,19 +27555,19 @@ async function importFromRepo(opts) {
27418
27555
  sourceMrUrl
27419
27556
  });
27420
27557
  if (await fs33.pathExists(cacheWiki)) {
27421
- const evidenceSrc = path90.join(cacheWiki, "evidence", "code", slug);
27422
- const evidenceDest = path90.join(teamwikiRoot, "evidence", "code", slug);
27558
+ const evidenceSrc = path91.join(cacheWiki, "evidence", "code", slug);
27559
+ const evidenceDest = path91.join(teamwikiRoot, "evidence", "code", slug);
27423
27560
  if (await fs33.pathExists(evidenceDest)) {
27424
27561
  const entries = await fs33.readdir(evidenceDest);
27425
27562
  for (const entry of entries) {
27426
27563
  if (entry === ".indices") continue;
27427
- await fs33.remove(path90.join(evidenceDest, entry));
27564
+ await fs33.remove(path91.join(evidenceDest, entry));
27428
27565
  }
27429
27566
  }
27430
27567
  await fs33.ensureDir(evidenceDest);
27431
27568
  await fs33.copy(evidenceSrc, evidenceDest, { overwrite: true });
27432
27569
  if (codebaseMd) {
27433
- const overviewPath = path90.join(evidenceDest, "overview.md");
27570
+ const overviewPath = path91.join(evidenceDest, "overview.md");
27434
27571
  const existing = await fs33.readFile(overviewPath, "utf8").catch(() => "");
27435
27572
  const aiNarrative = codebaseMd.replace(/^---[\s\S]*?---\n*/m, "");
27436
27573
  const marker = "## AI Architecture Narrative";
@@ -27453,31 +27590,31 @@ ${aiNarrative}`;
27453
27590
  }
27454
27591
  await fs33.writeFile(overviewPath, combined, "utf8");
27455
27592
  }
27456
- const srcGraph = path90.join(cacheWiki, ".indices", "graph-index.json");
27593
+ const srcGraph = path91.join(cacheWiki, ".indices", "graph-index.json");
27457
27594
  if (await fs33.pathExists(srcGraph)) {
27458
- const evidenceGraphDir = path90.join(teamwikiRoot, "evidence", "code", slug, ".indices");
27595
+ const evidenceGraphDir = path91.join(teamwikiRoot, "evidence", "code", slug, ".indices");
27459
27596
  await fs33.ensureDir(evidenceGraphDir);
27460
- await fs33.copy(srcGraph, path90.join(evidenceGraphDir, "graph-index.json"));
27597
+ await fs33.copy(srcGraph, path91.join(evidenceGraphDir, "graph-index.json"));
27461
27598
  } else {
27462
27599
  log.debug(`[graph] per-repo graph-index.json not found, skipping copy`);
27463
27600
  }
27464
- const cacheIndices = path90.join(cacheWiki, ".indices");
27465
- const destIndices = path90.join(teamwikiRoot, ".indices");
27601
+ const cacheIndices = path91.join(cacheWiki, ".indices");
27602
+ const destIndices = path91.join(teamwikiRoot, ".indices");
27466
27603
  for (const cacheFile of ["facts-cache.json", "interfaces-cache.json"]) {
27467
- const src = path90.join(cacheIndices, cacheFile);
27604
+ const src = path91.join(cacheIndices, cacheFile);
27468
27605
  if (await fs33.pathExists(src)) {
27469
27606
  await fs33.ensureDir(destIndices);
27470
- await fs33.copy(src, path90.join(destIndices, cacheFile), { overwrite: true });
27607
+ await fs33.copy(src, path91.join(destIndices, cacheFile), { overwrite: true });
27471
27608
  }
27472
27609
  }
27473
- const srcManifest = path90.join(cacheWiki, "source-manifest.json");
27610
+ const srcManifest = path91.join(cacheWiki, "source-manifest.json");
27474
27611
  if (await fs33.pathExists(srcManifest)) {
27475
- await fs33.copy(srcManifest, path90.join(teamwikiRoot, "source-manifest.json"), { overwrite: true });
27612
+ await fs33.copy(srcManifest, path91.join(teamwikiRoot, "source-manifest.json"), { overwrite: true });
27476
27613
  }
27477
27614
  await fs33.remove(cacheWiki);
27478
27615
  }
27479
27616
  if (explicitDomain) {
27480
- const domainsJsonPath = path90.join(teamwikiRoot, "evidence", "code", slug, "_domains.json");
27617
+ const domainsJsonPath = path91.join(teamwikiRoot, "evidence", "code", slug, "_domains.json");
27481
27618
  if (await fs33.pathExists(domainsJsonPath)) {
27482
27619
  try {
27483
27620
  const existing = JSON.parse(await fs33.readFile(domainsJsonPath, "utf8"));
@@ -27490,8 +27627,8 @@ ${aiNarrative}`;
27490
27627
  }
27491
27628
  }
27492
27629
  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");
27630
+ const routerPath = path91.join(teamwikiRoot, "router.md");
27631
+ const indexPath = path91.join(teamwikiRoot, "index.md");
27495
27632
  const projectLink = `[[evidence/code/${slug}/index]]`;
27496
27633
  if (await fs33.pathExists(routerPath)) {
27497
27634
  const router = await fs33.readFile(routerPath, "utf8");
@@ -27517,8 +27654,8 @@ ${aiNarrative}`;
27517
27654
  } else {
27518
27655
  await fs33.writeFile(indexPath, indexTemplate2([{ slug, label: slug }]), "utf8");
27519
27656
  }
27520
- if (!await fs33.pathExists(path90.join(teamwikiRoot, "hot.md"))) {
27521
- await fs33.writeFile(path90.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE2, "utf8");
27657
+ if (!await fs33.pathExists(path91.join(teamwikiRoot, "hot.md"))) {
27658
+ await fs33.writeFile(path91.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE2, "utf8");
27522
27659
  }
27523
27660
  log.info(chalk4.green(`\u2713 teamwiki/ knowledge graph updated: ${slug}`));
27524
27661
  } catch (err) {
@@ -27540,8 +27677,8 @@ ${aiNarrative}`;
27540
27677
  }
27541
27678
  }
27542
27679
  if (!dryRun && !skipEnrich && teamwikiRoot) {
27543
- const evidenceDir = path90.join(teamwikiRoot, "evidence", "code", slug);
27544
- if (await fs33.pathExists(path90.join(evidenceDir, "_manifest.json"))) {
27680
+ const evidenceDir = path91.join(teamwikiRoot, "evidence", "code", slug);
27681
+ if (await fs33.pathExists(path91.join(evidenceDir, "_manifest.json"))) {
27545
27682
  try {
27546
27683
  const { deepEnrich: deepEnrich2 } = await Promise.resolve().then(() => (init_deep_enrich(), deep_enrich_exports));
27547
27684
  await deepEnrich2({ project: slug, evidenceDir, wikiRoot: teamwikiRoot, cacheDir });
@@ -27657,7 +27794,7 @@ var init_store = __esm({
27657
27794
  });
27658
27795
 
27659
27796
  // src/import-repo-list.ts
27660
- import path91 from "path";
27797
+ import path92 from "path";
27661
27798
  function sortByPriority(entries) {
27662
27799
  const order = { high: 0, normal: 1, low: 2 };
27663
27800
  return [...entries].sort((a, b) => {
@@ -27734,7 +27871,7 @@ async function importFromRepoList(opts) {
27734
27871
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
27735
27872
  const { localConfig: lc } = await autoDetectInit2();
27736
27873
  const teamRepoPath = lc.repo.localPath;
27737
- const teamwikiRoot = path91.join(teamRepoPath, "teamwiki");
27874
+ const teamwikiRoot = path92.join(teamRepoPath, "teamwiki");
27738
27875
  const { aggregateGlobalGraph: aggregateGlobalGraph2 } = await Promise.resolve().then(() => (init_graph_aggregate(), graph_aggregate_exports));
27739
27876
  await aggregateGlobalGraph2(teamwikiRoot);
27740
27877
  } catch (e) {
@@ -27784,9 +27921,9 @@ __export(rebuild_wiki_index_exports, {
27784
27921
  rebuildWikiIndex: () => rebuildWikiIndex
27785
27922
  });
27786
27923
  import { readFile as readFile10, readdir as readdir6, stat as stat4, writeFile as writeFile11 } from "fs/promises";
27787
- import path92 from "path";
27924
+ import path93 from "path";
27788
27925
  async function rebuildWikiIndex(teamwikiRoot) {
27789
- const evidenceCodeDir = path92.join(teamwikiRoot, "evidence", "code");
27926
+ const evidenceCodeDir = path93.join(teamwikiRoot, "evidence", "code");
27790
27927
  if (!await pathExists(evidenceCodeDir)) return;
27791
27928
  const projects = [];
27792
27929
  let totalFacts = 0, totalNodes = 0, totalEdges = 0;
@@ -27794,7 +27931,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27794
27931
  let totalCallChains = 0;
27795
27932
  const dirs = await readdir6(evidenceCodeDir);
27796
27933
  for (const dir of dirs) {
27797
- const dirPath = path92.join(evidenceCodeDir, dir);
27934
+ const dirPath = path93.join(evidenceCodeDir, dir);
27798
27935
  const dirStat = await stat4(dirPath).catch(() => null);
27799
27936
  if (!dirStat?.isDirectory()) continue;
27800
27937
  const info = {
@@ -27807,7 +27944,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27807
27944
  keywords: [],
27808
27945
  domain: ""
27809
27946
  };
27810
- const overviewPath = path92.join(dirPath, "overview.md");
27947
+ const overviewPath = path93.join(dirPath, "overview.md");
27811
27948
  if (await pathExists(overviewPath)) {
27812
27949
  const content = await readFile10(overviewPath, "utf-8");
27813
27950
  const bodyStart = content.indexOf("\n\n", content.indexOf("---", 3));
@@ -27820,7 +27957,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27820
27957
  }
27821
27958
  }
27822
27959
  }
27823
- const projectIndex = path92.join(dirPath, "index.md");
27960
+ const projectIndex = path93.join(dirPath, "index.md");
27824
27961
  if (await pathExists(projectIndex)) {
27825
27962
  const content = await readFile10(projectIndex, "utf-8");
27826
27963
  const factsMatch = content.match(/Facts:\s*(\d+)/);
@@ -27830,7 +27967,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27830
27967
  info.interfaces[m[1]] = (info.interfaces[m[1]] ?? 0) + parseInt(m[2], 10);
27831
27968
  }
27832
27969
  }
27833
- const manifestPath = path92.join(dirPath, "_manifest.json");
27970
+ const manifestPath = path93.join(dirPath, "_manifest.json");
27834
27971
  if (await pathExists(manifestPath)) {
27835
27972
  try {
27836
27973
  const raw = await readFile10(manifestPath, "utf-8");
@@ -27842,7 +27979,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27842
27979
  } catch {
27843
27980
  }
27844
27981
  }
27845
- const domainsPath = path92.join(dirPath, "_domains.json");
27982
+ const domainsPath = path93.join(dirPath, "_domains.json");
27846
27983
  if (await pathExists(domainsPath)) {
27847
27984
  try {
27848
27985
  const raw = await readFile10(domainsPath, "utf-8");
@@ -27859,7 +27996,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27859
27996
  } catch {
27860
27997
  }
27861
27998
  }
27862
- const chainsPath = path92.join(dirPath, "dependency-paths.md");
27999
+ const chainsPath = path93.join(dirPath, "dependency-paths.md");
27863
28000
  if (await pathExists(chainsPath)) {
27864
28001
  const content = await readFile10(chainsPath, "utf-8");
27865
28002
  const chainMatch = content.match(/(\d+)\s*call chain/);
@@ -27875,7 +28012,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27875
28012
  }
27876
28013
  projects.push(info);
27877
28014
  }
27878
- const graphPath = path92.join(teamwikiRoot, ".indices", "graph-index.json");
28015
+ const graphPath = path93.join(teamwikiRoot, ".indices", "graph-index.json");
27879
28016
  if (await pathExists(graphPath)) {
27880
28017
  try {
27881
28018
  const raw = await readFile10(graphPath, "utf-8");
@@ -27916,7 +28053,7 @@ async function rebuildWikiIndex(teamwikiRoot) {
27916
28053
  routerLines.push("4. **\u8C03\u7528\u94FE/\u6392\u969C** \u2192 \u67E5\u5BF9\u5E94\u4ED3\u5E93\u7684 dependency-paths.md");
27917
28054
  routerLines.push("5. **\u6A21\u5757\u804C\u8D23\u6982\u8FF0** \u2192 \u67E5 overview.md \u6216 modules/*.md");
27918
28055
  routerLines.push("");
27919
- await writeFile11(path92.join(teamwikiRoot, "router.md"), routerLines.join("\n"), "utf-8");
28056
+ await writeFile11(path93.join(teamwikiRoot, "router.md"), routerLines.join("\n"), "utf-8");
27920
28057
  const indexLines = [
27921
28058
  "# Team Wiki Index",
27922
28059
  "",
@@ -27952,9 +28089,9 @@ async function rebuildWikiIndex(teamwikiRoot) {
27952
28089
  indexLines.push("- [router.md](./router.md) \u2014 \u4EA7\u54C1\u57DF\u8DEF\u7531\uFF08\u8868\u683C + \u8DEF\u7531\u89C4\u5219\uFF09");
27953
28090
  indexLines.push("- [hot.md](./hot.md) \u2014 \u6D3B\u8DC3\u5DE5\u4F5C\u8BB0\u5FC6");
27954
28091
  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");
28092
+ await writeFile11(path93.join(teamwikiRoot, "index.md"), indexLines.join("\n"), "utf-8");
28093
+ if (!await pathExists(path93.join(teamwikiRoot, "hot.md"))) {
28094
+ await writeFile11(path93.join(teamwikiRoot, "hot.md"), HOT_TEMPLATE, "utf-8");
27958
28095
  }
27959
28096
  log.debug(`rebuildWikiIndex: ${projects.length} projects, ${totalNodes} nodes, ${totalEdges} edges`);
27960
28097
  }
@@ -27993,7 +28130,7 @@ var init_rebuild_wiki_index = __esm({
27993
28130
  });
27994
28131
 
27995
28132
  // src/import-org.ts
27996
- import path93 from "path";
28133
+ import path94 from "path";
27997
28134
  import fs35 from "fs-extra";
27998
28135
  function parseOrgInput(org) {
27999
28136
  const trimmed = org.trim();
@@ -28064,9 +28201,9 @@ async function importFromOrg(opts) {
28064
28201
  return;
28065
28202
  }
28066
28203
  log.info(`${filteredRepos.length} repos after filtering, generating whitelist...`);
28067
- const whitelistDraftPath = path93.join(cwd, WHITELIST_DRAFT_PATH);
28204
+ const whitelistDraftPath = path94.join(cwd, WHITELIST_DRAFT_PATH);
28068
28205
  if (!opts.dryRun) {
28069
- await fs35.ensureDir(path93.dirname(whitelistDraftPath));
28206
+ await fs35.ensureDir(path94.dirname(whitelistDraftPath));
28070
28207
  const lines = ["version: 1", "repos:"];
28071
28208
  for (const repo of filteredRepos) {
28072
28209
  lines.push(` - url: ${repo.url}`);
@@ -28095,8 +28232,8 @@ async function importFromOrg(opts) {
28095
28232
  );
28096
28233
  try {
28097
28234
  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");
28235
+ const teamRepoPath = path94.join(cwd, ".teamai", "team-repo");
28236
+ const teamRepoWiki = path94.join(teamRepoPath, "teamwiki");
28100
28237
  if (await fs35.pathExists(teamRepoWiki)) {
28101
28238
  await rebuildWikiIndex2(teamRepoWiki);
28102
28239
  log.info("teamwiki router.md / index.md rebuilt");
@@ -28128,10 +28265,10 @@ var init_import_org = __esm({
28128
28265
 
28129
28266
  // src/review-store.ts
28130
28267
  import crypto4 from "crypto";
28131
- import path94 from "path";
28268
+ import path95 from "path";
28132
28269
  import fs36 from "fs-extra";
28133
28270
  function getPendingReviewPath(cwd) {
28134
- return path94.join(cwd, PENDING_REVIEW_PATH);
28271
+ return path95.join(cwd, PENDING_REVIEW_PATH);
28135
28272
  }
28136
28273
  function computeReviewId(file, section, ts) {
28137
28274
  return crypto4.createHash("sha1").update(`${file}|${section ?? ""}|${ts}`).digest("hex").slice(0, 12);
@@ -28207,7 +28344,7 @@ async function loadPendingReview(cwd) {
28207
28344
  async function savePendingReview(cwd, items) {
28208
28345
  const filePath = getPendingReviewPath(cwd);
28209
28346
  const tmpPath = `${filePath}.tmp`;
28210
- await fs36.ensureDir(path94.dirname(filePath));
28347
+ await fs36.ensureDir(path95.dirname(filePath));
28211
28348
  const content = items.map((item) => JSON.stringify(item)).join("\n") + (items.length > 0 ? "\n" : "");
28212
28349
  await fs36.writeFile(tmpPath, content, "utf8");
28213
28350
  await fs36.rename(tmpPath, filePath);
@@ -28227,7 +28364,7 @@ async function appendPendingReview(cwd, partial) {
28227
28364
  risk
28228
28365
  };
28229
28366
  const filePath = getPendingReviewPath(cwd);
28230
- await fs36.ensureDir(path94.dirname(filePath));
28367
+ await fs36.ensureDir(path95.dirname(filePath));
28231
28368
  await fs36.appendFile(filePath, JSON.stringify(item) + "\n", "utf8");
28232
28369
  return item;
28233
28370
  }
@@ -28262,14 +28399,14 @@ var init_review_store = __esm({
28262
28399
  });
28263
28400
 
28264
28401
  // src/utils/team-codebase-paths.ts
28265
- import path95 from "path";
28402
+ import path96 from "path";
28266
28403
  function getTeamCodebasePaths(cwd, output) {
28267
- const root = output ?? path95.join(cwd, "docs", TEAM_CODEBASE_DIR);
28404
+ const root = output ?? path96.join(cwd, "docs", TEAM_CODEBASE_DIR);
28268
28405
  return {
28269
28406
  root,
28270
- index: path95.join(root, "index.md"),
28271
- domainsDir: path95.join(root, "domains"),
28272
- reposDir: path95.join(root, "repos")
28407
+ index: path96.join(root, "index.md"),
28408
+ domainsDir: path96.join(root, "domains"),
28409
+ reposDir: path96.join(root, "repos")
28273
28410
  };
28274
28411
  }
28275
28412
  var TEAM_CODEBASE_DIR;
@@ -28281,7 +28418,7 @@ var init_team_codebase_paths = __esm({
28281
28418
  });
28282
28419
 
28283
28420
  // src/iwiki-dual.ts
28284
- import path96 from "path";
28421
+ import path97 from "path";
28285
28422
  import fs37 from "fs-extra";
28286
28423
  function parseIWikiInput2(input) {
28287
28424
  const trimmed = input.trim();
@@ -28446,10 +28583,10 @@ async function importFromIWikiDual(opts) {
28446
28583
  return { sectionsUpdated: [], pendingReview: false };
28447
28584
  }
28448
28585
  const paths = getTeamCodebasePaths(cwd, opts.output);
28449
- const filePath = path96.join(paths.root, "external-knowledge.md");
28586
+ const filePath = path97.join(paths.root, "external-knowledge.md");
28450
28587
  if (opts.requireReview) {
28451
28588
  if (!opts.dryRun) {
28452
- const relativeFilePath = path96.relative(cwd, filePath);
28589
+ const relativeFilePath = path97.relative(cwd, filePath);
28453
28590
  for (const sectionKey of sections) {
28454
28591
  const body = aiOutput[sectionKey] ?? "";
28455
28592
  if (!body) continue;
@@ -28516,7 +28653,7 @@ var import_exports = {};
28516
28653
  __export(import_exports, {
28517
28654
  importCmd: () => importCmd
28518
28655
  });
28519
- import path97 from "path";
28656
+ import path98 from "path";
28520
28657
  import os6 from "os";
28521
28658
  import fs38 from "fs-extra";
28522
28659
  import { Listr, PRESET_TIMER } from "listr2";
@@ -28632,7 +28769,7 @@ async function importCmd(opts) {
28632
28769
  task: async (ctx) => {
28633
28770
  const { learning, repoUrl } = await importFromMR({
28634
28771
  url: opts.fromMr,
28635
- learningsDir: path97.join(localConfig.repo.localPath, "learnings"),
28772
+ learningsDir: path98.join(localConfig.repo.localPath, "learnings"),
28636
28773
  all: opts.all,
28637
28774
  outputDir: opts.output,
28638
28775
  repoPath: opts.dryRun ? void 0 : localConfig.repo.localPath,
@@ -28646,7 +28783,7 @@ async function importCmd(opts) {
28646
28783
  title: "Incremental teamwiki update",
28647
28784
  skip: (ctx) => !ctx.repoUrl || !!opts.dryRun || !!opts.output,
28648
28785
  task: async (ctx, task) => {
28649
- const teamwikiRoot = path97.join(localConfig.repo.localPath, "teamwiki");
28786
+ const teamwikiRoot = path98.join(localConfig.repo.localPath, "teamwiki");
28650
28787
  try {
28651
28788
  const { detectProvider: detectProvider2, getProvider: getProvider2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
28652
28789
  const { getRepoSlug: getRepoSlug2 } = await Promise.resolve().then(() => (init_repo_cache(), repo_cache_exports));
@@ -28654,7 +28791,7 @@ async function importCmd(opts) {
28654
28791
  const provider = getProvider2(providerName);
28655
28792
  const repoInfo = provider.parseRepoInput(ctx.repoUrl);
28656
28793
  const slug = getRepoSlug2(providerName, repoInfo.owner, repoInfo.repo);
28657
- const evidenceDir = path97.join(teamwikiRoot, "evidence", "code", slug);
28794
+ const evidenceDir = path98.join(teamwikiRoot, "evidence", "code", slug);
28658
28795
  if (await fs38.pathExists(evidenceDir)) {
28659
28796
  task.output = `Updating ${slug}...`;
28660
28797
  await importFromRepo({
@@ -28700,18 +28837,18 @@ async function importCmd(opts) {
28700
28837
  setSilent(false);
28701
28838
  }
28702
28839
  } else if (opts.dir) {
28703
- const dirPath = path97.resolve(opts.dir);
28840
+ const dirPath = path98.resolve(opts.dir);
28704
28841
  if (!await fs38.pathExists(dirPath)) {
28705
28842
  throw new Error(`Directory not found: ${dirPath}`);
28706
28843
  }
28707
- const slug = path97.basename(dirPath);
28844
+ const slug = path98.basename(dirPath);
28708
28845
  log.info(`Scanning local directory: ${dirPath} (project: ${slug})`);
28709
28846
  if (opts.dryRun) {
28710
28847
  log.info(`[dry-run] skipping code extraction, no action taken`);
28711
28848
  log.success(`Local directory ${slug} import complete (dry-run)`);
28712
28849
  return;
28713
28850
  }
28714
- const tmpExtractDir = await fs38.mkdtemp(path97.join(os6.tmpdir(), "teamai-extract-"));
28851
+ const tmpExtractDir = await fs38.mkdtemp(path98.join(os6.tmpdir(), "teamai-extract-"));
28715
28852
  try {
28716
28853
  const { extractCodebase: extractCodebase2 } = await Promise.resolve().then(() => (init_codebase_extract(), codebase_extract_exports));
28717
28854
  await extractCodebase2({
@@ -28721,9 +28858,9 @@ async function importCmd(opts) {
28721
28858
  skipEnrich: opts.skipEnrich ?? false,
28722
28859
  outputRoot: tmpExtractDir
28723
28860
  });
28724
- const srcWiki = path97.join(tmpExtractDir, "teamwiki");
28861
+ const srcWiki = path98.join(tmpExtractDir, "teamwiki");
28725
28862
  if (opts.output) {
28726
- const outputWiki = path97.join(opts.output, "teamwiki");
28863
+ const outputWiki = path98.join(opts.output, "teamwiki");
28727
28864
  if (await fs38.pathExists(srcWiki)) {
28728
28865
  await fs38.copy(srcWiki, outputWiki, { overwrite: true });
28729
28866
  log.info(`Output written: ${outputWiki}`);
@@ -28731,19 +28868,19 @@ async function importCmd(opts) {
28731
28868
  } else {
28732
28869
  const { localConfig } = await autoDetectInit();
28733
28870
  const teamRepoPath = localConfig.repo.localPath;
28734
- const teamwikiRoot = path97.join(teamRepoPath, "teamwiki");
28871
+ const teamwikiRoot = path98.join(teamRepoPath, "teamwiki");
28735
28872
  if (await fs38.pathExists(srcWiki)) {
28736
- const evidenceSrc = path97.join(srcWiki, "evidence", "code", slug);
28737
- const evidenceDest = path97.join(teamwikiRoot, "evidence", "code", slug);
28873
+ const evidenceSrc = path98.join(srcWiki, "evidence", "code", slug);
28874
+ const evidenceDest = path98.join(teamwikiRoot, "evidence", "code", slug);
28738
28875
  if (await fs38.pathExists(evidenceSrc)) {
28739
- await fs38.ensureDir(path97.dirname(evidenceDest));
28876
+ await fs38.ensureDir(path98.dirname(evidenceDest));
28740
28877
  await fs38.copy(evidenceSrc, evidenceDest, { overwrite: true });
28741
28878
  }
28742
- const srcGraph = path97.join(srcWiki, ".indices", "graph-index.json");
28879
+ const srcGraph = path98.join(srcWiki, ".indices", "graph-index.json");
28743
28880
  if (await fs38.pathExists(srcGraph)) {
28744
- const destGraphDir = path97.join(evidenceDest, ".indices");
28881
+ const destGraphDir = path98.join(evidenceDest, ".indices");
28745
28882
  await fs38.ensureDir(destGraphDir);
28746
- await fs38.copy(srcGraph, path97.join(destGraphDir, "graph-index.json"), { overwrite: true });
28883
+ await fs38.copy(srcGraph, path98.join(destGraphDir, "graph-index.json"), { overwrite: true });
28747
28884
  }
28748
28885
  log.info(`teamwiki/ knowledge graph updated: ${slug}`);
28749
28886
  }
@@ -28804,11 +28941,11 @@ __export(codebase_upgrade_wiki_exports, {
28804
28941
  upgradeCodebaseWiki: () => upgradeCodebaseWiki
28805
28942
  });
28806
28943
  import { readdir as readdir7, readFile as readFile11 } from "fs/promises";
28807
- import path98 from "path";
28944
+ import path99 from "path";
28808
28945
  import chalk5 from "chalk";
28809
28946
  import matter9 from "gray-matter";
28810
28947
  async function upgradeCodebaseWiki(opts) {
28811
- const teamCodebaseDir = path98.join(opts.cwd, "docs", "team-codebase", "repos");
28948
+ const teamCodebaseDir = path99.join(opts.cwd, "docs", "team-codebase", "repos");
28812
28949
  if (!await pathExists(teamCodebaseDir)) {
28813
28950
  if (opts.json) {
28814
28951
  console.log(JSON.stringify({ status: "nothing-to-migrate", reason: "docs/team-codebase/repos/ not found" }));
@@ -28833,7 +28970,7 @@ async function upgradeCodebaseWiki(opts) {
28833
28970
  const result = { migrated: [], skipped: [], errors: [] };
28834
28971
  for (const file of mdFiles) {
28835
28972
  const slug = file.replace(".md", "");
28836
- const filePath = path98.join(teamCodebaseDir, file);
28973
+ const filePath = path99.join(teamCodebaseDir, file);
28837
28974
  try {
28838
28975
  const content = await readFile11(filePath, "utf-8");
28839
28976
  const parsed = matter9(content);
@@ -28846,9 +28983,9 @@ async function upgradeCodebaseWiki(opts) {
28846
28983
  result.migrated.push(`${slug} \u2192 teamwiki/evidence/code/${slug}/`);
28847
28984
  continue;
28848
28985
  }
28849
- const cacheBase = path98.join(process.env["HOME"] ?? "", ".teamai", "cache", "repos");
28986
+ const cacheBase = path99.join(process.env["HOME"] ?? "", ".teamai", "cache", "repos");
28850
28987
  const urlParts = String(source).replace(/^https?:\/\//, "").replace(/@.*$/, "").split("/");
28851
- const cachePath = path98.join(cacheBase, ...urlParts.slice(0, 3));
28988
+ const cachePath = path99.join(cacheBase, ...urlParts.slice(0, 3));
28852
28989
  if (await pathExists(cachePath)) {
28853
28990
  await extractCodebase({ path: cachePath, project: slug });
28854
28991
  result.migrated.push(slug);
@@ -28903,10 +29040,10 @@ __export(codebase_wiki_lint_exports, {
28903
29040
  lintTeamwiki: () => lintTeamwiki
28904
29041
  });
28905
29042
  import { readFile as readFile12, readdir as readdir8, stat as stat5 } from "fs/promises";
28906
- import path99 from "path";
29043
+ import path100 from "path";
28907
29044
  import chalk6 from "chalk";
28908
29045
  async function lintTeamwiki(opts) {
28909
- const wikiRoot = opts.wikiRoot ?? path99.join(opts.cwd ?? process.cwd(), "teamwiki");
29046
+ const wikiRoot = opts.wikiRoot ?? path100.join(opts.cwd ?? process.cwd(), "teamwiki");
28910
29047
  const issues = [];
28911
29048
  const minSeverity = opts.severity ?? "info";
28912
29049
  const severityOrder = ["info", "low", "medium", "high"];
@@ -28916,7 +29053,7 @@ async function lintTeamwiki(opts) {
28916
29053
  issues.push(issue);
28917
29054
  }
28918
29055
  }
28919
- const graphPath = path99.join(wikiRoot, ".indices", "graph-index.json");
29056
+ const graphPath = path100.join(wikiRoot, ".indices", "graph-index.json");
28920
29057
  let graph = null;
28921
29058
  if (!await pathExists(graphPath)) {
28922
29059
  addIssue({
@@ -28938,7 +29075,7 @@ async function lintTeamwiki(opts) {
28938
29075
  });
28939
29076
  }
28940
29077
  }
28941
- const evidenceDir = path99.join(wikiRoot, "evidence", "code");
29078
+ const evidenceDir = path100.join(wikiRoot, "evidence", "code");
28942
29079
  if (!await pathExists(evidenceDir)) {
28943
29080
  addIssue({
28944
29081
  severity: "high",
@@ -28957,7 +29094,7 @@ async function lintTeamwiki(opts) {
28957
29094
  });
28958
29095
  }
28959
29096
  for (const project of projects) {
28960
- const projectDir = path99.join(evidenceDir, project);
29097
+ const projectDir = path100.join(evidenceDir, project);
28961
29098
  const pStat = await stat5(projectDir).catch(() => null);
28962
29099
  if (!pStat?.isDirectory()) {
28963
29100
  if (!pStat) {
@@ -28977,7 +29114,7 @@ async function lintTeamwiki(opts) {
28977
29114
  }
28978
29115
  }
28979
29116
  for (const navFile of ["router.md", "index.md", "hot.md"]) {
28980
- if (!await pathExists(path99.join(wikiRoot, navFile))) {
29117
+ if (!await pathExists(path100.join(wikiRoot, navFile))) {
28981
29118
  addIssue({
28982
29119
  severity: "low",
28983
29120
  category: "nav-missing",
@@ -28986,7 +29123,7 @@ async function lintTeamwiki(opts) {
28986
29123
  });
28987
29124
  }
28988
29125
  }
28989
- const manifestPath = path99.join(wikiRoot, "source-manifest.json");
29126
+ const manifestPath = path100.join(wikiRoot, "source-manifest.json");
28990
29127
  if (!await pathExists(manifestPath)) {
28991
29128
  addIssue({
28992
29129
  severity: "low",
@@ -29102,7 +29239,7 @@ var codebase_cmd_exports = {};
29102
29239
  __export(codebase_cmd_exports, {
29103
29240
  codebaseCmd: () => codebaseCmd
29104
29241
  });
29105
- import path100 from "path";
29242
+ import path101 from "path";
29106
29243
  import { readFile as readFile13 } from "fs/promises";
29107
29244
  import chalk7 from "chalk";
29108
29245
  async function codebaseCmd(opts) {
@@ -29143,14 +29280,14 @@ async function codebaseCmd(opts) {
29143
29280
  const { pathExists: pathExists3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
29144
29281
  let teamwikiDir;
29145
29282
  if (opts.output) {
29146
- teamwikiDir = path100.resolve(opts.output, "teamwiki");
29283
+ teamwikiDir = path101.resolve(opts.output, "teamwiki");
29147
29284
  } else {
29148
29285
  try {
29149
29286
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
29150
29287
  const { localConfig: lc } = await autoDetectInit2();
29151
- teamwikiDir = path100.join(lc.repo.localPath, "teamwiki");
29288
+ teamwikiDir = path101.join(lc.repo.localPath, "teamwiki");
29152
29289
  } catch {
29153
- teamwikiDir = path100.join(cwd, ".teamai", "team-repo", "teamwiki");
29290
+ teamwikiDir = path101.join(cwd, ".teamai", "team-repo", "teamwiki");
29154
29291
  }
29155
29292
  }
29156
29293
  if (!await pathExists3(teamwikiDir)) {
@@ -29173,17 +29310,17 @@ async function printCodebaseStatus(opts) {
29173
29310
  const cwd = process.cwd();
29174
29311
  let teamwikiDir;
29175
29312
  if (opts.output) {
29176
- teamwikiDir = path100.resolve(opts.output, "teamwiki");
29313
+ teamwikiDir = path101.resolve(opts.output, "teamwiki");
29177
29314
  } else {
29178
29315
  try {
29179
29316
  const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
29180
29317
  const { localConfig: lc } = await autoDetectInit2();
29181
- teamwikiDir = path100.join(lc.repo.localPath, "teamwiki");
29318
+ teamwikiDir = path101.join(lc.repo.localPath, "teamwiki");
29182
29319
  } catch {
29183
- teamwikiDir = path100.join(cwd, ".teamai", "team-repo", "teamwiki");
29320
+ teamwikiDir = path101.join(cwd, ".teamai", "team-repo", "teamwiki");
29184
29321
  }
29185
29322
  }
29186
- const manifestPath = path100.join(teamwikiDir, "source-manifest.json");
29323
+ const manifestPath = path101.join(teamwikiDir, "source-manifest.json");
29187
29324
  let manifest;
29188
29325
  try {
29189
29326
  manifest = JSON.parse(await readFile13(manifestPath, "utf-8"));
@@ -29280,7 +29417,7 @@ var review_cmd_exports = {};
29280
29417
  __export(review_cmd_exports, {
29281
29418
  reviewCmd: () => reviewCmd
29282
29419
  });
29283
- import path101 from "path";
29420
+ import path102 from "path";
29284
29421
  import chalk8 from "chalk";
29285
29422
  import fs39 from "fs-extra";
29286
29423
  function riskAtMost(itemRisk, ceiling) {
@@ -29356,7 +29493,7 @@ async function applyOne(cwd, item) {
29356
29493
  if (!section) {
29357
29494
  return { ok: false, reason: "target.section \u7F3A\u5931" };
29358
29495
  }
29359
- const filePath = path101.isAbsolute(file) ? file : path101.join(cwd, file);
29496
+ const filePath = path102.isAbsolute(file) ? file : path102.join(cwd, file);
29360
29497
  if (!await fs39.pathExists(filePath)) {
29361
29498
  return { ok: false, reason: `\u76EE\u6807\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${filePath}` };
29362
29499
  }
@@ -29513,10 +29650,10 @@ function formatComment(learning, suggestions, marker) {
29513
29650
  lines.push("> _Auto-generated by `teamai ci extract-mr`_");
29514
29651
  return lines.join("\n");
29515
29652
  }
29516
- async function githubRequest(path106, method, body) {
29653
+ async function githubRequest(path107, method, body) {
29517
29654
  const token = process.env["GITHUB_TOKEN"];
29518
29655
  if (!token) throw new Error("\u672A\u8BBE\u7F6E GITHUB_TOKEN \u73AF\u5883\u53D8\u91CF");
29519
- const url = `https://api.github.com${path106}`;
29656
+ const url = `https://api.github.com${path107}`;
29520
29657
  const headers = {
29521
29658
  Authorization: `Bearer ${token}`,
29522
29659
  Accept: "application/vnd.github+json",
@@ -29565,8 +29702,8 @@ async function updateGitHubComment(owner, repo, commentId, body) {
29565
29702
  const data = await resp.json();
29566
29703
  return { created: false, url: data.html_url };
29567
29704
  }
29568
- async function tgitRequest(path106, method, body) {
29569
- return tgitFetch(path106, {
29705
+ async function tgitRequest(path107, method, body) {
29706
+ return tgitFetch(path107, {
29570
29707
  method,
29571
29708
  body: body ? JSON.stringify(body) : void 0
29572
29709
  });
@@ -29849,10 +29986,10 @@ function extractMarkerId(body) {
29849
29986
  const match = body.match(MARKER_REGEX);
29850
29987
  return match ? match[1] : null;
29851
29988
  }
29852
- async function githubRequest2(path106) {
29989
+ async function githubRequest2(path107) {
29853
29990
  const token = process.env["GITHUB_TOKEN"];
29854
29991
  if (!token) throw new Error("\u672A\u8BBE\u7F6E GITHUB_TOKEN");
29855
- return fetch(`https://api.github.com${path106}`, {
29992
+ return fetch(`https://api.github.com${path107}`, {
29856
29993
  headers: {
29857
29994
  Authorization: `Bearer ${token}`,
29858
29995
  Accept: "application/vnd.github+json",
@@ -29887,8 +30024,8 @@ async function readGitHubRejections(owner, repo, prNumber) {
29887
30024
  }
29888
30025
  return result;
29889
30026
  }
29890
- async function tgitRequest2(path106) {
29891
- return tgitFetch(path106);
30027
+ async function tgitRequest2(path107) {
30028
+ return tgitFetch(path107);
29892
30029
  }
29893
30030
  async function getMrGlobalId2(projectId, mrIid) {
29894
30031
  const resp = await tgitRequest2(`/projects/${projectId}/merge_requests?iid=${mrIid}`);
@@ -29949,7 +30086,7 @@ __export(extract_mr_exports, {
29949
30086
  ciExtractMr: () => ciExtractMr
29950
30087
  });
29951
30088
  import fs40 from "fs/promises";
29952
- import path102 from "path";
30089
+ import path103 from "path";
29953
30090
  async function configureGitUser2(repoPath, provider) {
29954
30091
  const { execFileSync: execFileSync4 } = await import("child_process");
29955
30092
  let name = "teamai-ci";
@@ -29996,8 +30133,8 @@ async function writeKnowledgeToRepo(teamRepo, learning, suggestions, writeMode,
29996
30133
  const safeTitle = learning.title.replace(/[^a-zA-Z0-9一-鿿_-]/g, "-").replace(/-+/g, "-").slice(0, 50);
29997
30134
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
29998
30135
  const filename = `${dateStr}-${safeTitle}.md`;
29999
- const learningsDir = path102.join(teamRepo, "learnings");
30000
- const learningPath = path102.join(learningsDir, filename);
30136
+ const learningsDir = path103.join(teamRepo, "learnings");
30137
+ const learningPath = path103.join(learningsDir, filename);
30001
30138
  if (!dryRun) {
30002
30139
  await fs40.mkdir(learningsDir, { recursive: true });
30003
30140
  await fs40.writeFile(learningPath, learning.content, "utf-8");
@@ -30037,11 +30174,11 @@ async function writeKnowledgeToRepo(teamRepo, learning, suggestions, writeMode,
30037
30174
  async function writeArtifacts(outputDir, learning, suggestions) {
30038
30175
  await fs40.mkdir(outputDir, { recursive: true });
30039
30176
  if (learning) {
30040
- await fs40.writeFile(path102.join(outputDir, "learning.md"), learning.content, "utf-8");
30177
+ await fs40.writeFile(path103.join(outputDir, "learning.md"), learning.content, "utf-8");
30041
30178
  }
30042
30179
  if (suggestions && suggestions.length > 0) {
30043
30180
  await fs40.writeFile(
30044
- path102.join(outputDir, "codebase-suggestions.json"),
30181
+ path103.join(outputDir, "codebase-suggestions.json"),
30045
30182
  JSON.stringify(suggestions, null, 2),
30046
30183
  "utf-8"
30047
30184
  );
@@ -30055,7 +30192,7 @@ async function ciExtractMr(opts) {
30055
30192
  const result = await importFromMR({
30056
30193
  url: opts.url,
30057
30194
  all: true,
30058
- learningsDir: opts.teamRepo ? path102.join(opts.teamRepo, "learnings") : void 0,
30195
+ learningsDir: opts.teamRepo ? path103.join(opts.teamRepo, "learnings") : void 0,
30059
30196
  dryRun: true
30060
30197
  // 不让 importFromMR 自己写文件,我们自己控制写入
30061
30198
  });
@@ -30164,21 +30301,21 @@ ${affectedModules.map((m) => `- \`${m}\` (evidence + G-document)`).join("\n")}`
30164
30301
  const projectName = parsed.repo;
30165
30302
  await extractCodebase2({ path: businessRepo, project: projectName });
30166
30303
  const fse12 = await import("fs-extra");
30167
- const srcWiki = path102.join(businessRepo, "teamwiki");
30168
- const teamWikiRoot = path102.join(path102.resolve(opts.teamRepo), "teamwiki");
30304
+ const srcWiki = path103.join(businessRepo, "teamwiki");
30305
+ const teamWikiRoot = path103.join(path103.resolve(opts.teamRepo), "teamwiki");
30169
30306
  try {
30170
30307
  if (await fse12.pathExists(srcWiki)) {
30171
- const evidenceSrc = path102.join(srcWiki, "evidence", "code", projectName);
30172
- const evidenceDest = path102.join(teamWikiRoot, "evidence", "code", projectName);
30308
+ const evidenceSrc = path103.join(srcWiki, "evidence", "code", projectName);
30309
+ const evidenceDest = path103.join(teamWikiRoot, "evidence", "code", projectName);
30173
30310
  if (await fse12.pathExists(evidenceSrc)) {
30174
30311
  await fse12.ensureDir(evidenceDest);
30175
30312
  await fse12.copy(evidenceSrc, evidenceDest, { overwrite: true });
30176
30313
  }
30177
- const srcGraph = path102.join(srcWiki, ".indices", "graph-index.json");
30314
+ const srcGraph = path103.join(srcWiki, ".indices", "graph-index.json");
30178
30315
  if (await fse12.pathExists(srcGraph)) {
30179
- const destGraphDir = path102.join(evidenceDest, ".indices");
30316
+ const destGraphDir = path103.join(evidenceDest, ".indices");
30180
30317
  await fse12.ensureDir(destGraphDir);
30181
- await fse12.copy(srcGraph, path102.join(destGraphDir, "graph-index.json"));
30318
+ await fse12.copy(srcGraph, path103.join(destGraphDir, "graph-index.json"));
30182
30319
  }
30183
30320
  const { aggregateGlobalGraph: aggregateGlobalGraph2 } = await Promise.resolve().then(() => (init_graph_aggregate(), graph_aggregate_exports));
30184
30321
  await aggregateGlobalGraph2(teamWikiRoot);
@@ -30235,7 +30372,7 @@ var init_extract_mr = __esm({
30235
30372
  });
30236
30373
 
30237
30374
  // src/maintenance/prune.ts
30238
- import path103 from "path";
30375
+ import path104 from "path";
30239
30376
  import matter10 from "gray-matter";
30240
30377
  async function findPruneCandidates(learningsDir, votesDir, options = {}) {
30241
30378
  const threshold = options.threshold ?? DEFAULT_THRESHOLD;
@@ -30246,7 +30383,7 @@ async function findPruneCandidates(learningsDir, votesDir, options = {}) {
30246
30383
  for (const file of files) {
30247
30384
  if (!file.endsWith(".md")) continue;
30248
30385
  const docId = file.replace(/\.md$/i, "");
30249
- const absPath = path103.join(learningsDir, file);
30386
+ const absPath = path104.join(learningsDir, file);
30250
30387
  const content = await readFileSafe(absPath);
30251
30388
  if (!content) continue;
30252
30389
  let date = "";
@@ -30288,9 +30425,9 @@ async function executePrune(repoPath, candidates, options = {}) {
30288
30425
  }
30289
30426
  for (const candidate of candidates) {
30290
30427
  if (options.archive) {
30291
- const archiveDir = path103.join(repoPath, "learnings", "_archive");
30428
+ const archiveDir = path104.join(repoPath, "learnings", "_archive");
30292
30429
  await ensureDir(archiveDir);
30293
- await copyFile(candidate.path, path103.join(archiveDir, candidate.filename));
30430
+ await copyFile(candidate.path, path104.join(archiveDir, candidate.filename));
30294
30431
  await remove(candidate.path);
30295
30432
  archived++;
30296
30433
  } else {
@@ -30315,7 +30452,7 @@ var init_prune = __esm({
30315
30452
  });
30316
30453
 
30317
30454
  // src/maintenance/quality-update.ts
30318
- import path104 from "path";
30455
+ import path105 from "path";
30319
30456
  async function findStaleEntries(votesDir, knowledgeDirs, options = {}) {
30320
30457
  const minRecalled = options.minRecalled ?? DEFAULT_MIN_RECALLED;
30321
30458
  const maxUpvoted = options.maxUpvoted ?? DEFAULT_MAX_UPVOTED;
@@ -30325,7 +30462,7 @@ async function findStaleEntries(votesDir, knowledgeDirs, options = {}) {
30325
30462
  for (const file of voteFiles) {
30326
30463
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
30327
30464
  const username = file.replace(/\.(yaml|yml)$/, "");
30328
- const filePath = path104.join(votesDir, file);
30465
+ const filePath = path105.join(votesDir, file);
30329
30466
  try {
30330
30467
  const data = await loadUserVotes(filePath);
30331
30468
  for (const [docId, entry] of Object.entries(data.votes)) {
@@ -30362,7 +30499,7 @@ async function resolveDocPath(docId, dirs) {
30362
30499
  const filename = docId.endsWith(".md") ? docId : `${docId}.md`;
30363
30500
  for (const dir of [dirs.docs, dirs.rules, dirs.skills]) {
30364
30501
  if (!dir) continue;
30365
- const candidate = path104.join(dir, filename);
30502
+ const candidate = path105.join(dir, filename);
30366
30503
  if (await pathExists(candidate)) return candidate;
30367
30504
  }
30368
30505
  return null;
@@ -30385,7 +30522,7 @@ async function findRelatedAdoptedLearnings(staleEntry, votesDir, learningsDir, l
30385
30522
  for (const file of voteFiles) {
30386
30523
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
30387
30524
  try {
30388
- const data = await loadUserVotes(path104.join(votesDir, file));
30525
+ const data = await loadUserVotes(path105.join(votesDir, file));
30389
30526
  for (const [docId, entry] of Object.entries(data.votes)) {
30390
30527
  if (docId === staleEntry.docId) continue;
30391
30528
  if ((entry.upvoted_count ?? 0) > 0) {
@@ -30400,7 +30537,7 @@ async function findRelatedAdoptedLearnings(staleEntry, votesDir, learningsDir, l
30400
30537
  const contents = [];
30401
30538
  for (const [docId] of sorted) {
30402
30539
  const filename = docId.endsWith(".md") ? docId : `${docId}.md`;
30403
- const filePath = path104.join(learningsDir, filename);
30540
+ const filePath = path105.join(learningsDir, filename);
30404
30541
  const content = await readFileSafe(filePath);
30405
30542
  if (content) contents.push(content);
30406
30543
  }
@@ -30456,7 +30593,7 @@ var init_quality_update = __esm({
30456
30593
  });
30457
30594
 
30458
30595
  // src/maintenance/promote.ts
30459
- import path105 from "path";
30596
+ import path106 from "path";
30460
30597
  import matter11 from "gray-matter";
30461
30598
  async function findPromotionCandidates(learningsDir, votesDir) {
30462
30599
  const confidenceMap = await computeAllConfidence(votesDir);
@@ -30473,7 +30610,7 @@ async function findPromotionCandidates(learningsDir, votesDir) {
30473
30610
  if (!docVotes) continue;
30474
30611
  if (docVotes.upvoted < MIN_UPVOTED) continue;
30475
30612
  if (docVotes.users.size < MIN_USERS) continue;
30476
- const absPath = path105.join(learningsDir, file);
30613
+ const absPath = path106.join(learningsDir, file);
30477
30614
  const content = await readFileSafe(absPath);
30478
30615
  if (!content) continue;
30479
30616
  let title = docId;
@@ -30545,9 +30682,9 @@ Output ONLY the transformed markdown content (including YAML frontmatter with ti
30545
30682
  }
30546
30683
  async function executePromotion(candidate, repoPath, options = {}) {
30547
30684
  const category = options.category ?? candidate.suggestedCategory;
30548
- const targetDir = path105.join(repoPath, category);
30685
+ const targetDir = path106.join(repoPath, category);
30549
30686
  await ensureDir(targetDir);
30550
- const targetPath = path105.join(targetDir, candidate.filename);
30687
+ const targetPath = path106.join(targetDir, candidate.filename);
30551
30688
  if (options.dryRun) {
30552
30689
  log.info(`[dry-run] Would promote ${candidate.docId} -> ${category}/${candidate.filename}`);
30553
30690
  return targetPath;
@@ -30609,7 +30746,7 @@ async function aggregatePerDocVotes(votesDir) {
30609
30746
  for (const file of voteFiles) {
30610
30747
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue;
30611
30748
  const username = file.replace(/\.(yaml|yml)$/, "");
30612
- const filePath = path105.join(votesDir, file);
30749
+ const filePath = path106.join(votesDir, file);
30613
30750
  try {
30614
30751
  const data = await loadUserVotes2(filePath);
30615
30752
  for (const [docId, entry] of Object.entries(data.votes)) {