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