@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.
- package/dist/adapters/cli-proxy.js +3 -2
- package/dist/adapters/copilot.js +3 -2
- package/dist/cli.js +2 -1
- package/dist/onboard.d.ts +3 -7
- package/dist/onboard.js +45 -69
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +6 -1
- package/dist/registry.test.js +7 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
118
|
-
await mkdir(
|
|
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(() => "");
|
package/dist/adapters/copilot.js
CHANGED
|
@@ -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
|
-
|
|
43
|
-
await mkdir(
|
|
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
|
|
32
|
-
* The agent
|
|
33
|
-
*
|
|
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
|
|
192
|
-
* The agent
|
|
193
|
-
*
|
|
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
|
-
|
|
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
|
-
###
|
|
243
|
+
### Step 1: Scan This Project
|
|
255
244
|
|
|
256
|
-
|
|
257
|
-
-
|
|
258
|
-
-
|
|
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
|
-
|
|
250
|
+
### Step 2: Adapt EVERY Imported Teammate
|
|
261
251
|
|
|
262
|
-
|
|
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
|
-
|
|
254
|
+
For each teammate's **SOUL.md**:
|
|
270
255
|
|
|
271
|
-
|
|
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
|
|
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**:
|
|
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
|
|
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
|
-
###
|
|
278
|
+
### Step 3: Evaluate Gaps and Create New Teammates
|
|
307
279
|
|
|
308
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
292
|
+
### Step 5: Verify
|
|
319
293
|
|
|
320
|
-
- Every
|
|
321
|
-
- Ownership globs
|
|
322
|
-
- Boundaries reference
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
390
|
+
Create teammate folders under \`.teammates/\`:
|
|
415
391
|
|
|
416
392
|
### Teammate folders
|
|
417
393
|
For each teammate, create \`.teammates/<name>/\` with:
|
package/dist/registry.d.ts
CHANGED
|
@@ -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() &&
|
|
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) {
|
package/dist/registry.test.js
CHANGED
|
@@ -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