@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,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orphan Handler
|
|
3
|
+
*
|
|
4
|
+
* Detects and handles orphaned tmux sessions from previous agent-farm runs.
|
|
5
|
+
* This prevents resource leaks and ensures clean startup.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Only cleans up sessions for THIS project (based on port).
|
|
8
|
+
* Sessions from other projects are left alone.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { resolve } from 'node:path';
|
|
12
|
+
import { logger } from './logger.js';
|
|
13
|
+
import { run } from './shell.js';
|
|
14
|
+
import { getConfig } from './config.js';
|
|
15
|
+
/**
|
|
16
|
+
* Find tmux sessions that match THIS project's agent-farm patterns
|
|
17
|
+
* Only matches sessions with this project's port to avoid killing other projects
|
|
18
|
+
*/
|
|
19
|
+
async function findOrphanedSessions() {
|
|
20
|
+
const config = getConfig();
|
|
21
|
+
const architectPort = config.architectPort;
|
|
22
|
+
// Project-specific patterns - only match THIS project's sessions
|
|
23
|
+
const projectPatterns = [
|
|
24
|
+
new RegExp(`^af-architect-${architectPort}$`), // Only this project's architect
|
|
25
|
+
/^builder-\d+$/, // Builder sessions (already unique per spec)
|
|
26
|
+
/^util-[A-Z0-9]+$/, // Util sessions (already unique)
|
|
27
|
+
/^af-architect$/, // Legacy pattern (no port) - safe to clean
|
|
28
|
+
];
|
|
29
|
+
try {
|
|
30
|
+
const result = await run('tmux list-sessions -F "#{session_name}" 2>/dev/null');
|
|
31
|
+
const sessions = result.stdout.trim().split('\n').filter(Boolean);
|
|
32
|
+
const orphans = [];
|
|
33
|
+
for (const name of sessions) {
|
|
34
|
+
if (projectPatterns[0].test(name) || projectPatterns[3].test(name)) {
|
|
35
|
+
orphans.push({ name, type: 'architect' });
|
|
36
|
+
}
|
|
37
|
+
else if (projectPatterns[1].test(name)) {
|
|
38
|
+
orphans.push({ name, type: 'builder' });
|
|
39
|
+
}
|
|
40
|
+
else if (projectPatterns[2].test(name)) {
|
|
41
|
+
orphans.push({ name, type: 'util' });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return orphans;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// tmux not available or no sessions
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Kill an orphaned tmux session
|
|
53
|
+
*/
|
|
54
|
+
async function killSession(name) {
|
|
55
|
+
try {
|
|
56
|
+
await run(`tmux kill-session -t "${name}" 2>/dev/null`);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check for and handle orphaned sessions on startup
|
|
65
|
+
*
|
|
66
|
+
* Returns the number of sessions that were cleaned up.
|
|
67
|
+
*/
|
|
68
|
+
export async function handleOrphanedSessions(options = {}) {
|
|
69
|
+
const orphans = await findOrphanedSessions();
|
|
70
|
+
if (orphans.length === 0) {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
if (!options.silent) {
|
|
74
|
+
logger.warn(`Found ${orphans.length} orphaned tmux session(s) from previous run:`);
|
|
75
|
+
for (const orphan of orphans) {
|
|
76
|
+
logger.info(` - ${orphan.name} (${orphan.type})`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (options.kill) {
|
|
80
|
+
let killed = 0;
|
|
81
|
+
for (const orphan of orphans) {
|
|
82
|
+
if (await killSession(orphan.name)) {
|
|
83
|
+
killed++;
|
|
84
|
+
if (!options.silent) {
|
|
85
|
+
logger.debug(` Killed: ${orphan.name}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!options.silent) {
|
|
90
|
+
logger.info(`Cleaned up ${killed} orphaned session(s)`);
|
|
91
|
+
}
|
|
92
|
+
return killed;
|
|
93
|
+
}
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check for stale artifacts from bash script era
|
|
98
|
+
*/
|
|
99
|
+
export function checkStaleArtifacts(codevDir) {
|
|
100
|
+
const staleFiles = [
|
|
101
|
+
'builders.md', // Old bash state file
|
|
102
|
+
'.architect.pid',
|
|
103
|
+
'.architect.log',
|
|
104
|
+
];
|
|
105
|
+
const found = [];
|
|
106
|
+
for (const file of staleFiles) {
|
|
107
|
+
const path = resolve(codevDir, file);
|
|
108
|
+
if (existsSync(path)) {
|
|
109
|
+
found.push(file);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return found;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Warn about stale artifacts if found
|
|
116
|
+
*/
|
|
117
|
+
export function warnAboutStaleArtifacts(codevDir) {
|
|
118
|
+
const stale = checkStaleArtifacts(codevDir);
|
|
119
|
+
if (stale.length > 0) {
|
|
120
|
+
logger.warn('Found stale artifacts from previous bash-based architect:');
|
|
121
|
+
for (const file of stale) {
|
|
122
|
+
logger.info(` - ${file}`);
|
|
123
|
+
}
|
|
124
|
+
logger.info('These can be safely deleted. The new TypeScript implementation uses .agent-farm/');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=orphan-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orphan-handler.js","sourceRoot":"","sources":["../../../src/agent-farm/utils/orphan-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Port Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages port block allocation across multiple repositories to prevent
|
|
5
|
+
* port conflicts when running multiple architect sessions simultaneously.
|
|
6
|
+
*
|
|
7
|
+
* Registry location: ~/.agent-farm/global.db
|
|
8
|
+
* Each repository gets a 100-port block (e.g., 4200-4299, 4300-4399, etc.)
|
|
9
|
+
*
|
|
10
|
+
* Uses SQLite with ACID transactions for proper concurrency handling.
|
|
11
|
+
*/
|
|
12
|
+
import { closeGlobalDb } from '../db/index.js';
|
|
13
|
+
/**
|
|
14
|
+
* Clean up stale registry entries (projects that no longer exist or have dead PIDs)
|
|
15
|
+
* Note: This function is now synchronous
|
|
16
|
+
*/
|
|
17
|
+
export declare function cleanupStaleEntries(): {
|
|
18
|
+
removed: string[];
|
|
19
|
+
remaining: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get or allocate a port block for a project
|
|
23
|
+
* Returns the base port for the project's block
|
|
24
|
+
* Note: This function is now synchronous and uses BEGIN IMMEDIATE for atomicity
|
|
25
|
+
*/
|
|
26
|
+
export declare function getPortBlock(projectRoot: string): number;
|
|
27
|
+
/**
|
|
28
|
+
* Get port configuration for a project
|
|
29
|
+
* Returns all port assignments based on the project's base port
|
|
30
|
+
*/
|
|
31
|
+
export interface ProjectPorts {
|
|
32
|
+
basePort: number;
|
|
33
|
+
dashboardPort: number;
|
|
34
|
+
architectPort: number;
|
|
35
|
+
builderPortRange: [number, number];
|
|
36
|
+
utilPortRange: [number, number];
|
|
37
|
+
annotatePortRange: [number, number];
|
|
38
|
+
}
|
|
39
|
+
export declare function getProjectPorts(projectRoot: string): ProjectPorts;
|
|
40
|
+
/**
|
|
41
|
+
* List all registered projects and their port blocks
|
|
42
|
+
*/
|
|
43
|
+
export declare function listAllocations(): Array<{
|
|
44
|
+
path: string;
|
|
45
|
+
basePort: number;
|
|
46
|
+
registered: string;
|
|
47
|
+
lastUsed?: string;
|
|
48
|
+
exists: boolean;
|
|
49
|
+
pid?: number;
|
|
50
|
+
pidAlive?: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Remove a project's port allocation
|
|
54
|
+
* Note: This function is now synchronous
|
|
55
|
+
*/
|
|
56
|
+
export declare function removeAllocation(projectRoot: string): boolean;
|
|
57
|
+
export { closeGlobalDb };
|
|
58
|
+
//# sourceMappingURL=port-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-registry.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/utils/port-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAe,aAAa,EAAE,MAAM,gBAAgB,CAAC;AA6B5D;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAgC9E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA2CxD;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAWjE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,KAAK,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC,CAaD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAO7D;AAGD,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Port Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages port block allocation across multiple repositories to prevent
|
|
5
|
+
* port conflicts when running multiple architect sessions simultaneously.
|
|
6
|
+
*
|
|
7
|
+
* Registry location: ~/.agent-farm/global.db
|
|
8
|
+
* Each repository gets a 100-port block (e.g., 4200-4299, 4300-4399, etc.)
|
|
9
|
+
*
|
|
10
|
+
* Uses SQLite with ACID transactions for proper concurrency handling.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
import { resolve } from 'node:path';
|
|
14
|
+
import { getGlobalDb, closeGlobalDb } from '../db/index.js';
|
|
15
|
+
// Base port for first allocation
|
|
16
|
+
const BASE_PORT = 4200;
|
|
17
|
+
// Ports per project
|
|
18
|
+
const PORT_BLOCK_SIZE = 100;
|
|
19
|
+
// Maximum allocations (4200-9999 = ~58 projects)
|
|
20
|
+
const MAX_ALLOCATIONS = 58;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a process is still running
|
|
23
|
+
*/
|
|
24
|
+
function isProcessAlive(pid) {
|
|
25
|
+
try {
|
|
26
|
+
process.kill(pid, 0);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if a project path still exists on disk
|
|
35
|
+
*/
|
|
36
|
+
function projectExists(projectPath) {
|
|
37
|
+
return existsSync(projectPath);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Clean up stale registry entries (projects that no longer exist or have dead PIDs)
|
|
41
|
+
* Note: This function is now synchronous
|
|
42
|
+
*/
|
|
43
|
+
export function cleanupStaleEntries() {
|
|
44
|
+
const db = getGlobalDb();
|
|
45
|
+
const removed = [];
|
|
46
|
+
// Get all allocations
|
|
47
|
+
const allocations = db.prepare('SELECT * FROM port_allocations').all();
|
|
48
|
+
const cleanup = db.transaction(() => {
|
|
49
|
+
for (const alloc of allocations) {
|
|
50
|
+
// Remove if project doesn't exist
|
|
51
|
+
if (!projectExists(alloc.project_path)) {
|
|
52
|
+
removed.push(alloc.project_path);
|
|
53
|
+
db.prepare('DELETE FROM port_allocations WHERE project_path = ?').run(alloc.project_path);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Clear PID if process is stale (process no longer running)
|
|
57
|
+
// Don't remove the entry, just clear the PID - project still exists
|
|
58
|
+
if (alloc.pid && !isProcessAlive(alloc.pid)) {
|
|
59
|
+
db.prepare('UPDATE port_allocations SET pid = NULL WHERE project_path = ?').run(alloc.project_path);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
cleanup();
|
|
64
|
+
const remaining = db.prepare('SELECT COUNT(*) as count FROM port_allocations').get();
|
|
65
|
+
return {
|
|
66
|
+
removed,
|
|
67
|
+
remaining: remaining.count,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get or allocate a port block for a project
|
|
72
|
+
* Returns the base port for the project's block
|
|
73
|
+
* Note: This function is now synchronous and uses BEGIN IMMEDIATE for atomicity
|
|
74
|
+
*/
|
|
75
|
+
export function getPortBlock(projectRoot) {
|
|
76
|
+
// Normalize path for consistent keys
|
|
77
|
+
const normalizedPath = resolve(projectRoot);
|
|
78
|
+
const db = getGlobalDb();
|
|
79
|
+
// Use immediate transaction to prevent race conditions
|
|
80
|
+
const allocate = db.transaction(() => {
|
|
81
|
+
// Check if project already has an allocation
|
|
82
|
+
const existing = db.prepare('SELECT * FROM port_allocations WHERE project_path = ?')
|
|
83
|
+
.get(normalizedPath);
|
|
84
|
+
if (existing) {
|
|
85
|
+
// Update last used timestamp and PID
|
|
86
|
+
db.prepare(`
|
|
87
|
+
UPDATE port_allocations
|
|
88
|
+
SET last_used_at = datetime('now'), pid = ?
|
|
89
|
+
WHERE project_path = ?
|
|
90
|
+
`).run(process.pid, normalizedPath);
|
|
91
|
+
return existing.base_port;
|
|
92
|
+
}
|
|
93
|
+
// Find next available port block
|
|
94
|
+
const maxPort = db.prepare('SELECT MAX(base_port) as max FROM port_allocations').get();
|
|
95
|
+
let nextPort = (maxPort.max ?? (BASE_PORT - PORT_BLOCK_SIZE)) + PORT_BLOCK_SIZE;
|
|
96
|
+
// Ensure we don't exceed max allocations
|
|
97
|
+
if (nextPort >= BASE_PORT + (MAX_ALLOCATIONS * PORT_BLOCK_SIZE)) {
|
|
98
|
+
throw new Error('No available port blocks. Maximum allocations reached.');
|
|
99
|
+
}
|
|
100
|
+
// Insert new allocation
|
|
101
|
+
db.prepare(`
|
|
102
|
+
INSERT INTO port_allocations (project_path, base_port, pid)
|
|
103
|
+
VALUES (?, ?, ?)
|
|
104
|
+
`).run(normalizedPath, nextPort, process.pid);
|
|
105
|
+
return nextPort;
|
|
106
|
+
});
|
|
107
|
+
// Use immediate() to serialize with other writers
|
|
108
|
+
return allocate.immediate();
|
|
109
|
+
}
|
|
110
|
+
export function getProjectPorts(projectRoot) {
|
|
111
|
+
const basePort = getPortBlock(projectRoot);
|
|
112
|
+
return {
|
|
113
|
+
basePort,
|
|
114
|
+
dashboardPort: basePort, // 4200
|
|
115
|
+
architectPort: basePort + 1, // 4201
|
|
116
|
+
builderPortRange: [basePort + 10, basePort + 29], // 4210-4229
|
|
117
|
+
utilPortRange: [basePort + 30, basePort + 49], // 4230-4249
|
|
118
|
+
annotatePortRange: [basePort + 50, basePort + 69], // 4250-4269
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* List all registered projects and their port blocks
|
|
123
|
+
*/
|
|
124
|
+
export function listAllocations() {
|
|
125
|
+
const db = getGlobalDb();
|
|
126
|
+
const allocations = db.prepare('SELECT * FROM port_allocations ORDER BY base_port').all();
|
|
127
|
+
return allocations.map((alloc) => ({
|
|
128
|
+
path: alloc.project_path,
|
|
129
|
+
basePort: alloc.base_port,
|
|
130
|
+
registered: alloc.registered_at,
|
|
131
|
+
lastUsed: alloc.last_used_at,
|
|
132
|
+
exists: projectExists(alloc.project_path),
|
|
133
|
+
pid: alloc.pid ?? undefined,
|
|
134
|
+
pidAlive: alloc.pid ? isProcessAlive(alloc.pid) : undefined,
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Remove a project's port allocation
|
|
139
|
+
* Note: This function is now synchronous
|
|
140
|
+
*/
|
|
141
|
+
export function removeAllocation(projectRoot) {
|
|
142
|
+
const normalizedPath = resolve(projectRoot);
|
|
143
|
+
const db = getGlobalDb();
|
|
144
|
+
const result = db.prepare('DELETE FROM port_allocations WHERE project_path = ?').run(normalizedPath);
|
|
145
|
+
return result.changes > 0;
|
|
146
|
+
}
|
|
147
|
+
// Re-export closeGlobalDb for cleanup
|
|
148
|
+
export { closeGlobalDb };
|
|
149
|
+
//# sourceMappingURL=port-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-registry.js","sourceRoot":"","sources":["../../../src/agent-farm/utils/port-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell command utilities for Agent Farm
|
|
3
|
+
*/
|
|
4
|
+
import { type ChildProcess } from 'node:child_process';
|
|
5
|
+
export interface ExecResult {
|
|
6
|
+
stdout: string;
|
|
7
|
+
stderr: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Execute a shell command and return output
|
|
11
|
+
*/
|
|
12
|
+
export declare function run(command: string, options?: {
|
|
13
|
+
cwd?: string;
|
|
14
|
+
silent?: boolean;
|
|
15
|
+
}): Promise<ExecResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Spawn a detached process that continues after parent exits
|
|
18
|
+
*/
|
|
19
|
+
export declare function spawnDetached(command: string, args: string[], options?: {
|
|
20
|
+
cwd?: string;
|
|
21
|
+
logFile?: string;
|
|
22
|
+
}): ChildProcess;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a command exists
|
|
25
|
+
* Uses spawn to avoid shell injection
|
|
26
|
+
*/
|
|
27
|
+
export declare function commandExists(command: string): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Find an available port starting from the given port
|
|
30
|
+
* Uses native Node socket binding instead of lsof for cross-platform support
|
|
31
|
+
*/
|
|
32
|
+
export declare function findAvailablePort(startPort: number): Promise<number>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a process is running
|
|
35
|
+
*/
|
|
36
|
+
export declare function isProcessRunning(pid: number): Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Kill a process tree
|
|
39
|
+
*/
|
|
40
|
+
export declare function killProcess(pid: number): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Open a URL in the default browser
|
|
43
|
+
*/
|
|
44
|
+
export declare function openBrowser(url: string): Promise<void>;
|
|
45
|
+
//# sourceMappingURL=shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/utils/shell.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKpE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,GAAG,CACvB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/C,OAAO,CAAC,UAAU,CAAC,CAgBrB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,YAAY,CASd;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYrE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB1E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOpE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5D;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell command utilities for Agent Farm
|
|
3
|
+
*/
|
|
4
|
+
import { exec, spawn } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
/**
|
|
8
|
+
* Execute a shell command and return output
|
|
9
|
+
*/
|
|
10
|
+
export async function run(command, options = {}) {
|
|
11
|
+
try {
|
|
12
|
+
const result = await execAsync(command, {
|
|
13
|
+
cwd: options.cwd,
|
|
14
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
stdout: result.stdout.trim(),
|
|
18
|
+
stderr: result.stderr.trim(),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const execError = error;
|
|
23
|
+
throw new Error(`Command failed: ${command}\n${execError.stderr || execError.message}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Spawn a detached process that continues after parent exits
|
|
28
|
+
*/
|
|
29
|
+
export function spawnDetached(command, args, options = {}) {
|
|
30
|
+
const child = spawn(command, args, {
|
|
31
|
+
cwd: options.cwd,
|
|
32
|
+
detached: true,
|
|
33
|
+
stdio: options.logFile ? ['ignore', 'pipe', 'pipe'] : 'ignore',
|
|
34
|
+
});
|
|
35
|
+
child.unref();
|
|
36
|
+
return child;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a command exists
|
|
40
|
+
* Uses spawn to avoid shell injection
|
|
41
|
+
*/
|
|
42
|
+
export async function commandExists(command) {
|
|
43
|
+
// Sanitize: only allow alphanumeric, dash, underscore
|
|
44
|
+
const sanitized = command.replace(/[^a-zA-Z0-9_-]/g, '');
|
|
45
|
+
if (sanitized !== command) {
|
|
46
|
+
return false; // Command name contains invalid characters
|
|
47
|
+
}
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
const child = spawn('which', [command], { stdio: 'ignore' });
|
|
50
|
+
child.on('close', (code) => resolve(code === 0));
|
|
51
|
+
child.on('error', () => resolve(false));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Find an available port starting from the given port
|
|
56
|
+
* Uses native Node socket binding instead of lsof for cross-platform support
|
|
57
|
+
*/
|
|
58
|
+
export async function findAvailablePort(startPort) {
|
|
59
|
+
const net = await import('node:net');
|
|
60
|
+
const isPortAvailable = (port) => {
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
const server = net.createServer();
|
|
63
|
+
server.once('error', () => resolve(false));
|
|
64
|
+
server.once('listening', () => {
|
|
65
|
+
server.close(() => resolve(true));
|
|
66
|
+
});
|
|
67
|
+
server.listen(port, '127.0.0.1');
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
let port = startPort;
|
|
71
|
+
while (port < startPort + 100) {
|
|
72
|
+
if (await isPortAvailable(port)) {
|
|
73
|
+
return port;
|
|
74
|
+
}
|
|
75
|
+
port++;
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`No available port found starting from ${startPort}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if a process is running
|
|
81
|
+
*/
|
|
82
|
+
export async function isProcessRunning(pid) {
|
|
83
|
+
try {
|
|
84
|
+
process.kill(pid, 0);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Kill a process tree
|
|
93
|
+
*/
|
|
94
|
+
export async function killProcess(pid) {
|
|
95
|
+
const treeKill = (await import('tree-kill')).default;
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
treeKill(pid, 'SIGTERM', (err) => {
|
|
98
|
+
if (err) {
|
|
99
|
+
// Try SIGKILL if SIGTERM fails
|
|
100
|
+
treeKill(pid, 'SIGKILL', (err2) => {
|
|
101
|
+
if (err2)
|
|
102
|
+
reject(err2);
|
|
103
|
+
else
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
resolve();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Open a URL in the default browser
|
|
115
|
+
*/
|
|
116
|
+
export async function openBrowser(url) {
|
|
117
|
+
const open = (await import('open')).default;
|
|
118
|
+
await open(url);
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/agent-farm/utils/shell.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Codev CLI - Unified entry point for codev framework
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Run the CLI with given arguments
|
|
7
|
+
* Used by bin shims (af.js, consult.js) to inject commands
|
|
8
|
+
*/
|
|
9
|
+
export declare function run(args: string[]): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;GAEG;AA+HH;;;GAGG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvD"}
|