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