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