teamai-cli 0.24.0-beta.4 → 0.24.0-beta.5
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/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/index.js +270 -87
- package/package.json +1 -1
- package/skills/team-wiki-codebase/README.md +1 -0
- package/skills/team-wiki-codebase/SKILL.md +1 -0
package/README.md
CHANGED
|
@@ -191,6 +191,7 @@ Matched: conflict | Missing: port
|
|
|
191
191
|
teamai import --from-repo https://github.com/org/repo
|
|
192
192
|
teamai import --from-org myorg # batch import all repos
|
|
193
193
|
teamai codebase --extract /path/to/repo # local extract into teamwiki/
|
|
194
|
+
teamai codebase --deep-enrich --project my-service --output /path/to/repo # generate deep knowledge docs
|
|
194
195
|
teamai codebase --reconcile --output /path/to/repo # map product docs to code pages
|
|
195
196
|
teamai codebase --lint --output /path/to/repo # check the locally extracted graph
|
|
196
197
|
```
|
|
@@ -244,6 +245,7 @@ Insight into how the team actually uses its AI tools, and a starting point for t
|
|
|
244
245
|
| `teamai recall maintenance` | Maintain knowledge base health: prune low-confidence learnings, writeback confidence scores, flag stale entries |
|
|
245
246
|
| `teamai import` | Import knowledge (`--dir`, `--from-repo`, `--from-org`, `--from-repo-list`, `--from-mr`) |
|
|
246
247
|
| `teamai codebase --extract [path]` | Extract code facts and build the local graph under `teamwiki/` |
|
|
248
|
+
| `teamai codebase --deep-enrich` | Generate deep knowledge docs from extracted evidence |
|
|
247
249
|
| `teamai codebase --reconcile` | Reconcile product documentation with extracted code knowledge |
|
|
248
250
|
| `teamai codebase --lint` | Knowledge graph health check |
|
|
249
251
|
| `teamai ci extract-mr --url <url>` | CI: extract knowledge from MR, post comments, write after merge |
|
package/README.zh-CN.md
CHANGED
|
@@ -191,6 +191,7 @@ Matched: conflict | Missing: port
|
|
|
191
191
|
teamai import --from-repo https://github.com/org/repo
|
|
192
192
|
teamai import --from-org myorg # 批量导入所有仓库
|
|
193
193
|
teamai codebase --extract /path/to/repo # 本地提取到 teamwiki/
|
|
194
|
+
teamai codebase --deep-enrich --project my-service --output /path/to/repo # 从提取结果生成深度知识文档
|
|
194
195
|
teamai codebase --reconcile --output /path/to/repo # 将产品文档映射到代码页面
|
|
195
196
|
teamai codebase --lint --output /path/to/repo # 检查本地提取的图谱
|
|
196
197
|
```
|
|
@@ -244,6 +245,7 @@ teamai recall maintenance --update-quality # 为过时 skills / docs 生
|
|
|
244
245
|
| `teamai recall maintenance` | 维护知识库健康:清理低置信度 learnings、回写置信度、标记过时条目 |
|
|
245
246
|
| `teamai import` | 导入知识(`--dir`、`--from-repo`、`--from-org`、`--from-repo-list`、`--from-mr`) |
|
|
246
247
|
| `teamai codebase --extract [path]` | 提取代码事实并在 `teamwiki/` 下构建本地图谱 |
|
|
248
|
+
| `teamai codebase --deep-enrich` | 从已提取的 evidence 生成深度知识文档 |
|
|
247
249
|
| `teamai codebase --reconcile` | 将产品文档与提取的代码知识进行对账 |
|
|
248
250
|
| `teamai codebase --lint` | 知识图谱健康检查 |
|
|
249
251
|
| `teamai ci extract-mr --url <url>` | CI:从 MR 提取知识、发评论、合并后写入 |
|
package/dist/index.js
CHANGED
|
@@ -453,7 +453,6 @@ __export(types_exports, {
|
|
|
453
453
|
CONTRIBUTE_LOW_QUALITY_BONUS: () => CONTRIBUTE_LOW_QUALITY_BONUS,
|
|
454
454
|
CONTRIBUTE_LOW_QUALITY_THRESHOLD: () => CONTRIBUTE_LOW_QUALITY_THRESHOLD,
|
|
455
455
|
CONTRIBUTE_REJECT_WEIGHT: () => CONTRIBUTE_REJECT_WEIGHT,
|
|
456
|
-
CONTRIBUTE_SESSIONS_DIR: () => CONTRIBUTE_SESSIONS_DIR,
|
|
457
456
|
CONTRIBUTE_SKILL_BONUS: () => CONTRIBUTE_SKILL_BONUS,
|
|
458
457
|
CONTRIBUTE_SMART_THRESHOLD: () => CONTRIBUTE_SMART_THRESHOLD,
|
|
459
458
|
CONTRIBUTE_TOOLERROR_TIERS: () => CONTRIBUTE_TOOLERROR_TIERS,
|
|
@@ -464,15 +463,12 @@ __export(types_exports, {
|
|
|
464
463
|
CultureTeamSchema: () => CultureTeamSchema,
|
|
465
464
|
DASHBOARD_COMPACTION_THRESHOLD: () => DASHBOARD_COMPACTION_THRESHOLD,
|
|
466
465
|
DASHBOARD_DEFAULT_PORT: () => DASHBOARD_DEFAULT_PORT,
|
|
467
|
-
DASHBOARD_EVENTS_DIR: () => DASHBOARD_EVENTS_DIR,
|
|
468
|
-
DASHBOARD_EVENTS_PATH: () => DASHBOARD_EVENTS_PATH,
|
|
469
466
|
DASHBOARD_IDLE_TIMEOUT_MS: () => DASHBOARD_IDLE_TIMEOUT_MS,
|
|
470
467
|
DASHBOARD_PID_CHECK_INTERVAL_MS: () => DASHBOARD_PID_CHECK_INTERVAL_MS,
|
|
471
468
|
DASHBOARD_STALE_TIMEOUT_MS: () => DASHBOARD_STALE_TIMEOUT_MS,
|
|
472
469
|
DASHBOARD_STOPPED_DISPLAY_MS: () => DASHBOARD_STOPPED_DISPLAY_MS,
|
|
473
470
|
INTERVENTION_SCAN_MAX_BYTES: () => INTERVENTION_SCAN_MAX_BYTES,
|
|
474
471
|
KNOWLEDGE_WORKTREE_DIRNAME: () => KNOWLEDGE_WORKTREE_DIRNAME,
|
|
475
|
-
LEARNINGS_LOCAL_DIR: () => LEARNINGS_LOCAL_DIR,
|
|
476
472
|
LocalConfigSchema: () => LocalConfigSchema,
|
|
477
473
|
MemberConfigSchema: () => MemberConfigSchema,
|
|
478
474
|
PendingPushItemSchema: () => PendingPushItemSchema,
|
|
@@ -481,9 +477,7 @@ __export(types_exports, {
|
|
|
481
477
|
REPORTS_LOCK_FILENAME: () => REPORTS_LOCK_FILENAME,
|
|
482
478
|
REPORTS_WORKTREE_DIRNAME: () => REPORTS_WORKTREE_DIRNAME,
|
|
483
479
|
RESOURCE_TYPES: () => RESOURCE_TYPES,
|
|
484
|
-
SEARCH_INDEX_PATH: () => SEARCH_INDEX_PATH,
|
|
485
480
|
SEARCH_INDEX_VERSION: () => SEARCH_INDEX_VERSION,
|
|
486
|
-
SESSION_LOGS_LOCAL_DIR: () => SESSION_LOGS_LOCAL_DIR,
|
|
487
481
|
SKILL_NAME_REGEX: () => SKILL_NAME_REGEX,
|
|
488
482
|
SOURCE_PULL_TTL_MS: () => SOURCE_PULL_TTL_MS,
|
|
489
483
|
SYNC_LOCK_FILENAME: () => SYNC_LOCK_FILENAME,
|
|
@@ -494,32 +488,23 @@ __export(types_exports, {
|
|
|
494
488
|
TEAMAI_AGENT_HOOK_PREFIX: () => TEAMAI_AGENT_HOOK_PREFIX,
|
|
495
489
|
TEAMAI_CLAUDEMD_END: () => TEAMAI_CLAUDEMD_END,
|
|
496
490
|
TEAMAI_CLAUDEMD_START: () => TEAMAI_CLAUDEMD_START,
|
|
497
|
-
TEAMAI_CONFIG_PATH: () => TEAMAI_CONFIG_PATH,
|
|
498
491
|
TEAMAI_CULTURE_END: () => TEAMAI_CULTURE_END,
|
|
499
492
|
TEAMAI_CULTURE_START: () => TEAMAI_CULTURE_START,
|
|
500
493
|
TEAMAI_CUSTOM_HOOK_PREFIX: () => TEAMAI_CUSTOM_HOOK_PREFIX,
|
|
501
494
|
TEAMAI_ENV_END: () => TEAMAI_ENV_END,
|
|
502
495
|
TEAMAI_ENV_START: () => TEAMAI_ENV_START,
|
|
503
|
-
TEAMAI_HOME: () => TEAMAI_HOME,
|
|
504
496
|
TEAMAI_HOOK_DESCRIPTION_PREFIX: () => TEAMAI_HOOK_DESCRIPTION_PREFIX,
|
|
505
|
-
TEAMAI_KNOWN_SKILLS_PATH: () => TEAMAI_KNOWN_SKILLS_PATH,
|
|
506
|
-
TEAMAI_PUSHIGNORE_PATH: () => TEAMAI_PUSHIGNORE_PATH,
|
|
507
497
|
TEAMAI_RECALL_RULES_END: () => TEAMAI_RECALL_RULES_END,
|
|
508
498
|
TEAMAI_RECALL_RULES_START: () => TEAMAI_RECALL_RULES_START,
|
|
509
499
|
TEAMAI_RULES_END: () => TEAMAI_RULES_END,
|
|
510
500
|
TEAMAI_RULES_START: () => TEAMAI_RULES_START,
|
|
511
501
|
TEAMAI_SOURCES_DIR: () => TEAMAI_SOURCES_DIR,
|
|
512
|
-
TEAMAI_STATE_PATH: () => TEAMAI_STATE_PATH,
|
|
513
|
-
TEAMAI_TOKEN_PATH: () => TEAMAI_TOKEN_PATH,
|
|
514
|
-
TEAMAI_UPDATE_LOCK_PATH: () => TEAMAI_UPDATE_LOCK_PATH,
|
|
515
|
-
TEAMAI_USAGE_PATH: () => TEAMAI_USAGE_PATH,
|
|
516
502
|
TRANSCRIPT_INTERRUPT_PREFIX: () => TRANSCRIPT_INTERRUPT_PREFIX,
|
|
517
503
|
TRANSCRIPT_REJECT_MARKERS: () => TRANSCRIPT_REJECT_MARKERS,
|
|
518
504
|
TRANSCRIPT_SYSTEM_PREFIXES: () => TRANSCRIPT_SYSTEM_PREFIXES,
|
|
519
505
|
TeamaiConfigSchema: () => TeamaiConfigSchema,
|
|
520
506
|
ToolPathsSchema: () => ToolPathsSchema,
|
|
521
507
|
UsageEventSchema: () => UsageEventSchema,
|
|
522
|
-
VOTES_LOCAL_DIR: () => VOTES_LOCAL_DIR,
|
|
523
508
|
addTokenUsage: () => addTokenUsage,
|
|
524
509
|
areTeamHooksDisabled: () => areTeamHooksDisabled,
|
|
525
510
|
emptyTokenUsage: () => emptyTokenUsage,
|
|
@@ -533,8 +518,17 @@ __export(types_exports, {
|
|
|
533
518
|
getPushignorePath: () => getPushignorePath,
|
|
534
519
|
getRecallSharing: () => getRecallSharing,
|
|
535
520
|
getReportsDir: () => getReportsDir,
|
|
521
|
+
getSessionLogsDir: () => getSessionLogsDir,
|
|
536
522
|
getStatePath: () => getStatePath,
|
|
537
523
|
getTeamaiHome: () => getTeamaiHome,
|
|
524
|
+
getTeamaiHomeDir: () => getTeamaiHomeDir,
|
|
525
|
+
getTokenPath: () => getTokenPath,
|
|
526
|
+
getUpdateLockPath: () => getUpdateLockPath,
|
|
527
|
+
getUserConfigPath: () => getUserConfigPath,
|
|
528
|
+
getUserLearningsDir: () => getUserLearningsDir,
|
|
529
|
+
getUserSearchIndexPath: () => getUserSearchIndexPath,
|
|
530
|
+
getUserStatePath: () => getUserStatePath,
|
|
531
|
+
getUserVotesDir: () => getUserVotesDir,
|
|
538
532
|
isAgentDisabled: () => isAgentDisabled,
|
|
539
533
|
isContributeHintEnabled: () => isContributeHintEnabled,
|
|
540
534
|
isRecallEnabled: () => isRecallEnabled,
|
|
@@ -599,6 +593,24 @@ function managedMcpManifestPath(dataHome, workspaceRoot) {
|
|
|
599
593
|
function legacyManagedMcpManifestPath(dataHome) {
|
|
600
594
|
return path3.join(dataHome, "managed-mcp.json");
|
|
601
595
|
}
|
|
596
|
+
function getTeamaiHomeDir() {
|
|
597
|
+
return path3.join(getUserHome(), ".teamai");
|
|
598
|
+
}
|
|
599
|
+
function getUserConfigPath() {
|
|
600
|
+
return path3.join(getTeamaiHomeDir(), "config.yaml");
|
|
601
|
+
}
|
|
602
|
+
function getUserStatePath() {
|
|
603
|
+
return path3.join(getTeamaiHomeDir(), "state.json");
|
|
604
|
+
}
|
|
605
|
+
function getTokenPath() {
|
|
606
|
+
return path3.join(getTeamaiHomeDir(), "token");
|
|
607
|
+
}
|
|
608
|
+
function getUpdateLockPath() {
|
|
609
|
+
return path3.join(getTeamaiHomeDir(), ".update-lock");
|
|
610
|
+
}
|
|
611
|
+
function getSessionLogsDir() {
|
|
612
|
+
return path3.join(getTeamaiHomeDir(), "session-logs");
|
|
613
|
+
}
|
|
602
614
|
function emptyTokenUsage() {
|
|
603
615
|
return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0 };
|
|
604
616
|
}
|
|
@@ -614,6 +626,15 @@ function addTokenUsage(a, b) {
|
|
|
614
626
|
cacheCreation: (a?.cacheCreation ?? 0) + (b?.cacheCreation ?? 0)
|
|
615
627
|
};
|
|
616
628
|
}
|
|
629
|
+
function getUserLearningsDir() {
|
|
630
|
+
return path3.join(getTeamaiHomeDir(), "learnings");
|
|
631
|
+
}
|
|
632
|
+
function getUserSearchIndexPath() {
|
|
633
|
+
return path3.join(getTeamaiHomeDir(), "search-index.json");
|
|
634
|
+
}
|
|
635
|
+
function getUserVotesDir() {
|
|
636
|
+
return path3.join(getTeamaiHomeDir(), "votes");
|
|
637
|
+
}
|
|
617
638
|
function resolveBaseDir(localConfig) {
|
|
618
639
|
if (localConfig.scope === "project") {
|
|
619
640
|
if (!localConfig.projectRoot) {
|
|
@@ -711,7 +732,7 @@ function getPushignorePath() {
|
|
|
711
732
|
function areTeamHooksDisabled() {
|
|
712
733
|
return process.env.TEAMAI_HOOKS_DISABLED === "1" || process.env.TEAMAI_HOOKS_DISABLED === "true";
|
|
713
734
|
}
|
|
714
|
-
var ToolPathsSchema, ScopeEnum, SharingConfigSchema, SourceConfigSchema, SOURCE_PULL_TTL_MS, TEAMAI_SOURCES_DIR, TeamaiConfigSchema, MemberConfigSchema, LocalConfigSchema, PendingPushItemSchema, PendingPushSchema, StateSchema,
|
|
735
|
+
var ToolPathsSchema, ScopeEnum, SharingConfigSchema, SourceConfigSchema, SOURCE_PULL_TTL_MS, TEAMAI_SOURCES_DIR, TeamaiConfigSchema, MemberConfigSchema, LocalConfigSchema, PendingPushItemSchema, PendingPushSchema, StateSchema, RESOURCE_TYPES, TEAMAI_RULES_START, TEAMAI_RULES_END, TEAMAI_HOOK_DESCRIPTION_PREFIX, TEAMAI_CUSTOM_HOOK_PREFIX, TEAMAI_AGENT_HOOK_PREFIX, TEAMAI_ENV_START, TEAMAI_ENV_END, TEAMAI_CULTURE_START, TEAMAI_CULTURE_END, TEAMAI_CLAUDEMD_START, TEAMAI_CLAUDEMD_END, TEAMAI_RECALL_RULES_START, TEAMAI_RECALL_RULES_END, SKILL_NAME_REGEX, UsageEventSchema, DASHBOARD_DEFAULT_PORT, DASHBOARD_IDLE_TIMEOUT_MS, DASHBOARD_STALE_TIMEOUT_MS, DASHBOARD_COMPACTION_THRESHOLD, DASHBOARD_STOPPED_DISPLAY_MS, DASHBOARD_PID_CHECK_INTERVAL_MS, CORRECTION_WINDOW_MS, CORRECTION_KEYWORDS, INTERVENTION_SCAN_MAX_BYTES, TRANSCRIPT_INTERRUPT_PREFIX, TRANSCRIPT_SYSTEM_PREFIXES, TRANSCRIPT_REJECT_MARKERS, CONTRIBUTE_BASE_THRESHOLD, CONTRIBUTE_SMART_THRESHOLD, CONTRIBUTE_INTERRUPT_WEIGHT, CONTRIBUTE_REJECT_WEIGHT, CONTRIBUTE_CORRECTION_WEIGHT, CONTRIBUTE_TOOLERROR_TIERS, CONTRIBUTE_SKILL_BONUS, CONTRIBUTE_DIVERSITY_BONUS_MAX, CONTRIBUTE_FASTPATH_TTL_MS, CONTRIBUTE_KNOWLEDGE_GAP_BONUS, CONTRIBUTE_LOW_QUALITY_BONUS, CONTRIBUTE_LOW_QUALITY_THRESHOLD, CONTRIBUTE_GIT_COMMIT_DOWNWEIGHT, SEARCH_INDEX_VERSION, CultureCompanySchema, CultureTeamSchema, CultureFrontmatterSchema, REPORTS_BRANCH, REPORTS_WORKTREE_DIRNAME, KNOWLEDGE_WORKTREE_DIRNAME, REPORTS_LOCK_FILENAME, BOOTSTRAP_LOCK_FILENAME, SYNC_LOCK_FILENAME;
|
|
715
736
|
var init_types = __esm({
|
|
716
737
|
"src/types.ts"() {
|
|
717
738
|
"use strict";
|
|
@@ -879,7 +900,7 @@ var init_types = __esm({
|
|
|
879
900
|
// .zcode/config.json (a different key), which the Claude writer cannot
|
|
880
901
|
// emit — so no mcpProject. ZCode has no user-level rules dir convention.
|
|
881
902
|
zcode: { skills: ".zcode/skills", agents: ".zcode/agents", settings: ".zcode/cli/config.json", mcp: ".agents/mcp.json" },
|
|
882
|
-
codebuddy: { skills: ".codebuddy/skills", rules: ".codebuddy/rules", settings: ".codebuddy/settings.json", claudemd: ".codebuddy/CODEBUDDY.md", agents: ".codebuddy/agents", mcp: ".codebuddy/mcp.json", mcpProject: ".
|
|
903
|
+
codebuddy: { skills: ".codebuddy/skills", rules: ".codebuddy/rules", settings: ".codebuddy/settings.json", claudemd: ".codebuddy/CODEBUDDY.md", agents: ".codebuddy/agents", mcp: ".codebuddy/mcp.json", mcpProject: ".mcp.json" },
|
|
883
904
|
openclaw: { skills: ".openclaw/skills", rules: ".openclaw/rules", claudemd: ".openclaw/workspace/AGENTS.md" },
|
|
884
905
|
hermes: { skills: ".hermes/skills", claudemd: "AGENTS.md" },
|
|
885
906
|
// DeepSeek Harness: skills synced to ~/.dsh/skills, which its skill-filesystem
|
|
@@ -1022,11 +1043,6 @@ var init_types = __esm({
|
|
|
1022
1043
|
lastUpdateCheck: z.string().nullable().default(null),
|
|
1023
1044
|
availableUpdate: z.string().nullable().default(null)
|
|
1024
1045
|
});
|
|
1025
|
-
TEAMAI_HOME = path3.join(getUserHome(), ".teamai");
|
|
1026
|
-
TEAMAI_CONFIG_PATH = path3.join(TEAMAI_HOME, "config.yaml");
|
|
1027
|
-
TEAMAI_STATE_PATH = path3.join(TEAMAI_HOME, "state.json");
|
|
1028
|
-
TEAMAI_TOKEN_PATH = path3.join(TEAMAI_HOME, "token");
|
|
1029
|
-
TEAMAI_UPDATE_LOCK_PATH = path3.join(TEAMAI_HOME, ".update-lock");
|
|
1030
1046
|
RESOURCE_TYPES = ["skills", "rules", "docs", "env", "agents", "hooks", "mcp"];
|
|
1031
1047
|
TEAMAI_RULES_START = "<!-- [teamai:rules:start] -->";
|
|
1032
1048
|
TEAMAI_RULES_END = "<!-- [teamai:rules:end] -->";
|
|
@@ -1042,17 +1058,11 @@ var init_types = __esm({
|
|
|
1042
1058
|
TEAMAI_RECALL_RULES_START = "<!-- [teamai:recall-rules:start] -->";
|
|
1043
1059
|
TEAMAI_RECALL_RULES_END = "<!-- [teamai:recall-rules:end] -->";
|
|
1044
1060
|
SKILL_NAME_REGEX = /^[a-zA-Z0-9_\-:.]{1,200}$/;
|
|
1045
|
-
TEAMAI_USAGE_PATH = `${TEAMAI_HOME}/usage.jsonl`;
|
|
1046
|
-
TEAMAI_KNOWN_SKILLS_PATH = `${TEAMAI_HOME}/known-skills.json`;
|
|
1047
|
-
TEAMAI_PUSHIGNORE_PATH = `${TEAMAI_HOME}/pushignore`;
|
|
1048
|
-
SESSION_LOGS_LOCAL_DIR = `${TEAMAI_HOME}/session-logs`;
|
|
1049
1061
|
UsageEventSchema = z.object({
|
|
1050
1062
|
skill: z.string().regex(SKILL_NAME_REGEX),
|
|
1051
1063
|
timestamp: z.string(),
|
|
1052
1064
|
tool: z.string()
|
|
1053
1065
|
});
|
|
1054
|
-
DASHBOARD_EVENTS_DIR = `${TEAMAI_HOME}/dashboard`;
|
|
1055
|
-
DASHBOARD_EVENTS_PATH = `${DASHBOARD_EVENTS_DIR}/events.jsonl`;
|
|
1056
1066
|
DASHBOARD_DEFAULT_PORT = 3721;
|
|
1057
1067
|
DASHBOARD_IDLE_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1058
1068
|
DASHBOARD_STALE_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
@@ -1118,11 +1128,7 @@ var init_types = __esm({
|
|
|
1118
1128
|
CONTRIBUTE_LOW_QUALITY_BONUS = 10;
|
|
1119
1129
|
CONTRIBUTE_LOW_QUALITY_THRESHOLD = 5;
|
|
1120
1130
|
CONTRIBUTE_GIT_COMMIT_DOWNWEIGHT = 0;
|
|
1121
|
-
CONTRIBUTE_SESSIONS_DIR = `${TEAMAI_HOME}/sessions`;
|
|
1122
1131
|
SEARCH_INDEX_VERSION = 6;
|
|
1123
|
-
LEARNINGS_LOCAL_DIR = `${TEAMAI_HOME}/learnings`;
|
|
1124
|
-
SEARCH_INDEX_PATH = `${TEAMAI_HOME}/search-index.json`;
|
|
1125
|
-
VOTES_LOCAL_DIR = `${TEAMAI_HOME}/votes`;
|
|
1126
1132
|
CultureCompanySchema = z.object({
|
|
1127
1133
|
name: z.string(),
|
|
1128
1134
|
mission: z.string().optional(),
|
|
@@ -3471,6 +3477,12 @@ import { execSync, spawnSync } from "child_process";
|
|
|
3471
3477
|
import fs4 from "fs";
|
|
3472
3478
|
import os2 from "os";
|
|
3473
3479
|
import path15 from "path";
|
|
3480
|
+
function gfInstallDir() {
|
|
3481
|
+
return path15.join(getTeamaiHomeDir(), "gf");
|
|
3482
|
+
}
|
|
3483
|
+
function gfBinPath() {
|
|
3484
|
+
return path15.join(gfInstallDir(), "gf", "bin", "gf");
|
|
3485
|
+
}
|
|
3474
3486
|
function shellQuote2(s) {
|
|
3475
3487
|
return "'" + s.replace(/'/g, "'\\''") + "'";
|
|
3476
3488
|
}
|
|
@@ -3500,11 +3512,11 @@ function gfExec(args, options) {
|
|
|
3500
3512
|
}
|
|
3501
3513
|
function getGfPath() {
|
|
3502
3514
|
try {
|
|
3503
|
-
const stat8 = execSync(`test -x "${
|
|
3515
|
+
const stat8 = execSync(`test -x "${gfBinPath()}" && echo ok`, {
|
|
3504
3516
|
encoding: "utf-8",
|
|
3505
3517
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3506
3518
|
});
|
|
3507
|
-
if (stat8.trim() === "ok") return
|
|
3519
|
+
if (stat8.trim() === "ok") return gfBinPath();
|
|
3508
3520
|
} catch {
|
|
3509
3521
|
}
|
|
3510
3522
|
try {
|
|
@@ -3553,17 +3565,17 @@ async function ensureGfInstalled() {
|
|
|
3553
3565
|
const url = getGfDownloadUrl();
|
|
3554
3566
|
const spin = spinner("Installing gf CLI (\u5DE5\u8702\u547D\u4EE4\u884C\u5DE5\u5177)...").start();
|
|
3555
3567
|
try {
|
|
3556
|
-
await ensureDir(
|
|
3568
|
+
await ensureDir(gfInstallDir());
|
|
3557
3569
|
execSync(
|
|
3558
|
-
`curl -fsSL "${url}" | tar xz -C "${
|
|
3570
|
+
`curl -fsSL "${url}" | tar xz -C "${gfInstallDir()}"`,
|
|
3559
3571
|
{ stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 }
|
|
3560
3572
|
);
|
|
3561
|
-
execSync(`test -x "${
|
|
3562
|
-
spin.succeed(`gf CLI installed to ${
|
|
3573
|
+
execSync(`test -x "${gfBinPath()}"`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
3574
|
+
spin.succeed(`gf CLI installed to ${gfInstallDir()}`);
|
|
3563
3575
|
} catch (e) {
|
|
3564
3576
|
spin.fail(`Failed to install gf CLI: ${e.message}`);
|
|
3565
3577
|
log.info(`You can install it manually from: ${url}`);
|
|
3566
|
-
log.info(`Extract to: ${
|
|
3578
|
+
log.info(`Extract to: ${gfInstallDir()}`);
|
|
3567
3579
|
throw e;
|
|
3568
3580
|
}
|
|
3569
3581
|
}
|
|
@@ -3706,7 +3718,7 @@ function gfMrCreate(opts) {
|
|
|
3706
3718
|
}
|
|
3707
3719
|
throw new Error(`gf mr create succeeded but returned unexpected output: ${output}`);
|
|
3708
3720
|
}
|
|
3709
|
-
var
|
|
3721
|
+
var GF_DOWNLOAD_BASE, AUTH_CWD, RepoNotFoundError2;
|
|
3710
3722
|
var init_gf_cli = __esm({
|
|
3711
3723
|
"src/providers/tgit/gf-cli.ts"() {
|
|
3712
3724
|
"use strict";
|
|
@@ -3714,8 +3726,6 @@ var init_gf_cli = __esm({
|
|
|
3714
3726
|
init_logger();
|
|
3715
3727
|
init_types();
|
|
3716
3728
|
init_rest_auth();
|
|
3717
|
-
GF_INSTALL_DIR = path15.join(TEAMAI_HOME, "gf");
|
|
3718
|
-
GF_BIN_PATH = path15.join(GF_INSTALL_DIR, "gf", "bin", "gf");
|
|
3719
3729
|
GF_DOWNLOAD_BASE = "http://mirrors.tencent.com/repository/generic/gongfeng-cli/files/channels/stable";
|
|
3720
3730
|
AUTH_CWD = os2.tmpdir();
|
|
3721
3731
|
RepoNotFoundError2 = class extends Error {
|
|
@@ -6494,6 +6504,13 @@ var init_roles = __esm({
|
|
|
6494
6504
|
});
|
|
6495
6505
|
|
|
6496
6506
|
// src/utils/path-safety.ts
|
|
6507
|
+
var path_safety_exports = {};
|
|
6508
|
+
__export(path_safety_exports, {
|
|
6509
|
+
assertSafePath: () => assertSafePath,
|
|
6510
|
+
assertSafeResourceName: () => assertSafeResourceName,
|
|
6511
|
+
assertWithinRoot: () => assertWithinRoot,
|
|
6512
|
+
defaultAllowedRoots: () => defaultAllowedRoots
|
|
6513
|
+
});
|
|
6497
6514
|
import os5 from "os";
|
|
6498
6515
|
import path19 from "path";
|
|
6499
6516
|
import fs7 from "fs";
|
|
@@ -10385,8 +10402,26 @@ async function reconcileClaudeModels(models, manifest) {
|
|
|
10385
10402
|
await writeModelJson(profilePath, { env: desired });
|
|
10386
10403
|
const conflictKeys = /* @__PURE__ */ new Set([
|
|
10387
10404
|
...Object.keys(desired),
|
|
10388
|
-
"ANTHROPIC_API_KEY"
|
|
10405
|
+
"ANTHROPIC_API_KEY",
|
|
10406
|
+
"ANTHROPIC_CUSTOM_HEADERS",
|
|
10407
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
10408
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
10409
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL"
|
|
10389
10410
|
]);
|
|
10411
|
+
const isManagedValue = (key, value) => previousHashes[key] !== void 0 && entryHash(value) === previousHashes[key] || env[key] !== void 0 && entryHash(value) === entryHash(env[key]);
|
|
10412
|
+
const userOwnsInShell = (key) => {
|
|
10413
|
+
const value = process.env[key];
|
|
10414
|
+
if (typeof value !== "string" || value.trim() === "") return false;
|
|
10415
|
+
return !isManagedValue(key, value);
|
|
10416
|
+
};
|
|
10417
|
+
const shellConflicts = [...conflictKeys].filter(userOwnsInShell);
|
|
10418
|
+
if (shellConflicts.length > 0) {
|
|
10419
|
+
await appendErrorLog({
|
|
10420
|
+
apply_model_config: "skipped claude gateway: user owns conflicting shell env",
|
|
10421
|
+
conflicts: shellConflicts
|
|
10422
|
+
});
|
|
10423
|
+
return;
|
|
10424
|
+
}
|
|
10390
10425
|
const canManage = [...conflictKeys].every((key) => env[key] === void 0 || previousHashes[key] !== void 0 && entryHash(env[key]) === previousHashes[key]);
|
|
10391
10426
|
if (!canManage) {
|
|
10392
10427
|
manifest.claudeEnv = {};
|
|
@@ -10950,7 +10985,7 @@ async function initLocalAgentHttp(options) {
|
|
|
10950
10985
|
await ensureDir(getLocalAgentHome());
|
|
10951
10986
|
await saveLocalAgentConfig(config);
|
|
10952
10987
|
if (options.token) {
|
|
10953
|
-
await writeTokenFile(
|
|
10988
|
+
await writeTokenFile(getTokenPath(), options.token);
|
|
10954
10989
|
}
|
|
10955
10990
|
const teamConfig = createLocalAgentTeamConfig(endpoint);
|
|
10956
10991
|
await injectHooksToAllTools(teamConfig.toolPaths, getUserHome(), options.filterAgents);
|
|
@@ -13768,7 +13803,7 @@ async function acquireReclaimSentinel(sentinel, owner) {
|
|
|
13768
13803
|
return exclusiveCreate(sentinel, payload);
|
|
13769
13804
|
}
|
|
13770
13805
|
async function acquireLock(lockPath) {
|
|
13771
|
-
const resolved = lockPath ?? expandHome(
|
|
13806
|
+
const resolved = lockPath ?? expandHome(getUpdateLockPath());
|
|
13772
13807
|
const owner = randomUUID2();
|
|
13773
13808
|
const payload = JSON.stringify({
|
|
13774
13809
|
pid: process.pid,
|
|
@@ -13807,7 +13842,7 @@ async function acquireLock(lockPath) {
|
|
|
13807
13842
|
}
|
|
13808
13843
|
}
|
|
13809
13844
|
async function releaseLock(lockPath) {
|
|
13810
|
-
const resolved = lockPath ?? expandHome(
|
|
13845
|
+
const resolved = lockPath ?? expandHome(getUpdateLockPath());
|
|
13811
13846
|
const ourOwner = heldLockOwners.get(resolved);
|
|
13812
13847
|
if (!ourOwner) return;
|
|
13813
13848
|
try {
|
|
@@ -15211,7 +15246,7 @@ async function initHttp(url, options) {
|
|
|
15211
15246
|
if (scope === "project") {
|
|
15212
15247
|
await saveLocalConfigForScope(localConfig, scope, projectRoot);
|
|
15213
15248
|
} else {
|
|
15214
|
-
await ensureDir(
|
|
15249
|
+
await ensureDir(getTeamaiHomeDir());
|
|
15215
15250
|
await saveLocalConfig(localConfig);
|
|
15216
15251
|
}
|
|
15217
15252
|
log.success(`Local config saved to ${teamaiHome}/config.yaml`);
|
|
@@ -15950,9 +15985,9 @@ async function init(options) {
|
|
|
15950
15985
|
log.debug("Generated .teamai/.gitignore for project scope");
|
|
15951
15986
|
}
|
|
15952
15987
|
} else {
|
|
15953
|
-
await ensureDir(
|
|
15988
|
+
await ensureDir(getTeamaiHomeDir());
|
|
15954
15989
|
await saveLocalConfig(localConfig);
|
|
15955
|
-
log.success(`Local config saved to ${
|
|
15990
|
+
log.success(`Local config saved to ${getTeamaiHomeDir()}/config.yaml`);
|
|
15956
15991
|
}
|
|
15957
15992
|
try {
|
|
15958
15993
|
const state = await loadStateForScope(localConfig);
|
|
@@ -17203,6 +17238,23 @@ function projectSlug(anchor) {
|
|
|
17203
17238
|
function projectDataHome(anchor) {
|
|
17204
17239
|
return path46.join(getUserHome(), ".teamai", "projects", projectSlug(anchor));
|
|
17205
17240
|
}
|
|
17241
|
+
function projectsRootDir() {
|
|
17242
|
+
return path46.join(getUserHome(), ".teamai", "projects");
|
|
17243
|
+
}
|
|
17244
|
+
async function writeAnchorFile(partitionDir, anchor) {
|
|
17245
|
+
await fs17.promises.mkdir(partitionDir, { recursive: true });
|
|
17246
|
+
await fs17.promises.writeFile(path46.join(partitionDir, "anchor"), `${anchor}
|
|
17247
|
+
`, "utf-8");
|
|
17248
|
+
}
|
|
17249
|
+
async function readAnchorFile(partitionDir) {
|
|
17250
|
+
try {
|
|
17251
|
+
const raw = await fs17.promises.readFile(path46.join(partitionDir, "anchor"), "utf-8");
|
|
17252
|
+
const trimmed = raw.trim();
|
|
17253
|
+
return trimmed || null;
|
|
17254
|
+
} catch {
|
|
17255
|
+
return null;
|
|
17256
|
+
}
|
|
17257
|
+
}
|
|
17206
17258
|
var caseInsensitiveCache;
|
|
17207
17259
|
var init_partition = __esm({
|
|
17208
17260
|
"src/utils/partition.ts"() {
|
|
@@ -17430,7 +17482,7 @@ async function loadTeamConfig(repoPath) {
|
|
|
17430
17482
|
}
|
|
17431
17483
|
}
|
|
17432
17484
|
async function loadLocalConfig() {
|
|
17433
|
-
const configPath = expandHome(
|
|
17485
|
+
const configPath = expandHome(getUserConfigPath());
|
|
17434
17486
|
const content = await readFileSafe(configPath);
|
|
17435
17487
|
if (!content) return null;
|
|
17436
17488
|
try {
|
|
@@ -17447,15 +17499,15 @@ function serializeLocalConfig(config) {
|
|
|
17447
17499
|
return YAML14.stringify(persisted);
|
|
17448
17500
|
}
|
|
17449
17501
|
async function saveLocalConfig(config) {
|
|
17450
|
-
await writeFile(expandHome(
|
|
17502
|
+
await writeFile(expandHome(getUserConfigPath()), serializeLocalConfig(config));
|
|
17451
17503
|
}
|
|
17452
17504
|
async function loadState() {
|
|
17453
|
-
const raw = await readJson(expandHome(
|
|
17505
|
+
const raw = await readJson(expandHome(getUserStatePath()));
|
|
17454
17506
|
if (!raw) return StateSchema.parse({});
|
|
17455
17507
|
return StateSchema.parse(raw);
|
|
17456
17508
|
}
|
|
17457
17509
|
async function saveState(state) {
|
|
17458
|
-
await writeJson(expandHome(
|
|
17510
|
+
await writeJson(expandHome(getUserStatePath()), state);
|
|
17459
17511
|
}
|
|
17460
17512
|
async function requireInit() {
|
|
17461
17513
|
const localConfig = await loadLocalConfig();
|
|
@@ -17488,8 +17540,19 @@ async function loadLocalConfigForScope(scope, projectRoot) {
|
|
|
17488
17540
|
}
|
|
17489
17541
|
}
|
|
17490
17542
|
async function saveLocalConfigForScope(config, _scope, _projectRoot) {
|
|
17491
|
-
const
|
|
17543
|
+
const dataHome = getDataHome(config);
|
|
17544
|
+
const configPath = path48.join(dataHome, "config.yaml");
|
|
17492
17545
|
await writeFile(expandHome(configPath), serializeLocalConfig(config));
|
|
17546
|
+
try {
|
|
17547
|
+
if (config.scope === "project" && config.projectRoot) {
|
|
17548
|
+
const partition = await resolveProjectDataHome(config.projectRoot);
|
|
17549
|
+
if (path48.resolve(expandHome(dataHome)) === path48.resolve(partition)) {
|
|
17550
|
+
const anchors = await resolveAnchors(config.projectRoot);
|
|
17551
|
+
if (anchors) await writeAnchorFile(partition, anchors.projectAnchor);
|
|
17552
|
+
}
|
|
17553
|
+
}
|
|
17554
|
+
} catch {
|
|
17555
|
+
}
|
|
17493
17556
|
}
|
|
17494
17557
|
async function loadStateForScope(localConfig) {
|
|
17495
17558
|
const statePath = getStatePath(localConfig);
|
|
@@ -18524,8 +18587,7 @@ async function runMigration(plan, opts = {}) {
|
|
|
18524
18587
|
await rebaseConfigPaths(path51.join(staging, "config.yaml"), legacyDir, partitionDir);
|
|
18525
18588
|
await remove(partitionDir);
|
|
18526
18589
|
await fse10.rename(staging, partitionDir);
|
|
18527
|
-
await
|
|
18528
|
-
`);
|
|
18590
|
+
await writeAnchorFile(partitionDir, anchor);
|
|
18529
18591
|
await releaseLock(lockPath);
|
|
18530
18592
|
lockReleased = true;
|
|
18531
18593
|
const backup = await retireLegacy(legacyDir);
|
|
@@ -18956,6 +19018,9 @@ async function mirrorLearnings(sourceDir, destinationDir, activeNamespaces) {
|
|
|
18956
19018
|
}
|
|
18957
19019
|
});
|
|
18958
19020
|
}
|
|
19021
|
+
async function addLearningToCache(sourceFile, destinationDir, relativePath) {
|
|
19022
|
+
await fse11.copy(sourceFile, path54.join(destinationDir, relativePath), { overwrite: true });
|
|
19023
|
+
}
|
|
18959
19024
|
var init_learnings_mirror = __esm({
|
|
18960
19025
|
"src/utils/learnings-mirror.ts"() {
|
|
18961
19026
|
"use strict";
|
|
@@ -19180,8 +19245,8 @@ async function recallFeedback(opts) {
|
|
|
19180
19245
|
const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
19181
19246
|
const { localConfig } = await autoDetectInit2();
|
|
19182
19247
|
const { username } = localConfig;
|
|
19183
|
-
const {
|
|
19184
|
-
const votePath = path55.join(
|
|
19248
|
+
const { getUserVotesDir: getUserVotesDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
19249
|
+
const votePath = path55.join(getUserVotesDir2(), `${username}.yaml`);
|
|
19185
19250
|
if (opts.positive) {
|
|
19186
19251
|
await incrementUpvoted(votePath, [opts.positive]);
|
|
19187
19252
|
log.success(`Upvoted: ${opts.positive}`);
|
|
@@ -20579,8 +20644,8 @@ function computeDailyStatsDelta(current, reported) {
|
|
|
20579
20644
|
const bucket = delta[date] ?? emptyDaily();
|
|
20580
20645
|
if (!previous) {
|
|
20581
20646
|
bucket.sessionsEnded += 1;
|
|
20582
|
-
bucket.sessionsSucceeded += snapshot.succeeded;
|
|
20583
20647
|
}
|
|
20648
|
+
bucket.sessionsSucceeded += snapshot.succeeded - (previous?.succeeded ?? 0);
|
|
20584
20649
|
bucket.promptTurns += positiveDelta(snapshot.prompts, previous?.prompts);
|
|
20585
20650
|
bucket.durationMs += positiveDelta(snapshot.durationMs, previous?.durationMs);
|
|
20586
20651
|
bucket.sessionsCorrected += positiveDelta(snapshot.corrected, previous?.corrected);
|
|
@@ -21539,7 +21604,12 @@ async function writeReportedDailySessions(data) {
|
|
|
21539
21604
|
}
|
|
21540
21605
|
function hasDailyDelta(delta) {
|
|
21541
21606
|
return Object.values(delta).some(
|
|
21542
|
-
(bucket) =>
|
|
21607
|
+
(bucket) => (
|
|
21608
|
+
// sessionsSucceeded can be negative (a resumed session that later failed
|
|
21609
|
+
// claws back an earlier increment), so it must not be checked with the
|
|
21610
|
+
// same "> 0" as the other, purely monotonic counters (#473).
|
|
21611
|
+
bucket.sessionsEnded > 0 || bucket.sessionsSucceeded !== 0 || bucket.promptTurns > 0 || bucket.durationMs > 0 || bucket.sessionsCorrected > 0 || bucket.pricedRequests > 0 || bucket.costMicros > 0 || bucket.cacheReadTokens > 0 || bucket.cacheEligibleInputTokens > 0
|
|
21612
|
+
)
|
|
21543
21613
|
);
|
|
21544
21614
|
}
|
|
21545
21615
|
function filterEventsByScope(events, opts) {
|
|
@@ -21640,9 +21710,9 @@ async function reportUsageToTeam(repoPath, username, options) {
|
|
|
21640
21710
|
filesToPush.push(`stats/${username}.yaml`);
|
|
21641
21711
|
}
|
|
21642
21712
|
try {
|
|
21643
|
-
if (await pathExists(
|
|
21713
|
+
if (await pathExists(getUserVotesDir())) {
|
|
21644
21714
|
const { syncVotesToTeam: syncVotesToTeam2 } = await Promise.resolve().then(() => (init_votes(), votes_exports));
|
|
21645
|
-
const synced = await syncVotesToTeam2(writeRoot, username,
|
|
21715
|
+
const synced = await syncVotesToTeam2(writeRoot, username, getUserVotesDir());
|
|
21646
21716
|
if (synced) {
|
|
21647
21717
|
filesToPush.push(`votes/${username}.yaml`);
|
|
21648
21718
|
}
|
|
@@ -22413,13 +22483,13 @@ async function pullForScope(localConfig, options, policy = {}) {
|
|
|
22413
22483
|
if (localConfig.scope === "user") {
|
|
22414
22484
|
await mirrorLearnings(
|
|
22415
22485
|
learningsRepoDir,
|
|
22416
|
-
|
|
22486
|
+
getUserLearningsDir(),
|
|
22417
22487
|
activeLearningsNamespaces
|
|
22418
22488
|
);
|
|
22419
22489
|
if (await pathExists(learningsRepoDir)) {
|
|
22420
22490
|
learningsCount = await countLearnings(learningsRepoDir);
|
|
22421
22491
|
}
|
|
22422
|
-
effectiveLearningsDir = await pathExists(
|
|
22492
|
+
effectiveLearningsDir = await pathExists(getUserLearningsDir()) ? getUserLearningsDir() : void 0;
|
|
22423
22493
|
} else {
|
|
22424
22494
|
effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
|
|
22425
22495
|
if (effectiveLearningsDir) {
|
|
@@ -23165,6 +23235,10 @@ __export(status_exports, {
|
|
|
23165
23235
|
import path66 from "path";
|
|
23166
23236
|
import YAML21 from "yaml";
|
|
23167
23237
|
async function status(options) {
|
|
23238
|
+
if (options.all) {
|
|
23239
|
+
await statusAll();
|
|
23240
|
+
return;
|
|
23241
|
+
}
|
|
23168
23242
|
const { localConfig, teamConfig } = await autoDetectInit();
|
|
23169
23243
|
const scopeLabel = localConfig.scope;
|
|
23170
23244
|
console.log("");
|
|
@@ -23244,6 +23318,56 @@ async function status(options) {
|
|
|
23244
23318
|
}
|
|
23245
23319
|
console.log("");
|
|
23246
23320
|
}
|
|
23321
|
+
async function statusAll() {
|
|
23322
|
+
const root = projectsRootDir();
|
|
23323
|
+
const slugs = await listDirs(root);
|
|
23324
|
+
console.log("");
|
|
23325
|
+
log.info(`Project data partitions (${root}):`);
|
|
23326
|
+
if (slugs.length === 0) {
|
|
23327
|
+
log.info(" (none \u2014 no project has been initialized or migrated on this machine)");
|
|
23328
|
+
console.log("");
|
|
23329
|
+
return;
|
|
23330
|
+
}
|
|
23331
|
+
let orphanCount = 0;
|
|
23332
|
+
for (const slug of slugs.sort()) {
|
|
23333
|
+
const partitionDir = path66.join(root, slug);
|
|
23334
|
+
const anchor = await readAnchorFile(partitionDir);
|
|
23335
|
+
let projectPath = anchor;
|
|
23336
|
+
let scope;
|
|
23337
|
+
let kind;
|
|
23338
|
+
const cfgRaw = await readFileSafe(path66.join(partitionDir, "config.yaml"));
|
|
23339
|
+
if (cfgRaw) {
|
|
23340
|
+
try {
|
|
23341
|
+
const parsed = LocalConfigSchema.parse(YAML21.parse(cfgRaw));
|
|
23342
|
+
scope = parsed.scope;
|
|
23343
|
+
kind = parsed.repo.kind;
|
|
23344
|
+
if (!projectPath) projectPath = parsed.repo.businessRepoRoot ?? parsed.projectRoot ?? null;
|
|
23345
|
+
} catch {
|
|
23346
|
+
}
|
|
23347
|
+
}
|
|
23348
|
+
let state;
|
|
23349
|
+
if (!anchor) {
|
|
23350
|
+
state = projectPath ? "unknown \u2014 no anchor; cannot confirm orphan (partition may still be active)" : "unknown (no anchor / project path)";
|
|
23351
|
+
} else if (!await pathExists(anchor)) {
|
|
23352
|
+
state = "ORPHAN \u2014 project path is gone, safe to delete";
|
|
23353
|
+
orphanCount++;
|
|
23354
|
+
} else if (projectSlug(anchor) !== slug) {
|
|
23355
|
+
state = "corrupt \u2014 dir name does not match anchor";
|
|
23356
|
+
} else {
|
|
23357
|
+
state = "active";
|
|
23358
|
+
}
|
|
23359
|
+
const kindLabel = kind ? ` ${kind}` : "";
|
|
23360
|
+
log.info(` ${slug} [${state}]`);
|
|
23361
|
+
log.info(` project: ${projectPath ?? "(unresolved)"}${scope ? ` (${scope}${kindLabel})` : ""}`);
|
|
23362
|
+
}
|
|
23363
|
+
console.log("");
|
|
23364
|
+
if (orphanCount > 0) {
|
|
23365
|
+
log.warn(
|
|
23366
|
+
`${orphanCount} orphan partition(s) found. teamai never deletes them automatically; remove one with: rm -rf "${root}/<slug>"`
|
|
23367
|
+
);
|
|
23368
|
+
console.log("");
|
|
23369
|
+
}
|
|
23370
|
+
}
|
|
23247
23371
|
async function list(type, options) {
|
|
23248
23372
|
const { localConfig, teamConfig } = await autoDetectInit();
|
|
23249
23373
|
const repoPath = localConfig.repo.localPath;
|
|
@@ -23440,6 +23564,7 @@ var init_status = __esm({
|
|
|
23440
23564
|
init_known_agents();
|
|
23441
23565
|
init_agent_skills();
|
|
23442
23566
|
init_types();
|
|
23567
|
+
init_partition();
|
|
23443
23568
|
init_env();
|
|
23444
23569
|
init_mcp();
|
|
23445
23570
|
init_hooks();
|
|
@@ -25855,16 +25980,16 @@ async function saveSession(options) {
|
|
|
25855
25980
|
}
|
|
25856
25981
|
if (options.dryRun) {
|
|
25857
25982
|
log.info(
|
|
25858
|
-
`[dry-run] Would record session ${sessionId.slice(0, 8)} (${summary.toolTotal} tools, ${summary.interventionCount} interventions, valuable=${summary.valuable}) to ${
|
|
25983
|
+
`[dry-run] Would record session ${sessionId.slice(0, 8)} (${summary.toolTotal} tools, ${summary.interventionCount} interventions, valuable=${summary.valuable}) to ${getSessionLogsDir()}/${monthKey(summary)}.md`
|
|
25859
25984
|
);
|
|
25860
25985
|
} else {
|
|
25861
|
-
const written = await appendMonthlyLog(
|
|
25986
|
+
const written = await appendMonthlyLog(getSessionLogsDir(), summary, { includePrompt: true });
|
|
25862
25987
|
if (written) {
|
|
25863
25988
|
log.info(`Recorded session to ${written}`);
|
|
25864
25989
|
} else {
|
|
25865
25990
|
log.info(`Session ${sessionId.slice(0, 8)} already recorded this month.`);
|
|
25866
25991
|
}
|
|
25867
|
-
await pruneMonthlyLogs(
|
|
25992
|
+
await pruneMonthlyLogs(getSessionLogsDir(), /* @__PURE__ */ new Date()).catch(() => []);
|
|
25868
25993
|
}
|
|
25869
25994
|
if (!options.push) return;
|
|
25870
25995
|
if (!summary.valuable && !options.force) {
|
|
@@ -28070,7 +28195,7 @@ async function resolveVizRoot(opts) {
|
|
|
28070
28195
|
const reportsRoot = getReportsDir(config);
|
|
28071
28196
|
const useProjectScope = config.scope === "project" && Boolean(config.projectRoot);
|
|
28072
28197
|
const teamaiHome2 = useProjectScope ? getDataHome(config) : getTeamaiHome("user");
|
|
28073
|
-
const learningsDir = useProjectScope ? path81.join(knowledgeRoot, "learnings") :
|
|
28198
|
+
const learningsDir = useProjectScope ? path81.join(knowledgeRoot, "learnings") : getUserLearningsDir();
|
|
28074
28199
|
const source = config.repo.kind === "self" ? { scope: "local", label: "Personal repo \xB7 your recalls only" } : { scope: "team", label: "Team repo \xB7 aggregated across the team" };
|
|
28075
28200
|
return {
|
|
28076
28201
|
root: knowledgeRoot,
|
|
@@ -28082,14 +28207,14 @@ async function resolveVizRoot(opts) {
|
|
|
28082
28207
|
source
|
|
28083
28208
|
};
|
|
28084
28209
|
}
|
|
28085
|
-
const teamaiHome =
|
|
28210
|
+
const teamaiHome = getTeamaiHomeDir();
|
|
28086
28211
|
return {
|
|
28087
28212
|
root: teamaiHome,
|
|
28088
28213
|
knowledgeRoot: teamaiHome,
|
|
28089
|
-
votesDir:
|
|
28090
|
-
learningsDir:
|
|
28214
|
+
votesDir: getUserVotesDir(),
|
|
28215
|
+
learningsDir: getUserLearningsDir(),
|
|
28091
28216
|
statsDir: path81.join(teamaiHome, "stats"),
|
|
28092
|
-
indexPath:
|
|
28217
|
+
indexPath: getUserSearchIndexPath(),
|
|
28093
28218
|
source: { scope: "local", label: "Local ~/.teamai \xB7 your recalls only" }
|
|
28094
28219
|
};
|
|
28095
28220
|
}
|
|
@@ -30048,8 +30173,8 @@ var init_hook_handlers = __esm({
|
|
|
30048
30173
|
const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
30049
30174
|
const voteData = await parseTranscriptForVotes2(transcriptPath);
|
|
30050
30175
|
const { localConfig } = await autoDetectInit2();
|
|
30051
|
-
const {
|
|
30052
|
-
const votesDir =
|
|
30176
|
+
const { getUserVotesDir: getUserVotesDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
30177
|
+
const votesDir = getUserVotesDir2();
|
|
30053
30178
|
const votePath = path90.join(votesDir, `${localConfig.username}.yaml`);
|
|
30054
30179
|
const recalledSet = new Set(voteData.recalledDocIds);
|
|
30055
30180
|
const verifiedDocIds = voteData.referencedDocIds.filter((id) => recalledSet.has(id));
|
|
@@ -30323,8 +30448,8 @@ async function rebuildIndexAfterContribute(localConfig) {
|
|
|
30323
30448
|
localConfig.projects ?? []
|
|
30324
30449
|
);
|
|
30325
30450
|
if (localConfig.scope === "user") {
|
|
30326
|
-
await mirrorLearnings(learningsRepoDir,
|
|
30327
|
-
effectiveLearningsDir = await pathExists(
|
|
30451
|
+
await mirrorLearnings(learningsRepoDir, getUserLearningsDir(), activeLearningsNamespaces);
|
|
30452
|
+
effectiveLearningsDir = await pathExists(getUserLearningsDir()) ? getUserLearningsDir() : void 0;
|
|
30328
30453
|
} else {
|
|
30329
30454
|
effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
|
|
30330
30455
|
}
|
|
@@ -30454,12 +30579,11 @@ async function contributeSelf(localConfig, content, options) {
|
|
|
30454
30579
|
await fs30.promises.writeFile(destAbs, content, "utf-8");
|
|
30455
30580
|
try {
|
|
30456
30581
|
const { pathExists: pathExists3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
30457
|
-
const wtLearnings = path91.join(wtRepo, "learnings");
|
|
30458
30582
|
const activeLearningsNamespaces = await resolveActiveLearningsNamespaces(
|
|
30459
30583
|
localConfig.repo.localPath,
|
|
30460
30584
|
localConfig.projects ?? []
|
|
30461
30585
|
);
|
|
30462
|
-
await
|
|
30586
|
+
await addLearningToCache(destAbs, getUserLearningsDir(), relPath.slice("learnings/".length));
|
|
30463
30587
|
const repoPath = localConfig.repo.localPath;
|
|
30464
30588
|
const docsDir = path91.join(repoPath, "docs");
|
|
30465
30589
|
const rulesDir = path91.join(repoPath, "rules");
|
|
@@ -30474,7 +30598,7 @@ async function contributeSelf(localConfig, content, options) {
|
|
|
30474
30598
|
const teamaiHome = getDataHome(localConfig);
|
|
30475
30599
|
const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
|
|
30476
30600
|
await buildIndex2({
|
|
30477
|
-
learningsDir: await pathExists3(
|
|
30601
|
+
learningsDir: await pathExists3(getUserLearningsDir()) ? getUserLearningsDir() : void 0,
|
|
30478
30602
|
learningsNamespaces: activeLearningsNamespaces,
|
|
30479
30603
|
docsDir: await pathExists3(docsDir) ? docsDir : void 0,
|
|
30480
30604
|
rulesDir: await pathExists3(rulesDir) ? rulesDir : void 0,
|
|
@@ -36050,6 +36174,9 @@ var init_reconciler_v2_types = __esm({
|
|
|
36050
36174
|
// src/wiki-engine/knowledge-reconciler.ts
|
|
36051
36175
|
import { readFile as readFile9, readdir as readdir3, stat as stat5 } from "fs/promises";
|
|
36052
36176
|
import path109 from "path";
|
|
36177
|
+
function isExpectedSelfLoop(edge) {
|
|
36178
|
+
return edge.from === edge.to && edge.relation === "IMPLEMENTS" && !!edge.source && REPAIRABLE_CODE_EDGE_SOURCES.has(edge.source);
|
|
36179
|
+
}
|
|
36053
36180
|
async function loadReconciliationBase(wikiRoot) {
|
|
36054
36181
|
const graphPath = path109.join(wikiRoot, ".indices", "graph-index.json");
|
|
36055
36182
|
const graph = await loadGraphIndex(wikiRoot);
|
|
@@ -36061,7 +36188,10 @@ async function loadReconciliationBase(wikiRoot) {
|
|
|
36061
36188
|
graph.nodes,
|
|
36062
36189
|
graph.edges.filter((edge) => edge.source !== BRIDGE_EDGE_SOURCE)
|
|
36063
36190
|
);
|
|
36064
|
-
|
|
36191
|
+
const hasUnexpectedSelfLoop = base.edges.some((edge) => edge.from === edge.to && !isExpectedSelfLoop(edge));
|
|
36192
|
+
if (hasUnexpectedSelfLoop || validateGraph(base).issues.some(
|
|
36193
|
+
(issue) => issue.code !== REPAIRABLE_VALIDATION_ISSUE_CODE && issue.code !== SELF_LOOP_VALIDATION_ISSUE_CODE
|
|
36194
|
+
)) {
|
|
36065
36195
|
throw new Error(`Cannot reconcile invalid graph index at ${graphPath}`);
|
|
36066
36196
|
}
|
|
36067
36197
|
const nodeSlugs = new Set(base.nodes.map((node) => node.slug));
|
|
@@ -36082,7 +36212,7 @@ async function loadReconciliationBase(wikiRoot) {
|
|
|
36082
36212
|
}
|
|
36083
36213
|
}
|
|
36084
36214
|
const repaired = mergeGraphs(base, createGraphIndex(endpointNodes));
|
|
36085
|
-
if (
|
|
36215
|
+
if (validateGraph(repaired).issues.some((issue) => issue.code !== SELF_LOOP_VALIDATION_ISSUE_CODE)) {
|
|
36086
36216
|
throw new Error(`Cannot reconcile invalid graph index at ${graphPath}`);
|
|
36087
36217
|
}
|
|
36088
36218
|
return repaired;
|
|
@@ -36406,7 +36536,7 @@ async function reconcileKnowledge(options) {
|
|
|
36406
36536
|
stats
|
|
36407
36537
|
};
|
|
36408
36538
|
}
|
|
36409
|
-
var BRIDGE_EDGE_SOURCE, PRODUCT_PAGE_TYPE, CODE_PAGE_TYPE, PAGE_CONFIDENCE, PRODUCT_PAGE_DOMAIN, CODE_PAGE_DOMAIN, REPAIRABLE_CODE_EDGE_SOURCES, MISSING_PATH_ERROR_CODE, REPAIRABLE_VALIDATION_ISSUE_CODE;
|
|
36539
|
+
var BRIDGE_EDGE_SOURCE, PRODUCT_PAGE_TYPE, CODE_PAGE_TYPE, PAGE_CONFIDENCE, PRODUCT_PAGE_DOMAIN, CODE_PAGE_DOMAIN, REPAIRABLE_CODE_EDGE_SOURCES, MISSING_PATH_ERROR_CODE, REPAIRABLE_VALIDATION_ISSUE_CODE, SELF_LOOP_VALIDATION_ISSUE_CODE;
|
|
36410
36540
|
var init_knowledge_reconciler = __esm({
|
|
36411
36541
|
"src/wiki-engine/knowledge-reconciler.ts"() {
|
|
36412
36542
|
"use strict";
|
|
@@ -36421,6 +36551,7 @@ var init_knowledge_reconciler = __esm({
|
|
|
36421
36551
|
REPAIRABLE_CODE_EDGE_SOURCES = /* @__PURE__ */ new Set(["code-ast", "code-heuristic"]);
|
|
36422
36552
|
MISSING_PATH_ERROR_CODE = "ENOENT";
|
|
36423
36553
|
REPAIRABLE_VALIDATION_ISSUE_CODE = "edge.missing_node";
|
|
36554
|
+
SELF_LOOP_VALIDATION_ISSUE_CODE = "edge.self_loop";
|
|
36424
36555
|
}
|
|
36425
36556
|
});
|
|
36426
36557
|
|
|
@@ -40464,7 +40595,7 @@ async function codebaseCmd(opts) {
|
|
|
40464
40595
|
await printCodebaseStatus(opts);
|
|
40465
40596
|
return;
|
|
40466
40597
|
}
|
|
40467
|
-
if (!opts.lint && !opts.reconcile) {
|
|
40598
|
+
if (!opts.lint && !opts.reconcile && !opts.deepEnrich) {
|
|
40468
40599
|
console.log("teamai codebase \u2014 team codebase knowledge management");
|
|
40469
40600
|
console.log("");
|
|
40470
40601
|
console.log("Usage:");
|
|
@@ -40474,6 +40605,7 @@ async function codebaseCmd(opts) {
|
|
|
40474
40605
|
console.log(" teamai codebase --lint --json Output JSON report (for CI)");
|
|
40475
40606
|
console.log(" teamai codebase --lint --severity high Only report high-severity issues");
|
|
40476
40607
|
console.log(" teamai codebase --reconcile Reconcile product and code knowledge");
|
|
40608
|
+
console.log(" teamai codebase --deep-enrich Generate deep knowledge from extracted evidence");
|
|
40477
40609
|
console.log(" teamai codebase --status Show knowledge-base git baseline");
|
|
40478
40610
|
return;
|
|
40479
40611
|
}
|
|
@@ -40492,7 +40624,58 @@ async function codebaseCmd(opts) {
|
|
|
40492
40624
|
}
|
|
40493
40625
|
if (!await pathExists3(teamwikiDir)) {
|
|
40494
40626
|
console.log("No teamwiki found. Run `teamai import` first.");
|
|
40495
|
-
if (opts.reconcile) process.exitCode = 1;
|
|
40627
|
+
if (opts.reconcile || opts.deepEnrich) process.exitCode = 1;
|
|
40628
|
+
return;
|
|
40629
|
+
}
|
|
40630
|
+
if (opts.deepEnrich) {
|
|
40631
|
+
const project = opts.project?.trim() ?? "";
|
|
40632
|
+
if (!project) {
|
|
40633
|
+
console.log("Deep enrichment requires --project <slug>.");
|
|
40634
|
+
process.exitCode = 1;
|
|
40635
|
+
return;
|
|
40636
|
+
}
|
|
40637
|
+
const { assertWithinRoot: assertWithinRoot2 } = await Promise.resolve().then(() => (init_path_safety(), path_safety_exports));
|
|
40638
|
+
const codeRoot = path125.join(teamwikiDir, "evidence", "code");
|
|
40639
|
+
const evidenceDir = path125.join(codeRoot, project);
|
|
40640
|
+
try {
|
|
40641
|
+
assertWithinRoot2(codeRoot, evidenceDir);
|
|
40642
|
+
} catch (e) {
|
|
40643
|
+
console.log(e.message);
|
|
40644
|
+
process.exitCode = 1;
|
|
40645
|
+
return;
|
|
40646
|
+
}
|
|
40647
|
+
if (!await pathExists3(evidenceDir)) {
|
|
40648
|
+
console.log(`No extracted evidence found for project "${project}". Run \`teamai codebase --extract\` first.`);
|
|
40649
|
+
process.exitCode = 1;
|
|
40650
|
+
return;
|
|
40651
|
+
}
|
|
40652
|
+
let componentCount = 0;
|
|
40653
|
+
try {
|
|
40654
|
+
const manifest = JSON.parse(await readFile15(path125.join(evidenceDir, "_manifest.json"), "utf-8"));
|
|
40655
|
+
componentCount = Array.isArray(manifest.components) ? manifest.components.length : 0;
|
|
40656
|
+
} catch {
|
|
40657
|
+
componentCount = 0;
|
|
40658
|
+
}
|
|
40659
|
+
if (componentCount === 0) {
|
|
40660
|
+
console.log(`No components in evidence for project "${project}". Run \`teamai codebase --extract\` first.`);
|
|
40661
|
+
process.exitCode = 1;
|
|
40662
|
+
return;
|
|
40663
|
+
}
|
|
40664
|
+
if (opts.dryRun) {
|
|
40665
|
+
if (opts.json) {
|
|
40666
|
+
console.log(JSON.stringify({ project, evidenceDir, dryRun: true }, null, 2));
|
|
40667
|
+
} else {
|
|
40668
|
+
console.log(`Deep enrichment preview: project=${project} (no writes)`);
|
|
40669
|
+
}
|
|
40670
|
+
return;
|
|
40671
|
+
}
|
|
40672
|
+
const { deepEnrich: deepEnrich2 } = await Promise.resolve().then(() => (init_deep_enrich(), deep_enrich_exports));
|
|
40673
|
+
await deepEnrich2({ project, evidenceDir, wikiRoot: teamwikiDir });
|
|
40674
|
+
if (opts.json) {
|
|
40675
|
+
console.log(JSON.stringify({ project, evidenceDir, complete: true }, null, 2));
|
|
40676
|
+
} else {
|
|
40677
|
+
console.log(`Deep enrichment complete: project=${project}`);
|
|
40678
|
+
}
|
|
40496
40679
|
return;
|
|
40497
40680
|
}
|
|
40498
40681
|
if (opts.reconcile) {
|
|
@@ -41699,10 +41882,10 @@ program.command("pull").description("Pull team resources and inject into local A
|
|
|
41699
41882
|
const { pull: pull2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
|
|
41700
41883
|
await pull2({ ...globalOpts, ...cmdOpts });
|
|
41701
41884
|
});
|
|
41702
|
-
program.command("status").description("Show local vs team repo diff").action(async () => {
|
|
41885
|
+
program.command("status").description("Show local vs team repo diff").option("--all", "List every project data partition under ~/.teamai/projects (flags stale/orphan ones)").action(async (cmdOpts) => {
|
|
41703
41886
|
const globalOpts = program.opts();
|
|
41704
41887
|
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
41705
|
-
await status2(globalOpts);
|
|
41888
|
+
await status2({ ...globalOpts, ...cmdOpts });
|
|
41706
41889
|
});
|
|
41707
41890
|
program.command("list [type]").description("List resources (skills|rules|docs|env|agents|hooks|mcp). For skills, --source local/all also scans installed AI agent skill directories.").option("--source <src>", "Where to look for skills: repo | local | all", "all").option("--agent <name>", "Filter local agents by id (only applies to skills)").option("--reveal", "Show env values in plaintext (default: masked)").action(async (type, cmdOpts) => {
|
|
41708
41891
|
const globalOpts = program.opts();
|
|
@@ -42087,7 +42270,7 @@ program.command("mr-hint", { hidden: true }).description("Hint AI about recently
|
|
|
42087
42270
|
await mrHint2();
|
|
42088
42271
|
}
|
|
42089
42272
|
});
|
|
42090
|
-
program.command("codebase").description("Inspect and maintain team-codebase outputs").option("--extract [path]", "Extract code knowledge and build graph from source").addOption(new Option("--incremental", "Only re-extract changed files (requires prior manifest)").hideHelp()).addOption(new Option("--project <name>", "Project slug for extract
|
|
42273
|
+
program.command("codebase").description("Inspect and maintain team-codebase outputs").option("--extract [path]", "Extract code knowledge and build graph from source").addOption(new Option("--incremental", "Only re-extract changed files (requires prior manifest)").hideHelp()).addOption(new Option("--project <name>", "Project slug for --extract (defaults to directory name) and required for --deep-enrich").hideHelp()).addOption(new Option("--max-files <n>", "Max source files to scan (default: 200)").hideHelp()).addOption(new Option("--upgrade-wiki", "Migrate docs/team-codebase/ to teamwiki/ graph format").hideHelp()).option("--lint", "Run global consistency lint over the teamwiki knowledge graph").option("--reconcile", "Reconcile product and code knowledge in teamwiki").option("--deep-enrich", "Generate deep knowledge docs from extracted evidence").addOption(new Option("--fix", "Deprecated: teamwiki lint has no autofix; runs lint in report-only mode").hideHelp()).option("--status", "Show knowledge-base git baseline (headSha / repoUrl / branch)").addOption(new Option("--severity <level>", "Minimum severity to report: high|medium|low|info").default("info").hideHelp()).option("--json", "Output report as JSON (suitable for CI)").addOption(new Option("--output <path>", "Custom teamwiki output root directory").hideHelp()).action(async (cmdOpts) => {
|
|
42091
42274
|
const globalOpts = program.opts();
|
|
42092
42275
|
const { codebaseCmd: codebaseCmd2 } = await Promise.resolve().then(() => (init_codebase_cmd(), codebase_cmd_exports));
|
|
42093
42276
|
await codebaseCmd2({ ...globalOpts, ...cmdOpts });
|
package/package.json
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
- 每次生成后有准确性统计,超标自动警告
|
|
24
24
|
- AI 读知识库而非读源码,**约 1/50 的 token 消耗**获得全局架构认知
|
|
25
25
|
- Phase 0 可用 `teamai codebase --extract` 生成可证据化的结构边(TS/JS/Python/Go AST + 多语言 heuristic)
|
|
26
|
+
- 提取后可用 `teamai codebase --deep-enrich --project <slug> --output <repo>` 生成确定性图谱文档(G1/G2/G3)与深度知识;无需单独的 team-wiki CLI
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -889,6 +889,7 @@ _review/ ← 过程文件(不入知识库)
|
|
|
889
889
|
| 阶段 | 命令 / 路径 |
|
|
890
890
|
|------|-------------|
|
|
891
891
|
| Phase 0 结构基线 | `teamai codebase --extract <repo> --project <slug>`(writes `<repo>/teamwiki/`) |
|
|
892
|
+
| Deep knowledge | Use `teamai codebase --deep-enrich --project <slug> --output <repo>` after extract has written `teamwiki/evidence/code/<slug>/`. `--output` is the repository root, not the `teamwiki/` directory. Prefix with `teamai --dry-run` to preview without writing. TeamAI does not ship a separate team-wiki CLI. No extra plugin is required. |
|
|
892
893
|
| K3 后编译进 wiki | Skip. TeamAI does not ship a separate team-wiki CLI. Continue with this skill using `teamai` and the files under this skill directory. No extra plugin is required. |
|
|
893
894
|
| 产品文档入图 | Skip. Same English note as above. |
|
|
894
895
|
| 产品↔代码桥接 | Use `teamai codebase --reconcile --output <repo>` after product pages and extracted code pages are under `<repo>/teamwiki/`. Prefix with `teamai --dry-run` to preview without updating the graph. |
|