@chuckssmith/agentloom 0.3.0 → 0.4.0

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/cli.js CHANGED
@@ -3,6 +3,8 @@ import { setup } from './commands/setup.js';
3
3
  import { crew } from './commands/crew.js';
4
4
  import { status } from './commands/status.js';
5
5
  import { logs } from './commands/logs.js';
6
+ import { collect } from './commands/collect.js';
7
+ import { reset } from './commands/reset.js';
6
8
  const [, , command, ...args] = process.argv;
7
9
  const usage = `
8
10
  agentloom (loom) — workflow layer for Claude Code
@@ -15,6 +17,9 @@ Usage:
15
17
  loom status Show active crew session
16
18
  loom logs Show worker output summary
17
19
  loom logs <workerId> Show full log for a specific worker
20
+ loom collect Synthesize worker results into a summary
21
+ loom collect --no-ai Collect results without Claude synthesis
22
+ loom reset --force Clear all session state
18
23
 
19
24
  Modes (use $grind or $crew inside a Claude Code session):
20
25
  $grind Persistence loop — keeps working until verified complete
@@ -42,6 +47,12 @@ switch (command) {
42
47
  case 'logs':
43
48
  await logs(args);
44
49
  break;
50
+ case 'collect':
51
+ await collect(args);
52
+ break;
53
+ case 'reset':
54
+ await reset(args);
55
+ break;
45
56
  default:
46
57
  console.log(usage);
47
58
  process.exit(command ? 1 : 0);
@@ -0,0 +1 @@
1
+ export declare function collect(args: string[]): Promise<void>;
@@ -0,0 +1,79 @@
1
+ import { readFile, readdir, writeFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { existsSync } from 'fs';
4
+ import { spawnSync } from 'child_process';
5
+ import { STATE_DIR, readSession, readTasks } from '../state/session.js';
6
+ const WORKERS_DIR = join(STATE_DIR, 'workers');
7
+ export async function collect(args) {
8
+ if (!existsSync(WORKERS_DIR)) {
9
+ console.log('No session found. Run: loom crew "<task>"');
10
+ return;
11
+ }
12
+ const session = await readSession();
13
+ const tasks = await readTasks();
14
+ const files = await readdir(WORKERS_DIR);
15
+ const resultFiles = files.filter(f => f.endsWith('-result.md')).sort();
16
+ if (resultFiles.length === 0) {
17
+ console.log('No worker results yet. Check status with: loom status');
18
+ console.log('Workers still running? Check: loom logs');
19
+ return;
20
+ }
21
+ console.log(`\nCollecting results from ${resultFiles.length} worker(s)...\n`);
22
+ const results = [];
23
+ for (const f of resultFiles) {
24
+ const workerId = f.replace('-result.md', '');
25
+ const content = await readFile(join(WORKERS_DIR, f), 'utf8');
26
+ results.push({ workerId, content });
27
+ console.log(` ✓ ${workerId}`);
28
+ }
29
+ const taskDesc = session?.description ?? 'unknown task';
30
+ const summaryPath = join(STATE_DIR, 'summary.md');
31
+ // Build raw summary
32
+ const raw = results.map(r => `## ${r.workerId}\n\n${r.content.trim()}`).join('\n\n---\n\n');
33
+ // Optionally synthesize with Claude
34
+ const synthesize = !args.includes('--no-ai');
35
+ let synthesis = '';
36
+ if (synthesize) {
37
+ console.log('\nSynthesizing with Claude...');
38
+ const prompt = `You are summarizing the results of a multi-agent crew that worked on this task:
39
+
40
+ "${taskDesc}"
41
+
42
+ Here are the individual worker results:
43
+
44
+ ${raw}
45
+
46
+ Write a concise synthesis (under 300 words) that:
47
+ 1. States what was accomplished overall
48
+ 2. Highlights the key findings or changes from each worker
49
+ 3. Calls out any blockers, conflicts, or follow-up work needed
50
+
51
+ Be direct and specific. No filler.`;
52
+ const result = spawnSync('claude', ['--print', '-p', prompt], {
53
+ encoding: 'utf8',
54
+ timeout: 60_000,
55
+ });
56
+ if (result.status === 0 && result.stdout.trim()) {
57
+ synthesis = result.stdout.trim();
58
+ }
59
+ }
60
+ const summaryContent = [
61
+ `# Crew Summary`,
62
+ ``,
63
+ `**Task:** ${taskDesc}`,
64
+ `**Workers:** ${resultFiles.length}`,
65
+ `**Collected:** ${new Date().toISOString()}`,
66
+ ``,
67
+ synthesis ? `## Synthesis\n\n${synthesis}` : '',
68
+ synthesis ? `\n---\n` : '',
69
+ `## Individual Results`,
70
+ ``,
71
+ raw,
72
+ ].filter(l => l !== undefined).join('\n');
73
+ await writeFile(summaryPath, summaryContent);
74
+ console.log(`\nSummary written to: ${summaryPath}`);
75
+ if (synthesis) {
76
+ console.log('\n── Synthesis ─────────────────────────────────');
77
+ console.log(synthesis);
78
+ }
79
+ }
@@ -0,0 +1 @@
1
+ export declare function reset(args: string[]): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import { rm } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { STATE_DIR } from '../state/session.js';
4
+ export async function reset(args) {
5
+ if (!existsSync(STATE_DIR)) {
6
+ console.log('Nothing to reset.');
7
+ return;
8
+ }
9
+ const force = args.includes('--force') || args.includes('-f');
10
+ if (!force) {
11
+ console.log(`This will delete all session state in ${STATE_DIR}/`);
12
+ console.log('Run with --force to confirm: loom reset --force');
13
+ return;
14
+ }
15
+ await rm(STATE_DIR, { recursive: true, force: true });
16
+ console.log(`✓ Session state cleared (${STATE_DIR}/)`);
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chuckssmith/agentloom",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A workflow layer for Claude Code — reusable roles, persistence loops, and multi-agent crew coordination",
5
5
  "keywords": [
6
6
  "ai",