smol-symphony 0.1.0 → 0.2.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.
Files changed (140) hide show
  1. package/AGENTS.md +105 -38
  2. package/PRODUCT.md +2 -1
  3. package/README.md +195 -98
  4. package/SPEC.md +543 -1915
  5. package/WORKFLOW.md +654 -179
  6. package/WORKFLOW.template.md +761 -121
  7. package/dist/acp-bridge.js +324 -0
  8. package/dist/acp-bridge.js.map +1 -0
  9. package/dist/actions/cache.js +191 -0
  10. package/dist/actions/cache.js.map +1 -0
  11. package/dist/actions/effects.js +41 -0
  12. package/dist/actions/effects.js.map +1 -0
  13. package/dist/actions/executor.js +570 -0
  14. package/dist/actions/executor.js.map +1 -0
  15. package/dist/actions/index.js +13 -0
  16. package/dist/actions/index.js.map +1 -0
  17. package/dist/actions/parsing.js +273 -0
  18. package/dist/actions/parsing.js.map +1 -0
  19. package/dist/actions/predicate-env.js +27 -0
  20. package/dist/actions/predicate-env.js.map +1 -0
  21. package/dist/actions/predicates.js +49 -0
  22. package/dist/actions/predicates.js.map +1 -0
  23. package/dist/actions/templating.js +66 -0
  24. package/dist/actions/templating.js.map +1 -0
  25. package/dist/actions/types.js +15 -0
  26. package/dist/actions/types.js.map +1 -0
  27. package/dist/agent/acp.js +232 -63
  28. package/dist/agent/acp.js.map +1 -1
  29. package/dist/agent/adapter-names.js +159 -0
  30. package/dist/agent/adapter-names.js.map +1 -0
  31. package/dist/agent/adapters.js +338 -102
  32. package/dist/agent/adapters.js.map +1 -1
  33. package/dist/agent/credential-extractors.js +342 -0
  34. package/dist/agent/credential-extractors.js.map +1 -0
  35. package/dist/agent/credential-secrets.js +628 -0
  36. package/dist/agent/credential-secrets.js.map +1 -0
  37. package/dist/agent/credential-ticker.js +57 -0
  38. package/dist/agent/credential-ticker.js.map +1 -0
  39. package/dist/agent/gondolin-creds-staging.js +356 -0
  40. package/dist/agent/gondolin-creds-staging.js.map +1 -0
  41. package/dist/agent/gondolin-dispatch.js +375 -0
  42. package/dist/agent/gondolin-dispatch.js.map +1 -0
  43. package/dist/agent/gondolin.js +124 -0
  44. package/dist/agent/gondolin.js.map +1 -0
  45. package/dist/agent/runner-decisions.js +134 -0
  46. package/dist/agent/runner-decisions.js.map +1 -0
  47. package/dist/agent/runner.js +1352 -290
  48. package/dist/agent/runner.js.map +1 -1
  49. package/dist/agent/tool-call-summary.js +102 -0
  50. package/dist/agent/tool-call-summary.js.map +1 -0
  51. package/dist/agent/vm-acp-mapping.js +73 -0
  52. package/dist/agent/vm-acp-mapping.js.map +1 -0
  53. package/dist/agent/vm-guards.js +262 -0
  54. package/dist/agent/vm-guards.js.map +1 -0
  55. package/dist/agent/vm-port.js +22 -0
  56. package/dist/agent/vm-port.js.map +1 -0
  57. package/dist/agent/vm-process-registry.js +79 -0
  58. package/dist/agent/vm-process-registry.js.map +1 -0
  59. package/dist/bin/cli-args.js +105 -0
  60. package/dist/bin/cli-args.js.map +1 -0
  61. package/dist/bin/symphony.js +719 -130
  62. package/dist/bin/symphony.js.map +1 -1
  63. package/dist/errors.js +15 -0
  64. package/dist/errors.js.map +1 -0
  65. package/dist/http-disk.js +135 -0
  66. package/dist/http-disk.js.map +1 -0
  67. package/dist/http-handlers.js +180 -0
  68. package/dist/http-handlers.js.map +1 -0
  69. package/dist/http.js +1476 -764
  70. package/dist/http.js.map +1 -1
  71. package/dist/issues.js +178 -0
  72. package/dist/issues.js.map +1 -0
  73. package/dist/logging.js +163 -5
  74. package/dist/logging.js.map +1 -1
  75. package/dist/mcp.js +391 -163
  76. package/dist/mcp.js.map +1 -1
  77. package/dist/memory.js +85 -0
  78. package/dist/memory.js.map +1 -0
  79. package/dist/orchestrator-decisions.js +331 -0
  80. package/dist/orchestrator-decisions.js.map +1 -0
  81. package/dist/orchestrator.js +1189 -303
  82. package/dist/orchestrator.js.map +1 -1
  83. package/dist/prompt.js +5 -5
  84. package/dist/prompt.js.map +1 -1
  85. package/dist/reconciler/cache.js +65 -0
  86. package/dist/reconciler/cache.js.map +1 -0
  87. package/dist/reconciler/index.js +448 -0
  88. package/dist/reconciler/index.js.map +1 -0
  89. package/dist/reconciler/ledger.js +131 -0
  90. package/dist/reconciler/ledger.js.map +1 -0
  91. package/dist/reconciler/pr-adapters.js +174 -0
  92. package/dist/reconciler/pr-adapters.js.map +1 -0
  93. package/dist/reconciler/pr-decide.js +167 -0
  94. package/dist/reconciler/pr-decide.js.map +1 -0
  95. package/dist/reconciler/pr.js +422 -0
  96. package/dist/reconciler/pr.js.map +1 -0
  97. package/dist/reconciler/types.js +12 -0
  98. package/dist/reconciler/types.js.map +1 -0
  99. package/dist/reconciler/vm.js +243 -0
  100. package/dist/reconciler/vm.js.map +1 -0
  101. package/dist/reconciler/workspace-defaults.js +83 -0
  102. package/dist/reconciler/workspace-defaults.js.map +1 -0
  103. package/dist/reconciler/workspace.js +272 -0
  104. package/dist/reconciler/workspace.js.map +1 -0
  105. package/dist/runlog.js +403 -0
  106. package/dist/runlog.js.map +1 -0
  107. package/dist/scaffold.js +165 -0
  108. package/dist/scaffold.js.map +1 -0
  109. package/dist/trackers/local.js +234 -133
  110. package/dist/trackers/local.js.map +1 -1
  111. package/dist/trackers/types.js +1 -1
  112. package/dist/trackers/types.js.map +1 -1
  113. package/dist/types.js +1 -1
  114. package/dist/util/clock.js +12 -0
  115. package/dist/util/clock.js.map +1 -0
  116. package/dist/util/crypto.js +25 -0
  117. package/dist/util/crypto.js.map +1 -0
  118. package/dist/util/frontmatter.js +70 -0
  119. package/dist/util/frontmatter.js.map +1 -0
  120. package/dist/util/fs-issues.js +22 -0
  121. package/dist/util/fs-issues.js.map +1 -0
  122. package/dist/util/process.js +152 -0
  123. package/dist/util/process.js.map +1 -0
  124. package/dist/util/workspace-key.js +10 -0
  125. package/dist/util/workspace-key.js.map +1 -0
  126. package/dist/workflow-loader.js +147 -0
  127. package/dist/workflow-loader.js.map +1 -0
  128. package/dist/workflow.js +656 -219
  129. package/dist/workflow.js.map +1 -1
  130. package/dist/workspace-types.js +8 -0
  131. package/dist/workspace-types.js.map +1 -0
  132. package/dist/workspace.js +367 -120
  133. package/dist/workspace.js.map +1 -1
  134. package/package.json +14 -6
  135. package/scripts/vm-agent.mjs +211 -0
  136. package/dist/agent/codex.js +0 -439
  137. package/dist/agent/codex.js.map +0 -1
  138. package/dist/agent/smolvm.js +0 -174
  139. package/dist/agent/smolvm.js.map +0 -1
  140. package/scripts/build-vm.sh +0 -67
@@ -0,0 +1,79 @@
1
+ // VmProcessRegistry — tracks the backing host (qemu) process of every live
2
+ // Gondolin VM the orchestrator created, so a forced shutdown can SIGKILL them
3
+ // before `process.exit` (issue 152).
4
+ //
5
+ // WHY this exists. Symphony creates VMs *in-process* (`VM.create` runs in the
6
+ // orchestrator), so each qemu instance is a DIRECT CHILD of the symphony
7
+ // process. On `process.exit` those children are reparented to init and survive
8
+ // as orphaned `qemu-system-x86_64`. The Gondolin session registry can't help
9
+ // reap them on the forced path: it records the *creating* process's pid
10
+ // (symphony's own — see session-registry.js `pid: process.pid`), so a
11
+ // session-pid reaper either skips them (self-pid guard) or, worse, would target
12
+ // the orchestrator. The only reliable handle on the backing qemu is each VM's
13
+ // `getHostPid()` (the qemu `child.pid`), which is what this registry signals.
14
+ //
15
+ // Adapter-layer module: no domain imports. The minimal `KillableVm` shape is
16
+ // satisfied structurally by Gondolin's `VM`, so this stays free of the heavy
17
+ // Gondolin import and is unit-testable in isolation.
18
+ export class VmProcessRegistry {
19
+ live = new Set();
20
+ kill;
21
+ selfPid;
22
+ constructor(opts = {}) {
23
+ this.kill = opts.kill ?? ((pid, signal) => process.kill(pid, signal));
24
+ this.selfPid = opts.selfPid ?? process.pid;
25
+ }
26
+ /**
27
+ * Register a live VM. Returns a deregister callback to invoke after a clean
28
+ * `close()` so the set stays bounded across many dispatches. Correctness does
29
+ * NOT depend on deregistration: once a VM's runner exits, `getHostPid()`
30
+ * returns null and {@link killAll} skips it, so a leaked entry can never
31
+ * signal a (possibly pid-reused) dead process.
32
+ */
33
+ track(vm) {
34
+ this.live.add(vm);
35
+ return () => {
36
+ this.live.delete(vm);
37
+ };
38
+ }
39
+ /**
40
+ * SIGKILL the backing host process of every tracked VM that still has a live
41
+ * runner pid. Synchronous and bounded (one signal per tracked VM, no IO), so
42
+ * the forced-shutdown path can call it and `process.exit` immediately without
43
+ * risking a hang. Best-effort: a VM with no live runner (`getHostPid → null`)
44
+ * is skipped, and ESRCH / any other signal failure is swallowed — a stuck pid
45
+ * must not wedge the forced exit. Returns the number of host pids targeted.
46
+ */
47
+ killAll() {
48
+ const pids = safeKillTargets([...this.live].map((vm) => vm.getHostPid()), this.selfPid);
49
+ for (const pid of pids) {
50
+ try {
51
+ this.kill(pid, 'SIGKILL');
52
+ }
53
+ catch {
54
+ // ESRCH (already gone) / EPERM / etc. — best-effort on the way out.
55
+ }
56
+ }
57
+ return pids.length;
58
+ }
59
+ }
60
+ /**
61
+ * Pure: reduce candidate VM host pids (some unknown/null) to the distinct, safe
62
+ * set to SIGKILL — positive safe integers, never the caller's own pid (which
63
+ * `process.kill` would aim at the orchestrator) and never `<= 0` (which would
64
+ * signal a whole process group). Exported for direct testing.
65
+ */
66
+ export function safeKillTargets(hostPids, selfPid) {
67
+ const out = new Set();
68
+ for (const pid of hostPids) {
69
+ if (pid === null || pid === undefined)
70
+ continue;
71
+ if (!Number.isSafeInteger(pid) || pid <= 0)
72
+ continue;
73
+ if (pid === selfPid)
74
+ continue;
75
+ out.add(pid);
76
+ }
77
+ return [...out];
78
+ }
79
+ //# sourceMappingURL=vm-process-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vm-process-registry.js","sourceRoot":"","sources":["../../src/agent/vm-process-registry.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,+EAA+E;AAC/E,6EAA6E;AAC7E,wEAAwE;AACxE,sEAAsE;AACtE,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,qDAAqD;AAmBrD,MAAM,OAAO,iBAAiB;IACX,IAAI,GAAG,IAAI,GAAG,EAAc,CAAC;IAC7B,IAAI,CAAoD;IACxD,OAAO,CAAS;IAEjC,YAAY,OAAiC,EAAE;QAC7C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC;IAC7C,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,EAAc;QAClB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvB,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,OAAO;QACL,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,oEAAoE;YACtE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,QAA0C,EAC1C,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAAE,SAAS;QACrD,IAAI,GAAG,KAAK,OAAO;YAAE,SAAS;QAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,105 @@
1
+ // CLI argument parsing for the `symphony` binary. Lives in its own module so
2
+ // tests can import `parseCli` without triggering the `main()` side effects of
3
+ // `src/bin/symphony.ts` (HTTP/ACP listeners, tracker init, etc.) at import
4
+ // time.
5
+ import path from 'node:path';
6
+ import process from 'node:process';
7
+ export function parseCli(argv) {
8
+ // Detect subcommands. `reconcile` and `rerun` share the parsed-args
9
+ // skeleton with the default `serve` mode; the subcommand is what differs
10
+ // at the action layer (main() dispatches accordingly). Preserve the
11
+ // subcommand verbatim in the return value — collapsing `reconcile` back to
12
+ // `serve` would let the missing-workflow scaffold prompt fire on a
13
+ // `symphony reconcile` invocation, which has nothing to scaffold against.
14
+ let subcommand = 'serve';
15
+ let rest = argv;
16
+ if (argv[0] === 'reconcile') {
17
+ subcommand = 'reconcile';
18
+ rest = argv.slice(1);
19
+ }
20
+ else if (argv[0] === 'rerun') {
21
+ subcommand = 'rerun';
22
+ rest = argv.slice(1);
23
+ }
24
+ let workflow = null;
25
+ let port = null;
26
+ let reconcileForce = false;
27
+ let rerunCheck = null;
28
+ let verbose = false;
29
+ for (let i = 0; i < rest.length; i++) {
30
+ const a = rest[i];
31
+ if (a === '--port' || a === '-p') {
32
+ const v = rest[++i];
33
+ if (!v) {
34
+ process.stderr.write(`error: --port requires a value\n`);
35
+ process.exit(2);
36
+ }
37
+ const n = parseInt(v, 10);
38
+ if (!Number.isFinite(n) || n < 0) {
39
+ process.stderr.write(`error: invalid --port value: ${v}\n`);
40
+ process.exit(2);
41
+ }
42
+ port = n;
43
+ }
44
+ else if (a.startsWith('--port=')) {
45
+ const n = parseInt(a.slice('--port='.length), 10);
46
+ if (!Number.isFinite(n) || n < 0) {
47
+ process.stderr.write(`error: invalid --port value: ${a}\n`);
48
+ process.exit(2);
49
+ }
50
+ port = n;
51
+ }
52
+ else if (subcommand === 'reconcile' && a === '--force') {
53
+ reconcileForce = true;
54
+ }
55
+ else if (a === '--reconcile-force') {
56
+ // Top-level alias for `reconcile --force`. Kept so existing invocations and
57
+ // process-manager unit files don't need rewriting; the new canonical shape is
58
+ // `symphony reconcile --force [path]`.
59
+ reconcileForce = true;
60
+ }
61
+ else if (subcommand === 'rerun' && (a === '--check' || a === '-c')) {
62
+ const v = rest[++i];
63
+ if (!v) {
64
+ process.stderr.write(`error: --check requires a value\n`);
65
+ process.exit(2);
66
+ }
67
+ rerunCheck = v;
68
+ }
69
+ else if (subcommand === 'rerun' && a.startsWith('--check=')) {
70
+ rerunCheck = a.slice('--check='.length);
71
+ }
72
+ else if (a === '--verbose' || a === '-v' || a === '--foreground') {
73
+ verbose = true;
74
+ }
75
+ else if (a === '-h' || a === '--help') {
76
+ process.stdout.write(`symphony [path-to-WORKFLOW.md] [--port PORT] [--reconcile-force] [--verbose]\n` +
77
+ `symphony reconcile [path-to-WORKFLOW.md] [--force] [--port PORT]\n` +
78
+ `symphony rerun --check=<name> [path-to-WORKFLOW.md]\n\n` +
79
+ `If path is omitted, ./WORKFLOW.md is used.\n` +
80
+ `\`reconcile --force\` (or the alias \`--reconcile-force\`) requests an\n` +
81
+ `immediate reconcile pass (VM / workspace / PR janitors) at startup.\n` +
82
+ `\`rerun --check=<name>\` invalidates the named run_in_vm action's content-hash\n` +
83
+ `cache entry so the next dispatch into its state re-executes it.\n` +
84
+ `\`--verbose\` (alias \`--foreground\`, \`-v\`) mirrors structured logs to the\n` +
85
+ `console; by default they go to the log file only so the console stays clean.\n`);
86
+ process.exit(0);
87
+ }
88
+ else if (!workflow) {
89
+ workflow = a;
90
+ }
91
+ else {
92
+ process.stderr.write(`error: unexpected argument: ${a}\n`);
93
+ process.exit(2);
94
+ }
95
+ }
96
+ return {
97
+ subcommand,
98
+ workflow: workflow ?? path.resolve(process.cwd(), 'WORKFLOW.md'),
99
+ port,
100
+ reconcileForce,
101
+ rerunCheck,
102
+ verbose,
103
+ };
104
+ }
105
+ //# sourceMappingURL=cli-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-args.js","sourceRoot":"","sources":["../../src/bin/cli-args.ts"],"names":[],"mappings":"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"}