teamai-cli 0.22.0-beta.2 → 0.22.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +275 -168
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -221,7 +221,6 @@ __export(types_exports, {
|
|
|
221
221
|
TEAMAI_RECALL_RULES_START: () => TEAMAI_RECALL_RULES_START,
|
|
222
222
|
TEAMAI_RULES_END: () => TEAMAI_RULES_END,
|
|
223
223
|
TEAMAI_RULES_START: () => TEAMAI_RULES_START,
|
|
224
|
-
TEAMAI_SESSIONS_DIR: () => TEAMAI_SESSIONS_DIR,
|
|
225
224
|
TEAMAI_SOURCES_DIR: () => TEAMAI_SOURCES_DIR,
|
|
226
225
|
TEAMAI_STATE_PATH: () => TEAMAI_STATE_PATH,
|
|
227
226
|
TEAMAI_TOKEN_PATH: () => TEAMAI_TOKEN_PATH,
|
|
@@ -398,7 +397,7 @@ function getPushignorePath() {
|
|
|
398
397
|
function areTeamHooksDisabled() {
|
|
399
398
|
return process.env.TEAMAI_HOOKS_DISABLED === "1" || process.env.TEAMAI_HOOKS_DISABLED === "true";
|
|
400
399
|
}
|
|
401
|
-
var ToolPathsSchema, ScopeEnum, SharingConfigSchema, SourceConfigSchema, SOURCE_PULL_TTL_MS, TEAMAI_SOURCES_DIR, TeamaiConfigSchema, MemberConfigSchema, LocalConfigSchema, PendingPushItemSchema, PendingPushSchema, StateSchema, TEAMAI_HOME, TEAMAI_CONFIG_PATH, TEAMAI_STATE_PATH, TEAMAI_TOKEN_PATH, TEAMAI_UPDATE_LOCK_PATH, 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, TEAMAI_USAGE_PATH, TEAMAI_KNOWN_SKILLS_PATH, TEAMAI_PUSHIGNORE_PATH,
|
|
400
|
+
var ToolPathsSchema, ScopeEnum, SharingConfigSchema, SourceConfigSchema, SOURCE_PULL_TTL_MS, TEAMAI_SOURCES_DIR, TeamaiConfigSchema, MemberConfigSchema, LocalConfigSchema, PendingPushItemSchema, PendingPushSchema, StateSchema, TEAMAI_HOME, TEAMAI_CONFIG_PATH, TEAMAI_STATE_PATH, TEAMAI_TOKEN_PATH, TEAMAI_UPDATE_LOCK_PATH, 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, TEAMAI_USAGE_PATH, TEAMAI_KNOWN_SKILLS_PATH, TEAMAI_PUSHIGNORE_PATH, SESSION_LOGS_LOCAL_DIR, UsageEventSchema, DASHBOARD_EVENTS_DIR, DASHBOARD_EVENTS_PATH, 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, CONTRIBUTE_SESSIONS_DIR, SEARCH_INDEX_VERSION, LEARNINGS_LOCAL_DIR, SEARCH_INDEX_PATH, VOTES_LOCAL_DIR, CultureCompanySchema, CultureTeamSchema, CultureFrontmatterSchema, REPORTS_BRANCH, REPORTS_WORKTREE_DIRNAME, KNOWLEDGE_WORKTREE_DIRNAME, REPORTS_LOCK_FILENAME, BOOTSTRAP_LOCK_FILENAME;
|
|
402
401
|
var init_types = __esm({
|
|
403
402
|
"src/types.ts"() {
|
|
404
403
|
"use strict";
|
|
@@ -678,7 +677,6 @@ var init_types = __esm({
|
|
|
678
677
|
TEAMAI_USAGE_PATH = `${TEAMAI_HOME}/usage.jsonl`;
|
|
679
678
|
TEAMAI_KNOWN_SKILLS_PATH = `${TEAMAI_HOME}/known-skills.json`;
|
|
680
679
|
TEAMAI_PUSHIGNORE_PATH = `${TEAMAI_HOME}/pushignore`;
|
|
681
|
-
TEAMAI_SESSIONS_DIR = `${TEAMAI_HOME}/sessions`;
|
|
682
680
|
SESSION_LOGS_LOCAL_DIR = `${TEAMAI_HOME}/session-logs`;
|
|
683
681
|
UsageEventSchema = z.object({
|
|
684
682
|
skill: z.string().regex(SKILL_NAME_REGEX),
|
|
@@ -4842,6 +4840,59 @@ var init_path_safety = __esm({
|
|
|
4842
4840
|
}
|
|
4843
4841
|
});
|
|
4844
4842
|
|
|
4843
|
+
// src/utils/frontmatter.ts
|
|
4844
|
+
import matter2 from "gray-matter";
|
|
4845
|
+
function stripBom(text) {
|
|
4846
|
+
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
4847
|
+
}
|
|
4848
|
+
function isPlainRecord(value) {
|
|
4849
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
4850
|
+
const prototype = Object.getPrototypeOf(value);
|
|
4851
|
+
return prototype === Object.prototype || prototype === null;
|
|
4852
|
+
}
|
|
4853
|
+
function splitFrontmatter2(content) {
|
|
4854
|
+
const match = content.match(FRONTMATTER_BLOCK);
|
|
4855
|
+
if (!match) {
|
|
4856
|
+
return { data: {}, valid: false, body: stripBom(content), raw: "" };
|
|
4857
|
+
}
|
|
4858
|
+
const rawFull = match[0];
|
|
4859
|
+
const body = content.slice(rawFull.length);
|
|
4860
|
+
const raw = stripBom(rawFull);
|
|
4861
|
+
let data = {};
|
|
4862
|
+
let valid = false;
|
|
4863
|
+
try {
|
|
4864
|
+
const parsed = matter2(raw, {});
|
|
4865
|
+
if (!isPlainRecord(parsed.data)) {
|
|
4866
|
+
return { data: {}, valid: false, body, raw };
|
|
4867
|
+
}
|
|
4868
|
+
data = { ...parsed.data };
|
|
4869
|
+
valid = true;
|
|
4870
|
+
} catch {
|
|
4871
|
+
data = {};
|
|
4872
|
+
}
|
|
4873
|
+
return { data, valid, body, raw };
|
|
4874
|
+
}
|
|
4875
|
+
function parseFrontmatter(content) {
|
|
4876
|
+
const { data, body } = splitFrontmatter2(content);
|
|
4877
|
+
return { data, body };
|
|
4878
|
+
}
|
|
4879
|
+
function stripFrontmatter(content) {
|
|
4880
|
+
return splitFrontmatter2(content).body;
|
|
4881
|
+
}
|
|
4882
|
+
function hasFrontmatter(content) {
|
|
4883
|
+
return FRONTMATTER_BLOCK.test(content);
|
|
4884
|
+
}
|
|
4885
|
+
function stringifyFrontmatter(data, body) {
|
|
4886
|
+
return matter2.stringify(body, data);
|
|
4887
|
+
}
|
|
4888
|
+
var FRONTMATTER_BLOCK;
|
|
4889
|
+
var init_frontmatter = __esm({
|
|
4890
|
+
"src/utils/frontmatter.ts"() {
|
|
4891
|
+
"use strict";
|
|
4892
|
+
FRONTMATTER_BLOCK = /^?---[ \t]*\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/;
|
|
4893
|
+
}
|
|
4894
|
+
});
|
|
4895
|
+
|
|
4845
4896
|
// src/builtin-hooks.ts
|
|
4846
4897
|
import fs7 from "fs";
|
|
4847
4898
|
import path14 from "path";
|
|
@@ -8088,7 +8139,6 @@ import path25 from "path";
|
|
|
8088
8139
|
import { execFile as execFile2 } from "child_process";
|
|
8089
8140
|
import { promisify } from "util";
|
|
8090
8141
|
import fse4 from "fs-extra";
|
|
8091
|
-
import YAML5 from "yaml";
|
|
8092
8142
|
function isUnimplementedCommand(command) {
|
|
8093
8143
|
const type = command.type ?? "";
|
|
8094
8144
|
if (IMPLEMENTED_HOOK_COMMAND_TYPES.has(type)) return false;
|
|
@@ -9054,14 +9104,7 @@ async function findMarkdownFile(extractDir, preferredName) {
|
|
|
9054
9104
|
async function readFrontmatter(filePath) {
|
|
9055
9105
|
const content = await readFileSafe(filePath);
|
|
9056
9106
|
if (!content) return {};
|
|
9057
|
-
|
|
9058
|
-
if (!match) return {};
|
|
9059
|
-
try {
|
|
9060
|
-
const parsed = YAML5.parse(match[1]);
|
|
9061
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
9062
|
-
} catch {
|
|
9063
|
-
return {};
|
|
9064
|
-
}
|
|
9107
|
+
return parseFrontmatter(content).data;
|
|
9065
9108
|
}
|
|
9066
9109
|
async function resolveSkillDirName(skillRoot, slug) {
|
|
9067
9110
|
const fm = await readFrontmatter(path25.join(skillRoot, "SKILL.md"));
|
|
@@ -9879,6 +9922,7 @@ var init_local_agent = __esm({
|
|
|
9879
9922
|
"src/local-agent.ts"() {
|
|
9880
9923
|
"use strict";
|
|
9881
9924
|
init_logger();
|
|
9925
|
+
init_frontmatter();
|
|
9882
9926
|
init_fs();
|
|
9883
9927
|
init_base();
|
|
9884
9928
|
init_resources();
|
|
@@ -9938,7 +9982,7 @@ __export(source_exports, {
|
|
|
9938
9982
|
});
|
|
9939
9983
|
import path26 from "path";
|
|
9940
9984
|
import fse5 from "fs-extra";
|
|
9941
|
-
import
|
|
9985
|
+
import YAML5 from "yaml";
|
|
9942
9986
|
function getSourceDir(sourceName) {
|
|
9943
9987
|
assertSafeResourceName(sourceName);
|
|
9944
9988
|
return path26.join(getUserHome(), ".teamai", "sources", sourceName);
|
|
@@ -10034,12 +10078,12 @@ async function sourceAdd(repoUrl, options) {
|
|
|
10034
10078
|
log.error("Could not read teamai.yaml");
|
|
10035
10079
|
return;
|
|
10036
10080
|
}
|
|
10037
|
-
const raw =
|
|
10081
|
+
const raw = YAML5.parse(content);
|
|
10038
10082
|
if (!raw.sources) {
|
|
10039
10083
|
raw.sources = [];
|
|
10040
10084
|
}
|
|
10041
10085
|
raw.sources.push({ name, repo: repoUrl });
|
|
10042
|
-
await fse5.writeFile(yamlPath,
|
|
10086
|
+
await fse5.writeFile(yamlPath, YAML5.stringify(raw));
|
|
10043
10087
|
log.success(`Added source "${name}" (${repoUrl})`);
|
|
10044
10088
|
log.info("Run `teamai push` to share this change with your team.");
|
|
10045
10089
|
}
|
|
@@ -10061,9 +10105,9 @@ async function sourceRemove(name, options) {
|
|
|
10061
10105
|
log.error("Could not read teamai.yaml");
|
|
10062
10106
|
return;
|
|
10063
10107
|
}
|
|
10064
|
-
const raw =
|
|
10108
|
+
const raw = YAML5.parse(content);
|
|
10065
10109
|
raw.sources = (raw.sources ?? []).filter((s) => s.name !== name);
|
|
10066
|
-
await fse5.writeFile(yamlPath,
|
|
10110
|
+
await fse5.writeFile(yamlPath, YAML5.stringify(raw));
|
|
10067
10111
|
await cleanupSourceSkills(name, teamConfig, localConfig);
|
|
10068
10112
|
const sourceDir = getSourceDir(name);
|
|
10069
10113
|
if (await pathExists(sourceDir)) {
|
|
@@ -10301,16 +10345,10 @@ async function findSkillInRepo(skillsDir, skillName) {
|
|
|
10301
10345
|
async function extractSkillDescription(skillDir) {
|
|
10302
10346
|
const content = await readFileSafe(path26.join(skillDir, "SKILL.md"));
|
|
10303
10347
|
if (!content) return "";
|
|
10304
|
-
const
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
if (singleMatch) return singleMatch[1].trim();
|
|
10309
|
-
const multiMatch = frontmatter.match(/description:\s*>-?\s*\n([\s\S]*?)(?=\n\w|\n---)/);
|
|
10310
|
-
if (multiMatch) {
|
|
10311
|
-
return multiMatch[1].split("\n").map((l) => l.trim()).filter((l) => l).join(" ");
|
|
10312
|
-
}
|
|
10313
|
-
return "";
|
|
10348
|
+
const { data } = parseFrontmatter(content);
|
|
10349
|
+
const desc = data["description"];
|
|
10350
|
+
if (!desc) return "";
|
|
10351
|
+
return String(desc).replace(/\s+/g, " ").trim();
|
|
10314
10352
|
}
|
|
10315
10353
|
async function getLocalTeamSkillNames(teamConfig, localConfig) {
|
|
10316
10354
|
const handler = getHandler("skills");
|
|
@@ -10358,6 +10396,7 @@ var init_source = __esm({
|
|
|
10358
10396
|
"use strict";
|
|
10359
10397
|
init_config();
|
|
10360
10398
|
init_git2();
|
|
10399
|
+
init_frontmatter();
|
|
10361
10400
|
init_providers();
|
|
10362
10401
|
init_logger();
|
|
10363
10402
|
init_fs();
|
|
@@ -10372,41 +10411,38 @@ var init_source = __esm({
|
|
|
10372
10411
|
|
|
10373
10412
|
// src/resources/skills.ts
|
|
10374
10413
|
import path27 from "path";
|
|
10414
|
+
import YAML6 from "yaml";
|
|
10415
|
+
function appendFrontmatterFields(raw, fields) {
|
|
10416
|
+
const eol = raw.includes("\r\n") ? "\r\n" : "\n";
|
|
10417
|
+
const yaml = YAML6.stringify(fields).trimEnd().replace(/\n/g, eol);
|
|
10418
|
+
return raw.replace(
|
|
10419
|
+
/(\r?\n---[ \t]*)(\r?\n|$)$/,
|
|
10420
|
+
(_match, closing, trailing) => `${eol}${yaml}${closing}${trailing}`
|
|
10421
|
+
);
|
|
10422
|
+
}
|
|
10375
10423
|
async function ensureSkillFrontmatter(skillDir, skillName) {
|
|
10376
10424
|
const skillMdPath = path27.join(skillDir, SKILL_MD);
|
|
10377
10425
|
const content = await readFileSafe(skillMdPath);
|
|
10378
10426
|
if (!content) return false;
|
|
10379
|
-
const
|
|
10380
|
-
if (!
|
|
10381
|
-
const description = extractDescriptionFromContent(
|
|
10382
|
-
const
|
|
10383
|
-
name: ${skillName}
|
|
10384
|
-
description: ${description}
|
|
10385
|
-
---
|
|
10386
|
-
`;
|
|
10387
|
-
const newContent2 = frontmatter + (content.startsWith("\n") ? content : "\n" + content);
|
|
10427
|
+
const { data, body, raw, valid } = splitFrontmatter2(content);
|
|
10428
|
+
if (!raw) {
|
|
10429
|
+
const description = extractDescriptionFromContent(body, skillName);
|
|
10430
|
+
const newContent2 = stringifyFrontmatter({ name: skillName, description }, body);
|
|
10388
10431
|
await writeFile(skillMdPath, newContent2);
|
|
10389
10432
|
log.debug(`Injected YAML frontmatter into ${skillName}/SKILL.md`);
|
|
10390
10433
|
return true;
|
|
10391
10434
|
}
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10435
|
+
if (!valid) {
|
|
10436
|
+
log.warn(`Could not repair malformed frontmatter in ${skillName}/SKILL.md; leaving it unchanged`);
|
|
10437
|
+
return false;
|
|
10438
|
+
}
|
|
10439
|
+
const hasName = typeof data["name"] === "string" && String(data["name"]).trim() !== "";
|
|
10440
|
+
const hasDescription = typeof data["description"] === "string" && String(data["description"]).trim() !== "";
|
|
10396
10441
|
if (hasName && hasDescription) return false;
|
|
10397
|
-
const
|
|
10398
|
-
if (!hasName)
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
if (!hasDescription) {
|
|
10402
|
-
const restContent = content.slice(fmMatch[0].length);
|
|
10403
|
-
const description = extractDescriptionFromContent(restContent, skillName);
|
|
10404
|
-
lines.push(`description: ${description}`);
|
|
10405
|
-
}
|
|
10406
|
-
const newFrontmatter = `---
|
|
10407
|
-
${lines.join("\n")}
|
|
10408
|
-
---`;
|
|
10409
|
-
const newContent = content.replace(FRONTMATTER_REGEX, newFrontmatter);
|
|
10442
|
+
const missingFields = {};
|
|
10443
|
+
if (!hasName) missingFields.name = skillName;
|
|
10444
|
+
if (!hasDescription) missingFields.description = extractDescriptionFromContent(body, skillName);
|
|
10445
|
+
const newContent = appendFrontmatterFields(raw, missingFields) + body;
|
|
10410
10446
|
await writeFile(skillMdPath, newContent);
|
|
10411
10447
|
log.debug(`Added missing frontmatter fields to ${skillName}/SKILL.md`);
|
|
10412
10448
|
return true;
|
|
@@ -10486,7 +10522,7 @@ async function scanSkillsRecursively(dirPath) {
|
|
|
10486
10522
|
await walk2(dirPath);
|
|
10487
10523
|
return results;
|
|
10488
10524
|
}
|
|
10489
|
-
var CONTRIBUTORS_FILE, SKILL_MD,
|
|
10525
|
+
var CONTRIBUTORS_FILE, SKILL_MD, SkillsHandler;
|
|
10490
10526
|
var init_skills = __esm({
|
|
10491
10527
|
"src/resources/skills.ts"() {
|
|
10492
10528
|
"use strict";
|
|
@@ -10499,9 +10535,9 @@ var init_skills = __esm({
|
|
|
10499
10535
|
init_hermes_home();
|
|
10500
10536
|
init_roles();
|
|
10501
10537
|
init_path_safety();
|
|
10538
|
+
init_frontmatter();
|
|
10502
10539
|
CONTRIBUTORS_FILE = "CONTRIBUTORS";
|
|
10503
10540
|
SKILL_MD = "SKILL.md";
|
|
10504
|
-
FRONTMATTER_REGEX = /^---\n[\s\S]*?\n---/;
|
|
10505
10541
|
SkillsHandler = class extends ResourceHandler {
|
|
10506
10542
|
type = "skills";
|
|
10507
10543
|
/**
|
|
@@ -11404,7 +11440,7 @@ var init_env = __esm({
|
|
|
11404
11440
|
// src/resources/agent-format.ts
|
|
11405
11441
|
import path32 from "path";
|
|
11406
11442
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
11407
|
-
import
|
|
11443
|
+
import matter3 from "gray-matter";
|
|
11408
11444
|
import { stringify as stringifyToml, parse as parseToml } from "smol-toml";
|
|
11409
11445
|
function agentFileExtensionForTool(tool) {
|
|
11410
11446
|
switch (tool) {
|
|
@@ -11492,7 +11528,7 @@ function renderForCursor(spec) {
|
|
|
11492
11528
|
frontmatterData[key] = value;
|
|
11493
11529
|
}
|
|
11494
11530
|
}
|
|
11495
|
-
const content =
|
|
11531
|
+
const content = matter3.stringify(spec.instructions, frontmatterData);
|
|
11496
11532
|
return { ext: agentFileExtensionForTool("cursor"), content };
|
|
11497
11533
|
}
|
|
11498
11534
|
function renderForOpencode(spec) {
|
|
@@ -11509,7 +11545,7 @@ function renderForOpencode(spec) {
|
|
|
11509
11545
|
frontmatterData[key] = value;
|
|
11510
11546
|
}
|
|
11511
11547
|
}
|
|
11512
|
-
const content =
|
|
11548
|
+
const content = matter3.stringify(spec.instructions, frontmatterData);
|
|
11513
11549
|
return { ext: agentFileExtensionForTool("opencode"), content };
|
|
11514
11550
|
}
|
|
11515
11551
|
function renderMarkdownAgent(spec, extras) {
|
|
@@ -11528,7 +11564,7 @@ function renderMarkdownAgent(spec, extras) {
|
|
|
11528
11564
|
frontmatterData[key] = value;
|
|
11529
11565
|
}
|
|
11530
11566
|
}
|
|
11531
|
-
return
|
|
11567
|
+
return matter3.stringify(spec.instructions, frontmatterData);
|
|
11532
11568
|
}
|
|
11533
11569
|
function renderTomlAgent(spec, extras) {
|
|
11534
11570
|
const tomlData = {
|
|
@@ -11549,7 +11585,7 @@ function renderTomlAgent(spec, extras) {
|
|
|
11549
11585
|
function reverseFromClaude(filePath, content) {
|
|
11550
11586
|
let parsed;
|
|
11551
11587
|
try {
|
|
11552
|
-
parsed =
|
|
11588
|
+
parsed = matter3(content);
|
|
11553
11589
|
} catch (err) {
|
|
11554
11590
|
return { ok: false, reason: `parse error: ${err.message}` };
|
|
11555
11591
|
}
|
|
@@ -11613,7 +11649,7 @@ function reverseFromCodex(filePath, content) {
|
|
|
11613
11649
|
function reverseFromCursor(filePath, content) {
|
|
11614
11650
|
let parsed;
|
|
11615
11651
|
try {
|
|
11616
|
-
parsed =
|
|
11652
|
+
parsed = matter3(content);
|
|
11617
11653
|
} catch (err) {
|
|
11618
11654
|
return { ok: false, reason: `parse error: ${err.message}` };
|
|
11619
11655
|
}
|
|
@@ -11642,7 +11678,7 @@ function reverseFromCursor(filePath, content) {
|
|
|
11642
11678
|
function reverseFromOpencode(filePath, content) {
|
|
11643
11679
|
let parsed;
|
|
11644
11680
|
try {
|
|
11645
|
-
parsed =
|
|
11681
|
+
parsed = matter3(content);
|
|
11646
11682
|
} catch (err) {
|
|
11647
11683
|
return { ok: false, reason: `parse error: ${err.message}` };
|
|
11648
11684
|
}
|
|
@@ -12261,18 +12297,10 @@ async function extractSkillDescription2(skillDir) {
|
|
|
12261
12297
|
const skillMdPath = path35.join(skillDir, SKILL_MD2);
|
|
12262
12298
|
const content = await readFileSafe(skillMdPath);
|
|
12263
12299
|
if (!content) return "";
|
|
12264
|
-
const
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
if (descMatch) {
|
|
12269
|
-
return descMatch[1].split("\n").map((l) => l.trim()).filter((l) => l).join(" ");
|
|
12270
|
-
}
|
|
12271
|
-
const singleMatch = frontmatter.match(/description:\s*["']?(.+?)["']?\s*$/m);
|
|
12272
|
-
if (singleMatch) {
|
|
12273
|
-
return singleMatch[1].trim();
|
|
12274
|
-
}
|
|
12275
|
-
return "";
|
|
12300
|
+
const { data } = parseFrontmatter(content);
|
|
12301
|
+
const desc = data["description"];
|
|
12302
|
+
if (!desc) return "";
|
|
12303
|
+
return String(desc).replace(/\s+/g, " ").trim();
|
|
12276
12304
|
}
|
|
12277
12305
|
async function refreshMarketplace(repoPath) {
|
|
12278
12306
|
const marketplacePath = path35.join(repoPath, MARKETPLACE_PATH);
|
|
@@ -12351,6 +12379,7 @@ var init_marketplace = __esm({
|
|
|
12351
12379
|
"use strict";
|
|
12352
12380
|
init_fs();
|
|
12353
12381
|
init_logger();
|
|
12382
|
+
init_frontmatter();
|
|
12354
12383
|
MARKETPLACE_PATH = ".codebuddy-plugin/marketplace.json";
|
|
12355
12384
|
SKILL_MD2 = "SKILL.md";
|
|
12356
12385
|
}
|
|
@@ -15762,7 +15791,7 @@ __export(confidence_exports, {
|
|
|
15762
15791
|
writeBackConfidence: () => writeBackConfidence
|
|
15763
15792
|
});
|
|
15764
15793
|
import path46 from "path";
|
|
15765
|
-
import
|
|
15794
|
+
import matter4 from "gray-matter";
|
|
15766
15795
|
function computeConfidence(factors) {
|
|
15767
15796
|
const { recalledCount, upvotedCount, lastRecalledAt } = factors;
|
|
15768
15797
|
const base = Math.min(1, recalledCount * 0.1 + upvotedCount * 0.3);
|
|
@@ -15824,11 +15853,11 @@ async function writeBackConfidence(learningsDir, confidenceMap) {
|
|
|
15824
15853
|
const content = await readFileSafe(absPath);
|
|
15825
15854
|
if (!content) continue;
|
|
15826
15855
|
try {
|
|
15827
|
-
const { data, content: body } =
|
|
15856
|
+
const { data, content: body } = matter4(content);
|
|
15828
15857
|
const existingConf = typeof data.confidence === "number" ? data.confidence : void 0;
|
|
15829
15858
|
if (existingConf !== void 0 && Math.abs(existingConf - newConf) <= 0.05) continue;
|
|
15830
15859
|
data.confidence = newConf;
|
|
15831
|
-
const newContent =
|
|
15860
|
+
const newContent = matter4.stringify(body, data);
|
|
15832
15861
|
await writeFile(absPath, newContent);
|
|
15833
15862
|
updated++;
|
|
15834
15863
|
} catch {
|
|
@@ -15891,7 +15920,7 @@ __export(search_index_exports, {
|
|
|
15891
15920
|
wordSegments: () => wordSegments
|
|
15892
15921
|
});
|
|
15893
15922
|
import path47 from "path";
|
|
15894
|
-
import
|
|
15923
|
+
import matter5 from "gray-matter";
|
|
15895
15924
|
function getSearchIndexPath() {
|
|
15896
15925
|
return path47.join(getUserHome(), ".teamai", "search-index.json");
|
|
15897
15926
|
}
|
|
@@ -15945,7 +15974,7 @@ function inferDomain(frontmatterDomain, tags, filePath, type) {
|
|
|
15945
15974
|
function parseLearningDoc(content, filename) {
|
|
15946
15975
|
if (!content.trim()) return null;
|
|
15947
15976
|
try {
|
|
15948
|
-
const { data, content: body } =
|
|
15977
|
+
const { data, content: body } = matter5(content);
|
|
15949
15978
|
const meta = {
|
|
15950
15979
|
title: typeof data.title === "string" ? data.title : void 0,
|
|
15951
15980
|
author: typeof data.author === "string" ? data.author : void 0,
|
|
@@ -15974,8 +16003,8 @@ async function aggregateVotes(votesDir) {
|
|
|
15974
16003
|
const content = await readFileSafe(path47.join(votesDir, file));
|
|
15975
16004
|
if (!content) continue;
|
|
15976
16005
|
try {
|
|
15977
|
-
const
|
|
15978
|
-
const parsed =
|
|
16006
|
+
const YAML19 = (await import("yaml")).default;
|
|
16007
|
+
const parsed = YAML19.parse(content);
|
|
15979
16008
|
if (!parsed?.votes) continue;
|
|
15980
16009
|
if (parsed.version === 2) {
|
|
15981
16010
|
const votes = parsed.votes;
|
|
@@ -16039,7 +16068,7 @@ async function entryFromMdFile(absPath, filenameForId, type, voteCounts) {
|
|
|
16039
16068
|
const tags = meta.tags ?? [];
|
|
16040
16069
|
const rawFrontmatterDomain = (() => {
|
|
16041
16070
|
try {
|
|
16042
|
-
return
|
|
16071
|
+
return matter5(content).data["domain"];
|
|
16043
16072
|
} catch {
|
|
16044
16073
|
return void 0;
|
|
16045
16074
|
}
|
|
@@ -18164,7 +18193,7 @@ __export(pull_exports, {
|
|
|
18164
18193
|
});
|
|
18165
18194
|
import path54 from "path";
|
|
18166
18195
|
import fse10 from "fs-extra";
|
|
18167
|
-
import
|
|
18196
|
+
import matter6 from "gray-matter";
|
|
18168
18197
|
async function refreshTeamRepo(localConfig) {
|
|
18169
18198
|
if (localConfig.repo.kind === "http") {
|
|
18170
18199
|
const { resolveApiKey: resolveApiKey2 } = await Promise.resolve().then(() => (init_api_key(), api_key_exports));
|
|
@@ -18783,7 +18812,7 @@ async function pullForScope(localConfig, options, policy = {}) {
|
|
|
18783
18812
|
}
|
|
18784
18813
|
if (!options.silent && !options.dryRun) {
|
|
18785
18814
|
try {
|
|
18786
|
-
const
|
|
18815
|
+
const YAML19 = (await import("yaml")).default;
|
|
18787
18816
|
const { listFiles: listFiles2, readFileSafe: readFileSafe5 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
18788
18817
|
const { getRecommendations: getRecommendations2, displayRecommendations: displayRecommendations2 } = await Promise.resolve().then(() => (init_skill_recommend(), skill_recommend_exports));
|
|
18789
18818
|
let statsDir = path54.join(localConfig.repo.localPath, "stats");
|
|
@@ -18802,7 +18831,7 @@ async function pullForScope(localConfig, options, policy = {}) {
|
|
|
18802
18831
|
const content = await readFileSafe5(path54.join(statsDir, file));
|
|
18803
18832
|
if (!content) continue;
|
|
18804
18833
|
try {
|
|
18805
|
-
const parsed =
|
|
18834
|
+
const parsed = YAML19.parse(content);
|
|
18806
18835
|
if (parsed?.username && parsed?.skills) teamStats.push(parsed);
|
|
18807
18836
|
} catch {
|
|
18808
18837
|
}
|
|
@@ -18818,7 +18847,7 @@ async function pullForScope(localConfig, options, policy = {}) {
|
|
|
18818
18847
|
function compileCulture(raw) {
|
|
18819
18848
|
let parsed;
|
|
18820
18849
|
try {
|
|
18821
|
-
parsed =
|
|
18850
|
+
parsed = matter6(raw);
|
|
18822
18851
|
} catch {
|
|
18823
18852
|
return null;
|
|
18824
18853
|
}
|
|
@@ -19212,7 +19241,6 @@ var init_pull = __esm({
|
|
|
19212
19241
|
|
|
19213
19242
|
// src/agent-skills.ts
|
|
19214
19243
|
import path55 from "path";
|
|
19215
|
-
import YAML16 from "yaml";
|
|
19216
19244
|
async function buildClassifyContext(localConfig) {
|
|
19217
19245
|
const teamSkills = await collectTeamRepoSkills(localConfig.repo.localPath);
|
|
19218
19246
|
const sourceSkills = /* @__PURE__ */ new Map();
|
|
@@ -19308,16 +19336,8 @@ async function scanAgentSkills(agent, ctx) {
|
|
|
19308
19336
|
async function readSkillDescription(skillMdPath) {
|
|
19309
19337
|
const content = await readFileSafe(skillMdPath);
|
|
19310
19338
|
if (!content) return "";
|
|
19311
|
-
const
|
|
19312
|
-
|
|
19313
|
-
let parsed;
|
|
19314
|
-
try {
|
|
19315
|
-
parsed = YAML16.parse(fm[1]);
|
|
19316
|
-
} catch {
|
|
19317
|
-
return "";
|
|
19318
|
-
}
|
|
19319
|
-
if (!parsed || typeof parsed !== "object") return "";
|
|
19320
|
-
const desc = parsed.description;
|
|
19339
|
+
const { data } = parseFrontmatter(content);
|
|
19340
|
+
const desc = data["description"];
|
|
19321
19341
|
if (typeof desc !== "string") return "";
|
|
19322
19342
|
return desc.split("\n").map((l) => l.trim()).filter(Boolean).join(" ");
|
|
19323
19343
|
}
|
|
@@ -19325,7 +19345,6 @@ function truncate(text, max) {
|
|
|
19325
19345
|
if (text.length <= max) return text;
|
|
19326
19346
|
return text.slice(0, Math.max(0, max - 3)) + "...";
|
|
19327
19347
|
}
|
|
19328
|
-
var FRONTMATTER_REGEX2;
|
|
19329
19348
|
var init_agent_skills = __esm({
|
|
19330
19349
|
"src/agent-skills.ts"() {
|
|
19331
19350
|
"use strict";
|
|
@@ -19333,7 +19352,7 @@ var init_agent_skills = __esm({
|
|
|
19333
19352
|
init_known_agents();
|
|
19334
19353
|
init_builtin_skills();
|
|
19335
19354
|
init_home();
|
|
19336
|
-
|
|
19355
|
+
init_frontmatter();
|
|
19337
19356
|
}
|
|
19338
19357
|
});
|
|
19339
19358
|
|
|
@@ -19344,7 +19363,7 @@ __export(status_exports, {
|
|
|
19344
19363
|
status: () => status
|
|
19345
19364
|
});
|
|
19346
19365
|
import path56 from "path";
|
|
19347
|
-
import
|
|
19366
|
+
import YAML16 from "yaml";
|
|
19348
19367
|
async function status(options) {
|
|
19349
19368
|
const { localConfig, teamConfig } = await autoDetectInit();
|
|
19350
19369
|
const scopeLabel = localConfig.scope;
|
|
@@ -19389,7 +19408,7 @@ async function status(options) {
|
|
|
19389
19408
|
const envContent = await readFileSafe(envYamlPath);
|
|
19390
19409
|
if (envContent) {
|
|
19391
19410
|
try {
|
|
19392
|
-
const envData =
|
|
19411
|
+
const envData = YAML16.parse(envContent);
|
|
19393
19412
|
envCount = Array.isArray(envData?.variables) ? envData.variables.length : 0;
|
|
19394
19413
|
} catch {
|
|
19395
19414
|
}
|
|
@@ -19476,7 +19495,7 @@ async function printRepoSection(t, options, ctx) {
|
|
|
19476
19495
|
const envContent = await readFileSafe(envYamlPath);
|
|
19477
19496
|
if (envContent) {
|
|
19478
19497
|
try {
|
|
19479
|
-
const envData =
|
|
19498
|
+
const envData = YAML16.parse(envContent);
|
|
19480
19499
|
if (envData?.variables && envData.variables.length > 0) {
|
|
19481
19500
|
if (options.reveal) {
|
|
19482
19501
|
process.stderr.write("[warn] Env values will be shown in plaintext\n");
|
|
@@ -19821,14 +19840,14 @@ __export(members_exports, {
|
|
|
19821
19840
|
getMemberConfig: () => getMemberConfig,
|
|
19822
19841
|
listMembers: () => listMembers
|
|
19823
19842
|
});
|
|
19824
|
-
import
|
|
19843
|
+
import YAML17 from "yaml";
|
|
19825
19844
|
import path58 from "path";
|
|
19826
19845
|
async function getMemberConfig(repoPath, username) {
|
|
19827
19846
|
const memberPath = path58.join(repoPath, "members", `${username}.yaml`);
|
|
19828
19847
|
const content = await readFileSafe(memberPath);
|
|
19829
19848
|
if (!content) return null;
|
|
19830
19849
|
try {
|
|
19831
|
-
const raw =
|
|
19850
|
+
const raw = YAML17.parse(content);
|
|
19832
19851
|
return MemberConfigSchema.parse(raw);
|
|
19833
19852
|
} catch {
|
|
19834
19853
|
return null;
|
|
@@ -19860,7 +19879,7 @@ async function listMembers(options) {
|
|
|
19860
19879
|
const content = await readFileSafe(path58.join(membersDir, file));
|
|
19861
19880
|
if (!content) continue;
|
|
19862
19881
|
try {
|
|
19863
|
-
const raw =
|
|
19882
|
+
const raw = YAML17.parse(content);
|
|
19864
19883
|
const member = MemberConfigSchema.parse(raw);
|
|
19865
19884
|
const isSelf = member.username === localConfig.username;
|
|
19866
19885
|
const marker = isSelf ? " (you)" : "";
|
|
@@ -20232,7 +20251,7 @@ __export(roles_cmd_exports, {
|
|
|
20232
20251
|
rolesUpdate: () => rolesUpdate
|
|
20233
20252
|
});
|
|
20234
20253
|
import path60 from "path";
|
|
20235
|
-
import
|
|
20254
|
+
import YAML18 from "yaml";
|
|
20236
20255
|
function parseNamespaces(input) {
|
|
20237
20256
|
return input.split(",").map((s) => s.trim()).filter(Boolean);
|
|
20238
20257
|
}
|
|
@@ -20349,7 +20368,7 @@ async function rolesInit(options) {
|
|
|
20349
20368
|
};
|
|
20350
20369
|
if (options.dryRun) {
|
|
20351
20370
|
log.info("[dry-run] Would write manifest:");
|
|
20352
|
-
console.log(
|
|
20371
|
+
console.log(YAML18.stringify(manifest));
|
|
20353
20372
|
return;
|
|
20354
20373
|
}
|
|
20355
20374
|
const allNamespaces = [...new Set(roles.flatMap((r) => r.resources.skills))];
|
|
@@ -22936,6 +22955,42 @@ var init_dashboard = __esm({
|
|
|
22936
22955
|
});
|
|
22937
22956
|
|
|
22938
22957
|
// src/hook-dispatch.ts
|
|
22958
|
+
function asObject(value) {
|
|
22959
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22960
|
+
}
|
|
22961
|
+
function mergeHookOutputs(outputs) {
|
|
22962
|
+
if (outputs.length === 0) return null;
|
|
22963
|
+
if (outputs.length === 1) return outputs[0];
|
|
22964
|
+
let parsed;
|
|
22965
|
+
try {
|
|
22966
|
+
parsed = outputs.map((output) => {
|
|
22967
|
+
const value = asObject(JSON.parse(output));
|
|
22968
|
+
if (!value) throw new Error("Hook output is not an object");
|
|
22969
|
+
return value;
|
|
22970
|
+
});
|
|
22971
|
+
} catch {
|
|
22972
|
+
return outputs[0];
|
|
22973
|
+
}
|
|
22974
|
+
const followups = parsed.map((value) => value.followup_message);
|
|
22975
|
+
if (followups.every((value) => typeof value === "string")) {
|
|
22976
|
+
return JSON.stringify({ ...parsed[0], followup_message: followups.join("\n") });
|
|
22977
|
+
}
|
|
22978
|
+
const specificOutputs = parsed.map((value) => asObject(value.hookSpecificOutput));
|
|
22979
|
+
if (specificOutputs.every((value) => value !== null)) {
|
|
22980
|
+
const contexts = specificOutputs.map((value) => value.additionalContext);
|
|
22981
|
+
const eventNames = new Set(specificOutputs.map((value) => value.hookEventName).filter(Boolean));
|
|
22982
|
+
if (contexts.every((value) => typeof value === "string") && eventNames.size <= 1) {
|
|
22983
|
+
return JSON.stringify({
|
|
22984
|
+
...parsed[0],
|
|
22985
|
+
hookSpecificOutput: {
|
|
22986
|
+
...specificOutputs[0],
|
|
22987
|
+
additionalContext: contexts.join("\n")
|
|
22988
|
+
}
|
|
22989
|
+
});
|
|
22990
|
+
}
|
|
22991
|
+
}
|
|
22992
|
+
return outputs[0];
|
|
22993
|
+
}
|
|
22939
22994
|
function withTimeout2(promise, ms, handlerName) {
|
|
22940
22995
|
return new Promise((resolve, reject) => {
|
|
22941
22996
|
const timer = setTimeout(() => {
|
|
@@ -22971,7 +23026,7 @@ function createDispatcher(config) {
|
|
|
22971
23026
|
return withTimeout2(reg.handler.execute(stdin, tool), timeoutMs, reg.handler.name);
|
|
22972
23027
|
})
|
|
22973
23028
|
);
|
|
22974
|
-
|
|
23029
|
+
const outputs = [];
|
|
22975
23030
|
const errors = [];
|
|
22976
23031
|
for (let i = 0; i < settled.length; i++) {
|
|
22977
23032
|
const result = settled[i];
|
|
@@ -22982,12 +23037,10 @@ function createDispatcher(config) {
|
|
|
22982
23037
|
error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
|
|
22983
23038
|
});
|
|
22984
23039
|
} else if (result.status === "fulfilled" && result.value != null) {
|
|
22985
|
-
|
|
22986
|
-
output = result.value;
|
|
22987
|
-
}
|
|
23040
|
+
outputs.push(result.value);
|
|
22988
23041
|
}
|
|
22989
23042
|
}
|
|
22990
|
-
return { output, errors };
|
|
23043
|
+
return { output: mergeHookOutputs(outputs), errors };
|
|
22991
23044
|
}
|
|
22992
23045
|
};
|
|
22993
23046
|
}
|
|
@@ -23166,6 +23219,7 @@ var init_hook_output = __esm({
|
|
|
23166
23219
|
var contribute_check_exports = {};
|
|
23167
23220
|
__export(contribute_check_exports, {
|
|
23168
23221
|
applyPhase2Adjustments: () => applyPhase2Adjustments,
|
|
23222
|
+
claimVotesNudge: () => claimVotesNudge,
|
|
23169
23223
|
cleanupStaleSessions: () => cleanupStaleSessions,
|
|
23170
23224
|
computeSmartScore: () => computeSmartScore,
|
|
23171
23225
|
contributeCheck: () => contributeCheck,
|
|
@@ -23173,7 +23227,9 @@ __export(contribute_check_exports, {
|
|
|
23173
23227
|
hasGitCommitInSession: () => hasGitCommitInSession,
|
|
23174
23228
|
markContributed: () => markContributed,
|
|
23175
23229
|
readContributeState: () => readContributeState,
|
|
23230
|
+
stashVotesHint: () => stashVotesHint,
|
|
23176
23231
|
takePendingHint: () => takePendingHint,
|
|
23232
|
+
takePendingVotesHint: () => takePendingVotesHint,
|
|
23177
23233
|
writeContributeState: () => writeContributeState
|
|
23178
23234
|
});
|
|
23179
23235
|
import fs22 from "fs";
|
|
@@ -23210,6 +23266,22 @@ function getSessionPath(sessionId) {
|
|
|
23210
23266
|
`${sanitizeSessionId2(sessionId)}.json`
|
|
23211
23267
|
);
|
|
23212
23268
|
}
|
|
23269
|
+
function getPendingVotesHintPath(sessionId) {
|
|
23270
|
+
return path71.join(
|
|
23271
|
+
getUserHome(),
|
|
23272
|
+
".teamai",
|
|
23273
|
+
"sessions",
|
|
23274
|
+
`${sanitizeSessionId2(sessionId)}.votes-hint.json`
|
|
23275
|
+
);
|
|
23276
|
+
}
|
|
23277
|
+
function getVotesNudgeMarkerPath(sessionId) {
|
|
23278
|
+
return path71.join(
|
|
23279
|
+
getUserHome(),
|
|
23280
|
+
".teamai",
|
|
23281
|
+
"sessions",
|
|
23282
|
+
`${sanitizeSessionId2(sessionId)}.votes-nudged.json`
|
|
23283
|
+
);
|
|
23284
|
+
}
|
|
23213
23285
|
function defaultState() {
|
|
23214
23286
|
return {
|
|
23215
23287
|
contributed: false
|
|
@@ -23556,6 +23628,33 @@ async function contributeCheck(toolArg) {
|
|
|
23556
23628
|
process.stdout.write(formatStopHookOutput2(hint, toolArg ?? "claude"));
|
|
23557
23629
|
}
|
|
23558
23630
|
}
|
|
23631
|
+
async function stashVotesHint(sessionId, hintText) {
|
|
23632
|
+
try {
|
|
23633
|
+
await writeJsonAtomic(getPendingVotesHintPath(sessionId), { hintText });
|
|
23634
|
+
} catch (e) {
|
|
23635
|
+
log.error(`Failed to write pending votes hint: ${e.message}`);
|
|
23636
|
+
}
|
|
23637
|
+
}
|
|
23638
|
+
async function takePendingVotesHint(sessionId) {
|
|
23639
|
+
const sidecarPath = getPendingVotesHintPath(sessionId);
|
|
23640
|
+
const pending = await readJson(sidecarPath);
|
|
23641
|
+
if (!pending || typeof pending.hintText !== "string" || !pending.hintText) return null;
|
|
23642
|
+
await fs22.promises.unlink(sidecarPath).catch(() => void 0);
|
|
23643
|
+
return pending.hintText;
|
|
23644
|
+
}
|
|
23645
|
+
async function claimVotesNudge(sessionId) {
|
|
23646
|
+
const markerPath = getVotesNudgeMarkerPath(sessionId);
|
|
23647
|
+
try {
|
|
23648
|
+
await ensureDir(path71.dirname(markerPath));
|
|
23649
|
+
await fs22.promises.writeFile(markerPath, "{}\n", { encoding: "utf-8", flag: "wx" });
|
|
23650
|
+
await cleanupStaleSessions(path71.dirname(markerPath), sessionId).catch(() => void 0);
|
|
23651
|
+
return true;
|
|
23652
|
+
} catch (e) {
|
|
23653
|
+
if (e.code === "EEXIST") return false;
|
|
23654
|
+
log.error(`Failed to claim votes nudge: ${e.message}`);
|
|
23655
|
+
return false;
|
|
23656
|
+
}
|
|
23657
|
+
}
|
|
23559
23658
|
async function markContributed(sessionId) {
|
|
23560
23659
|
const state = await readContributeState(sessionId);
|
|
23561
23660
|
const updated = { ...state, contributed: true };
|
|
@@ -23604,18 +23703,19 @@ async function parseTranscriptForVotes(transcriptPath) {
|
|
|
23604
23703
|
const trimmed = line.trim();
|
|
23605
23704
|
if (!trimmed) continue;
|
|
23606
23705
|
extractRecalledDocIdsFromComment(trimmed, recalledSet);
|
|
23607
|
-
if (!trimmed.includes('"assistant"')) continue;
|
|
23608
23706
|
let entry;
|
|
23609
23707
|
try {
|
|
23610
23708
|
entry = JSON.parse(trimmed);
|
|
23611
23709
|
} catch {
|
|
23612
23710
|
continue;
|
|
23613
23711
|
}
|
|
23614
|
-
if (entry["type"] !== "assistant") continue;
|
|
23615
23712
|
const message = entry["message"];
|
|
23616
23713
|
if (!message || !Array.isArray(message["content"])) continue;
|
|
23617
23714
|
for (const block of message["content"]) {
|
|
23618
|
-
if (block["type"]
|
|
23715
|
+
if (block["type"] === "tool_result") {
|
|
23716
|
+
extractRecalledDocIdsFromValue(block["content"], recalledSet);
|
|
23717
|
+
}
|
|
23718
|
+
if (entry["type"] !== "assistant" || block["type"] !== "text") continue;
|
|
23619
23719
|
const text = block["text"];
|
|
23620
23720
|
if (typeof text !== "string") continue;
|
|
23621
23721
|
extractRecalledDocIds(text, recalledSet);
|
|
@@ -23631,7 +23731,7 @@ function isValidDocId(docId) {
|
|
|
23631
23731
|
return docId.length > 0 && !/[<>]/.test(docId) && docId !== "...";
|
|
23632
23732
|
}
|
|
23633
23733
|
function extractRecalledDocIdsFromComment(text, out) {
|
|
23634
|
-
const pattern =
|
|
23734
|
+
const pattern = /(?:<!--|<!—)\s*teamai:recalled-doc-ids:\s*\[([^\]]*)\]\s*(?:-->|—>)/gi;
|
|
23635
23735
|
let match;
|
|
23636
23736
|
while ((match = pattern.exec(text)) !== null) {
|
|
23637
23737
|
for (const item of match[1].split(",")) {
|
|
@@ -23640,6 +23740,22 @@ function extractRecalledDocIdsFromComment(text, out) {
|
|
|
23640
23740
|
}
|
|
23641
23741
|
}
|
|
23642
23742
|
}
|
|
23743
|
+
function extractRecalledDocIdsFromValue(value, out) {
|
|
23744
|
+
if (typeof value === "string") {
|
|
23745
|
+
extractRecalledDocIdsFromComment(value, out);
|
|
23746
|
+
extractRecalledDocIds(value, out);
|
|
23747
|
+
return;
|
|
23748
|
+
}
|
|
23749
|
+
if (Array.isArray(value)) {
|
|
23750
|
+
for (const item of value) extractRecalledDocIdsFromValue(item, out);
|
|
23751
|
+
return;
|
|
23752
|
+
}
|
|
23753
|
+
if (value !== null && typeof value === "object") {
|
|
23754
|
+
for (const item of Object.values(value)) {
|
|
23755
|
+
extractRecalledDocIdsFromValue(item, out);
|
|
23756
|
+
}
|
|
23757
|
+
}
|
|
23758
|
+
}
|
|
23643
23759
|
function extractRecalledDocIds(text, out) {
|
|
23644
23760
|
const START = "--- [teamai:recall:start] ---";
|
|
23645
23761
|
const END = "--- [teamai:recall:end] ---";
|
|
@@ -23662,7 +23778,7 @@ function extractRecalledDocIds(text, out) {
|
|
|
23662
23778
|
}
|
|
23663
23779
|
}
|
|
23664
23780
|
function extractReferencedDocIds(text, out) {
|
|
23665
|
-
const pattern =
|
|
23781
|
+
const pattern = /(?:<!--|<!—)\s*teamai:referenced-doc-ids:\s*\[([^\]]*)\]\s*(?:-->|—>)/gi;
|
|
23666
23782
|
let match;
|
|
23667
23783
|
while ((match = pattern.exec(text)) !== null) {
|
|
23668
23784
|
const raw = match[1];
|
|
@@ -24194,14 +24310,16 @@ var init_hook_handlers = __esm({
|
|
|
24194
24310
|
async execute(stdin, tool) {
|
|
24195
24311
|
const { STOP_STDOUT_UNSUPPORTED_TOOLS: STOP_STDOUT_UNSUPPORTED_TOOLS2 } = await Promise.resolve().then(() => (init_tool_names(), tool_names_exports));
|
|
24196
24312
|
if (!STOP_STDOUT_UNSUPPORTED_TOOLS2.has(tool)) return null;
|
|
24197
|
-
const { takePendingHint: takePendingHint2 } = await Promise.resolve().then(() => (init_contribute_check(), contribute_check_exports));
|
|
24313
|
+
const { takePendingHint: takePendingHint2, takePendingVotesHint: takePendingVotesHint2 } = await Promise.resolve().then(() => (init_contribute_check(), contribute_check_exports));
|
|
24198
24314
|
const sessionId = deriveSessionId(stdin, { includeCwd: true });
|
|
24199
24315
|
const hint = await takePendingHint2(sessionId);
|
|
24200
|
-
|
|
24316
|
+
const votesHint = await takePendingVotesHint2(sessionId);
|
|
24317
|
+
const combined = [hint, votesHint].filter(Boolean).join("\n");
|
|
24318
|
+
if (!combined) return null;
|
|
24201
24319
|
return JSON.stringify({
|
|
24202
24320
|
hookSpecificOutput: {
|
|
24203
24321
|
hookEventName: "UserPromptSubmit",
|
|
24204
|
-
additionalContext:
|
|
24322
|
+
additionalContext: combined
|
|
24205
24323
|
}
|
|
24206
24324
|
});
|
|
24207
24325
|
}
|
|
@@ -24218,11 +24336,13 @@ var init_hook_handlers = __esm({
|
|
|
24218
24336
|
const { autoDetectInit: autoDetectInit2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
24219
24337
|
const voteData = await parseTranscriptForVotes2(transcriptPath);
|
|
24220
24338
|
const { localConfig } = await autoDetectInit2();
|
|
24221
|
-
const { VOTES_LOCAL_DIR: VOTES_LOCAL_DIR2
|
|
24339
|
+
const { VOTES_LOCAL_DIR: VOTES_LOCAL_DIR2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
24222
24340
|
const votesDir = VOTES_LOCAL_DIR2;
|
|
24223
24341
|
const votePath = path75.join(votesDir, `${localConfig.username}.yaml`);
|
|
24224
|
-
|
|
24225
|
-
|
|
24342
|
+
const recalledSet = new Set(voteData.recalledDocIds);
|
|
24343
|
+
const verifiedDocIds = voteData.referencedDocIds.filter((id) => recalledSet.has(id));
|
|
24344
|
+
if (verifiedDocIds.length > 0) {
|
|
24345
|
+
await incrementUpvoted2(votePath, verifiedDocIds);
|
|
24226
24346
|
}
|
|
24227
24347
|
if (localConfig.repo.kind === "self") {
|
|
24228
24348
|
try {
|
|
@@ -24243,24 +24363,10 @@ var init_hook_handlers = __esm({
|
|
|
24243
24363
|
const declared = voteData.referencedDocIds;
|
|
24244
24364
|
let nudged = false;
|
|
24245
24365
|
if (recalled.length > 0 && declared.length === 0) {
|
|
24246
|
-
|
|
24247
|
-
|
|
24248
|
-
|
|
24249
|
-
|
|
24250
|
-
try {
|
|
24251
|
-
await fsp.access(marker);
|
|
24252
|
-
already = true;
|
|
24253
|
-
} catch {
|
|
24254
|
-
already = false;
|
|
24255
|
-
}
|
|
24256
|
-
if (!already) {
|
|
24257
|
-
try {
|
|
24258
|
-
const { ensureDir: ensureDir3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
24259
|
-
await ensureDir3(TEAMAI_SESSIONS_DIR2);
|
|
24260
|
-
await fsp.writeFile(marker, "");
|
|
24261
|
-
nudged = true;
|
|
24262
|
-
} catch {
|
|
24263
|
-
}
|
|
24366
|
+
nudged = true;
|
|
24367
|
+
if ((tool ?? "").toLowerCase() === "cursor") {
|
|
24368
|
+
const { claimVotesNudge: claimVotesNudge2 } = await Promise.resolve().then(() => (init_contribute_check(), contribute_check_exports));
|
|
24369
|
+
nudged = await claimVotesNudge2(sessionId);
|
|
24264
24370
|
}
|
|
24265
24371
|
}
|
|
24266
24372
|
if (process.env.TEAMAI_ADOPTION_EVAL_LOG) {
|
|
@@ -24281,7 +24387,13 @@ var init_hook_handlers = __esm({
|
|
|
24281
24387
|
}
|
|
24282
24388
|
if (nudged) {
|
|
24283
24389
|
const { formatStopHookOutput: formatStopHookOutput2 } = await Promise.resolve().then(() => (init_hook_output(), hook_output_exports));
|
|
24390
|
+
const { STOP_STDOUT_UNSUPPORTED_TOOLS: STOP_STDOUT_UNSUPPORTED_TOOLS2 } = await Promise.resolve().then(() => (init_tool_names(), tool_names_exports));
|
|
24284
24391
|
const msg = `\u4F60\u672C\u6B21\u901A\u8FC7 teamai \u53EC\u56DE\u4E86\u56E2\u961F\u77E5\u8BC6\uFF08\u5019\u9009 doc-id\uFF1A${recalled.join(", ")}\uFF09\u3002\u7ED3\u675F\u524D\u8BF7\u5728\u56DE\u590D\u672B\u5C3E\u58F0\u660E\u4F60\u5B9E\u9645\u7528\u5230\u7684\u6761\u76EE\uFF1A<!-- teamai:referenced-doc-ids: [\u7528\u5230\u7684doc-id] -->\uFF1B\u6CA1\u7528\u5230\u5C31\u7559\u7A7A []\u3002`;
|
|
24392
|
+
if (STOP_STDOUT_UNSUPPORTED_TOOLS2.has(tool ?? "")) {
|
|
24393
|
+
const { stashVotesHint: stashVotesHint2 } = await Promise.resolve().then(() => (init_contribute_check(), contribute_check_exports));
|
|
24394
|
+
await stashVotesHint2(sessionId, msg);
|
|
24395
|
+
return null;
|
|
24396
|
+
}
|
|
24285
24397
|
return formatStopHookOutput2(msg, tool ?? "claude");
|
|
24286
24398
|
}
|
|
24287
24399
|
} catch {
|
|
@@ -24973,7 +25085,7 @@ var init_graph_index_schema = __esm({
|
|
|
24973
25085
|
// src/code-knowledge-recall.ts
|
|
24974
25086
|
import { readFile as readFile4, readdir } from "fs/promises";
|
|
24975
25087
|
import path79 from "path";
|
|
24976
|
-
import
|
|
25088
|
+
import matter7 from "gray-matter";
|
|
24977
25089
|
function countOccurrences(text, token) {
|
|
24978
25090
|
let count = 0;
|
|
24979
25091
|
let idx = 0;
|
|
@@ -25225,7 +25337,7 @@ async function loadPagesRecursive(dir, relativePath, pages, depth, currentDepth
|
|
|
25225
25337
|
let title;
|
|
25226
25338
|
let sources;
|
|
25227
25339
|
try {
|
|
25228
|
-
const { data } =
|
|
25340
|
+
const { data } = matter7(content);
|
|
25229
25341
|
title = typeof data.title === "string" && data.title.trim() ? data.title.trim() : entry.name.replace(".md", "");
|
|
25230
25342
|
const raw = data.source;
|
|
25231
25343
|
if (Array.isArray(raw)) {
|
|
@@ -27333,7 +27445,7 @@ var init_mr_fetch4 = __esm({
|
|
|
27333
27445
|
// src/utils/dedup.ts
|
|
27334
27446
|
import fs29 from "fs/promises";
|
|
27335
27447
|
import path85 from "path";
|
|
27336
|
-
import
|
|
27448
|
+
import matter8 from "gray-matter";
|
|
27337
27449
|
function extractKeywords(text) {
|
|
27338
27450
|
const keywords = /* @__PURE__ */ new Set();
|
|
27339
27451
|
const enWords = text.match(/[a-zA-Z]+/g) ?? [];
|
|
@@ -27397,7 +27509,7 @@ async function findSupersededLearnings(draftKeywords, learningsDir, withinDays =
|
|
|
27397
27509
|
continue;
|
|
27398
27510
|
}
|
|
27399
27511
|
const raw = await fs29.readFile(filePath, "utf8");
|
|
27400
|
-
const { content: body } =
|
|
27512
|
+
const { content: body } = matter8(raw);
|
|
27401
27513
|
const fileKeywords = extractKeywords(body);
|
|
27402
27514
|
const ratio = overlapRatio(draftKeywords, fileKeywords);
|
|
27403
27515
|
if (ratio >= 0.6) {
|
|
@@ -27474,7 +27586,7 @@ var init_dedup = __esm({
|
|
|
27474
27586
|
import fs30 from "fs/promises";
|
|
27475
27587
|
import path86 from "path";
|
|
27476
27588
|
import readline5 from "readline/promises";
|
|
27477
|
-
import
|
|
27589
|
+
import matter9 from "gray-matter";
|
|
27478
27590
|
async function fetchMR(url) {
|
|
27479
27591
|
if (url.includes("github.com")) {
|
|
27480
27592
|
return fetchGitHubPR(url);
|
|
@@ -27543,7 +27655,7 @@ function parseLearningDraft(raw) {
|
|
|
27543
27655
|
content = content.slice(frontmatterStart);
|
|
27544
27656
|
}
|
|
27545
27657
|
try {
|
|
27546
|
-
const parsed =
|
|
27658
|
+
const parsed = matter9(content);
|
|
27547
27659
|
return { content, data: parsed.data };
|
|
27548
27660
|
} catch (err) {
|
|
27549
27661
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -27664,7 +27776,7 @@ var init_import_mr = __esm({
|
|
|
27664
27776
|
import { execSync as execSync6 } from "child_process";
|
|
27665
27777
|
import fs31 from "fs";
|
|
27666
27778
|
import path87 from "path";
|
|
27667
|
-
import
|
|
27779
|
+
import matter10 from "gray-matter";
|
|
27668
27780
|
async function gatherRepoContext(repoPath) {
|
|
27669
27781
|
const parts = [];
|
|
27670
27782
|
try {
|
|
@@ -27790,7 +27902,7 @@ ${lines.join("\n")}`);
|
|
|
27790
27902
|
try {
|
|
27791
27903
|
const filePath = path87.join(learningsDir, entry);
|
|
27792
27904
|
const raw = fs31.readFileSync(filePath, "utf-8");
|
|
27793
|
-
const parsed =
|
|
27905
|
+
const parsed = matter10(raw);
|
|
27794
27906
|
const tags = parsed.data["tags"];
|
|
27795
27907
|
if (Array.isArray(tags)) {
|
|
27796
27908
|
for (const tag of tags) {
|
|
@@ -27830,15 +27942,7 @@ function buildFrontmatter(repoPath) {
|
|
|
27830
27942
|
].join("\n");
|
|
27831
27943
|
}
|
|
27832
27944
|
function stripExistingFrontmatter(md) {
|
|
27833
|
-
|
|
27834
|
-
return md;
|
|
27835
|
-
}
|
|
27836
|
-
const secondDash = md.indexOf("\n---\n", 4);
|
|
27837
|
-
if (secondDash === -1) {
|
|
27838
|
-
return md;
|
|
27839
|
-
}
|
|
27840
|
-
const afterFrontmatter = md.slice(secondDash + 5);
|
|
27841
|
-
return afterFrontmatter.replace(/^\n+/, "");
|
|
27945
|
+
return stripFrontmatter(md);
|
|
27842
27946
|
}
|
|
27843
27947
|
async function generateCodebaseMd(opts) {
|
|
27844
27948
|
const { repoPath, existingCodebaseMd, learningsSuggestions, learningsDir } = opts;
|
|
@@ -27968,6 +28072,7 @@ var init_codebase = __esm({
|
|
|
27968
28072
|
"use strict";
|
|
27969
28073
|
init_ai_client();
|
|
27970
28074
|
init_git2();
|
|
28075
|
+
init_frontmatter();
|
|
27971
28076
|
init_logger();
|
|
27972
28077
|
FILE_TREE_MAX_CHARS = 5e3;
|
|
27973
28078
|
DOC_MAX_CHARS = 2e3;
|
|
@@ -33032,14 +33137,14 @@ async function importFromRepo(opts) {
|
|
|
33032
33137
|
if (codebaseMd) {
|
|
33033
33138
|
const overviewPath = path101.join(evidenceDest, "overview.md");
|
|
33034
33139
|
const existing = await fs35.readFile(overviewPath, "utf8").catch(() => "");
|
|
33035
|
-
const aiNarrative = codebaseMd
|
|
33140
|
+
const aiNarrative = stripFrontmatter(codebaseMd);
|
|
33036
33141
|
const marker = "## AI Architecture Narrative";
|
|
33037
33142
|
const oldMarker = "## AI \u67B6\u6784\u53D9\u4E8B";
|
|
33038
33143
|
let markerIdx = existing.indexOf(marker);
|
|
33039
33144
|
if (markerIdx < 0) markerIdx = existing.indexOf(oldMarker);
|
|
33040
33145
|
const base = markerIdx >= 0 ? existing.slice(0, markerIdx).trimEnd() : existing.trimEnd();
|
|
33041
33146
|
let combined;
|
|
33042
|
-
if (!base || !base
|
|
33147
|
+
if (!base || !hasFrontmatter(base)) {
|
|
33043
33148
|
combined = `---
|
|
33044
33149
|
title: ${slug} overview
|
|
33045
33150
|
domain: code-knowledge
|
|
@@ -33175,6 +33280,7 @@ var init_import_repo = __esm({
|
|
|
33175
33280
|
init_repo_cache();
|
|
33176
33281
|
init_cache_index();
|
|
33177
33282
|
init_logger();
|
|
33283
|
+
init_frontmatter();
|
|
33178
33284
|
}
|
|
33179
33285
|
});
|
|
33180
33286
|
|
|
@@ -34261,7 +34367,7 @@ __export(codebase_upgrade_wiki_exports, {
|
|
|
34261
34367
|
import { readdir as readdir7, readFile as readFile13 } from "fs/promises";
|
|
34262
34368
|
import path108 from "path";
|
|
34263
34369
|
import chalk5 from "chalk";
|
|
34264
|
-
import
|
|
34370
|
+
import matter11 from "gray-matter";
|
|
34265
34371
|
async function upgradeCodebaseWiki(opts) {
|
|
34266
34372
|
const teamCodebaseDir = path108.join(opts.cwd, "docs", "team-codebase", "repos");
|
|
34267
34373
|
if (!await pathExists(teamCodebaseDir)) {
|
|
@@ -34291,7 +34397,7 @@ async function upgradeCodebaseWiki(opts) {
|
|
|
34291
34397
|
const filePath = path108.join(teamCodebaseDir, file);
|
|
34292
34398
|
try {
|
|
34293
34399
|
const content = await readFile13(filePath, "utf-8");
|
|
34294
|
-
const parsed =
|
|
34400
|
+
const parsed = matter11(content);
|
|
34295
34401
|
const source = parsed.data["source"] ?? parsed.data["repo_url"];
|
|
34296
34402
|
if (!source) {
|
|
34297
34403
|
result.skipped.push(`${slug}: \u65E0 source/repo_url \u5B57\u6BB5`);
|
|
@@ -34727,6 +34833,7 @@ function escapeRegex(str) {
|
|
|
34727
34833
|
var init_section_patcher = __esm({
|
|
34728
34834
|
"src/section-patcher.ts"() {
|
|
34729
34835
|
"use strict";
|
|
34836
|
+
init_frontmatter();
|
|
34730
34837
|
}
|
|
34731
34838
|
});
|
|
34732
34839
|
|
|
@@ -35691,7 +35798,7 @@ var init_extract_mr = __esm({
|
|
|
35691
35798
|
|
|
35692
35799
|
// src/maintenance/prune.ts
|
|
35693
35800
|
import path113 from "path";
|
|
35694
|
-
import
|
|
35801
|
+
import matter12 from "gray-matter";
|
|
35695
35802
|
async function findPruneCandidates(learningsDir, votesDir, options = {}) {
|
|
35696
35803
|
const threshold = options.threshold ?? DEFAULT_THRESHOLD;
|
|
35697
35804
|
const confidenceMap = await computeAllConfidence(votesDir);
|
|
@@ -35706,7 +35813,7 @@ async function findPruneCandidates(learningsDir, votesDir, options = {}) {
|
|
|
35706
35813
|
if (!content) continue;
|
|
35707
35814
|
let date = "";
|
|
35708
35815
|
try {
|
|
35709
|
-
const { data } =
|
|
35816
|
+
const { data } = matter12(content);
|
|
35710
35817
|
date = typeof data.date === "string" ? data.date : "";
|
|
35711
35818
|
} catch {
|
|
35712
35819
|
continue;
|
|
@@ -35912,7 +36019,7 @@ var init_quality_update = __esm({
|
|
|
35912
36019
|
|
|
35913
36020
|
// src/maintenance/promote.ts
|
|
35914
36021
|
import path115 from "path";
|
|
35915
|
-
import
|
|
36022
|
+
import matter13 from "gray-matter";
|
|
35916
36023
|
async function findPromotionCandidates(learningsDir, votesDir) {
|
|
35917
36024
|
const confidenceMap = await computeAllConfidence(votesDir);
|
|
35918
36025
|
const candidates = [];
|
|
@@ -35934,7 +36041,7 @@ async function findPromotionCandidates(learningsDir, votesDir) {
|
|
|
35934
36041
|
let title = docId;
|
|
35935
36042
|
let date = "";
|
|
35936
36043
|
try {
|
|
35937
|
-
const { data } =
|
|
36044
|
+
const { data } = matter13(content);
|
|
35938
36045
|
title = typeof data.title === "string" ? data.title : docId;
|
|
35939
36046
|
date = typeof data.date === "string" ? data.date : "";
|
|
35940
36047
|
if (data.promoted_to) continue;
|
|
@@ -36014,9 +36121,9 @@ async function executePromotion(candidate, repoPath, options = {}) {
|
|
|
36014
36121
|
}
|
|
36015
36122
|
const promotedContent = await generatePromotedContent(originalContent, category, candidate.title);
|
|
36016
36123
|
await writeFile(targetPath, promotedContent);
|
|
36017
|
-
const { data, content: body } =
|
|
36124
|
+
const { data, content: body } = matter13(originalContent);
|
|
36018
36125
|
data.promoted_to = `${category}/${candidate.filename}`;
|
|
36019
|
-
const updated =
|
|
36126
|
+
const updated = matter13.stringify(body, data);
|
|
36020
36127
|
await writeFile(candidate.path, updated);
|
|
36021
36128
|
log.success(`Promoted: ${candidate.docId} -> ${category}/${candidate.filename}`);
|
|
36022
36129
|
return targetPath;
|