@teammates/cli 0.2.3 → 0.2.4

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.
@@ -114,8 +114,9 @@ export class CliProxyAdapter {
114
114
  // Create session file inside .teammates/.tmp so sandboxed agents can access it
115
115
  if (!this.sessionsDir) {
116
116
  const tmpBase = join(teammate.cwd ?? process.cwd(), ".teammates", ".tmp");
117
- this.sessionsDir = join(tmpBase, "sessions");
118
- await mkdir(this.sessionsDir, { recursive: true });
117
+ const dir = join(tmpBase, "sessions");
118
+ await mkdir(dir, { recursive: true });
119
+ this.sessionsDir = dir;
119
120
  // Ensure .tmp is gitignored
120
121
  const gitignorePath = join(tmpBase, "..", ".gitignore");
121
122
  const existing = await readFile(gitignorePath, "utf-8").catch(() => "");
@@ -39,8 +39,9 @@ export class CopilotAdapter {
39
39
  // Create session file inside .teammates/.tmp so the agent can access it
40
40
  if (!this.sessionsDir) {
41
41
  const tmpBase = join(teammate.cwd ?? process.cwd(), ".teammates", ".tmp");
42
- this.sessionsDir = join(tmpBase, "sessions");
43
- await mkdir(this.sessionsDir, { recursive: true });
42
+ const dir = join(tmpBase, "sessions");
43
+ await mkdir(dir, { recursive: true });
44
+ this.sessionsDir = dir;
44
45
  const gitignorePath = join(tmpBase, "..", ".gitignore");
45
46
  const existing = await readFile(gitignorePath, "utf-8").catch(() => "");
46
47
  if (!existing.includes(".tmp/")) {
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import { spawn as cpSpawn, exec as execCb, execSync, } from "node:child_process"
11
11
  import { appendFileSync, readFileSync, writeFileSync } from "node:fs";
12
12
  import { mkdir, readdir, rm, stat, unlink } from "node:fs/promises";
13
13
  import { tmpdir } from "node:os";
14
- import { join, resolve } from "node:path";
14
+ import { dirname, join, resolve } from "node:path";
15
15
  import { createInterface } from "node:readline";
16
16
  import { promisify } from "node:util";
17
17
  const execAsync = promisify(execCb);
@@ -1974,6 +1974,7 @@ Do NOT modify any other teammate's files. Only edit your own SOUL.md and daily l
1974
1974
  weeklyLogs: [],
1975
1975
  ownership: { primary: [], secondary: [] },
1976
1976
  routingKeywords: [],
1977
+ cwd: dirname(this.teammatesDir),
1977
1978
  });
1978
1979
  // Add status entry (init() already ran, so we add it manually)
1979
1980
  this.orchestrator.getAllStatuses().set(this.adapterName, { state: "idle" });
package/dist/onboard.d.ts CHANGED
@@ -28,13 +28,9 @@ export declare function importTeammates(sourceDir: string, targetDir: string): P
28
28
  files: string[];
29
29
  }>;
30
30
  /**
31
- * Build a comprehensive import-adaptation prompt that runs as a single agent session.
32
- * The agent will:
33
- * 1. Scan the current project
34
- * 2. Evaluate which imported teammates are needed
35
- * 3. Adapt kept teammates (add Previous Projects section + rewrite for new project)
36
- * 4. Create any new teammates the project needs
37
- * 5. Remove teammates that don't apply
31
+ * Build an import-adaptation prompt that runs as a single non-interactive agent session.
32
+ * The agent scans the target project and adapts all imported teammates in one pass.
33
+ * No pauses or approval gates — the agent must complete all work autonomously.
38
34
  *
39
35
  * @param teammatesDir - The .teammates/ directory in the target project
40
36
  * @param teammateNames - Names of all imported teammates
package/dist/onboard.js CHANGED
@@ -188,13 +188,9 @@ export async function importTeammates(sourceDir, targetDir) {
188
188
  return { teammates, files };
189
189
  }
190
190
  /**
191
- * Build a comprehensive import-adaptation prompt that runs as a single agent session.
192
- * The agent will:
193
- * 1. Scan the current project
194
- * 2. Evaluate which imported teammates are needed
195
- * 3. Adapt kept teammates (add Previous Projects section + rewrite for new project)
196
- * 4. Create any new teammates the project needs
197
- * 5. Remove teammates that don't apply
191
+ * Build an import-adaptation prompt that runs as a single non-interactive agent session.
192
+ * The agent scans the target project and adapts all imported teammates in one pass.
193
+ * No pauses or approval gates — the agent must complete all work autonomously.
198
194
  *
199
195
  * @param teammatesDir - The .teammates/ directory in the target project
200
196
  * @param teammateNames - Names of all imported teammates
@@ -227,101 +223,83 @@ export async function buildImportAdaptationPrompt(teammatesDir, teammateNames, s
227
223
  teammateSections.push(`### @${name}\n${soulBlock}${wisdomBlock}`);
228
224
  }
229
225
  const projectDir = dirname(teammatesDir);
230
- return `You are adapting an imported team to a new project.
226
+ return `You are adapting an imported team to a new project. This is a non-interactive session — complete ALL work without pausing. Do not ask for confirmation or wait for user input.
231
227
 
232
228
  **Source project:** \`${sourceProjectPath}\`
233
229
  **Target project:** \`${projectDir}\`
234
230
  **Target .teammates/ directory:** \`${teammatesDir}\`
235
231
  **Imported teammates:** ${teammateNames.map((n) => `@${n}`).join(", ")}
236
232
 
233
+ > **IMPORTANT:** The \`example/\` directory inside \`.teammates/\` is a **template reference**, NOT a teammate. Do not adapt it, rename it, or treat it as a teammate. When creating new teammates, never use "example" as a folder name.
234
+
237
235
  ## Imported Teammates (from source project)
238
236
 
239
237
  ${teammateSections.join("\n\n---\n\n")}
240
238
 
241
239
  ## Instructions
242
240
 
243
- Work through these phases in order. **Pause after Phase 1 and Phase 2** to present your analysis and get user approval before making changes.
244
-
245
- ### Phase 1: Scan This Project
246
-
247
- Analyze the current project to understand its structure:
248
- - Read the project root: package manifest, README, config files
249
- - Identify major subsystems, languages, frameworks, file patterns
250
- - Understand the dependency flow and architecture
251
-
252
- **Present your analysis to the user and wait for confirmation.**
241
+ Complete these steps in order. Do NOT pause, ask questions, or wait for approval. Make all changes directly.
253
242
 
254
- ### Phase 2: Evaluate Imported Teammates
243
+ ### Step 1: Scan This Project
255
244
 
256
- For each imported teammate, decide:
257
- - **KEEP** their domain or expertise is relevant to this project (even if specific details need updating)
258
- - **DROP** their domain doesn't exist here and their skills aren't transferable
245
+ Read the project root to understand its structure:
246
+ - Package manifest, README, config files
247
+ - Major subsystems, languages, frameworks, file patterns
248
+ - Dependency flow and architecture
259
249
 
260
- Also identify **gaps** major subsystems in this project that none of the imported teammates cover. Propose new teammates for these gaps.
250
+ ### Step 2: Adapt EVERY Imported Teammate
261
251
 
262
- **Present your evaluation as a structured plan and wait for user approval:**
263
- \`\`\`
264
- KEEP: @name1, @name2
265
- DROP: @name3
266
- CREATE: @newname (role description)
267
- \`\`\`
252
+ This is the most important step. For EACH imported teammate listed above, you MUST edit their SOUL.md and WISDOM.md to reflect THIS project, not the source project.
268
253
 
269
- ### Phase 3: Adapt Kept Teammates
254
+ For each teammate's **SOUL.md**:
270
255
 
271
- For each KEEP teammate, edit their SOUL.md and WISDOM.md:
272
-
273
- 1. **Add a "Previous Projects" section** to SOUL.md (place it after Ethics, before any appendix). Compress what the teammate did in the source project into a portable summary:
256
+ 1. **Add a "Previous Projects" section** (place it after Ethics). Compress what the teammate did in the source project:
274
257
  \`\`\`markdown
275
258
  ## Previous Projects
276
259
 
277
- ### <project-name>
260
+ ### <source-project-name>
278
261
  - **Role**: <one-line summary of what they did>
279
262
  - **Stack**: <key technologies they worked with>
280
263
  - **Domains**: <what they owned — file patterns or subsystem names>
281
264
  - **Key learnings**: <1-3 bullets of notable patterns, decisions, or lessons>
282
265
  \`\`\`
283
266
 
284
- 2. **Rewrite the rest of SOUL.md** for this project:
267
+ 2. **Rewrite project-specific sections** for THIS project:
285
268
  - **Preserve**: Identity (name, personality), Core Principles, Ethics
286
- - **Rewrite**: Ownership (primary/secondary file globs for THIS project), Boundaries, Capabilities (commands, file patterns, technologies), Routing keywords, Quality Bar
287
- - **Update**: Any codebase-specific references (paths, package names, tools, teammate names)
288
-
289
- 3. **Update WISDOM.md**:
290
- - **Add** a "Previous Projects" section at the top with a compressed note:
291
- \`\`\`markdown
292
- ## Previous Projects
293
-
294
- ### <project-name>
295
- - Carried over universal wisdom entries from the source project
296
- - Project-specific entries removed or adapted
297
- \`\`\`
298
- - **Keep** wisdom entries that are universal (general principles, patterns, lessons)
299
- - **Remove** entries that reference source project paths, architecture, or tools not used here
300
- - **Adapt** entries with transferable knowledge but old-project-specific details
301
-
302
- ### Phase 4: Handle Dropped Teammates
269
+ - **Rewrite completely**: Ownership (primary/secondary file globs for THIS project's actual files), Boundaries, Capabilities (commands, file patterns, technologies for THIS project), Routing keywords, Quality Bar
270
+ - **Update**: All codebase-specific references paths, package names, tools, teammate names must reference THIS project
303
271
 
304
- For each DROP teammate, delete their directory under \`${teammatesDir}\`.
272
+ For each teammate's **WISDOM.md**:
273
+ - Add a "Previous Projects" note at the top
274
+ - Keep universal wisdom entries (general principles, patterns)
275
+ - Remove entries that reference source project paths, architecture, or tools not used here
276
+ - Adapt entries with transferable knowledge but old-project-specific details
305
277
 
306
- ### Phase 5: Create New Teammates
278
+ ### Step 3: Evaluate Gaps and Create New Teammates
307
279
 
308
- For each new teammate proposed in Phase 2 (after user approval):
280
+ After adapting all existing teammates, check if THIS project has major subsystems that no teammate covers. If so, create new teammates:
309
281
  - Create \`${teammatesDir}/<name>/\` with SOUL.md, WISDOM.md, and \`memory/\`
310
282
  - Use the template at \`${teammatesDir}/TEMPLATE.md\` for structure
311
283
  - WISDOM.md starts with one creation entry
312
284
 
313
- ### Phase 6: Update Framework Files
285
+ If a teammate's domain doesn't exist at all in this project and their skills aren't transferable, delete their directory under \`${teammatesDir}\`.
286
+
287
+ ### Step 4: Update Framework Files
314
288
 
315
289
  - Update \`${teammatesDir}/README.md\` with the final roster
316
290
  - Update \`${teammatesDir}/CROSS-TEAM.md\` ownership table
317
291
 
318
- ### Phase 7: Verify
292
+ ### Step 5: Verify
319
293
 
320
- - Every kept/new teammate has SOUL.md and WISDOM.md
321
- - Ownership globs cover the codebase without major gaps
322
- - Boundaries reference the correct owning teammate
294
+ - Every teammate has SOUL.md and WISDOM.md adapted to THIS project
295
+ - Ownership globs reference actual files in THIS project
296
+ - Boundaries reference correct teammate names
323
297
  - Previous Projects sections are present for all imported teammates
324
- - CROSS-TEAM.md has one row per teammate`;
298
+ - CROSS-TEAM.md has one row per teammate
299
+
300
+ ## Critical Reminder
301
+
302
+ The PRIMARY goal is adapting the imported teammates. Every SOUL.md must be rewritten so the teammate understands THIS project's codebase, not the source project's. If you only have time for one thing, adapt the existing teammates — that is more important than creating new ones.`;
325
303
  }
326
304
  /**
327
305
  * Load ONBOARDING.md from the project dir, package root, or built-in fallback.
@@ -368,7 +346,9 @@ function wrapPrompt(onboardingContent, projectDir) {
368
346
 
369
347
  You do NOT need to create the framework files listed above — they're already there.
370
348
 
371
- Follow the onboarding instructions below. Work through each step, pausing after Step 1 and Step 2 to present your analysis and proposed roster to the user for approval before proceeding.
349
+ > **IMPORTANT:** The \`example/\` directory is a **template reference**, NOT a teammate. Do not modify it or treat it as a teammate. Never name a new teammate "example".
350
+
351
+ Follow the onboarding instructions below. This is a non-interactive session — complete ALL work without pausing. Do not ask for confirmation or wait for user input. Work through each step and make all changes directly.
372
352
 
373
353
  ---
374
354
 
@@ -392,26 +372,22 @@ Identify:
392
372
  3. **Key technologies** — languages, frameworks, tools per area
393
373
  4. **File patterns** — glob patterns for each domain
394
374
 
395
- **Present your analysis to the user and get confirmation before proceeding.**
396
-
397
375
  ## Step 2: Design the Team
398
376
 
399
- Propose a roster of teammates:
377
+ Based on your analysis, design a roster of teammates:
400
378
  - **Aim for 3–7 teammates.** Fewer for small projects, more for monorepos.
401
379
  - **Each teammate owns a distinct domain** with minimal overlap.
402
380
  - **Pick short, memorable names** — one word, evocative of the domain.
403
381
 
404
- For each proposed teammate, define:
382
+ For each teammate, define:
405
383
  - Name and one-line persona
406
384
  - Primary ownership (file patterns)
407
385
  - Key technologies
408
386
  - Boundaries (what they do NOT own)
409
387
 
410
- **Present the proposed roster to the user for approval.**
411
-
412
388
  ## Step 3: Create the Directory Structure
413
389
 
414
- Once approved, create teammate folders under \`.teammates/\`:
390
+ Create teammate folders under \`.teammates/\`:
415
391
 
416
392
  ### Teammate folders
417
393
  For each teammate, create \`.teammates/<name>/\` with:
@@ -9,6 +9,8 @@ export declare class Registry {
9
9
  private teammatesDir;
10
10
  private teammates;
11
11
  constructor(teammatesDir: string);
12
+ /** Names that are never teammates (template references, config files) */
13
+ private static NON_TEAMMATE_NAMES;
12
14
  /** Discover and load all teammates from .teammates/ */
13
15
  loadAll(): Promise<Map<string, TeammateConfig>>;
14
16
  /** Load a single teammate by name */
package/dist/registry.js CHANGED
@@ -12,10 +12,15 @@ export class Registry {
12
12
  constructor(teammatesDir) {
13
13
  this.teammatesDir = teammatesDir;
14
14
  }
15
+ /** Names that are never teammates (template references, config files) */
16
+ static NON_TEAMMATE_NAMES = new Set(["example"]);
15
17
  /** Discover and load all teammates from .teammates/ */
16
18
  async loadAll() {
17
19
  const entries = await readdir(this.teammatesDir, { withFileTypes: true });
18
- const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("_"));
20
+ const dirs = entries.filter((e) => e.isDirectory() &&
21
+ !e.name.startsWith(".") &&
22
+ !e.name.startsWith("_") &&
23
+ !Registry.NON_TEAMMATE_NAMES.has(e.name));
19
24
  for (const dir of dirs) {
20
25
  const config = await this.loadTeammate(dir.name);
21
26
  if (config) {
@@ -56,6 +56,13 @@ describe("Registry.loadAll", () => {
56
56
  await registry.loadAll();
57
57
  expect(registry.list()).toEqual(["beacon"]);
58
58
  });
59
+ it("skips the example directory even if it has SOUL.md", async () => {
60
+ await createTeammate("beacon", "# Beacon\n\nPlatform engineer.");
61
+ await createTeammate("example", "# Example\n\nTemplate reference.");
62
+ const registry = new Registry(tempDir);
63
+ await registry.loadAll();
64
+ expect(registry.list()).toEqual(["beacon"]);
65
+ });
59
66
  });
60
67
  describe("Registry.loadTeammate", () => {
61
68
  it("loads soul content", async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teammates/cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Agent-agnostic CLI for teammates. Routes tasks, manages handoffs, and plugs into any coding agent backend.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",