teamai-cli 0.20.0-beta.3 → 0.20.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +122 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -218,6 +218,7 @@ __export(types_exports, {
|
|
|
218
218
|
areTeamHooksDisabled: () => areTeamHooksDisabled,
|
|
219
219
|
emptyTokenUsage: () => emptyTokenUsage,
|
|
220
220
|
getConfigPath: () => getConfigPath,
|
|
221
|
+
getEnvBackupPath: () => getEnvBackupPath,
|
|
221
222
|
getHooksSharing: () => getHooksSharing,
|
|
222
223
|
getKnowledgeDir: () => getKnowledgeDir,
|
|
223
224
|
getManagedHooksPath: () => getManagedHooksPath,
|
|
@@ -313,6 +314,10 @@ function getTeamaiHome(scope, projectRoot) {
|
|
|
313
314
|
}
|
|
314
315
|
return path2.join(process.env.HOME ?? "", ".teamai");
|
|
315
316
|
}
|
|
317
|
+
function getEnvBackupPath(localConfig) {
|
|
318
|
+
const home = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
|
|
319
|
+
return path2.join(home, isSelfMode(localConfig) ? "env.local" : "env");
|
|
320
|
+
}
|
|
316
321
|
function getConfigPath(scope, projectRoot) {
|
|
317
322
|
return path2.join(getTeamaiHome(scope, projectRoot), "config.yaml");
|
|
318
323
|
}
|
|
@@ -8004,6 +8009,20 @@ var init_env = __esm({
|
|
|
8004
8009
|
* Compares local env/env.yaml against the committed version.
|
|
8005
8010
|
*/
|
|
8006
8011
|
async scanLocalForPush(_teamConfig, localConfig) {
|
|
8012
|
+
if (isSelfMode(localConfig) && localConfig.projectRoot) {
|
|
8013
|
+
const activeEnv = path25.join(localConfig.projectRoot, ".teamai", "env", "env.yaml");
|
|
8014
|
+
if (!await pathExists(activeEnv)) return [];
|
|
8015
|
+
const baseEnv = path25.join(localConfig.repo.localPath, "env", "env.yaml");
|
|
8016
|
+
if (await pathExists(baseEnv) && await fileContentEqual(activeEnv, baseEnv)) {
|
|
8017
|
+
return [];
|
|
8018
|
+
}
|
|
8019
|
+
return [{
|
|
8020
|
+
name: "env.yaml",
|
|
8021
|
+
type: "env",
|
|
8022
|
+
sourcePath: activeEnv,
|
|
8023
|
+
relativePath: "env/env.yaml"
|
|
8024
|
+
}];
|
|
8025
|
+
}
|
|
8007
8026
|
const envYamlPath = path25.join(localConfig.repo.localPath, "env", "env.yaml");
|
|
8008
8027
|
if (!await pathExists(envYamlPath)) return [];
|
|
8009
8028
|
const { execFile: execFile5 } = await import("child_process");
|
|
@@ -8036,7 +8055,15 @@ var init_env = __esm({
|
|
|
8036
8055
|
relativePath: "env/env.yaml"
|
|
8037
8056
|
}];
|
|
8038
8057
|
}
|
|
8039
|
-
async pushItem(
|
|
8058
|
+
async pushItem(item, _teamConfig, localConfig) {
|
|
8059
|
+
if (isSelfMode(localConfig)) {
|
|
8060
|
+
const dest = path25.join(localConfig.repo.localPath, "env", "env.yaml");
|
|
8061
|
+
if (item.sourcePath !== dest) {
|
|
8062
|
+
await ensureDir(path25.dirname(dest));
|
|
8063
|
+
const content = await readFileSafe(item.sourcePath);
|
|
8064
|
+
if (content !== null) await writeFile(dest, content);
|
|
8065
|
+
}
|
|
8066
|
+
}
|
|
8040
8067
|
}
|
|
8041
8068
|
/**
|
|
8042
8069
|
* Pull env variables: parse env.yaml, write env.sh, inject source line into shell profile.
|
|
@@ -8056,7 +8083,7 @@ var init_env = __esm({
|
|
|
8056
8083
|
const teamaiHome = getTeamaiHome(localConfig.scope, localConfig.projectRoot);
|
|
8057
8084
|
const backupLines = envConfig.variables.map((v) => `${v.key}=${v.value}`);
|
|
8058
8085
|
await ensureDir(teamaiHome);
|
|
8059
|
-
await writeFile(
|
|
8086
|
+
await writeFile(getEnvBackupPath(localConfig), backupLines.join("\n") + "\n");
|
|
8060
8087
|
const envShContent = this.generateEnvFile(envConfig.variables);
|
|
8061
8088
|
await writeFile(path25.join(teamaiHome, "env.sh"), envShContent);
|
|
8062
8089
|
const inject = teamConfig.sharing.env.injectShellProfile !== false;
|
|
@@ -8568,6 +8595,34 @@ var init_agents = __esm({
|
|
|
8568
8595
|
const teamAgentsDir = path28.join(localConfig.repo.localPath, "agents");
|
|
8569
8596
|
const tombstones = await this.readTombstones(localConfig);
|
|
8570
8597
|
const baseDir = resolveBaseDir(localConfig);
|
|
8598
|
+
const directItems = [];
|
|
8599
|
+
const directStems = /* @__PURE__ */ new Set();
|
|
8600
|
+
if (isSelfMode(localConfig) && localConfig.projectRoot) {
|
|
8601
|
+
const activeAgentsDir = path28.join(localConfig.projectRoot, ".teamai", "agents");
|
|
8602
|
+
if (await pathExists(activeAgentsDir)) {
|
|
8603
|
+
for (const file of await listFiles(activeAgentsDir)) {
|
|
8604
|
+
const isYaml = file.endsWith(".yaml");
|
|
8605
|
+
const isMd = file.endsWith(".md");
|
|
8606
|
+
if (!isYaml && !isMd) continue;
|
|
8607
|
+
const stem = file.replace(/\.(yaml|md)$/, "");
|
|
8608
|
+
if (tombstones.has(stem)) continue;
|
|
8609
|
+
if (BUILTIN_AGENT_NAMES.has(stem)) continue;
|
|
8610
|
+
const activePath = path28.join(activeAgentsDir, file);
|
|
8611
|
+
const basePath = path28.join(teamAgentsDir, file);
|
|
8612
|
+
const baseExists = await pathExists(basePath);
|
|
8613
|
+
if (baseExists && await fileContentEqual(activePath, basePath)) continue;
|
|
8614
|
+
directItems.push({
|
|
8615
|
+
name: stem,
|
|
8616
|
+
type: "agents",
|
|
8617
|
+
sourcePath: activePath,
|
|
8618
|
+
relativePath: `agents/${file}`,
|
|
8619
|
+
status: baseExists ? "modified" : "new",
|
|
8620
|
+
legacy: isMd
|
|
8621
|
+
});
|
|
8622
|
+
directStems.add(stem);
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8571
8626
|
const grouped = /* @__PURE__ */ new Map();
|
|
8572
8627
|
for (const [tool, toolPath] of Object.entries(teamConfig.toolPaths)) {
|
|
8573
8628
|
if (!toolPath.agents) continue;
|
|
@@ -8579,6 +8634,7 @@ var init_agents = __esm({
|
|
|
8579
8634
|
if (stem === null) continue;
|
|
8580
8635
|
if (tombstones.has(stem)) continue;
|
|
8581
8636
|
if (BUILTIN_AGENT_NAMES.has(stem)) continue;
|
|
8637
|
+
if (directStems.has(stem)) continue;
|
|
8582
8638
|
const filePath = path28.join(agentsDir, file);
|
|
8583
8639
|
let toolGroup = grouped.get(stem);
|
|
8584
8640
|
if (!toolGroup) {
|
|
@@ -8590,7 +8646,7 @@ var init_agents = __esm({
|
|
|
8590
8646
|
}
|
|
8591
8647
|
}
|
|
8592
8648
|
}
|
|
8593
|
-
const items = [];
|
|
8649
|
+
const items = [...directItems];
|
|
8594
8650
|
for (const [stem, toolFiles] of grouped) {
|
|
8595
8651
|
const teamYamlPath = path28.join(teamAgentsDir, `${stem}.yaml`);
|
|
8596
8652
|
const teamMdPath = path28.join(teamAgentsDir, `${stem}.md`);
|
|
@@ -8722,12 +8778,13 @@ var init_agents = __esm({
|
|
|
8722
8778
|
log.debug(`Wrote agent ${item.name} \u2192 team repo (YAML format)`);
|
|
8723
8779
|
return;
|
|
8724
8780
|
}
|
|
8725
|
-
const
|
|
8781
|
+
const ext = item.sourcePath.endsWith(".yaml") ? ".yaml" : ".md";
|
|
8782
|
+
const dest = path28.join(localConfig.repo.localPath, "agents", `${item.name}${ext}`);
|
|
8726
8783
|
if (item.sourcePath !== dest) {
|
|
8727
8784
|
await ensureDir(path28.dirname(dest));
|
|
8728
8785
|
await copyFile(item.sourcePath, dest);
|
|
8729
8786
|
}
|
|
8730
|
-
log.debug(`Copied agent ${item.name} \u2192 team repo (
|
|
8787
|
+
log.debug(`Copied agent ${item.name} \u2192 team repo (${ext} verbatim)`);
|
|
8731
8788
|
}
|
|
8732
8789
|
/**
|
|
8733
8790
|
* Pull an agent to every installed tool's agents/ directory.
|
|
@@ -10791,7 +10848,8 @@ __export(init_exports, {
|
|
|
10791
10848
|
promptForSelfModeAgents: () => promptForSelfModeAgents,
|
|
10792
10849
|
resolveInheritUserScope: () => resolveInheritUserScope,
|
|
10793
10850
|
resolveInitRepo: () => resolveInitRepo,
|
|
10794
|
-
resolveInitScope: () => resolveInitScope
|
|
10851
|
+
resolveInitScope: () => resolveInitScope,
|
|
10852
|
+
resolveSelfModeSelection: () => resolveSelfModeSelection
|
|
10795
10853
|
});
|
|
10796
10854
|
import YAML10 from "yaml";
|
|
10797
10855
|
import fs14 from "fs";
|
|
@@ -11052,8 +11110,14 @@ function buildSelfModeGitignore() {
|
|
|
11052
11110
|
".update-lock",
|
|
11053
11111
|
".reports-lock",
|
|
11054
11112
|
".bootstrap-lock",
|
|
11055
|
-
|
|
11113
|
+
// NB: env/ is intentionally NOT ignored in single-repo mode — team env vars
|
|
11114
|
+
// (.teamai/env/env.yaml) are committed to main so `teamai push` can carry them
|
|
11115
|
+
// and teammates get them on clone. env.yaml holds plaintext key/value pairs, so
|
|
11116
|
+
// only put non-secret config there; keep real secrets out of the repo.
|
|
11056
11117
|
"env.sh",
|
|
11118
|
+
// env.local is the machine-local KEY=value backup pull writes for ${VAR}
|
|
11119
|
+
// resolution (self mode uses this name to avoid colliding with the env/ dir).
|
|
11120
|
+
"env.local",
|
|
11057
11121
|
"usage.jsonl",
|
|
11058
11122
|
"known-skills.json",
|
|
11059
11123
|
"search-index.json",
|
|
@@ -11072,34 +11136,60 @@ function buildSelfModeGitignore() {
|
|
|
11072
11136
|
""
|
|
11073
11137
|
].join("\n");
|
|
11074
11138
|
}
|
|
11139
|
+
function resolveSelfModeSelection(indices, detected) {
|
|
11140
|
+
const out = [];
|
|
11141
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11142
|
+
const add = (id) => {
|
|
11143
|
+
if (id && !seen.has(id)) {
|
|
11144
|
+
seen.add(id);
|
|
11145
|
+
out.push(id);
|
|
11146
|
+
}
|
|
11147
|
+
};
|
|
11148
|
+
const pickedAuto = indices.includes(0);
|
|
11149
|
+
if (pickedAuto) {
|
|
11150
|
+
if (detected.length > 0) detected.forEach(add);
|
|
11151
|
+
else add("claude");
|
|
11152
|
+
}
|
|
11153
|
+
for (const i of indices) {
|
|
11154
|
+
if (i === 0) continue;
|
|
11155
|
+
const id = SELF_MODE_AGENT_CHOICES[i - 1];
|
|
11156
|
+
if (id) add(id);
|
|
11157
|
+
}
|
|
11158
|
+
return out;
|
|
11159
|
+
}
|
|
11075
11160
|
async function promptForSelfModeAgents(options) {
|
|
11076
11161
|
const explicit = normalizeAgentList(options.agent);
|
|
11077
11162
|
if (explicit.length > 0) return explicit;
|
|
11078
11163
|
if (options.silent || options.force || !process.stdin.isTTY) {
|
|
11079
11164
|
return detectHomeInstalledAgents();
|
|
11080
11165
|
}
|
|
11081
|
-
const
|
|
11166
|
+
const detected = await detectHomeInstalledAgents();
|
|
11167
|
+
const tools = SELF_MODE_AGENT_CHOICES.map((id) => {
|
|
11082
11168
|
const meta = KNOWN_AGENTS.find((a) => a.id === id);
|
|
11083
11169
|
const root = meta?.skillsPath.split("/")[0] ?? `.${id}`;
|
|
11084
11170
|
return { id, label: meta?.displayName ?? id, root };
|
|
11085
11171
|
});
|
|
11172
|
+
const detectedLabels = detected.map((id) => tools.find((t) => t.id === id)?.label ?? id).join(", ");
|
|
11173
|
+
const autoLabel = detected.length > 0 ? `Auto \u2014 the AI tools already installed here: ${detectedLabels}` : "Auto \u2014 none detected (will set up Claude Code)";
|
|
11086
11174
|
console.log("");
|
|
11087
11175
|
console.log("Which AI tools should teamai set up in this repo?");
|
|
11088
11176
|
console.log("(creates the skills dir, injects hooks, commits settings to main)");
|
|
11089
11177
|
console.log("");
|
|
11090
|
-
|
|
11091
|
-
|
|
11178
|
+
console.log(` 1. ${autoLabel}`);
|
|
11179
|
+
tools.forEach((t, i) => {
|
|
11180
|
+
console.log(` ${i + 2}. ${t.label} (${t.root})`);
|
|
11092
11181
|
});
|
|
11093
11182
|
console.log("");
|
|
11183
|
+
const optionCount = tools.length + 1;
|
|
11094
11184
|
const indices = await askSelection(
|
|
11095
|
-
`Select [1-${
|
|
11096
|
-
|
|
11185
|
+
`Select [1-${optionCount}, comma/range, or "all"] (default: 1 = Auto): `,
|
|
11186
|
+
optionCount,
|
|
11097
11187
|
false
|
|
11098
11188
|
);
|
|
11099
11189
|
if (!indices || indices.length === 0) {
|
|
11100
|
-
return [
|
|
11190
|
+
return resolveSelfModeSelection([0], detected);
|
|
11101
11191
|
}
|
|
11102
|
-
return indices
|
|
11192
|
+
return resolveSelfModeSelection(indices, detected);
|
|
11103
11193
|
}
|
|
11104
11194
|
async function initSelfRepo(options) {
|
|
11105
11195
|
log.info("Initializing teamai (single-repo mode)...");
|
|
@@ -11166,7 +11256,7 @@ async function initSelfRepo(options) {
|
|
|
11166
11256
|
return;
|
|
11167
11257
|
}
|
|
11168
11258
|
await ensureDir(localPath);
|
|
11169
|
-
for (const dir of ["skills", "rules", "docs", "learnings", "env"]) {
|
|
11259
|
+
for (const dir of ["skills", "rules", "docs", "learnings", "env", "agents", "hooks", "mcp"]) {
|
|
11170
11260
|
await ensureDir(path38.join(localPath, dir));
|
|
11171
11261
|
const gitkeep = path38.join(localPath, dir, ".gitkeep");
|
|
11172
11262
|
if (!await pathExists(gitkeep)) {
|
|
@@ -11243,6 +11333,10 @@ async function initSelfRepo(options) {
|
|
|
11243
11333
|
".teamai/rules",
|
|
11244
11334
|
".teamai/docs",
|
|
11245
11335
|
".teamai/learnings",
|
|
11336
|
+
".teamai/env",
|
|
11337
|
+
".teamai/agents",
|
|
11338
|
+
".teamai/hooks",
|
|
11339
|
+
".teamai/mcp",
|
|
11246
11340
|
".teamai/teamai.yaml",
|
|
11247
11341
|
".teamai/.gitignore"
|
|
11248
11342
|
];
|
|
@@ -11295,8 +11389,18 @@ async function initSelfRepo(options) {
|
|
|
11295
11389
|
} catch {
|
|
11296
11390
|
}
|
|
11297
11391
|
log.success("teamai initialized (single-repo mode)!");
|
|
11298
|
-
log.info("
|
|
11299
|
-
log.info("Add
|
|
11392
|
+
log.info("Next steps:");
|
|
11393
|
+
log.info(" 1. Add team resources by dropping them into .teamai/ (or author them in your AI tool as usual):");
|
|
11394
|
+
log.info(" .teamai/skills/ team skills");
|
|
11395
|
+
log.info(" .teamai/rules/ shared rules");
|
|
11396
|
+
log.info(" .teamai/agents/ subagent definitions (<name>.yaml)");
|
|
11397
|
+
log.info(" .teamai/env/env.yaml shared env vars \u2014 committed to main, so keep real secrets out");
|
|
11398
|
+
log.info(" 2. Run `teamai push` for the above \u2014 it scans .teamai/{skills,rules,agents,env} plus your AI tool dirs and opens a PR against your repo, without touching your working tree.");
|
|
11399
|
+
log.info(" 3. docs / hooks / mcp are edited directly and shipped with a normal commit \u2014 no push needed:");
|
|
11400
|
+
log.info(" .teamai/docs/ team docs");
|
|
11401
|
+
log.info(" .teamai/hooks/hooks.yaml team hooks");
|
|
11402
|
+
log.info(" .teamai/mcp/mcp.yaml shared MCP servers");
|
|
11403
|
+
log.info(" 4. Push your business repo (e.g. `git push -u origin HEAD`) so teammates get the .teamai/ knowledge and are auto-initialized on clone.");
|
|
11300
11404
|
closePrompt();
|
|
11301
11405
|
}
|
|
11302
11406
|
async function init(options) {
|
|
@@ -14229,7 +14333,7 @@ async function readManifest2(manifestPath) {
|
|
|
14229
14333
|
}
|
|
14230
14334
|
async function buildVarTable(localConfig) {
|
|
14231
14335
|
const table = {};
|
|
14232
|
-
const envFile =
|
|
14336
|
+
const envFile = getEnvBackupPath(localConfig);
|
|
14233
14337
|
const content = await readFileSafe(envFile);
|
|
14234
14338
|
if (content) {
|
|
14235
14339
|
for (const line of content.split("\n")) {
|