teamai-cli 0.24.0-beta.4 → 0.24.0-beta.6
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 +7 -1
- package/README.zh-CN.md +7 -1
- package/dist/index.js +451 -174
- package/package.json +1 -1
- package/skills/team-wiki-codebase/README.md +1 -0
- package/skills/team-wiki-codebase/SKILL.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
17
17
|
### 📝 Documentation
|
|
18
18
|
|
|
19
19
|
- Align the public usage guides, drop internal-only details, and cover the missing commands and configuration ([#442](https://github.com/Tencent/teamai-cli/pull/442)).
|
|
20
|
+
- Document `teamai projects` in the bilingual READMEs as the lead distribution control, including learnings isolation ([#490](https://github.com/Tencent/teamai-cli/pull/490), for [#487](https://github.com/Tencent/teamai-cli/issues/487)).
|
|
20
21
|
|
|
21
22
|
## [0.23.0](https://github.com/Tencent/teamai-cli/compare/v0.22.0...v0.23.0) (2026-09-08)
|
|
22
23
|
|
package/README.md
CHANGED
|
@@ -103,10 +103,13 @@ Team-wide settings an admin configures once and delivers to every member on `tea
|
|
|
103
103
|
|
|
104
104
|
| Capability | Command | What it does |
|
|
105
105
|
|------------|---------|--------------|
|
|
106
|
+
| **Projects** | `teamai projects` | Bind a working directory to one or more logical projects so it syncs that project's skills, knowledge, and isolated learnings. Orthogonal to roles. |
|
|
106
107
|
| **Roles** | `teamai roles` | Define role → namespace mappings so each member syncs only the skills for their role. |
|
|
107
108
|
| **Tags** | `teamai tags` | Tag skills / rules so members subscribe to just the tags they need. |
|
|
108
109
|
| **Sources** | `teamai source` | Subscribe to additional skill repos — other teams' public repos, or shared/public repos within your own org; subscribed skills sync automatically on pull. |
|
|
109
110
|
|
|
111
|
+
Learnings isolation: `learnings/` at the repo root is shared with everyone; `learnings/<project-id>/` is project-private. See the [usage guide](docs/usage-guide.md#multi-project-project-as-a-dimension-orthogonal-to-role).
|
|
112
|
+
|
|
110
113
|
## Team Execution
|
|
111
114
|
|
|
112
115
|
> One Team. One Harness. Every Agent.
|
|
@@ -191,6 +194,7 @@ Matched: conflict | Missing: port
|
|
|
191
194
|
teamai import --from-repo https://github.com/org/repo
|
|
192
195
|
teamai import --from-org myorg # batch import all repos
|
|
193
196
|
teamai codebase --extract /path/to/repo # local extract into teamwiki/
|
|
197
|
+
teamai codebase --deep-enrich --project my-service --output /path/to/repo # generate deep knowledge docs
|
|
194
198
|
teamai codebase --reconcile --output /path/to/repo # map product docs to code pages
|
|
195
199
|
teamai codebase --lint --output /path/to/repo # check the locally extracted graph
|
|
196
200
|
```
|
|
@@ -236,7 +240,7 @@ Insight into how the team actually uses its AI tools, and a starting point for t
|
|
|
236
240
|
| `teamai pull` | Pull team resources and inject into local AI tools |
|
|
237
241
|
| `teamai push` | Push local resources to a branch and open a Merge Request |
|
|
238
242
|
| `teamai packages [install] [target]` | Install declared npm packages and Claude plugins; with a target, also update `teamai.yaml`. Bare `teamai packages` installs everything; `teamai packages install <target>` adds one |
|
|
239
|
-
| `teamai status` | Show local vs team repo diff |
|
|
243
|
+
| `teamai status` | Show local vs team repo diff and resource counts, including namespaced skills and nested docs |
|
|
240
244
|
| `teamai contribute` | Share session experience to team repo |
|
|
241
245
|
| `teamai recall <query>` | Search the team knowledge base (BM25 + graph-boost) |
|
|
242
246
|
| `teamai recall enable/disable/status` | Toggle or check recall state |
|
|
@@ -244,10 +248,12 @@ Insight into how the team actually uses its AI tools, and a starting point for t
|
|
|
244
248
|
| `teamai recall maintenance` | Maintain knowledge base health: prune low-confidence learnings, writeback confidence scores, flag stale entries |
|
|
245
249
|
| `teamai import` | Import knowledge (`--dir`, `--from-repo`, `--from-org`, `--from-repo-list`, `--from-mr`) |
|
|
246
250
|
| `teamai codebase --extract [path]` | Extract code facts and build the local graph under `teamwiki/` |
|
|
251
|
+
| `teamai codebase --deep-enrich` | Generate deep knowledge docs from extracted evidence |
|
|
247
252
|
| `teamai codebase --reconcile` | Reconcile product documentation with extracted code knowledge |
|
|
248
253
|
| `teamai codebase --lint` | Knowledge graph health check |
|
|
249
254
|
| `teamai ci extract-mr --url <url>` | CI: extract knowledge from MR, post comments, write after merge |
|
|
250
255
|
| `teamai members` | List team members |
|
|
256
|
+
| `teamai projects` | Bind a working directory to one or more logical projects |
|
|
251
257
|
| `teamai roles` | Manage team roles and namespaces |
|
|
252
258
|
| `teamai tags` | Manage tag-based skill/rule filtering |
|
|
253
259
|
| `teamai skill exclude add/remove/list` | Manage skills excluded from local sync ([usage guide](docs/usage-guide.md#excluding-skills-you-dont-need)) |
|
package/README.zh-CN.md
CHANGED
|
@@ -103,10 +103,13 @@ teamai init https://github.com/yourorg/yourrepo --scope user
|
|
|
103
103
|
|
|
104
104
|
| 能力 | 命令 | 作用 |
|
|
105
105
|
|------|------|------|
|
|
106
|
+
| **项目(Projects)** | `teamai projects` | 将工作目录绑定到一个或多个逻辑项目,使其同步该项目的 skills、knowledge 以及隔离的 learnings。与角色正交。 |
|
|
106
107
|
| **角色(Roles)** | `teamai roles` | 定义「角色 → 命名空间」映射,让每位成员只同步与自身角色匹配的 skills。 |
|
|
107
108
|
| **标签(Tags)** | `teamai tags` | 给 skills / rules 打标签,成员只订阅自己需要的标签。 |
|
|
108
109
|
| **订阅源(Sources)** | `teamai source` | 订阅额外的 skill 仓库——其他团队的公开仓库,或本团队内的公共/共享仓库;已订阅的 skills 会在 pull 时自动同步。 |
|
|
109
110
|
|
|
111
|
+
learnings 隔离:仓库 `learnings/` 根目录对所有人共享;`learnings/<project-id>/` 为项目私有。详见[使用指南](docs/usage-guide.zh-CN.md#多项目project-作为与-role-正交的维度)。
|
|
112
|
+
|
|
110
113
|
## Team Execution
|
|
111
114
|
|
|
112
115
|
> One Team. One Harness. Every Agent.
|
|
@@ -191,6 +194,7 @@ Matched: conflict | Missing: port
|
|
|
191
194
|
teamai import --from-repo https://github.com/org/repo
|
|
192
195
|
teamai import --from-org myorg # 批量导入所有仓库
|
|
193
196
|
teamai codebase --extract /path/to/repo # 本地提取到 teamwiki/
|
|
197
|
+
teamai codebase --deep-enrich --project my-service --output /path/to/repo # 从提取结果生成深度知识文档
|
|
194
198
|
teamai codebase --reconcile --output /path/to/repo # 将产品文档映射到代码页面
|
|
195
199
|
teamai codebase --lint --output /path/to/repo # 检查本地提取的图谱
|
|
196
200
|
```
|
|
@@ -236,7 +240,7 @@ teamai recall maintenance --update-quality # 为过时 skills / docs 生
|
|
|
236
240
|
| `teamai pull` | 拉取团队资源并注入到本地 AI 工具 |
|
|
237
241
|
| `teamai push` | 推送本地资源到分支并创建合并请求 |
|
|
238
242
|
| `teamai packages [install] [target]` | 安装团队 npm 包和 Claude 插件。裸 `teamai packages` 安装全部;`teamai packages install <target>` 添加单个并更新声明 |
|
|
239
|
-
| `teamai status` |
|
|
243
|
+
| `teamai status` | 显示本地与团队仓库的差异及资源数量,包含 namespace 下的技能和子目录中的文档 |
|
|
240
244
|
| `teamai contribute` | 将 session 经验分享到团队仓库 |
|
|
241
245
|
| `teamai recall <query>` | 搜索团队知识库(BM25 + 图谱增强) |
|
|
242
246
|
| `teamai recall enable/disable/status` | 开关或查看 recall 状态 |
|
|
@@ -244,10 +248,12 @@ teamai recall maintenance --update-quality # 为过时 skills / docs 生
|
|
|
244
248
|
| `teamai recall maintenance` | 维护知识库健康:清理低置信度 learnings、回写置信度、标记过时条目 |
|
|
245
249
|
| `teamai import` | 导入知识(`--dir`、`--from-repo`、`--from-org`、`--from-repo-list`、`--from-mr`) |
|
|
246
250
|
| `teamai codebase --extract [path]` | 提取代码事实并在 `teamwiki/` 下构建本地图谱 |
|
|
251
|
+
| `teamai codebase --deep-enrich` | 从已提取的 evidence 生成深度知识文档 |
|
|
247
252
|
| `teamai codebase --reconcile` | 将产品文档与提取的代码知识进行对账 |
|
|
248
253
|
| `teamai codebase --lint` | 知识图谱健康检查 |
|
|
249
254
|
| `teamai ci extract-mr --url <url>` | CI:从 MR 提取知识、发评论、合并后写入 |
|
|
250
255
|
| `teamai members` | 查看团队成员 |
|
|
256
|
+
| `teamai projects` | 将工作目录绑定到一个或多个逻辑项目 |
|
|
251
257
|
| `teamai roles` | 管理团队角色和命名空间 |
|
|
252
258
|
| `teamai tags` | 管理基于标签的 skill/rule 过滤 |
|
|
253
259
|
| `teamai skill exclude add/remove/list` | 管理不参与本地同步的 skills([使用指南](docs/usage-guide.zh-CN.md#排除个人不需要的-skill)) |
|
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);
|
|
@@ -11939,6 +11974,10 @@ var init_skills = __esm({
|
|
|
11939
11974
|
}
|
|
11940
11975
|
dest = path28.join(wsDir, "skills", item.name);
|
|
11941
11976
|
} else if (tool === "hermes") {
|
|
11977
|
+
if (!await pathExists(getHermesHome())) {
|
|
11978
|
+
log.debug(`Skipping skill sync for ${tool}: tool not installed`);
|
|
11979
|
+
continue;
|
|
11980
|
+
}
|
|
11942
11981
|
dest = path28.join(getHermesHome(), "skills", item.name);
|
|
11943
11982
|
} else {
|
|
11944
11983
|
if (!await ResourceHandler.isToolInstalled(toolPath.skills, baseDir)) {
|
|
@@ -12386,10 +12425,7 @@ var init_docs = __esm({
|
|
|
12386
12425
|
}
|
|
12387
12426
|
async scanTeamForPull(_teamConfig, localConfig) {
|
|
12388
12427
|
const docsDir = path31.join(localConfig.repo.localPath, "docs");
|
|
12389
|
-
if (
|
|
12390
|
-
const files = await listFiles(docsDir);
|
|
12391
|
-
const realFiles = files.filter((f) => !f.startsWith("."));
|
|
12392
|
-
if (realFiles.length === 0) return [];
|
|
12428
|
+
if (await this.countDocFiles(docsDir) === 0) return [];
|
|
12393
12429
|
return [{
|
|
12394
12430
|
name: "docs",
|
|
12395
12431
|
type: "docs",
|
|
@@ -12398,8 +12434,8 @@ var init_docs = __esm({
|
|
|
12398
12434
|
}];
|
|
12399
12435
|
}
|
|
12400
12436
|
async countDocFiles(sourcePath) {
|
|
12401
|
-
const files = await
|
|
12402
|
-
return files.filter((f) =>
|
|
12437
|
+
const files = await listFilesRecursive(sourcePath);
|
|
12438
|
+
return files.filter((f) => f.split("/").every((segment) => !segment.startsWith("."))).length;
|
|
12403
12439
|
}
|
|
12404
12440
|
async pushItem(_item, _teamConfig, _localConfig) {
|
|
12405
12441
|
}
|
|
@@ -13768,7 +13804,7 @@ async function acquireReclaimSentinel(sentinel, owner) {
|
|
|
13768
13804
|
return exclusiveCreate(sentinel, payload);
|
|
13769
13805
|
}
|
|
13770
13806
|
async function acquireLock(lockPath) {
|
|
13771
|
-
const resolved = lockPath ?? expandHome(
|
|
13807
|
+
const resolved = lockPath ?? expandHome(getUpdateLockPath());
|
|
13772
13808
|
const owner = randomUUID2();
|
|
13773
13809
|
const payload = JSON.stringify({
|
|
13774
13810
|
pid: process.pid,
|
|
@@ -13807,7 +13843,7 @@ async function acquireLock(lockPath) {
|
|
|
13807
13843
|
}
|
|
13808
13844
|
}
|
|
13809
13845
|
async function releaseLock(lockPath) {
|
|
13810
|
-
const resolved = lockPath ?? expandHome(
|
|
13846
|
+
const resolved = lockPath ?? expandHome(getUpdateLockPath());
|
|
13811
13847
|
const ourOwner = heldLockOwners.get(resolved);
|
|
13812
13848
|
if (!ourOwner) return;
|
|
13813
13849
|
try {
|
|
@@ -15211,7 +15247,7 @@ async function initHttp(url, options) {
|
|
|
15211
15247
|
if (scope === "project") {
|
|
15212
15248
|
await saveLocalConfigForScope(localConfig, scope, projectRoot);
|
|
15213
15249
|
} else {
|
|
15214
|
-
await ensureDir(
|
|
15250
|
+
await ensureDir(getTeamaiHomeDir());
|
|
15215
15251
|
await saveLocalConfig(localConfig);
|
|
15216
15252
|
}
|
|
15217
15253
|
log.success(`Local config saved to ${teamaiHome}/config.yaml`);
|
|
@@ -15950,9 +15986,9 @@ async function init(options) {
|
|
|
15950
15986
|
log.debug("Generated .teamai/.gitignore for project scope");
|
|
15951
15987
|
}
|
|
15952
15988
|
} else {
|
|
15953
|
-
await ensureDir(
|
|
15989
|
+
await ensureDir(getTeamaiHomeDir());
|
|
15954
15990
|
await saveLocalConfig(localConfig);
|
|
15955
|
-
log.success(`Local config saved to ${
|
|
15991
|
+
log.success(`Local config saved to ${getTeamaiHomeDir()}/config.yaml`);
|
|
15956
15992
|
}
|
|
15957
15993
|
try {
|
|
15958
15994
|
const state = await loadStateForScope(localConfig);
|
|
@@ -17203,6 +17239,23 @@ function projectSlug(anchor) {
|
|
|
17203
17239
|
function projectDataHome(anchor) {
|
|
17204
17240
|
return path46.join(getUserHome(), ".teamai", "projects", projectSlug(anchor));
|
|
17205
17241
|
}
|
|
17242
|
+
function projectsRootDir() {
|
|
17243
|
+
return path46.join(getUserHome(), ".teamai", "projects");
|
|
17244
|
+
}
|
|
17245
|
+
async function writeAnchorFile(partitionDir, anchor) {
|
|
17246
|
+
await fs17.promises.mkdir(partitionDir, { recursive: true });
|
|
17247
|
+
await fs17.promises.writeFile(path46.join(partitionDir, "anchor"), `${anchor}
|
|
17248
|
+
`, "utf-8");
|
|
17249
|
+
}
|
|
17250
|
+
async function readAnchorFile(partitionDir) {
|
|
17251
|
+
try {
|
|
17252
|
+
const raw = await fs17.promises.readFile(path46.join(partitionDir, "anchor"), "utf-8");
|
|
17253
|
+
const trimmed = raw.trim();
|
|
17254
|
+
return trimmed || null;
|
|
17255
|
+
} catch {
|
|
17256
|
+
return null;
|
|
17257
|
+
}
|
|
17258
|
+
}
|
|
17206
17259
|
var caseInsensitiveCache;
|
|
17207
17260
|
var init_partition = __esm({
|
|
17208
17261
|
"src/utils/partition.ts"() {
|
|
@@ -17430,7 +17483,7 @@ async function loadTeamConfig(repoPath) {
|
|
|
17430
17483
|
}
|
|
17431
17484
|
}
|
|
17432
17485
|
async function loadLocalConfig() {
|
|
17433
|
-
const configPath = expandHome(
|
|
17486
|
+
const configPath = expandHome(getUserConfigPath());
|
|
17434
17487
|
const content = await readFileSafe(configPath);
|
|
17435
17488
|
if (!content) return null;
|
|
17436
17489
|
try {
|
|
@@ -17447,15 +17500,15 @@ function serializeLocalConfig(config) {
|
|
|
17447
17500
|
return YAML14.stringify(persisted);
|
|
17448
17501
|
}
|
|
17449
17502
|
async function saveLocalConfig(config) {
|
|
17450
|
-
await writeFile(expandHome(
|
|
17503
|
+
await writeFile(expandHome(getUserConfigPath()), serializeLocalConfig(config));
|
|
17451
17504
|
}
|
|
17452
17505
|
async function loadState() {
|
|
17453
|
-
const raw = await readJson(expandHome(
|
|
17506
|
+
const raw = await readJson(expandHome(getUserStatePath()));
|
|
17454
17507
|
if (!raw) return StateSchema.parse({});
|
|
17455
17508
|
return StateSchema.parse(raw);
|
|
17456
17509
|
}
|
|
17457
17510
|
async function saveState(state) {
|
|
17458
|
-
await writeJson(expandHome(
|
|
17511
|
+
await writeJson(expandHome(getUserStatePath()), state);
|
|
17459
17512
|
}
|
|
17460
17513
|
async function requireInit() {
|
|
17461
17514
|
const localConfig = await loadLocalConfig();
|
|
@@ -17488,8 +17541,19 @@ async function loadLocalConfigForScope(scope, projectRoot) {
|
|
|
17488
17541
|
}
|
|
17489
17542
|
}
|
|
17490
17543
|
async function saveLocalConfigForScope(config, _scope, _projectRoot) {
|
|
17491
|
-
const
|
|
17544
|
+
const dataHome = getDataHome(config);
|
|
17545
|
+
const configPath = path48.join(dataHome, "config.yaml");
|
|
17492
17546
|
await writeFile(expandHome(configPath), serializeLocalConfig(config));
|
|
17547
|
+
try {
|
|
17548
|
+
if (config.scope === "project" && config.projectRoot) {
|
|
17549
|
+
const partition = await resolveProjectDataHome(config.projectRoot);
|
|
17550
|
+
if (path48.resolve(expandHome(dataHome)) === path48.resolve(partition)) {
|
|
17551
|
+
const anchors = await resolveAnchors(config.projectRoot);
|
|
17552
|
+
if (anchors) await writeAnchorFile(partition, anchors.projectAnchor);
|
|
17553
|
+
}
|
|
17554
|
+
}
|
|
17555
|
+
} catch {
|
|
17556
|
+
}
|
|
17493
17557
|
}
|
|
17494
17558
|
async function loadStateForScope(localConfig) {
|
|
17495
17559
|
const statePath = getStatePath(localConfig);
|
|
@@ -18524,8 +18588,7 @@ async function runMigration(plan, opts = {}) {
|
|
|
18524
18588
|
await rebaseConfigPaths(path51.join(staging, "config.yaml"), legacyDir, partitionDir);
|
|
18525
18589
|
await remove(partitionDir);
|
|
18526
18590
|
await fse10.rename(staging, partitionDir);
|
|
18527
|
-
await
|
|
18528
|
-
`);
|
|
18591
|
+
await writeAnchorFile(partitionDir, anchor);
|
|
18529
18592
|
await releaseLock(lockPath);
|
|
18530
18593
|
lockReleased = true;
|
|
18531
18594
|
const backup = await retireLegacy(legacyDir);
|
|
@@ -18956,6 +19019,9 @@ async function mirrorLearnings(sourceDir, destinationDir, activeNamespaces) {
|
|
|
18956
19019
|
}
|
|
18957
19020
|
});
|
|
18958
19021
|
}
|
|
19022
|
+
async function addLearningToCache(sourceFile, destinationDir, relativePath) {
|
|
19023
|
+
await fse11.copy(sourceFile, path54.join(destinationDir, relativePath), { overwrite: true });
|
|
19024
|
+
}
|
|
18959
19025
|
var init_learnings_mirror = __esm({
|
|
18960
19026
|
"src/utils/learnings-mirror.ts"() {
|
|
18961
19027
|
"use strict";
|
|
@@ -19180,8 +19246,8 @@ async function recallFeedback(opts) {
|
|
|
19180
19246
|
const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
19181
19247
|
const { localConfig } = await autoDetectInit2();
|
|
19182
19248
|
const { username } = localConfig;
|
|
19183
|
-
const {
|
|
19184
|
-
const votePath = path55.join(
|
|
19249
|
+
const { getUserVotesDir: getUserVotesDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
19250
|
+
const votePath = path55.join(getUserVotesDir2(), `${username}.yaml`);
|
|
19185
19251
|
if (opts.positive) {
|
|
19186
19252
|
await incrementUpvoted(votePath, [opts.positive]);
|
|
19187
19253
|
log.success(`Upvoted: ${opts.positive}`);
|
|
@@ -20579,8 +20645,8 @@ function computeDailyStatsDelta(current, reported) {
|
|
|
20579
20645
|
const bucket = delta[date] ?? emptyDaily();
|
|
20580
20646
|
if (!previous) {
|
|
20581
20647
|
bucket.sessionsEnded += 1;
|
|
20582
|
-
bucket.sessionsSucceeded += snapshot.succeeded;
|
|
20583
20648
|
}
|
|
20649
|
+
bucket.sessionsSucceeded += snapshot.succeeded - (previous?.succeeded ?? 0);
|
|
20584
20650
|
bucket.promptTurns += positiveDelta(snapshot.prompts, previous?.prompts);
|
|
20585
20651
|
bucket.durationMs += positiveDelta(snapshot.durationMs, previous?.durationMs);
|
|
20586
20652
|
bucket.sessionsCorrected += positiveDelta(snapshot.corrected, previous?.corrected);
|
|
@@ -21539,7 +21605,12 @@ async function writeReportedDailySessions(data) {
|
|
|
21539
21605
|
}
|
|
21540
21606
|
function hasDailyDelta(delta) {
|
|
21541
21607
|
return Object.values(delta).some(
|
|
21542
|
-
(bucket) =>
|
|
21608
|
+
(bucket) => (
|
|
21609
|
+
// sessionsSucceeded can be negative (a resumed session that later failed
|
|
21610
|
+
// claws back an earlier increment), so it must not be checked with the
|
|
21611
|
+
// same "> 0" as the other, purely monotonic counters (#473).
|
|
21612
|
+
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
|
|
21613
|
+
)
|
|
21543
21614
|
);
|
|
21544
21615
|
}
|
|
21545
21616
|
function filterEventsByScope(events, opts) {
|
|
@@ -21640,9 +21711,9 @@ async function reportUsageToTeam(repoPath, username, options) {
|
|
|
21640
21711
|
filesToPush.push(`stats/${username}.yaml`);
|
|
21641
21712
|
}
|
|
21642
21713
|
try {
|
|
21643
|
-
if (await pathExists(
|
|
21714
|
+
if (await pathExists(getUserVotesDir())) {
|
|
21644
21715
|
const { syncVotesToTeam: syncVotesToTeam2 } = await Promise.resolve().then(() => (init_votes(), votes_exports));
|
|
21645
|
-
const synced = await syncVotesToTeam2(writeRoot, username,
|
|
21716
|
+
const synced = await syncVotesToTeam2(writeRoot, username, getUserVotesDir());
|
|
21646
21717
|
if (synced) {
|
|
21647
21718
|
filesToPush.push(`votes/${username}.yaml`);
|
|
21648
21719
|
}
|
|
@@ -22413,13 +22484,13 @@ async function pullForScope(localConfig, options, policy = {}) {
|
|
|
22413
22484
|
if (localConfig.scope === "user") {
|
|
22414
22485
|
await mirrorLearnings(
|
|
22415
22486
|
learningsRepoDir,
|
|
22416
|
-
|
|
22487
|
+
getUserLearningsDir(),
|
|
22417
22488
|
activeLearningsNamespaces
|
|
22418
22489
|
);
|
|
22419
22490
|
if (await pathExists(learningsRepoDir)) {
|
|
22420
22491
|
learningsCount = await countLearnings(learningsRepoDir);
|
|
22421
22492
|
}
|
|
22422
|
-
effectiveLearningsDir = await pathExists(
|
|
22493
|
+
effectiveLearningsDir = await pathExists(getUserLearningsDir()) ? getUserLearningsDir() : void 0;
|
|
22423
22494
|
} else {
|
|
22424
22495
|
effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
|
|
22425
22496
|
if (effectiveLearningsDir) {
|
|
@@ -23165,6 +23236,10 @@ __export(status_exports, {
|
|
|
23165
23236
|
import path66 from "path";
|
|
23166
23237
|
import YAML21 from "yaml";
|
|
23167
23238
|
async function status(options) {
|
|
23239
|
+
if (options.all) {
|
|
23240
|
+
await statusAll();
|
|
23241
|
+
return;
|
|
23242
|
+
}
|
|
23168
23243
|
const { localConfig, teamConfig } = await autoDetectInit();
|
|
23169
23244
|
const scopeLabel = localConfig.scope;
|
|
23170
23245
|
console.log("");
|
|
@@ -23196,13 +23271,10 @@ async function status(options) {
|
|
|
23196
23271
|
log.info("Team resources:");
|
|
23197
23272
|
const repoPath = localConfig.repo.localPath;
|
|
23198
23273
|
const counts = {};
|
|
23199
|
-
|
|
23200
|
-
counts.skills = skillsDirs.length;
|
|
23274
|
+
counts.skills = (await new SkillsHandler().scanTeamForPull(teamConfig, localConfig)).length;
|
|
23201
23275
|
const rulesFiles = (await listFilesRecursive(path66.join(repoPath, "rules"))).filter((f) => f.endsWith(".md"));
|
|
23202
23276
|
counts.rules = rulesFiles.length;
|
|
23203
|
-
|
|
23204
|
-
const docFiles = docsExists ? (await listFiles(path66.join(repoPath, "docs"))).filter((f) => !f.startsWith(".")) : [];
|
|
23205
|
-
counts.docs = docFiles.length;
|
|
23277
|
+
counts.docs = await new DocsHandler().countDocFiles(path66.join(repoPath, "docs"));
|
|
23206
23278
|
const envYamlPath = path66.join(repoPath, "env", "env.yaml");
|
|
23207
23279
|
let envCount = 0;
|
|
23208
23280
|
if (await pathExists(envYamlPath)) {
|
|
@@ -23244,6 +23316,56 @@ async function status(options) {
|
|
|
23244
23316
|
}
|
|
23245
23317
|
console.log("");
|
|
23246
23318
|
}
|
|
23319
|
+
async function statusAll() {
|
|
23320
|
+
const root = projectsRootDir();
|
|
23321
|
+
const slugs = await listDirs(root);
|
|
23322
|
+
console.log("");
|
|
23323
|
+
log.info(`Project data partitions (${root}):`);
|
|
23324
|
+
if (slugs.length === 0) {
|
|
23325
|
+
log.info(" (none \u2014 no project has been initialized or migrated on this machine)");
|
|
23326
|
+
console.log("");
|
|
23327
|
+
return;
|
|
23328
|
+
}
|
|
23329
|
+
let orphanCount = 0;
|
|
23330
|
+
for (const slug of slugs.sort()) {
|
|
23331
|
+
const partitionDir = path66.join(root, slug);
|
|
23332
|
+
const anchor = await readAnchorFile(partitionDir);
|
|
23333
|
+
let projectPath = anchor;
|
|
23334
|
+
let scope;
|
|
23335
|
+
let kind;
|
|
23336
|
+
const cfgRaw = await readFileSafe(path66.join(partitionDir, "config.yaml"));
|
|
23337
|
+
if (cfgRaw) {
|
|
23338
|
+
try {
|
|
23339
|
+
const parsed = LocalConfigSchema.parse(YAML21.parse(cfgRaw));
|
|
23340
|
+
scope = parsed.scope;
|
|
23341
|
+
kind = parsed.repo.kind;
|
|
23342
|
+
if (!projectPath) projectPath = parsed.repo.businessRepoRoot ?? parsed.projectRoot ?? null;
|
|
23343
|
+
} catch {
|
|
23344
|
+
}
|
|
23345
|
+
}
|
|
23346
|
+
let state;
|
|
23347
|
+
if (!anchor) {
|
|
23348
|
+
state = projectPath ? "unknown \u2014 no anchor; cannot confirm orphan (partition may still be active)" : "unknown (no anchor / project path)";
|
|
23349
|
+
} else if (!await pathExists(anchor)) {
|
|
23350
|
+
state = "ORPHAN \u2014 project path is gone, safe to delete";
|
|
23351
|
+
orphanCount++;
|
|
23352
|
+
} else if (projectSlug(anchor) !== slug) {
|
|
23353
|
+
state = "corrupt \u2014 dir name does not match anchor";
|
|
23354
|
+
} else {
|
|
23355
|
+
state = "active";
|
|
23356
|
+
}
|
|
23357
|
+
const kindLabel = kind ? ` ${kind}` : "";
|
|
23358
|
+
log.info(` ${slug} [${state}]`);
|
|
23359
|
+
log.info(` project: ${projectPath ?? "(unresolved)"}${scope ? ` (${scope}${kindLabel})` : ""}`);
|
|
23360
|
+
}
|
|
23361
|
+
console.log("");
|
|
23362
|
+
if (orphanCount > 0) {
|
|
23363
|
+
log.warn(
|
|
23364
|
+
`${orphanCount} orphan partition(s) found. teamai never deletes them automatically; remove one with: rm -rf "${root}/<slug>"`
|
|
23365
|
+
);
|
|
23366
|
+
console.log("");
|
|
23367
|
+
}
|
|
23368
|
+
}
|
|
23247
23369
|
async function list(type, options) {
|
|
23248
23370
|
const { localConfig, teamConfig } = await autoDetectInit();
|
|
23249
23371
|
const repoPath = localConfig.repo.localPath;
|
|
@@ -23437,9 +23559,11 @@ var init_status = __esm({
|
|
|
23437
23559
|
init_resources();
|
|
23438
23560
|
init_fs();
|
|
23439
23561
|
init_skills();
|
|
23562
|
+
init_docs();
|
|
23440
23563
|
init_known_agents();
|
|
23441
23564
|
init_agent_skills();
|
|
23442
23565
|
init_types();
|
|
23566
|
+
init_partition();
|
|
23443
23567
|
init_env();
|
|
23444
23568
|
init_mcp();
|
|
23445
23569
|
init_hooks();
|
|
@@ -25855,16 +25979,16 @@ async function saveSession(options) {
|
|
|
25855
25979
|
}
|
|
25856
25980
|
if (options.dryRun) {
|
|
25857
25981
|
log.info(
|
|
25858
|
-
`[dry-run] Would record session ${sessionId.slice(0, 8)} (${summary.toolTotal} tools, ${summary.interventionCount} interventions, valuable=${summary.valuable}) to ${
|
|
25982
|
+
`[dry-run] Would record session ${sessionId.slice(0, 8)} (${summary.toolTotal} tools, ${summary.interventionCount} interventions, valuable=${summary.valuable}) to ${getSessionLogsDir()}/${monthKey(summary)}.md`
|
|
25859
25983
|
);
|
|
25860
25984
|
} else {
|
|
25861
|
-
const written = await appendMonthlyLog(
|
|
25985
|
+
const written = await appendMonthlyLog(getSessionLogsDir(), summary, { includePrompt: true });
|
|
25862
25986
|
if (written) {
|
|
25863
25987
|
log.info(`Recorded session to ${written}`);
|
|
25864
25988
|
} else {
|
|
25865
25989
|
log.info(`Session ${sessionId.slice(0, 8)} already recorded this month.`);
|
|
25866
25990
|
}
|
|
25867
|
-
await pruneMonthlyLogs(
|
|
25991
|
+
await pruneMonthlyLogs(getSessionLogsDir(), /* @__PURE__ */ new Date()).catch(() => []);
|
|
25868
25992
|
}
|
|
25869
25993
|
if (!options.push) return;
|
|
25870
25994
|
if (!summary.valuable && !options.force) {
|
|
@@ -26860,46 +26984,78 @@ var ai_client_exports = {};
|
|
|
26860
26984
|
__export(ai_client_exports, {
|
|
26861
26985
|
callClaude: () => callClaude,
|
|
26862
26986
|
callClaudeParallel: () => callClaudeParallel,
|
|
26863
|
-
getAICliName: () => getAICliName
|
|
26987
|
+
getAICliName: () => getAICliName,
|
|
26988
|
+
pickWindowsCommand: () => pickWindowsCommand,
|
|
26989
|
+
resolveCliPath: () => resolveCliPath
|
|
26864
26990
|
});
|
|
26865
|
-
import {
|
|
26991
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
26992
|
+
import spawn2 from "cross-spawn";
|
|
26866
26993
|
import { existsSync } from "fs";
|
|
26994
|
+
function pickWindowsCommand(whereOutput) {
|
|
26995
|
+
const lines = whereOutput.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
26996
|
+
for (const ext of WIN_EXEC_EXTENSIONS) {
|
|
26997
|
+
const hit = lines.find((line) => line.toLowerCase().endsWith(ext));
|
|
26998
|
+
if (hit !== void 0) return hit;
|
|
26999
|
+
}
|
|
27000
|
+
return null;
|
|
27001
|
+
}
|
|
27002
|
+
function whereOnWindows(cmd) {
|
|
27003
|
+
try {
|
|
27004
|
+
const out = execFileSync2("where", [cmd], {
|
|
27005
|
+
encoding: "utf8",
|
|
27006
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27007
|
+
shell: false,
|
|
27008
|
+
timeout: CLI_DETECT_TIMEOUT_MS
|
|
27009
|
+
});
|
|
27010
|
+
const p = pickWindowsCommand(out);
|
|
27011
|
+
return p !== null && existsSync(p) ? p : null;
|
|
27012
|
+
} catch {
|
|
27013
|
+
return null;
|
|
27014
|
+
}
|
|
27015
|
+
}
|
|
27016
|
+
function whichOnPosix(cmd) {
|
|
27017
|
+
try {
|
|
27018
|
+
const p = execFileSync2("bash", ["-lc", `command -v ${cmd}`], {
|
|
27019
|
+
encoding: "utf8",
|
|
27020
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27021
|
+
shell: false,
|
|
27022
|
+
timeout: CLI_DETECT_TIMEOUT_MS
|
|
27023
|
+
}).trim();
|
|
27024
|
+
if (p && existsSync(p)) return p;
|
|
27025
|
+
} catch {
|
|
27026
|
+
}
|
|
27027
|
+
try {
|
|
27028
|
+
const p = execFileSync2("zsh", ["-lc", `command -v ${cmd}`], {
|
|
27029
|
+
encoding: "utf8",
|
|
27030
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27031
|
+
shell: false,
|
|
27032
|
+
timeout: CLI_DETECT_TIMEOUT_MS
|
|
27033
|
+
}).trim();
|
|
27034
|
+
if (p && existsSync(p)) return p;
|
|
27035
|
+
} catch {
|
|
27036
|
+
}
|
|
27037
|
+
try {
|
|
27038
|
+
const p = execFileSync2("which", [cmd], {
|
|
27039
|
+
encoding: "utf8",
|
|
27040
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27041
|
+
shell: false,
|
|
27042
|
+
timeout: CLI_DETECT_TIMEOUT_MS
|
|
27043
|
+
}).trim();
|
|
27044
|
+
if (p && existsSync(p)) return p;
|
|
27045
|
+
} catch {
|
|
27046
|
+
}
|
|
27047
|
+
return null;
|
|
27048
|
+
}
|
|
27049
|
+
function resolveCliPath(cmd, platform = process.platform) {
|
|
27050
|
+
return platform === "win32" ? whereOnWindows(cmd) : whichOnPosix(cmd);
|
|
27051
|
+
}
|
|
26867
27052
|
function detectClaudeCli() {
|
|
26868
|
-
const
|
|
26869
|
-
|
|
26870
|
-
|
|
26871
|
-
const p = execFileSync2("bash", ["-lc", `command -v ${cmd}`], {
|
|
26872
|
-
encoding: "utf8",
|
|
26873
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
26874
|
-
shell: false,
|
|
26875
|
-
timeout: CLI_DETECT_TIMEOUT_MS
|
|
26876
|
-
}).trim();
|
|
26877
|
-
if (p && existsSync(p)) return { cmd, absPath: p };
|
|
26878
|
-
} catch {
|
|
26879
|
-
}
|
|
26880
|
-
try {
|
|
26881
|
-
const p = execFileSync2("zsh", ["-lc", `command -v ${cmd}`], {
|
|
26882
|
-
encoding: "utf8",
|
|
26883
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
26884
|
-
shell: false,
|
|
26885
|
-
timeout: CLI_DETECT_TIMEOUT_MS
|
|
26886
|
-
}).trim();
|
|
26887
|
-
if (p && existsSync(p)) return { cmd, absPath: p };
|
|
26888
|
-
} catch {
|
|
26889
|
-
}
|
|
26890
|
-
try {
|
|
26891
|
-
const p = execFileSync2("which", [cmd], {
|
|
26892
|
-
encoding: "utf8",
|
|
26893
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
26894
|
-
shell: false,
|
|
26895
|
-
timeout: CLI_DETECT_TIMEOUT_MS
|
|
26896
|
-
}).trim();
|
|
26897
|
-
if (p && existsSync(p)) return { cmd, absPath: p };
|
|
26898
|
-
} catch {
|
|
26899
|
-
}
|
|
27053
|
+
for (const cmd of ALLOWED_CLI_CANDIDATES) {
|
|
27054
|
+
const absPath = resolveCliPath(cmd);
|
|
27055
|
+
if (absPath !== null) return { cmd, absPath };
|
|
26900
27056
|
}
|
|
26901
27057
|
throw new Error(
|
|
26902
|
-
"AI CLI
|
|
27058
|
+
"AI CLI unavailable: install one of claude / claude-internal / codex / codex-internal / codebuddy / workbuddy / openclaw"
|
|
26903
27059
|
);
|
|
26904
27060
|
}
|
|
26905
27061
|
function buildCliArgs(cmd, prompt) {
|
|
@@ -26925,8 +27081,8 @@ async function callClaude(prompt, opts) {
|
|
|
26925
27081
|
}
|
|
26926
27082
|
log.debug(`[ai-client] calling ${_cliInfo.cmd}, timeout=${Math.round(timeoutMs / 1e3)}s, prompt=${prompt.slice(0, 60).replace(/\n/g, " ")}...`);
|
|
26927
27083
|
const child = spawn2(_cliInfo.absPath, buildCliArgs(_cliInfo.cmd, prompt), { stdio: ["ignore", "pipe", "pipe"] });
|
|
26928
|
-
child.stdout
|
|
26929
|
-
child.stderr
|
|
27084
|
+
child.stdout?.on("data", (chunk) => chunks.push(chunk));
|
|
27085
|
+
child.stderr?.on("data", (chunk) => errChunks.push(chunk));
|
|
26930
27086
|
const timer = setTimeout(() => {
|
|
26931
27087
|
child.kill();
|
|
26932
27088
|
const seconds = Math.round(timeoutMs / 1e3);
|
|
@@ -27007,7 +27163,7 @@ async function runWithConcurrency(tasks, concurrency) {
|
|
|
27007
27163
|
await Promise.all(promises);
|
|
27008
27164
|
return results;
|
|
27009
27165
|
}
|
|
27010
|
-
var ALLOWED_CLI_CANDIDATES, CLI_DETECT_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, DEFAULT_CONCURRENCY, _cliInfo;
|
|
27166
|
+
var ALLOWED_CLI_CANDIDATES, CLI_DETECT_TIMEOUT_MS, WIN_EXEC_EXTENSIONS, DEFAULT_TIMEOUT_MS, DEFAULT_CONCURRENCY, _cliInfo;
|
|
27011
27167
|
var init_ai_client = __esm({
|
|
27012
27168
|
"src/utils/ai-client.ts"() {
|
|
27013
27169
|
"use strict";
|
|
@@ -27024,6 +27180,7 @@ var init_ai_client = __esm({
|
|
|
27024
27180
|
"openclaw"
|
|
27025
27181
|
];
|
|
27026
27182
|
CLI_DETECT_TIMEOUT_MS = 5e3;
|
|
27183
|
+
WIN_EXEC_EXTENSIONS = [".exe", ".cmd", ".bat"];
|
|
27027
27184
|
DEFAULT_TIMEOUT_MS = 6e5;
|
|
27028
27185
|
DEFAULT_CONCURRENCY = 3;
|
|
27029
27186
|
}
|
|
@@ -28070,7 +28227,7 @@ async function resolveVizRoot(opts) {
|
|
|
28070
28227
|
const reportsRoot = getReportsDir(config);
|
|
28071
28228
|
const useProjectScope = config.scope === "project" && Boolean(config.projectRoot);
|
|
28072
28229
|
const teamaiHome2 = useProjectScope ? getDataHome(config) : getTeamaiHome("user");
|
|
28073
|
-
const learningsDir = useProjectScope ? path81.join(knowledgeRoot, "learnings") :
|
|
28230
|
+
const learningsDir = useProjectScope ? path81.join(knowledgeRoot, "learnings") : getUserLearningsDir();
|
|
28074
28231
|
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
28232
|
return {
|
|
28076
28233
|
root: knowledgeRoot,
|
|
@@ -28082,14 +28239,14 @@ async function resolveVizRoot(opts) {
|
|
|
28082
28239
|
source
|
|
28083
28240
|
};
|
|
28084
28241
|
}
|
|
28085
|
-
const teamaiHome =
|
|
28242
|
+
const teamaiHome = getTeamaiHomeDir();
|
|
28086
28243
|
return {
|
|
28087
28244
|
root: teamaiHome,
|
|
28088
28245
|
knowledgeRoot: teamaiHome,
|
|
28089
|
-
votesDir:
|
|
28090
|
-
learningsDir:
|
|
28246
|
+
votesDir: getUserVotesDir(),
|
|
28247
|
+
learningsDir: getUserLearningsDir(),
|
|
28091
28248
|
statsDir: path81.join(teamaiHome, "stats"),
|
|
28092
|
-
indexPath:
|
|
28249
|
+
indexPath: getUserSearchIndexPath(),
|
|
28093
28250
|
source: { scope: "local", label: "Local ~/.teamai \xB7 your recalls only" }
|
|
28094
28251
|
};
|
|
28095
28252
|
}
|
|
@@ -30048,8 +30205,8 @@ var init_hook_handlers = __esm({
|
|
|
30048
30205
|
const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
30049
30206
|
const voteData = await parseTranscriptForVotes2(transcriptPath);
|
|
30050
30207
|
const { localConfig } = await autoDetectInit2();
|
|
30051
|
-
const {
|
|
30052
|
-
const votesDir =
|
|
30208
|
+
const { getUserVotesDir: getUserVotesDir2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
30209
|
+
const votesDir = getUserVotesDir2();
|
|
30053
30210
|
const votePath = path90.join(votesDir, `${localConfig.username}.yaml`);
|
|
30054
30211
|
const recalledSet = new Set(voteData.recalledDocIds);
|
|
30055
30212
|
const verifiedDocIds = voteData.referencedDocIds.filter((id) => recalledSet.has(id));
|
|
@@ -30323,8 +30480,8 @@ async function rebuildIndexAfterContribute(localConfig) {
|
|
|
30323
30480
|
localConfig.projects ?? []
|
|
30324
30481
|
);
|
|
30325
30482
|
if (localConfig.scope === "user") {
|
|
30326
|
-
await mirrorLearnings(learningsRepoDir,
|
|
30327
|
-
effectiveLearningsDir = await pathExists(
|
|
30483
|
+
await mirrorLearnings(learningsRepoDir, getUserLearningsDir(), activeLearningsNamespaces);
|
|
30484
|
+
effectiveLearningsDir = await pathExists(getUserLearningsDir()) ? getUserLearningsDir() : void 0;
|
|
30328
30485
|
} else {
|
|
30329
30486
|
effectiveLearningsDir = await pathExists(learningsRepoDir) ? learningsRepoDir : void 0;
|
|
30330
30487
|
}
|
|
@@ -30454,12 +30611,11 @@ async function contributeSelf(localConfig, content, options) {
|
|
|
30454
30611
|
await fs30.promises.writeFile(destAbs, content, "utf-8");
|
|
30455
30612
|
try {
|
|
30456
30613
|
const { pathExists: pathExists3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
30457
|
-
const wtLearnings = path91.join(wtRepo, "learnings");
|
|
30458
30614
|
const activeLearningsNamespaces = await resolveActiveLearningsNamespaces(
|
|
30459
30615
|
localConfig.repo.localPath,
|
|
30460
30616
|
localConfig.projects ?? []
|
|
30461
30617
|
);
|
|
30462
|
-
await
|
|
30618
|
+
await addLearningToCache(destAbs, getUserLearningsDir(), relPath.slice("learnings/".length));
|
|
30463
30619
|
const repoPath = localConfig.repo.localPath;
|
|
30464
30620
|
const docsDir = path91.join(repoPath, "docs");
|
|
30465
30621
|
const rulesDir = path91.join(repoPath, "rules");
|
|
@@ -30474,7 +30630,7 @@ async function contributeSelf(localConfig, content, options) {
|
|
|
30474
30630
|
const teamaiHome = getDataHome(localConfig);
|
|
30475
30631
|
const { buildIndex: buildIndex2 } = await Promise.resolve().then(() => (init_search_index(), search_index_exports));
|
|
30476
30632
|
await buildIndex2({
|
|
30477
|
-
learningsDir: await pathExists3(
|
|
30633
|
+
learningsDir: await pathExists3(getUserLearningsDir()) ? getUserLearningsDir() : void 0,
|
|
30478
30634
|
learningsNamespaces: activeLearningsNamespaces,
|
|
30479
30635
|
docsDir: await pathExists3(docsDir) ? docsDir : void 0,
|
|
30480
30636
|
rulesDir: await pathExists3(rulesDir) ? rulesDir : void 0,
|
|
@@ -36050,6 +36206,9 @@ var init_reconciler_v2_types = __esm({
|
|
|
36050
36206
|
// src/wiki-engine/knowledge-reconciler.ts
|
|
36051
36207
|
import { readFile as readFile9, readdir as readdir3, stat as stat5 } from "fs/promises";
|
|
36052
36208
|
import path109 from "path";
|
|
36209
|
+
function isExpectedSelfLoop(edge) {
|
|
36210
|
+
return edge.from === edge.to && edge.relation === "IMPLEMENTS" && !!edge.source && REPAIRABLE_CODE_EDGE_SOURCES.has(edge.source);
|
|
36211
|
+
}
|
|
36053
36212
|
async function loadReconciliationBase(wikiRoot) {
|
|
36054
36213
|
const graphPath = path109.join(wikiRoot, ".indices", "graph-index.json");
|
|
36055
36214
|
const graph = await loadGraphIndex(wikiRoot);
|
|
@@ -36061,7 +36220,10 @@ async function loadReconciliationBase(wikiRoot) {
|
|
|
36061
36220
|
graph.nodes,
|
|
36062
36221
|
graph.edges.filter((edge) => edge.source !== BRIDGE_EDGE_SOURCE)
|
|
36063
36222
|
);
|
|
36064
|
-
|
|
36223
|
+
const hasUnexpectedSelfLoop = base.edges.some((edge) => edge.from === edge.to && !isExpectedSelfLoop(edge));
|
|
36224
|
+
if (hasUnexpectedSelfLoop || validateGraph(base).issues.some(
|
|
36225
|
+
(issue) => issue.code !== REPAIRABLE_VALIDATION_ISSUE_CODE && issue.code !== SELF_LOOP_VALIDATION_ISSUE_CODE
|
|
36226
|
+
)) {
|
|
36065
36227
|
throw new Error(`Cannot reconcile invalid graph index at ${graphPath}`);
|
|
36066
36228
|
}
|
|
36067
36229
|
const nodeSlugs = new Set(base.nodes.map((node) => node.slug));
|
|
@@ -36082,7 +36244,7 @@ async function loadReconciliationBase(wikiRoot) {
|
|
|
36082
36244
|
}
|
|
36083
36245
|
}
|
|
36084
36246
|
const repaired = mergeGraphs(base, createGraphIndex(endpointNodes));
|
|
36085
|
-
if (
|
|
36247
|
+
if (validateGraph(repaired).issues.some((issue) => issue.code !== SELF_LOOP_VALIDATION_ISSUE_CODE)) {
|
|
36086
36248
|
throw new Error(`Cannot reconcile invalid graph index at ${graphPath}`);
|
|
36087
36249
|
}
|
|
36088
36250
|
return repaired;
|
|
@@ -36406,7 +36568,7 @@ async function reconcileKnowledge(options) {
|
|
|
36406
36568
|
stats
|
|
36407
36569
|
};
|
|
36408
36570
|
}
|
|
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;
|
|
36571
|
+
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
36572
|
var init_knowledge_reconciler = __esm({
|
|
36411
36573
|
"src/wiki-engine/knowledge-reconciler.ts"() {
|
|
36412
36574
|
"use strict";
|
|
@@ -36421,6 +36583,7 @@ var init_knowledge_reconciler = __esm({
|
|
|
36421
36583
|
REPAIRABLE_CODE_EDGE_SOURCES = /* @__PURE__ */ new Set(["code-ast", "code-heuristic"]);
|
|
36422
36584
|
MISSING_PATH_ERROR_CODE = "ENOENT";
|
|
36423
36585
|
REPAIRABLE_VALIDATION_ISSUE_CODE = "edge.missing_node";
|
|
36586
|
+
SELF_LOOP_VALIDATION_ISSUE_CODE = "edge.self_loop";
|
|
36424
36587
|
}
|
|
36425
36588
|
});
|
|
36426
36589
|
|
|
@@ -37782,7 +37945,7 @@ var deep_enrich_exports = {};
|
|
|
37782
37945
|
__export(deep_enrich_exports, {
|
|
37783
37946
|
deepEnrich: () => deepEnrich
|
|
37784
37947
|
});
|
|
37785
|
-
import { readFile as readFile11, writeFile as writeFile11, readdir as readdir4, mkdir as mkdir8 } from "fs/promises";
|
|
37948
|
+
import { readFile as readFile11, writeFile as writeFile11, readdir as readdir4, mkdir as mkdir8, unlink as unlink2 } from "fs/promises";
|
|
37786
37949
|
import path113 from "path";
|
|
37787
37950
|
async function readFileSafe4(filePath) {
|
|
37788
37951
|
try {
|
|
@@ -38239,6 +38402,10 @@ async function runPhaseAiGraph(opts, ctx, docsDir) {
|
|
|
38239
38402
|
const g6 = buildG6Content(project, ctx.manifest);
|
|
38240
38403
|
await writeFile11(path113.join(docsDir, "graph-g6-multihop.md"), g6, "utf-8");
|
|
38241
38404
|
log.debug(`deep-enrich[${project}]: G6 multi-hop analysis written`);
|
|
38405
|
+
const g5Path = path113.join(docsDir, "graph-g5-scenarios.md");
|
|
38406
|
+
if (await pathExists(g5Path)) {
|
|
38407
|
+
return { g5Generated: true, g6Generated: g6HasEdges };
|
|
38408
|
+
}
|
|
38242
38409
|
let g5Generated = false;
|
|
38243
38410
|
if (ctx.moduleDocs.size < 2) {
|
|
38244
38411
|
log.warn(`deep-enrich[${project}]: Insufficient modules (${ctx.moduleDocs.size} < 2), skipping G5`);
|
|
@@ -38317,6 +38484,47 @@ async function runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags) {
|
|
|
38317
38484
|
}
|
|
38318
38485
|
log.debug(`deep-enrich[${project}]: Index incremental update complete`);
|
|
38319
38486
|
}
|
|
38487
|
+
function architectureDocPath(docsDir) {
|
|
38488
|
+
return path113.join(docsDir, "architecture.md");
|
|
38489
|
+
}
|
|
38490
|
+
async function existingComponentSlugs(docsDir, slugs) {
|
|
38491
|
+
const found = [];
|
|
38492
|
+
for (const slug of slugs) {
|
|
38493
|
+
try {
|
|
38494
|
+
assertSafeResourceName(slug);
|
|
38495
|
+
} catch {
|
|
38496
|
+
continue;
|
|
38497
|
+
}
|
|
38498
|
+
if (await pathExists(path113.join(docsDir, `${slug}.md`))) found.push(slug);
|
|
38499
|
+
}
|
|
38500
|
+
return found;
|
|
38501
|
+
}
|
|
38502
|
+
async function collectMissingAiDocs(docsDir, slugs) {
|
|
38503
|
+
const existing = new Set(await existingComponentSlugs(docsDir, slugs));
|
|
38504
|
+
return {
|
|
38505
|
+
missingComponents: slugs.filter((slug) => !existing.has(slug)),
|
|
38506
|
+
missingArchitecture: !await pathExists(architectureDocPath(docsDir))
|
|
38507
|
+
};
|
|
38508
|
+
}
|
|
38509
|
+
async function removeIfExists(filePath) {
|
|
38510
|
+
try {
|
|
38511
|
+
await unlink2(filePath);
|
|
38512
|
+
} catch (err) {
|
|
38513
|
+
if (err.code !== "ENOENT") throw err;
|
|
38514
|
+
}
|
|
38515
|
+
}
|
|
38516
|
+
async function invalidateStaleAiDocs(docsDir, slugs) {
|
|
38517
|
+
for (const slug of slugs) {
|
|
38518
|
+
try {
|
|
38519
|
+
assertSafeResourceName(slug);
|
|
38520
|
+
} catch {
|
|
38521
|
+
continue;
|
|
38522
|
+
}
|
|
38523
|
+
await removeIfExists(path113.join(docsDir, `${slug}.md`));
|
|
38524
|
+
}
|
|
38525
|
+
await removeIfExists(architectureDocPath(docsDir));
|
|
38526
|
+
await removeIfExists(path113.join(docsDir, "graph-g5-scenarios.md"));
|
|
38527
|
+
}
|
|
38320
38528
|
async function deepEnrich(opts) {
|
|
38321
38529
|
const { project, evidenceDir } = opts;
|
|
38322
38530
|
const docsDir = path113.join(evidenceDir, "docs");
|
|
@@ -38325,7 +38533,7 @@ async function deepEnrich(opts) {
|
|
|
38325
38533
|
let components = ctx.manifest.components ?? [];
|
|
38326
38534
|
if (components.length === 0) {
|
|
38327
38535
|
log.warn(`deep-enrich[${project}]: No components in _manifest.json, aborting`);
|
|
38328
|
-
return;
|
|
38536
|
+
return { project, complete: false, missingComponents: [], missingArchitecture: true };
|
|
38329
38537
|
}
|
|
38330
38538
|
if (opts.maxModules && components.length > opts.maxModules) {
|
|
38331
38539
|
log.info(`deep-enrich[${project}]: Limited to first ${opts.maxModules} components (${components.length} total)`);
|
|
@@ -38334,52 +38542,55 @@ async function deepEnrich(opts) {
|
|
|
38334
38542
|
}
|
|
38335
38543
|
const allSlugs = components.map((c) => c.slug);
|
|
38336
38544
|
const progress = await loadProgress(evidenceDir, project, allSlugs);
|
|
38337
|
-
|
|
38338
|
-
|
|
38339
|
-
|
|
38340
|
-
|
|
38341
|
-
|
|
38342
|
-
|
|
38343
|
-
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38347
|
-
|
|
38348
|
-
progress.componentsDone = [];
|
|
38349
|
-
progress.componentsPending = [...allSlugs];
|
|
38350
|
-
progress.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38351
|
-
await saveProgress(evidenceDir, progress);
|
|
38352
|
-
}
|
|
38545
|
+
const manifestTime = ctx.manifest.generatedAt;
|
|
38546
|
+
if (manifestTime && progress.startedAt < manifestTime) {
|
|
38547
|
+
log.info(
|
|
38548
|
+
`deep-enrich[${project}]: stale progress detected (manifest newer than progress.startedAt), invalidating AI docs`
|
|
38549
|
+
);
|
|
38550
|
+
await invalidateStaleAiDocs(docsDir, allSlugs);
|
|
38551
|
+
progress.phase = "pending";
|
|
38552
|
+
progress.componentsDone = [];
|
|
38553
|
+
progress.componentsPending = [...allSlugs];
|
|
38554
|
+
progress.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38555
|
+
await saveProgress(evidenceDir, progress);
|
|
38353
38556
|
}
|
|
38354
|
-
|
|
38557
|
+
const existing = await existingComponentSlugs(docsDir, allSlugs);
|
|
38558
|
+
progress.componentsDone = existing;
|
|
38559
|
+
progress.componentsPending = allSlugs.filter((slug) => !existing.includes(slug));
|
|
38560
|
+
if (progress.componentsPending.length > 0) {
|
|
38355
38561
|
progress.phase = "components";
|
|
38356
38562
|
await saveProgress(evidenceDir, progress);
|
|
38357
38563
|
await runPhaseComponents(opts, ctx, progress, docsDir);
|
|
38358
38564
|
}
|
|
38359
|
-
if (
|
|
38565
|
+
if (!await pathExists(architectureDocPath(docsDir))) {
|
|
38360
38566
|
progress.phase = "architecture";
|
|
38361
38567
|
await saveProgress(evidenceDir, progress);
|
|
38362
38568
|
await runPhaseArchitecture(opts, ctx, docsDir);
|
|
38363
38569
|
}
|
|
38364
|
-
|
|
38365
|
-
progress.phase = "graph";
|
|
38366
|
-
await saveProgress(evidenceDir, progress);
|
|
38367
|
-
await runPhaseGraph(opts, ctx, docsDir);
|
|
38368
|
-
}
|
|
38369
|
-
let graphFlags = { g5Generated: false, g6Generated: true };
|
|
38370
|
-
if (progress.phase === "graph" || progress.phase === "ai-graph") {
|
|
38371
|
-
progress.phase = "ai-graph";
|
|
38372
|
-
await saveProgress(evidenceDir, progress);
|
|
38373
|
-
graphFlags = await runPhaseAiGraph(opts, ctx, docsDir);
|
|
38374
|
-
}
|
|
38375
|
-
if (progress.phase === "ai-graph" || progress.phase === "index-enhance") {
|
|
38376
|
-
progress.phase = "index-enhance";
|
|
38377
|
-
await saveProgress(evidenceDir, progress);
|
|
38378
|
-
await runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags);
|
|
38379
|
-
}
|
|
38380
|
-
progress.phase = "done";
|
|
38570
|
+
progress.phase = "graph";
|
|
38381
38571
|
await saveProgress(evidenceDir, progress);
|
|
38382
|
-
|
|
38572
|
+
await runPhaseGraph(opts, ctx, docsDir);
|
|
38573
|
+
progress.phase = "ai-graph";
|
|
38574
|
+
await saveProgress(evidenceDir, progress);
|
|
38575
|
+
const graphFlags = await runPhaseAiGraph(opts, ctx, docsDir);
|
|
38576
|
+
progress.phase = "index-enhance";
|
|
38577
|
+
await saveProgress(evidenceDir, progress);
|
|
38578
|
+
await runPhaseIndexEnhance(opts, ctx, docsDir, graphFlags);
|
|
38579
|
+
const missing = await collectMissingAiDocs(docsDir, allSlugs);
|
|
38580
|
+
const complete = missing.missingComponents.length === 0 && !missing.missingArchitecture;
|
|
38581
|
+
progress.componentsDone = allSlugs.filter((slug) => !missing.missingComponents.includes(slug));
|
|
38582
|
+
progress.componentsPending = missing.missingComponents;
|
|
38583
|
+
progress.phase = complete ? "done" : missing.missingComponents.length > 0 ? "components" : "architecture";
|
|
38584
|
+
await saveProgress(evidenceDir, progress);
|
|
38585
|
+
if (complete) {
|
|
38586
|
+
log.success(`deep-enrich[${project}]: Deep knowledge generation complete`);
|
|
38587
|
+
} else {
|
|
38588
|
+
const missingComps = missing.missingComponents.join(", ") || "(none)";
|
|
38589
|
+
log.warn(
|
|
38590
|
+
`deep-enrich[${project}]: incomplete \u2014 missing component docs: ${missingComps}, architecture: ${missing.missingArchitecture}`
|
|
38591
|
+
);
|
|
38592
|
+
}
|
|
38593
|
+
return { project, complete, ...missing };
|
|
38383
38594
|
}
|
|
38384
38595
|
var PROGRESS_PATH_SUBDIR, PROGRESS_FILENAME, VALID_PHASES;
|
|
38385
38596
|
var init_deep_enrich = __esm({
|
|
@@ -40464,7 +40675,7 @@ async function codebaseCmd(opts) {
|
|
|
40464
40675
|
await printCodebaseStatus(opts);
|
|
40465
40676
|
return;
|
|
40466
40677
|
}
|
|
40467
|
-
if (!opts.lint && !opts.reconcile) {
|
|
40678
|
+
if (!opts.lint && !opts.reconcile && !opts.deepEnrich) {
|
|
40468
40679
|
console.log("teamai codebase \u2014 team codebase knowledge management");
|
|
40469
40680
|
console.log("");
|
|
40470
40681
|
console.log("Usage:");
|
|
@@ -40474,6 +40685,7 @@ async function codebaseCmd(opts) {
|
|
|
40474
40685
|
console.log(" teamai codebase --lint --json Output JSON report (for CI)");
|
|
40475
40686
|
console.log(" teamai codebase --lint --severity high Only report high-severity issues");
|
|
40476
40687
|
console.log(" teamai codebase --reconcile Reconcile product and code knowledge");
|
|
40688
|
+
console.log(" teamai codebase --deep-enrich Generate deep knowledge from extracted evidence");
|
|
40477
40689
|
console.log(" teamai codebase --status Show knowledge-base git baseline");
|
|
40478
40690
|
return;
|
|
40479
40691
|
}
|
|
@@ -40492,7 +40704,72 @@ async function codebaseCmd(opts) {
|
|
|
40492
40704
|
}
|
|
40493
40705
|
if (!await pathExists3(teamwikiDir)) {
|
|
40494
40706
|
console.log("No teamwiki found. Run `teamai import` first.");
|
|
40495
|
-
if (opts.reconcile) process.exitCode = 1;
|
|
40707
|
+
if (opts.reconcile || opts.deepEnrich) process.exitCode = 1;
|
|
40708
|
+
return;
|
|
40709
|
+
}
|
|
40710
|
+
if (opts.deepEnrich) {
|
|
40711
|
+
const project = opts.project?.trim() ?? "";
|
|
40712
|
+
if (!project) {
|
|
40713
|
+
console.log("Deep enrichment requires --project <slug>.");
|
|
40714
|
+
process.exitCode = 1;
|
|
40715
|
+
return;
|
|
40716
|
+
}
|
|
40717
|
+
const { assertWithinRoot: assertWithinRoot2 } = await Promise.resolve().then(() => (init_path_safety(), path_safety_exports));
|
|
40718
|
+
const codeRoot = path125.join(teamwikiDir, "evidence", "code");
|
|
40719
|
+
const evidenceDir = path125.join(codeRoot, project);
|
|
40720
|
+
try {
|
|
40721
|
+
assertWithinRoot2(codeRoot, evidenceDir);
|
|
40722
|
+
} catch (e) {
|
|
40723
|
+
console.log(e.message);
|
|
40724
|
+
process.exitCode = 1;
|
|
40725
|
+
return;
|
|
40726
|
+
}
|
|
40727
|
+
if (!await pathExists3(evidenceDir)) {
|
|
40728
|
+
console.log(`No extracted evidence found for project "${project}". Run \`teamai codebase --extract\` first.`);
|
|
40729
|
+
process.exitCode = 1;
|
|
40730
|
+
return;
|
|
40731
|
+
}
|
|
40732
|
+
let componentCount = 0;
|
|
40733
|
+
try {
|
|
40734
|
+
const manifest = JSON.parse(await readFile15(path125.join(evidenceDir, "_manifest.json"), "utf-8"));
|
|
40735
|
+
componentCount = Array.isArray(manifest.components) ? manifest.components.length : 0;
|
|
40736
|
+
} catch {
|
|
40737
|
+
componentCount = 0;
|
|
40738
|
+
}
|
|
40739
|
+
if (componentCount === 0) {
|
|
40740
|
+
console.log(`No components in evidence for project "${project}". Run \`teamai codebase --extract\` first.`);
|
|
40741
|
+
process.exitCode = 1;
|
|
40742
|
+
return;
|
|
40743
|
+
}
|
|
40744
|
+
if (opts.dryRun) {
|
|
40745
|
+
if (opts.json) {
|
|
40746
|
+
console.log(JSON.stringify({ project, evidenceDir, dryRun: true }, null, 2));
|
|
40747
|
+
} else {
|
|
40748
|
+
console.log(`Deep enrichment preview: project=${project} (no writes)`);
|
|
40749
|
+
}
|
|
40750
|
+
return;
|
|
40751
|
+
}
|
|
40752
|
+
const { deepEnrich: deepEnrich2 } = await Promise.resolve().then(() => (init_deep_enrich(), deep_enrich_exports));
|
|
40753
|
+
const result = await deepEnrich2({ project, evidenceDir, wikiRoot: teamwikiDir });
|
|
40754
|
+
if (opts.json) {
|
|
40755
|
+
console.log(JSON.stringify({
|
|
40756
|
+
project,
|
|
40757
|
+
evidenceDir,
|
|
40758
|
+
complete: result.complete,
|
|
40759
|
+
missingComponents: result.missingComponents,
|
|
40760
|
+
missingArchitecture: result.missingArchitecture
|
|
40761
|
+
}, null, 2));
|
|
40762
|
+
} else if (result.complete) {
|
|
40763
|
+
console.log(`Deep enrichment complete: project=${project}`);
|
|
40764
|
+
} else {
|
|
40765
|
+
const parts = [];
|
|
40766
|
+
if (result.missingComponents.length > 0) {
|
|
40767
|
+
parts.push(`missing component docs: ${result.missingComponents.join(", ")}`);
|
|
40768
|
+
}
|
|
40769
|
+
if (result.missingArchitecture) parts.push("missing architecture.md");
|
|
40770
|
+
console.log(`Deep enrichment incomplete: project=${project}, ${parts.join(", ")}`);
|
|
40771
|
+
}
|
|
40772
|
+
if (!result.complete) process.exitCode = 1;
|
|
40496
40773
|
return;
|
|
40497
40774
|
}
|
|
40498
40775
|
if (opts.reconcile) {
|
|
@@ -41699,10 +41976,10 @@ program.command("pull").description("Pull team resources and inject into local A
|
|
|
41699
41976
|
const { pull: pull2 } = await Promise.resolve().then(() => (init_pull(), pull_exports));
|
|
41700
41977
|
await pull2({ ...globalOpts, ...cmdOpts });
|
|
41701
41978
|
});
|
|
41702
|
-
program.command("status").description("Show local vs team repo diff").action(async () => {
|
|
41979
|
+
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
41980
|
const globalOpts = program.opts();
|
|
41704
41981
|
const { status: status2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
41705
|
-
await status2(globalOpts);
|
|
41982
|
+
await status2({ ...globalOpts, ...cmdOpts });
|
|
41706
41983
|
});
|
|
41707
41984
|
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
41985
|
const globalOpts = program.opts();
|
|
@@ -42087,7 +42364,7 @@ program.command("mr-hint", { hidden: true }).description("Hint AI about recently
|
|
|
42087
42364
|
await mrHint2();
|
|
42088
42365
|
}
|
|
42089
42366
|
});
|
|
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
|
|
42367
|
+
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
42368
|
const globalOpts = program.opts();
|
|
42092
42369
|
const { codebaseCmd: codebaseCmd2 } = await Promise.resolve().then(() => (init_codebase_cmd(), codebase_cmd_exports));
|
|
42093
42370
|
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. |
|