smol-symphony 0.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.
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ // CLI entry (SPEC §17.7). Usage:
3
+ // symphony [path-to-WORKFLOW.md] [--port <port>]
4
+ //
5
+ // Default workflow path is ./WORKFLOW.md.
6
+ import path from 'node:path';
7
+ import process from 'node:process';
8
+ import { existsSync } from 'node:fs';
9
+ import { watchWorkflow } from '../workflow.js';
10
+ import { LocalMarkdownTracker } from '../trackers/local.js';
11
+ import { WorkspaceManager } from '../workspace.js';
12
+ import { SmolvmClient } from '../agent/smolvm.js';
13
+ import { AgentRunner } from '../agent/runner.js';
14
+ import { Orchestrator } from '../orchestrator.js';
15
+ import { startHttpServer } from '../http.js';
16
+ import { McpRegistry } from '../mcp.js';
17
+ import { log } from '../logging.js';
18
+ function parseCli(argv) {
19
+ let workflow = null;
20
+ let port = null;
21
+ for (let i = 0; i < argv.length; i++) {
22
+ const a = argv[i];
23
+ if (a === '--port' || a === '-p') {
24
+ const v = argv[++i];
25
+ if (!v) {
26
+ process.stderr.write(`error: --port requires a value\n`);
27
+ process.exit(2);
28
+ }
29
+ const n = parseInt(v, 10);
30
+ if (!Number.isFinite(n) || n < 0) {
31
+ process.stderr.write(`error: invalid --port value: ${v}\n`);
32
+ process.exit(2);
33
+ }
34
+ port = n;
35
+ }
36
+ else if (a.startsWith('--port=')) {
37
+ const n = parseInt(a.slice('--port='.length), 10);
38
+ if (!Number.isFinite(n) || n < 0) {
39
+ process.stderr.write(`error: invalid --port value: ${a}\n`);
40
+ process.exit(2);
41
+ }
42
+ port = n;
43
+ }
44
+ else if (a === '-h' || a === '--help') {
45
+ process.stdout.write(`symphony [path-to-WORKFLOW.md] [--port PORT]\n\n` +
46
+ `If path is omitted, ./WORKFLOW.md is used.\n`);
47
+ process.exit(0);
48
+ }
49
+ else if (!workflow) {
50
+ workflow = a;
51
+ }
52
+ else {
53
+ process.stderr.write(`error: unexpected argument: ${a}\n`);
54
+ process.exit(2);
55
+ }
56
+ }
57
+ return { workflow: workflow ?? path.resolve(process.cwd(), 'WORKFLOW.md'), port };
58
+ }
59
+ async function main() {
60
+ const cli = parseCli(process.argv.slice(2));
61
+ const workflowPath = path.resolve(cli.workflow);
62
+ if (!existsSync(workflowPath)) {
63
+ process.stderr.write(`error: workflow file not found: ${workflowPath}\n`);
64
+ process.exit(2);
65
+ }
66
+ let src;
67
+ try {
68
+ src = await watchWorkflow(workflowPath);
69
+ }
70
+ catch (err) {
71
+ process.stderr.write(`error: failed to load workflow: ${err.message}\n`);
72
+ process.exit(1);
73
+ }
74
+ const { definition, config } = src.current();
75
+ if (config.tracker.kind !== 'local') {
76
+ process.stderr.write(`error: this build supports tracker.kind=local only (got: ${config.tracker.kind || '<unset>'})\n`);
77
+ process.exit(2);
78
+ }
79
+ const tracker = new LocalMarkdownTracker(config.tracker);
80
+ const workspaces = new WorkspaceManager(config);
81
+ const smolvm = new SmolvmClient(config.smolvm);
82
+ // Always instantiate the registry so a workflow reload that flips mcp.enabled from
83
+ // false to true takes effect without a process restart. The runner and HTTP routes
84
+ // gate behavior on cfg.mcp.enabled at runtime; an inactive registry holds no entries
85
+ // and answers all routes with "not active."
86
+ const mcp = new McpRegistry(tracker, { terminalStates: config.tracker.terminal_states });
87
+ // Build the runner with stubs first; we attach the orchestrator's hook callbacks after
88
+ // construction since they reference the orchestrator instance.
89
+ let orch;
90
+ const runner = new AgentRunner(config, definition, workspaces, tracker, smolvm, {
91
+ onRuntimeEvent: (id, ev) => orch.reportRuntimeEvent(id, ev),
92
+ onTokenUsage: (id, u) => orch.reportTokenUsage(id, u),
93
+ onRateLimits: (id, s) => orch.reportRateLimits(id, s),
94
+ onTurn: (id, turn) => orch.reportTurnStarted(id, turn),
95
+ onSessionStarted: (info) => orch.reportSessionStarted(info.issueId, {
96
+ sessionId: info.sessionId,
97
+ threadId: info.threadId,
98
+ pid: info.pid,
99
+ }),
100
+ }, mcp);
101
+ orch = new Orchestrator(config, definition, src, tracker, workspaces, runner);
102
+ // The tracker view is resolved through a getter so reloaded config (e.g. a moved
103
+ // tracker.root, changed active/terminal states) is reflected by both the propagation
104
+ // hook and the HTTP UI without rebinding the server.
105
+ let liveCfg = config;
106
+ orch.setOnConfigReloaded((cfg, def) => {
107
+ tracker.updateConfig(cfg.tracker);
108
+ workspaces.updateConfig(cfg);
109
+ runner.updateConfig(cfg, def);
110
+ mcp.updateTerminalStates(cfg.tracker.terminal_states);
111
+ liveCfg = cfg;
112
+ });
113
+ let http = null;
114
+ const httpPort = cli.port ?? config.server.port;
115
+ if (httpPort !== null && httpPort !== undefined) {
116
+ try {
117
+ http = await startHttpServer(orch, {
118
+ port: httpPort,
119
+ host: config.server.host,
120
+ getTrackerView: () => ({
121
+ trackerRoot: liveCfg.tracker.root,
122
+ activeStates: liveCfg.tracker.active_states,
123
+ terminalStates: liveCfg.tracker.terminal_states,
124
+ workflowPath,
125
+ }),
126
+ mcp,
127
+ });
128
+ // Tell the registry the actually-bound port (which differs from httpPort when
129
+ // --port 0 is used and the kernel picks an ephemeral port). MCP URLs injected into
130
+ // agents must point at the real listener, not the requested-port placeholder.
131
+ mcp.setEffectivePort(http.port);
132
+ }
133
+ catch (err) {
134
+ process.stderr.write(`error: failed to bind HTTP server on ${config.server.host}:${httpPort}: ${err.message}\n`);
135
+ await src.stop().catch(() => undefined);
136
+ process.exit(1);
137
+ }
138
+ }
139
+ // MCP precondition check: with mcp.enabled (the default), every dispatch will
140
+ // require a reachable MCP URL. Verify NOW that one can be constructed, rather
141
+ // than letting each per-issue dispatch fail with the same error after VM
142
+ // bring-up costs are sunk. This catches the "WORKFLOW.md has no server.port,
143
+ // and no --port was passed" misconfiguration at boot.
144
+ if (config.mcp.enabled) {
145
+ // The mcp.host_url override exists so an operator can point the in-VM agent
146
+ // at a reverse-proxy-visible URL even when symphony binds the listener at
147
+ // a different host/port. It does NOT replace the listener itself: symphony
148
+ // is the process that actually serves /api/v1/issues/<id>/mcp. If no HTTP
149
+ // listener was bound, the override would advertise a URL nothing answers,
150
+ // and mark_done calls from the agent would fail. Refuse to boot in that
151
+ // shape so the misconfiguration surfaces at startup instead of mid-dispatch.
152
+ if (http === null) {
153
+ process.stderr.write(`error: mcp.enabled=true but no HTTP server is configured. Symphony itself\n` +
154
+ `must bind a listener (set --port or server.port) so it can serve the MCP\n` +
155
+ `endpoint, even when mcp.host_url points the in-VM agent at a reverse proxy.\n`);
156
+ await src.stop().catch(() => undefined);
157
+ process.exit(1);
158
+ }
159
+ const probeUrl = mcp.buildUrl('startup-check', {
160
+ host: config.mcp.host,
161
+ explicit_host_url: config.mcp.explicit_host_url,
162
+ });
163
+ if (probeUrl === null) {
164
+ process.stderr.write(`error: mcp.enabled=true but no MCP URL can be constructed. ` +
165
+ `Set --port, server.port, or mcp.host_url so the in-VM agent can reach ` +
166
+ `the symphony MCP endpoint.\n`);
167
+ if (http)
168
+ await http.close().catch(() => undefined);
169
+ await src.stop().catch(() => undefined);
170
+ process.exit(1);
171
+ }
172
+ }
173
+ try {
174
+ await orch.start();
175
+ }
176
+ catch (err) {
177
+ process.stderr.write(`startup failed: ${err.message}\n`);
178
+ if (http)
179
+ await http.close().catch(() => undefined);
180
+ await src.stop().catch(() => undefined);
181
+ process.exit(1);
182
+ }
183
+ log.info('symphony started', {
184
+ workflow: workflowPath,
185
+ workspace_root: config.workspace.root,
186
+ tracker_root: config.tracker.root,
187
+ poll_interval_ms: config.polling.interval_ms,
188
+ http_port: httpPort,
189
+ });
190
+ const shutdown = async (signal) => {
191
+ log.info('shutdown requested', { signal });
192
+ await orch.stop();
193
+ if (http)
194
+ await http.close().catch(() => undefined);
195
+ await src.stop().catch(() => undefined);
196
+ process.exit(0);
197
+ };
198
+ process.on('SIGINT', () => void shutdown('SIGINT'));
199
+ process.on('SIGTERM', () => void shutdown('SIGTERM'));
200
+ }
201
+ main().catch((err) => {
202
+ process.stderr.write(`fatal: ${err.message}\n${err.stack ?? ''}\n`);
203
+ process.exit(1);
204
+ });
205
+ //# sourceMappingURL=symphony.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symphony.js","sourceRoot":"","sources":["../../src/bin/symphony.ts"],"names":[],"mappings":"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"}