teamai-cli 0.20.0-beta.4 → 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.
Files changed (2) hide show
  1. package/dist/index.js +87 -10
  2. 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(_item, _teamConfig, _localConfig) {
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(path25.join(teamaiHome, "env"), backupLines.join("\n") + "\n");
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 dest = path28.join(localConfig.repo.localPath, "agents", `${item.name}.md`);
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 (legacy MD format)`);
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.
@@ -11053,8 +11110,14 @@ function buildSelfModeGitignore() {
11053
11110
  ".update-lock",
11054
11111
  ".reports-lock",
11055
11112
  ".bootstrap-lock",
11056
- "env",
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.
11057
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",
11058
11121
  "usage.jsonl",
11059
11122
  "known-skills.json",
11060
11123
  "search-index.json",
@@ -11193,7 +11256,7 @@ async function initSelfRepo(options) {
11193
11256
  return;
11194
11257
  }
11195
11258
  await ensureDir(localPath);
11196
- for (const dir of ["skills", "rules", "docs", "learnings", "env"]) {
11259
+ for (const dir of ["skills", "rules", "docs", "learnings", "env", "agents", "hooks", "mcp"]) {
11197
11260
  await ensureDir(path38.join(localPath, dir));
11198
11261
  const gitkeep = path38.join(localPath, dir, ".gitkeep");
11199
11262
  if (!await pathExists(gitkeep)) {
@@ -11270,6 +11333,10 @@ async function initSelfRepo(options) {
11270
11333
  ".teamai/rules",
11271
11334
  ".teamai/docs",
11272
11335
  ".teamai/learnings",
11336
+ ".teamai/env",
11337
+ ".teamai/agents",
11338
+ ".teamai/hooks",
11339
+ ".teamai/mcp",
11273
11340
  ".teamai/teamai.yaml",
11274
11341
  ".teamai/.gitignore"
11275
11342
  ];
@@ -11322,8 +11389,18 @@ async function initSelfRepo(options) {
11322
11389
  } catch {
11323
11390
  }
11324
11391
  log.success("teamai initialized (single-repo mode)!");
11325
- log.info("Push your business repo (e.g. `git push -u origin HEAD`) so teammates get the .teamai/ knowledge and are auto-initialized on clone.");
11326
- log.info("Add skills/rules later with `teamai push` \u2014 it opens a PR against your repo without touching your working tree.");
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.");
11327
11404
  closePrompt();
11328
11405
  }
11329
11406
  async function init(options) {
@@ -14256,7 +14333,7 @@ async function readManifest2(manifestPath) {
14256
14333
  }
14257
14334
  async function buildVarTable(localConfig) {
14258
14335
  const table = {};
14259
- const envFile = path47.join(getTeamaiHome(localConfig.scope, localConfig.projectRoot), "env");
14336
+ const envFile = getEnvBackupPath(localConfig);
14260
14337
  const content = await readFileSafe(envFile);
14261
14338
  if (content) {
14262
14339
  for (const line of content.split("\n")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamai-cli",
3
- "version": "0.20.0-beta.4",
3
+ "version": "0.20.0-beta.5",
4
4
  "description": "TeamAI — the team harness for AI agents (skill sync + shared knowledge base, powered by Git)",
5
5
  "type": "module",
6
6
  "bin": {