@cluesmith/codev 1.1.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/bin/af.js +8 -0
- package/bin/codev.js +4 -0
- package/bin/consult.js +7 -0
- package/dist/agent-farm/cli.d.ts +11 -0
- package/dist/agent-farm/cli.d.ts.map +1 -0
- package/dist/agent-farm/cli.js +359 -0
- package/dist/agent-farm/cli.js.map +1 -0
- package/dist/agent-farm/commands/cleanup.d.ts +12 -0
- package/dist/agent-farm/commands/cleanup.d.ts.map +1 -0
- package/dist/agent-farm/commands/cleanup.js +154 -0
- package/dist/agent-farm/commands/cleanup.js.map +1 -0
- package/dist/agent-farm/commands/db.d.ts +38 -0
- package/dist/agent-farm/commands/db.d.ts.map +1 -0
- package/dist/agent-farm/commands/db.js +133 -0
- package/dist/agent-farm/commands/db.js.map +1 -0
- package/dist/agent-farm/commands/index.d.ts +11 -0
- package/dist/agent-farm/commands/index.d.ts.map +1 -0
- package/dist/agent-farm/commands/index.js +11 -0
- package/dist/agent-farm/commands/index.js.map +1 -0
- package/dist/agent-farm/commands/open.d.ts +15 -0
- package/dist/agent-farm/commands/open.d.ts.map +1 -0
- package/dist/agent-farm/commands/open.js +118 -0
- package/dist/agent-farm/commands/open.js.map +1 -0
- package/dist/agent-farm/commands/rename.d.ts +13 -0
- package/dist/agent-farm/commands/rename.d.ts.map +1 -0
- package/dist/agent-farm/commands/rename.js +33 -0
- package/dist/agent-farm/commands/rename.js.map +1 -0
- package/dist/agent-farm/commands/send.d.ts +9 -0
- package/dist/agent-farm/commands/send.d.ts.map +1 -0
- package/dist/agent-farm/commands/send.js +282 -0
- package/dist/agent-farm/commands/send.js.map +1 -0
- package/dist/agent-farm/commands/spawn.d.ts +15 -0
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -0
- package/dist/agent-farm/commands/spawn.js +575 -0
- package/dist/agent-farm/commands/spawn.js.map +1 -0
- package/dist/agent-farm/commands/start.d.ts +9 -0
- package/dist/agent-farm/commands/start.d.ts.map +1 -0
- package/dist/agent-farm/commands/start.js +175 -0
- package/dist/agent-farm/commands/start.js.map +1 -0
- package/dist/agent-farm/commands/status.d.ts +8 -0
- package/dist/agent-farm/commands/status.d.ts.map +1 -0
- package/dist/agent-farm/commands/status.js +123 -0
- package/dist/agent-farm/commands/status.js.map +1 -0
- package/dist/agent-farm/commands/stop.d.ts +8 -0
- package/dist/agent-farm/commands/stop.d.ts.map +1 -0
- package/dist/agent-farm/commands/stop.js +76 -0
- package/dist/agent-farm/commands/stop.js.map +1 -0
- package/dist/agent-farm/commands/tower.d.ts +19 -0
- package/dist/agent-farm/commands/tower.d.ts.map +1 -0
- package/dist/agent-farm/commands/tower.js +125 -0
- package/dist/agent-farm/commands/tower.js.map +1 -0
- package/dist/agent-farm/commands/tutorial.d.ts +10 -0
- package/dist/agent-farm/commands/tutorial.d.ts.map +1 -0
- package/dist/agent-farm/commands/tutorial.js +49 -0
- package/dist/agent-farm/commands/tutorial.js.map +1 -0
- package/dist/agent-farm/commands/util.d.ts +15 -0
- package/dist/agent-farm/commands/util.d.ts.map +1 -0
- package/dist/agent-farm/commands/util.js +108 -0
- package/dist/agent-farm/commands/util.js.map +1 -0
- package/dist/agent-farm/db/errors.d.ts +17 -0
- package/dist/agent-farm/db/errors.d.ts.map +1 -0
- package/dist/agent-farm/db/errors.js +46 -0
- package/dist/agent-farm/db/errors.js.map +1 -0
- package/dist/agent-farm/db/index.d.ts +41 -0
- package/dist/agent-farm/db/index.d.ts.map +1 -0
- package/dist/agent-farm/db/index.js +168 -0
- package/dist/agent-farm/db/index.js.map +1 -0
- package/dist/agent-farm/db/migrate.d.ts +15 -0
- package/dist/agent-farm/db/migrate.d.ts.map +1 -0
- package/dist/agent-farm/db/migrate.js +137 -0
- package/dist/agent-farm/db/migrate.js.map +1 -0
- package/dist/agent-farm/db/schema.d.ts +16 -0
- package/dist/agent-farm/db/schema.d.ts.map +1 -0
- package/dist/agent-farm/db/schema.js +103 -0
- package/dist/agent-farm/db/schema.js.map +1 -0
- package/dist/agent-farm/db/types.d.ts +87 -0
- package/dist/agent-farm/db/types.d.ts.map +1 -0
- package/dist/agent-farm/db/types.js +65 -0
- package/dist/agent-farm/db/types.js.map +1 -0
- package/dist/agent-farm/index.d.ts +7 -0
- package/dist/agent-farm/index.d.ts.map +1 -0
- package/dist/agent-farm/index.js +373 -0
- package/dist/agent-farm/index.js.map +1 -0
- package/dist/agent-farm/servers/annotate-server.d.ts +9 -0
- package/dist/agent-farm/servers/annotate-server.d.ts.map +1 -0
- package/dist/agent-farm/servers/annotate-server.js +136 -0
- package/dist/agent-farm/servers/annotate-server.js.map +1 -0
- package/dist/agent-farm/servers/dashboard-server.d.ts +9 -0
- package/dist/agent-farm/servers/dashboard-server.d.ts.map +1 -0
- package/dist/agent-farm/servers/dashboard-server.js +939 -0
- package/dist/agent-farm/servers/dashboard-server.js.map +1 -0
- package/dist/agent-farm/servers/tower-server.d.ts +9 -0
- package/dist/agent-farm/servers/tower-server.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-server.js +463 -0
- package/dist/agent-farm/servers/tower-server.js.map +1 -0
- package/dist/agent-farm/state.d.ts +93 -0
- package/dist/agent-farm/state.d.ts.map +1 -0
- package/dist/agent-farm/state.js +253 -0
- package/dist/agent-farm/state.js.map +1 -0
- package/dist/agent-farm/tutorial/index.d.ts +8 -0
- package/dist/agent-farm/tutorial/index.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/index.js +8 -0
- package/dist/agent-farm/tutorial/index.js.map +1 -0
- package/dist/agent-farm/tutorial/prompts.d.ts +57 -0
- package/dist/agent-farm/tutorial/prompts.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/prompts.js +147 -0
- package/dist/agent-farm/tutorial/prompts.js.map +1 -0
- package/dist/agent-farm/tutorial/runner.d.ts +52 -0
- package/dist/agent-farm/tutorial/runner.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/runner.js +204 -0
- package/dist/agent-farm/tutorial/runner.js.map +1 -0
- package/dist/agent-farm/tutorial/state.d.ts +26 -0
- package/dist/agent-farm/tutorial/state.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/state.js +89 -0
- package/dist/agent-farm/tutorial/state.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/first-spec.d.ts +7 -0
- package/dist/agent-farm/tutorial/steps/first-spec.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/first-spec.js +136 -0
- package/dist/agent-farm/tutorial/steps/first-spec.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/implementation.d.ts +7 -0
- package/dist/agent-farm/tutorial/steps/implementation.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/implementation.js +76 -0
- package/dist/agent-farm/tutorial/steps/implementation.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/index.d.ts +10 -0
- package/dist/agent-farm/tutorial/steps/index.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/index.js +10 -0
- package/dist/agent-farm/tutorial/steps/index.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/planning.d.ts +7 -0
- package/dist/agent-farm/tutorial/steps/planning.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/planning.js +143 -0
- package/dist/agent-farm/tutorial/steps/planning.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/review.d.ts +7 -0
- package/dist/agent-farm/tutorial/steps/review.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/review.js +78 -0
- package/dist/agent-farm/tutorial/steps/review.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/setup.d.ts +7 -0
- package/dist/agent-farm/tutorial/steps/setup.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/setup.js +126 -0
- package/dist/agent-farm/tutorial/steps/setup.js.map +1 -0
- package/dist/agent-farm/tutorial/steps/welcome.d.ts +7 -0
- package/dist/agent-farm/tutorial/steps/welcome.d.ts.map +1 -0
- package/dist/agent-farm/tutorial/steps/welcome.js +50 -0
- package/dist/agent-farm/tutorial/steps/welcome.js.map +1 -0
- package/dist/agent-farm/types.d.ts +131 -0
- package/dist/agent-farm/types.d.ts.map +1 -0
- package/dist/agent-farm/types.js +5 -0
- package/dist/agent-farm/types.js.map +1 -0
- package/dist/agent-farm/utils/config.d.ts +27 -0
- package/dist/agent-farm/utils/config.d.ts.map +1 -0
- package/dist/agent-farm/utils/config.js +242 -0
- package/dist/agent-farm/utils/config.js.map +1 -0
- package/dist/agent-farm/utils/deps.d.ts +51 -0
- package/dist/agent-farm/utils/deps.d.ts.map +1 -0
- package/dist/agent-farm/utils/deps.js +194 -0
- package/dist/agent-farm/utils/deps.js.map +1 -0
- package/dist/agent-farm/utils/index.d.ts +6 -0
- package/dist/agent-farm/utils/index.d.ts.map +1 -0
- package/dist/agent-farm/utils/index.js +6 -0
- package/dist/agent-farm/utils/index.js.map +1 -0
- package/dist/agent-farm/utils/logger.d.ts +31 -0
- package/dist/agent-farm/utils/logger.d.ts.map +1 -0
- package/dist/agent-farm/utils/logger.js +58 -0
- package/dist/agent-farm/utils/logger.js.map +1 -0
- package/dist/agent-farm/utils/orphan-handler.d.ts +27 -0
- package/dist/agent-farm/utils/orphan-handler.d.ts.map +1 -0
- package/dist/agent-farm/utils/orphan-handler.js +127 -0
- package/dist/agent-farm/utils/orphan-handler.js.map +1 -0
- package/dist/agent-farm/utils/port-registry.d.ts +58 -0
- package/dist/agent-farm/utils/port-registry.d.ts.map +1 -0
- package/dist/agent-farm/utils/port-registry.js +149 -0
- package/dist/agent-farm/utils/port-registry.js.map +1 -0
- package/dist/agent-farm/utils/shell.d.ts +45 -0
- package/dist/agent-farm/utils/shell.d.ts.map +1 -0
- package/dist/agent-farm/utils/shell.js +120 -0
- package/dist/agent-farm/utils/shell.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +160 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/adopt.d.ts +12 -0
- package/dist/commands/adopt.d.ts.map +1 -0
- package/dist/commands/adopt.js +178 -0
- package/dist/commands/adopt.js.map +1 -0
- package/dist/commands/consult/index.d.ts +17 -0
- package/dist/commands/consult/index.d.ts.map +1 -0
- package/dist/commands/consult/index.js +405 -0
- package/dist/commands/consult/index.js.map +1 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +346 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +167 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/tower.d.ts +16 -0
- package/dist/commands/tower.d.ts.map +1 -0
- package/dist/commands/tower.js +21 -0
- package/dist/commands/tower.js.map +1 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +137 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/lib/templates.d.ts +57 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +205 -0
- package/dist/lib/templates.js.map +1 -0
- package/package.json +55 -0
- package/templates/AGENTS.md +49 -0
- package/templates/CLAUDE.md +47 -0
- package/templates/DEPENDENCIES.md +344 -0
- package/templates/agents/architecture-documenter.md +189 -0
- package/templates/agents/codev-updater.md +276 -0
- package/templates/agents/spider-protocol-updater.md +118 -0
- package/templates/annotate.html +903 -0
- package/templates/bin/agent-farm +18 -0
- package/templates/bin/annotate-server.js +140 -0
- package/templates/bin/codev-doctor +335 -0
- package/templates/builders.md +30 -0
- package/templates/config.json +7 -0
- package/templates/dashboard-split.html +1679 -0
- package/templates/dashboard.html +149 -0
- package/templates/plans/.gitkeep +0 -0
- package/templates/protocols/experiment/protocol.md +229 -0
- package/templates/protocols/experiment/templates/notes.md +97 -0
- package/templates/protocols/maintain/protocol.md +235 -0
- package/templates/protocols/spider/protocol.md +639 -0
- package/templates/protocols/spider/templates/plan.md +169 -0
- package/templates/protocols/spider/templates/review.md +207 -0
- package/templates/protocols/spider/templates/spec.md +140 -0
- package/templates/protocols/spider-solo/protocol.md +619 -0
- package/templates/protocols/spider-solo/templates/plan.md +169 -0
- package/templates/protocols/spider-solo/templates/review.md +207 -0
- package/templates/protocols/spider-solo/templates/spec.md +140 -0
- package/templates/protocols/tick/protocol.md +250 -0
- package/templates/protocols/tick/templates/plan.md +67 -0
- package/templates/protocols/tick/templates/review.md +90 -0
- package/templates/protocols/tick/templates/spec.md +61 -0
- package/templates/reviews/.gitkeep +0 -0
- package/templates/roles/architect.md +230 -0
- package/templates/roles/builder.md +175 -0
- package/templates/roles/consultant.md +27 -0
- package/templates/specs/.gitkeep +0 -0
- package/templates/templates/projectlist.md +129 -0
- package/templates/tower.html +1032 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database CLI commands
|
|
3
|
+
*
|
|
4
|
+
* Commands for debugging and managing the SQLite databases:
|
|
5
|
+
* - af db dump: Export all tables to JSON
|
|
6
|
+
* - af db query: Run arbitrary SELECT queries
|
|
7
|
+
* - af db reset: Delete database and start fresh
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, unlinkSync } from 'node:fs';
|
|
10
|
+
import { getDb, getGlobalDb, getDbPath, getGlobalDbPath, closeDb, closeGlobalDb } from '../db/index.js';
|
|
11
|
+
import { logger, fatal } from '../utils/logger.js';
|
|
12
|
+
/**
|
|
13
|
+
* Export all tables to JSON
|
|
14
|
+
*/
|
|
15
|
+
export function dbDump(options = {}) {
|
|
16
|
+
const db = options.global ? getGlobalDb() : getDb();
|
|
17
|
+
// Get all table names (excluding internal sqlite tables and _migrations)
|
|
18
|
+
const tables = db.prepare(`
|
|
19
|
+
SELECT name FROM sqlite_master
|
|
20
|
+
WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != '_migrations'
|
|
21
|
+
ORDER BY name
|
|
22
|
+
`).all();
|
|
23
|
+
const dump = {};
|
|
24
|
+
for (const { name } of tables) {
|
|
25
|
+
dump[name] = db.prepare(`SELECT * FROM ${name}`).all();
|
|
26
|
+
}
|
|
27
|
+
console.log(JSON.stringify(dump, null, 2));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run a SELECT query against the database
|
|
31
|
+
*/
|
|
32
|
+
export function dbQuery(sql, options = {}) {
|
|
33
|
+
// Safety check: only allow SELECT queries
|
|
34
|
+
const normalizedSql = sql.trim().toLowerCase();
|
|
35
|
+
if (!normalizedSql.startsWith('select')) {
|
|
36
|
+
fatal('Only SELECT queries are allowed for safety. Use "af db reset" to modify data.');
|
|
37
|
+
}
|
|
38
|
+
const db = options.global ? getGlobalDb() : getDb();
|
|
39
|
+
try {
|
|
40
|
+
const results = db.prepare(sql).all();
|
|
41
|
+
console.log(JSON.stringify(results, null, 2));
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
const error = err;
|
|
45
|
+
fatal(`Query failed: ${error.message}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Delete database and start fresh
|
|
50
|
+
*/
|
|
51
|
+
export function dbReset(options = {}) {
|
|
52
|
+
const dbPath = options.global ? getGlobalDbPath() : getDbPath();
|
|
53
|
+
const dbType = options.global ? 'global' : 'local';
|
|
54
|
+
if (!existsSync(dbPath)) {
|
|
55
|
+
logger.info(`No ${dbType} database found at ${dbPath}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!options.force) {
|
|
59
|
+
logger.warn(`This will delete the ${dbType} database at ${dbPath}`);
|
|
60
|
+
logger.warn('Use --force to confirm.');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Close the database connection first
|
|
64
|
+
if (options.global) {
|
|
65
|
+
closeGlobalDb();
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
closeDb();
|
|
69
|
+
}
|
|
70
|
+
// Delete main database file
|
|
71
|
+
try {
|
|
72
|
+
unlinkSync(dbPath);
|
|
73
|
+
logger.info(`Deleted ${dbPath}`);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// File might not exist or be locked
|
|
77
|
+
}
|
|
78
|
+
// Delete WAL files if they exist
|
|
79
|
+
const walPath = dbPath + '-wal';
|
|
80
|
+
const shmPath = dbPath + '-shm';
|
|
81
|
+
try {
|
|
82
|
+
if (existsSync(walPath)) {
|
|
83
|
+
unlinkSync(walPath);
|
|
84
|
+
logger.info(`Deleted ${walPath}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// File might not exist
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
if (existsSync(shmPath)) {
|
|
92
|
+
unlinkSync(shmPath);
|
|
93
|
+
logger.info(`Deleted ${shmPath}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// File might not exist
|
|
98
|
+
}
|
|
99
|
+
logger.success(`${dbType.charAt(0).toUpperCase() + dbType.slice(1)} database reset complete`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Show database statistics
|
|
103
|
+
*/
|
|
104
|
+
export function dbStats(options = {}) {
|
|
105
|
+
const db = options.global ? getGlobalDb() : getDb();
|
|
106
|
+
const dbPath = options.global ? getGlobalDbPath() : getDbPath();
|
|
107
|
+
const dbType = options.global ? 'Global' : 'Local';
|
|
108
|
+
logger.header(`${dbType} Database Statistics`);
|
|
109
|
+
logger.kv('Path', dbPath);
|
|
110
|
+
// Get table row counts
|
|
111
|
+
const tables = db.prepare(`
|
|
112
|
+
SELECT name FROM sqlite_master
|
|
113
|
+
WHERE type='table' AND name NOT LIKE 'sqlite_%'
|
|
114
|
+
ORDER BY name
|
|
115
|
+
`).all();
|
|
116
|
+
logger.blank();
|
|
117
|
+
logger.info('Table row counts:');
|
|
118
|
+
for (const { name } of tables) {
|
|
119
|
+
const result = db.prepare(`SELECT COUNT(*) as count FROM ${name}`).get();
|
|
120
|
+
logger.kv(` ${name}`, String(result.count));
|
|
121
|
+
}
|
|
122
|
+
// Get database page info
|
|
123
|
+
const pageCount = db.pragma('page_count', { simple: true });
|
|
124
|
+
const pageSize = db.pragma('page_size', { simple: true });
|
|
125
|
+
const journalMode = db.pragma('journal_mode', { simple: true });
|
|
126
|
+
logger.blank();
|
|
127
|
+
logger.info('Database info:');
|
|
128
|
+
logger.kv(' Journal mode', journalMode.toUpperCase());
|
|
129
|
+
logger.kv(' Page size', `${pageSize} bytes`);
|
|
130
|
+
logger.kv(' Page count', String(pageCount));
|
|
131
|
+
logger.kv(' Total size', `${Math.round(pageCount * pageSize / 1024)} KB`);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command exports for Agent Farm
|
|
3
|
+
*/
|
|
4
|
+
export { start } from './start.js';
|
|
5
|
+
export { stop } from './stop.js';
|
|
6
|
+
export { status } from './status.js';
|
|
7
|
+
export { spawn } from './spawn.js';
|
|
8
|
+
export { util } from './util.js';
|
|
9
|
+
export { open } from './open.js';
|
|
10
|
+
export { send } from './send.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command exports for Agent Farm
|
|
3
|
+
*/
|
|
4
|
+
export { start } from './start.js';
|
|
5
|
+
export { stop } from './stop.js';
|
|
6
|
+
export { status } from './status.js';
|
|
7
|
+
export { spawn } from './spawn.js';
|
|
8
|
+
export { util } from './util.js';
|
|
9
|
+
export { open } from './open.js';
|
|
10
|
+
export { send } from './send.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open command - opens file annotation viewer
|
|
3
|
+
*
|
|
4
|
+
* When the dashboard is running, this creates a tab in the dashboard.
|
|
5
|
+
* When the dashboard is not running, it opens the annotation viewer directly.
|
|
6
|
+
*/
|
|
7
|
+
interface OpenOptions {
|
|
8
|
+
file: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Open file annotation viewer
|
|
12
|
+
*/
|
|
13
|
+
export declare function open(options: OpenOptions): Promise<void>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/open.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AA0CD;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyE9D"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open command - opens file annotation viewer
|
|
3
|
+
*
|
|
4
|
+
* When the dashboard is running, this creates a tab in the dashboard.
|
|
5
|
+
* When the dashboard is not running, it opens the annotation viewer directly.
|
|
6
|
+
*/
|
|
7
|
+
import { resolve } from 'node:path';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { getConfig } from '../utils/index.js';
|
|
10
|
+
import { logger, fatal } from '../utils/logger.js';
|
|
11
|
+
import { spawnDetached, findAvailablePort, openBrowser } from '../utils/shell.js';
|
|
12
|
+
import { addAnnotation, loadState } from '../state.js';
|
|
13
|
+
/**
|
|
14
|
+
* Try to create a file tab via the dashboard API
|
|
15
|
+
* Returns true if successful, false if dashboard not available
|
|
16
|
+
*/
|
|
17
|
+
async function tryDashboardApi(filePath) {
|
|
18
|
+
const state = loadState();
|
|
19
|
+
// Dashboard runs on dashboardPort (not architectPort + 1)
|
|
20
|
+
if (!state.architect) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const config = getConfig();
|
|
24
|
+
const dashboardPort = config.dashboardPort;
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(`http://localhost:${dashboardPort}/api/tabs/file`, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
|
+
body: JSON.stringify({ path: filePath }),
|
|
30
|
+
});
|
|
31
|
+
if (response.ok) {
|
|
32
|
+
const result = (await response.json());
|
|
33
|
+
logger.success(`Opened in dashboard tab`);
|
|
34
|
+
logger.kv('File', filePath);
|
|
35
|
+
if (result.existing) {
|
|
36
|
+
logger.info('(File was already open)');
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// Dashboard returned an error, fall through to direct open
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Dashboard not available
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Open file annotation viewer
|
|
50
|
+
*/
|
|
51
|
+
export async function open(options) {
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
// Resolve file path relative to current directory (works correctly in worktrees)
|
|
54
|
+
let filePath;
|
|
55
|
+
if (options.file.startsWith('/')) {
|
|
56
|
+
filePath = options.file;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
filePath = resolve(process.cwd(), options.file);
|
|
60
|
+
}
|
|
61
|
+
// Check file exists
|
|
62
|
+
if (!existsSync(filePath)) {
|
|
63
|
+
fatal(`File not found: ${filePath}`);
|
|
64
|
+
}
|
|
65
|
+
// Try to use dashboard API first (if dashboard is running)
|
|
66
|
+
const dashboardOpened = await tryDashboardApi(filePath);
|
|
67
|
+
if (dashboardOpened) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Fall back to direct open
|
|
71
|
+
logger.header('Opening Annotation Viewer');
|
|
72
|
+
logger.kv('File', filePath);
|
|
73
|
+
// Generate ID
|
|
74
|
+
const id = generateAnnotationId();
|
|
75
|
+
// Find available port
|
|
76
|
+
const port = await findAvailablePort(config.annotatePortRange[0]);
|
|
77
|
+
logger.kv('Port', port);
|
|
78
|
+
// Find annotation server script (compiled TypeScript)
|
|
79
|
+
const serverScript = resolve(config.serversDir, 'annotate-server.js');
|
|
80
|
+
if (!existsSync(serverScript)) {
|
|
81
|
+
fatal(`Annotation server not found at ${serverScript}`);
|
|
82
|
+
}
|
|
83
|
+
// Start annotation server
|
|
84
|
+
const serverProcess = spawnDetached('node', [serverScript, String(port), filePath], {
|
|
85
|
+
cwd: config.projectRoot,
|
|
86
|
+
});
|
|
87
|
+
if (!serverProcess.pid) {
|
|
88
|
+
fatal('Failed to start annotation server');
|
|
89
|
+
}
|
|
90
|
+
// Create annotation record
|
|
91
|
+
const annotation = {
|
|
92
|
+
id,
|
|
93
|
+
file: filePath,
|
|
94
|
+
port,
|
|
95
|
+
pid: serverProcess.pid,
|
|
96
|
+
parent: {
|
|
97
|
+
type: 'architect',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
addAnnotation(annotation);
|
|
101
|
+
// Wait a moment for server to start
|
|
102
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
103
|
+
// Open in browser
|
|
104
|
+
const url = `http://localhost:${port}`;
|
|
105
|
+
await openBrowser(url);
|
|
106
|
+
logger.blank();
|
|
107
|
+
logger.success('Annotation viewer opened!');
|
|
108
|
+
logger.kv('URL', url);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Generate a unique annotation ID
|
|
112
|
+
*/
|
|
113
|
+
function generateAnnotationId() {
|
|
114
|
+
const timestamp = Date.now().toString(36);
|
|
115
|
+
const random = Math.random().toString(36).substring(2, 4);
|
|
116
|
+
return `A${timestamp.slice(-3)}${random}`.toUpperCase();
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/open.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rename command - rename a builder or utility terminal
|
|
3
|
+
*/
|
|
4
|
+
interface RenameOptions {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Rename a builder or utility terminal
|
|
10
|
+
*/
|
|
11
|
+
export declare function rename(options: RenameOptions): void;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=rename.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/rename.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CA2BnD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rename command - rename a builder or utility terminal
|
|
3
|
+
*/
|
|
4
|
+
import { renameBuilder, renameUtil } from '../state.js';
|
|
5
|
+
import { logger, fatal } from '../utils/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Rename a builder or utility terminal
|
|
8
|
+
*/
|
|
9
|
+
export function rename(options) {
|
|
10
|
+
const { id, name } = options;
|
|
11
|
+
if (!name.trim()) {
|
|
12
|
+
fatal('Name cannot be empty');
|
|
13
|
+
}
|
|
14
|
+
// Try to rename as builder first
|
|
15
|
+
const oldBuilderName = renameBuilder(id, name);
|
|
16
|
+
if (oldBuilderName !== null) {
|
|
17
|
+
logger.success(`Renamed builder "${id}"`);
|
|
18
|
+
logger.kv('Old name', oldBuilderName);
|
|
19
|
+
logger.kv('New name', name);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Try to rename as util
|
|
23
|
+
const oldUtilName = renameUtil(id, name);
|
|
24
|
+
if (oldUtilName !== null) {
|
|
25
|
+
logger.success(`Renamed utility "${id}"`);
|
|
26
|
+
logger.kv('Old name', oldUtilName);
|
|
27
|
+
logger.kv('New name', name);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Not found
|
|
31
|
+
fatal(`No builder or utility found with ID: ${id}`);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=rename.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename.js","sourceRoot":"","sources":["../../../src/agent-farm/commands/rename.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAOnD;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,OAAsB;IAC3C,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAE7B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChC,CAAC;IAED,iCAAiC;IACjC,MAAM,cAAc,GAAG,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC/C,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,wBAAwB;IACxB,MAAM,WAAW,GAAG,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACzC,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,YAAY;IACZ,KAAK,CAAC,wCAAwC,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send command - send instructions to running builders via tmux buffer paste
|
|
3
|
+
*/
|
|
4
|
+
import type { SendOptions } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Main send command handler
|
|
7
|
+
*/
|
|
8
|
+
export declare function send(options: SendOptions): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=send.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/send.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAoQ/C;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkE9D"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send command - send instructions to running builders via tmux buffer paste
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { randomUUID } from 'node:crypto';
|
|
9
|
+
import { logger, fatal } from '../utils/logger.js';
|
|
10
|
+
import { run } from '../utils/shell.js';
|
|
11
|
+
import { loadState, getArchitect } from '../state.js';
|
|
12
|
+
const MAX_FILE_SIZE = 48 * 1024; // 48KB limit per spec
|
|
13
|
+
/**
|
|
14
|
+
* Format message from architect to builder
|
|
15
|
+
*/
|
|
16
|
+
function formatArchitectMessage(message, fileContent, raw = false) {
|
|
17
|
+
let content = message;
|
|
18
|
+
if (fileContent) {
|
|
19
|
+
content += '\n\nAttached content:\n```\n' + fileContent + '\n```';
|
|
20
|
+
}
|
|
21
|
+
if (raw) {
|
|
22
|
+
return content;
|
|
23
|
+
}
|
|
24
|
+
// Structured format helps Claude identify Architect instructions
|
|
25
|
+
const timestamp = new Date().toISOString();
|
|
26
|
+
return `### [ARCHITECT INSTRUCTION | ${timestamp}] ###
|
|
27
|
+
${content}
|
|
28
|
+
###############################`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Format message from builder to architect
|
|
32
|
+
*/
|
|
33
|
+
function formatBuilderMessage(builderId, message, fileContent, raw = false) {
|
|
34
|
+
let content = message;
|
|
35
|
+
if (fileContent) {
|
|
36
|
+
content += '\n\nAttached content:\n```\n' + fileContent + '\n```';
|
|
37
|
+
}
|
|
38
|
+
if (raw) {
|
|
39
|
+
return content;
|
|
40
|
+
}
|
|
41
|
+
// Structured format helps Claude identify Builder messages
|
|
42
|
+
const timestamp = new Date().toISOString();
|
|
43
|
+
return `### [BUILDER ${builderId} MESSAGE | ${timestamp}] ###
|
|
44
|
+
${content}
|
|
45
|
+
###############################`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Send a message to a specific builder
|
|
49
|
+
*/
|
|
50
|
+
async function sendToBuilder(builderId, message, options) {
|
|
51
|
+
const state = loadState();
|
|
52
|
+
const builder = state.builders.find((b) => b.id === builderId);
|
|
53
|
+
if (!builder) {
|
|
54
|
+
throw new Error(`Builder ${builderId} not found. Use 'af status' to see active builders.`);
|
|
55
|
+
}
|
|
56
|
+
if (!builder.tmuxSession) {
|
|
57
|
+
throw new Error(`Builder ${builderId} has no tmux session recorded.`);
|
|
58
|
+
}
|
|
59
|
+
// Verify session exists
|
|
60
|
+
try {
|
|
61
|
+
await run(`tmux has-session -t "${builder.tmuxSession}" 2>/dev/null`);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
throw new Error(`tmux session "${builder.tmuxSession}" not found (builder may have exited). Use 'af status' to check.`);
|
|
65
|
+
}
|
|
66
|
+
// Optional: Send Ctrl+C first to interrupt any running process
|
|
67
|
+
if (options.interrupt) {
|
|
68
|
+
await run(`tmux send-keys -t "${builder.tmuxSession}" C-c`);
|
|
69
|
+
// Brief pause for prompt to appear
|
|
70
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
71
|
+
}
|
|
72
|
+
// Load file content if specified
|
|
73
|
+
let fileContent;
|
|
74
|
+
if (options.file) {
|
|
75
|
+
if (!existsSync(options.file)) {
|
|
76
|
+
throw new Error(`File not found: ${options.file}`);
|
|
77
|
+
}
|
|
78
|
+
const fileBuffer = readFileSync(options.file);
|
|
79
|
+
if (fileBuffer.length > MAX_FILE_SIZE) {
|
|
80
|
+
throw new Error(`File too large: ${fileBuffer.length} bytes (max ${MAX_FILE_SIZE} bytes / 48KB)`);
|
|
81
|
+
}
|
|
82
|
+
fileContent = fileBuffer.toString('utf-8');
|
|
83
|
+
}
|
|
84
|
+
// Format the message
|
|
85
|
+
const formattedMessage = formatArchitectMessage(message, fileContent, options.raw);
|
|
86
|
+
// Write message to temp file (avoids all shell escaping issues)
|
|
87
|
+
const tempFile = join(tmpdir(), `architect-msg-${randomUUID()}.txt`);
|
|
88
|
+
writeFileSync(tempFile, formattedMessage);
|
|
89
|
+
try {
|
|
90
|
+
// Load into tmux buffer and paste
|
|
91
|
+
const bufferName = `architect-${builderId}`;
|
|
92
|
+
await run(`tmux load-buffer -b "${bufferName}" "${tempFile}"`);
|
|
93
|
+
await run(`tmux paste-buffer -b "${bufferName}" -t "${builder.tmuxSession}"`);
|
|
94
|
+
// Clean up tmux buffer
|
|
95
|
+
await run(`tmux delete-buffer -b "${bufferName}"`).catch(() => {
|
|
96
|
+
// Ignore delete-buffer errors (buffer may not exist)
|
|
97
|
+
});
|
|
98
|
+
// Send Enter to submit (unless --no-enter)
|
|
99
|
+
if (!options.noEnter) {
|
|
100
|
+
await run(`tmux send-keys -t "${builder.tmuxSession}" Enter`);
|
|
101
|
+
}
|
|
102
|
+
logger.debug(`Sent to ${builderId}: ${message.substring(0, 50)}...`);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
// Clean up temp file
|
|
106
|
+
try {
|
|
107
|
+
unlinkSync(tempFile);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Ignore cleanup errors
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Send a message to the architect (from a builder)
|
|
116
|
+
*/
|
|
117
|
+
async function sendToArchitect(fromBuilderId, message, options) {
|
|
118
|
+
const architect = getArchitect();
|
|
119
|
+
if (!architect) {
|
|
120
|
+
throw new Error('Architect not running. Use "af status" to check.');
|
|
121
|
+
}
|
|
122
|
+
if (!architect.tmuxSession) {
|
|
123
|
+
throw new Error('Architect has no tmux session recorded.');
|
|
124
|
+
}
|
|
125
|
+
// Verify session exists
|
|
126
|
+
try {
|
|
127
|
+
await run(`tmux has-session -t "${architect.tmuxSession}" 2>/dev/null`);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
throw new Error(`tmux session "${architect.tmuxSession}" not found (architect may have exited). Use 'af status' to check.`);
|
|
131
|
+
}
|
|
132
|
+
// Optional: Send Ctrl+C first to interrupt any running process
|
|
133
|
+
if (options.interrupt) {
|
|
134
|
+
await run(`tmux send-keys -t "${architect.tmuxSession}" C-c`);
|
|
135
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
136
|
+
}
|
|
137
|
+
// Load file content if specified
|
|
138
|
+
let fileContent;
|
|
139
|
+
if (options.file) {
|
|
140
|
+
if (!existsSync(options.file)) {
|
|
141
|
+
throw new Error(`File not found: ${options.file}`);
|
|
142
|
+
}
|
|
143
|
+
const fileBuffer = readFileSync(options.file);
|
|
144
|
+
if (fileBuffer.length > MAX_FILE_SIZE) {
|
|
145
|
+
throw new Error(`File too large: ${fileBuffer.length} bytes (max ${MAX_FILE_SIZE} bytes / 48KB)`);
|
|
146
|
+
}
|
|
147
|
+
fileContent = fileBuffer.toString('utf-8');
|
|
148
|
+
}
|
|
149
|
+
// Format the message (from builder)
|
|
150
|
+
const formattedMessage = formatBuilderMessage(fromBuilderId, message, fileContent, options.raw);
|
|
151
|
+
// Write message to temp file
|
|
152
|
+
const tempFile = join(tmpdir(), `builder-msg-${randomUUID()}.txt`);
|
|
153
|
+
writeFileSync(tempFile, formattedMessage);
|
|
154
|
+
try {
|
|
155
|
+
// Load into tmux buffer and paste
|
|
156
|
+
const bufferName = `builder-${fromBuilderId}`;
|
|
157
|
+
await run(`tmux load-buffer -b "${bufferName}" "${tempFile}"`);
|
|
158
|
+
await run(`tmux paste-buffer -b "${bufferName}" -t "${architect.tmuxSession}"`);
|
|
159
|
+
// Clean up tmux buffer
|
|
160
|
+
await run(`tmux delete-buffer -b "${bufferName}"`).catch(() => { });
|
|
161
|
+
// Send Enter to submit (unless --no-enter)
|
|
162
|
+
if (!options.noEnter) {
|
|
163
|
+
await run(`tmux send-keys -t "${architect.tmuxSession}" Enter`);
|
|
164
|
+
}
|
|
165
|
+
logger.debug(`Sent to architect from ${fromBuilderId}: ${message.substring(0, 50)}...`);
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
try {
|
|
169
|
+
unlinkSync(tempFile);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Ignore cleanup errors
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Send a message to all builders
|
|
178
|
+
*/
|
|
179
|
+
async function sendToAll(message, options) {
|
|
180
|
+
const state = loadState();
|
|
181
|
+
const results = { sent: [], failed: [] };
|
|
182
|
+
if (state.builders.length === 0) {
|
|
183
|
+
logger.warn('No active builders found.');
|
|
184
|
+
return results;
|
|
185
|
+
}
|
|
186
|
+
for (const builder of state.builders) {
|
|
187
|
+
try {
|
|
188
|
+
await sendToBuilder(builder.id, message, options);
|
|
189
|
+
results.sent.push(builder.id);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
logger.error(`Failed to send to ${builder.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
193
|
+
results.failed.push(builder.id);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return results;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Read message from stdin
|
|
200
|
+
*/
|
|
201
|
+
async function readStdin() {
|
|
202
|
+
const chunks = [];
|
|
203
|
+
for await (const chunk of process.stdin) {
|
|
204
|
+
chunks.push(chunk);
|
|
205
|
+
}
|
|
206
|
+
return Buffer.concat(chunks).toString('utf-8').trim();
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Detect the current builder ID from worktree path
|
|
210
|
+
* Returns null if not in a builder worktree
|
|
211
|
+
*/
|
|
212
|
+
function detectCurrentBuilderId() {
|
|
213
|
+
const cwd = process.cwd();
|
|
214
|
+
// Builder worktrees are at .builders/<id>/
|
|
215
|
+
const match = cwd.match(/\.builders\/([^/]+)/);
|
|
216
|
+
return match ? match[1] : null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Main send command handler
|
|
220
|
+
*/
|
|
221
|
+
export async function send(options) {
|
|
222
|
+
// Determine the message
|
|
223
|
+
let message = options.message;
|
|
224
|
+
let builder = options.builder;
|
|
225
|
+
// When using --all, the first positional arg (builder) is actually the message
|
|
226
|
+
if (options.all && builder && !message) {
|
|
227
|
+
message = builder;
|
|
228
|
+
builder = undefined;
|
|
229
|
+
}
|
|
230
|
+
// Handle stdin input (message is "-")
|
|
231
|
+
if (message === '-') {
|
|
232
|
+
message = await readStdin();
|
|
233
|
+
}
|
|
234
|
+
// Validate inputs
|
|
235
|
+
if (!message) {
|
|
236
|
+
fatal('No message provided. Usage: af send <builder> "message" or af send --all "message"');
|
|
237
|
+
}
|
|
238
|
+
if (!options.all && !builder) {
|
|
239
|
+
fatal('Must specify a builder ID or use --all flag. Usage: af send <builder> "message"');
|
|
240
|
+
}
|
|
241
|
+
if (options.all && builder) {
|
|
242
|
+
fatal('Cannot use --all with a specific builder ID.');
|
|
243
|
+
}
|
|
244
|
+
logger.header('Sending Instruction');
|
|
245
|
+
// Check if sending to architect
|
|
246
|
+
const isArchitectTarget = builder?.toLowerCase() === 'architect' || builder?.toLowerCase() === 'arch';
|
|
247
|
+
if (isArchitectTarget) {
|
|
248
|
+
// Sending to architect (from a builder)
|
|
249
|
+
const currentBuilderId = detectCurrentBuilderId();
|
|
250
|
+
if (!currentBuilderId) {
|
|
251
|
+
fatal('Cannot send to architect: not running from a builder worktree. Use from .builders/<id>/ directory.');
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
await sendToArchitect(currentBuilderId, message, options);
|
|
255
|
+
logger.success(`Message sent to architect from builder ${currentBuilderId}`);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
fatal(error instanceof Error ? error.message : String(error));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if (options.all) {
|
|
262
|
+
// Broadcast to all builders
|
|
263
|
+
const results = await sendToAll(message, options);
|
|
264
|
+
if (results.sent.length > 0) {
|
|
265
|
+
logger.success(`Sent to ${results.sent.length} builder(s): ${results.sent.join(', ')}`);
|
|
266
|
+
}
|
|
267
|
+
if (results.failed.length > 0) {
|
|
268
|
+
logger.error(`Failed for ${results.failed.length} builder(s): ${results.failed.join(', ')}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
// Send to specific builder
|
|
273
|
+
try {
|
|
274
|
+
await sendToBuilder(builder, message, options);
|
|
275
|
+
logger.success(`Message sent to builder ${builder}`);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
fatal(error instanceof Error ? error.message : String(error));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=send.js.map
|