@alisio/plugin-swarm 0.0.0-stage → 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.
Files changed (266) hide show
  1. package/.agents/agents/swarm-architect.md +20 -0
  2. package/.agents/agents/swarm-cleaner.md +20 -0
  3. package/.agents/agents/swarm-coder.md +20 -0
  4. package/.agents/agents/swarm-hardener.md +20 -0
  5. package/.agents/agents/swarm-lieutenant.md +20 -0
  6. package/.agents/agents/swarm-qa.md +20 -0
  7. package/.agents/agents/swarm-refactorer.md +20 -0
  8. package/.agents/agents/swarm-specifier.md +20 -0
  9. package/.agents/skills/swarm-architecture-rules/SKILL.md +43 -0
  10. package/.agents/skills/swarm-clarification/SKILL.md +42 -0
  11. package/.agents/skills/swarm-cleaner-metrics/SKILL.md +44 -0
  12. package/.agents/skills/swarm-engineering-constitution/SKILL.md +44 -0
  13. package/.agents/skills/swarm-gherkin-spec/SKILL.md +43 -0
  14. package/.agents/skills/swarm-handoff-protocol/SKILL.md +45 -0
  15. package/.agents/skills/swarm-lieutenant/SKILL.md +41 -0
  16. package/.agents/skills/swarm-mutation-hardening/SKILL.md +43 -0
  17. package/.agents/skills/swarm-qa-acceptance/SKILL.md +42 -0
  18. package/.agents/skills/swarm-tdd-slice/SKILL.md +44 -0
  19. package/.agents/skills/swarm-toolchain-profile/SKILL.md +41 -0
  20. package/LICENSE +21 -0
  21. package/README.es.md +337 -0
  22. package/README.md +322 -2
  23. package/assets/approval-flow.svg +1 -0
  24. package/assets/architecture.svg +1 -0
  25. package/assets/audit-states.svg +1 -0
  26. package/assets/dashboard.css +964 -0
  27. package/assets/dashboard.html +123 -0
  28. package/assets/dashboard.js +965 -0
  29. package/assets/dashboard.svg +1 -0
  30. package/assets/handoff-sequence.svg +1 -0
  31. package/assets/pack-pipelines.svg +1 -0
  32. package/assets/packs/four-pack/pack.json +18 -0
  33. package/assets/packs/six-pack/pack.json +22 -0
  34. package/assets/packs/two-pack/pack.json +14 -0
  35. package/assets/screenshots/dashboard-board-dark.png +0 -0
  36. package/assets/screenshots/dashboard-board-light.png +0 -0
  37. package/assets/screenshots/dashboard-documents-diff.png +0 -0
  38. package/assets/screenshots/dashboard-empty-state.png +0 -0
  39. package/assets/screenshots/dashboard-phone.png +0 -0
  40. package/assets/screenshots/dashboard-reject-dialog.png +0 -0
  41. package/assets/screenshots/dashboard-transcript-tail.png +0 -0
  42. package/assets/screenshots/dashboard-work-queue.png +0 -0
  43. package/assets/task-states.svg +1 -0
  44. package/assets/toolchains/node-ts.json +61 -0
  45. package/cover.svg +46 -0
  46. package/dist/adapters/child-session-runner.d.ts +36 -0
  47. package/dist/adapters/child-session-runner.d.ts.map +1 -0
  48. package/dist/adapters/child-session-runner.js +156 -0
  49. package/dist/adapters/child-session-runner.js.map +1 -0
  50. package/dist/adapters/fs-board-store.d.ts +11 -0
  51. package/dist/adapters/fs-board-store.d.ts.map +1 -0
  52. package/dist/adapters/fs-board-store.js +27 -0
  53. package/dist/adapters/fs-board-store.js.map +1 -0
  54. package/dist/adapters/fs-handoff-store.d.ts +36 -0
  55. package/dist/adapters/fs-handoff-store.d.ts.map +1 -0
  56. package/dist/adapters/fs-handoff-store.js +254 -0
  57. package/dist/adapters/fs-handoff-store.js.map +1 -0
  58. package/dist/adapters/fs-task-state-store.d.ts +16 -0
  59. package/dist/adapters/fs-task-state-store.d.ts.map +1 -0
  60. package/dist/adapters/fs-task-state-store.js +66 -0
  61. package/dist/adapters/fs-task-state-store.js.map +1 -0
  62. package/dist/adapters/git-worktree.d.ts +31 -0
  63. package/dist/adapters/git-worktree.d.ts.map +1 -0
  64. package/dist/adapters/git-worktree.js +209 -0
  65. package/dist/adapters/git-worktree.js.map +1 -0
  66. package/dist/adapters/process-exec.d.ts +36 -0
  67. package/dist/adapters/process-exec.d.ts.map +1 -0
  68. package/dist/adapters/process-exec.js +138 -0
  69. package/dist/adapters/process-exec.js.map +1 -0
  70. package/dist/adapters/process-gate-runner.d.ts +39 -0
  71. package/dist/adapters/process-gate-runner.d.ts.map +1 -0
  72. package/dist/adapters/process-gate-runner.js +242 -0
  73. package/dist/adapters/process-gate-runner.js.map +1 -0
  74. package/dist/adapters/unavailable-runner.d.ts +4 -0
  75. package/dist/adapters/unavailable-runner.d.ts.map +1 -0
  76. package/dist/adapters/unavailable-runner.js +12 -0
  77. package/dist/adapters/unavailable-runner.js.map +1 -0
  78. package/dist/app/audit.d.ts +23 -0
  79. package/dist/app/audit.d.ts.map +1 -0
  80. package/dist/app/audit.js +9 -0
  81. package/dist/app/audit.js.map +1 -0
  82. package/dist/app/budget.d.ts +29 -0
  83. package/dist/app/budget.d.ts.map +1 -0
  84. package/dist/app/budget.js +78 -0
  85. package/dist/app/budget.js.map +1 -0
  86. package/dist/app/chat-store.d.ts +18 -0
  87. package/dist/app/chat-store.d.ts.map +1 -0
  88. package/dist/app/chat-store.js +48 -0
  89. package/dist/app/chat-store.js.map +1 -0
  90. package/dist/app/documents.d.ts +33 -0
  91. package/dist/app/documents.d.ts.map +1 -0
  92. package/dist/app/documents.js +63 -0
  93. package/dist/app/documents.js.map +1 -0
  94. package/dist/app/forge.d.ts +106 -0
  95. package/dist/app/forge.d.ts.map +1 -0
  96. package/dist/app/forge.js +420 -0
  97. package/dist/app/forge.js.map +1 -0
  98. package/dist/app/operator.d.ts +46 -0
  99. package/dist/app/operator.d.ts.map +1 -0
  100. package/dist/app/operator.js +168 -0
  101. package/dist/app/operator.js.map +1 -0
  102. package/dist/app/pidfile.d.ts +18 -0
  103. package/dist/app/pidfile.d.ts.map +1 -0
  104. package/dist/app/pidfile.js +56 -0
  105. package/dist/app/pidfile.js.map +1 -0
  106. package/dist/app/project.d.ts +93 -0
  107. package/dist/app/project.d.ts.map +1 -0
  108. package/dist/app/project.js +291 -0
  109. package/dist/app/project.js.map +1 -0
  110. package/dist/app/prompts.d.ts +48 -0
  111. package/dist/app/prompts.d.ts.map +1 -0
  112. package/dist/app/prompts.js +88 -0
  113. package/dist/app/prompts.js.map +1 -0
  114. package/dist/app/pump.d.ts +144 -0
  115. package/dist/app/pump.d.ts.map +1 -0
  116. package/dist/app/pump.js +707 -0
  117. package/dist/app/pump.js.map +1 -0
  118. package/dist/app/services.d.ts +112 -0
  119. package/dist/app/services.d.ts.map +1 -0
  120. package/dist/app/services.js +323 -0
  121. package/dist/app/services.js.map +1 -0
  122. package/dist/app/state.d.ts +70 -0
  123. package/dist/app/state.d.ts.map +1 -0
  124. package/dist/app/state.js +96 -0
  125. package/dist/app/state.js.map +1 -0
  126. package/dist/args.d.ts +10 -0
  127. package/dist/args.d.ts.map +1 -0
  128. package/dist/args.js +33 -0
  129. package/dist/args.js.map +1 -0
  130. package/dist/coordinator.d.ts +80 -0
  131. package/dist/coordinator.d.ts.map +1 -0
  132. package/dist/coordinator.js +481 -0
  133. package/dist/coordinator.js.map +1 -0
  134. package/dist/dashboard/api.d.ts +28 -0
  135. package/dist/dashboard/api.d.ts.map +1 -0
  136. package/dist/dashboard/api.js +178 -0
  137. package/dist/dashboard/api.js.map +1 -0
  138. package/dist/dashboard/auth.d.ts +13 -0
  139. package/dist/dashboard/auth.d.ts.map +1 -0
  140. package/dist/dashboard/auth.js +36 -0
  141. package/dist/dashboard/auth.js.map +1 -0
  142. package/dist/dashboard/open.d.ts +7 -0
  143. package/dist/dashboard/open.d.ts.map +1 -0
  144. package/dist/dashboard/open.js +17 -0
  145. package/dist/dashboard/open.js.map +1 -0
  146. package/dist/dashboard/server.d.ts +28 -0
  147. package/dist/dashboard/server.d.ts.map +1 -0
  148. package/dist/dashboard/server.js +176 -0
  149. package/dist/dashboard/server.js.map +1 -0
  150. package/dist/doctor.d.ts +28 -0
  151. package/dist/doctor.d.ts.map +1 -0
  152. package/dist/doctor.js +108 -0
  153. package/dist/doctor.js.map +1 -0
  154. package/dist/domain/attention.d.ts +20 -0
  155. package/dist/domain/attention.d.ts.map +1 -0
  156. package/dist/domain/attention.js +41 -0
  157. package/dist/domain/attention.js.map +1 -0
  158. package/dist/domain/envelope.d.ts +37 -0
  159. package/dist/domain/envelope.d.ts.map +1 -0
  160. package/dist/domain/envelope.js +106 -0
  161. package/dist/domain/envelope.js.map +1 -0
  162. package/dist/domain/handoff.d.ts +57 -0
  163. package/dist/domain/handoff.d.ts.map +1 -0
  164. package/dist/domain/handoff.js +191 -0
  165. package/dist/domain/handoff.js.map +1 -0
  166. package/dist/domain/identifiers.d.ts +18 -0
  167. package/dist/domain/identifiers.d.ts.map +1 -0
  168. package/dist/domain/identifiers.js +70 -0
  169. package/dist/domain/identifiers.js.map +1 -0
  170. package/dist/domain/pack.d.ts +45 -0
  171. package/dist/domain/pack.d.ts.map +1 -0
  172. package/dist/domain/pack.js +207 -0
  173. package/dist/domain/pack.js.map +1 -0
  174. package/dist/domain/pipeline.d.ts +33 -0
  175. package/dist/domain/pipeline.d.ts.map +1 -0
  176. package/dist/domain/pipeline.js +50 -0
  177. package/dist/domain/pipeline.js.map +1 -0
  178. package/dist/domain/task.d.ts +26 -0
  179. package/dist/domain/task.d.ts.map +1 -0
  180. package/dist/domain/task.js +154 -0
  181. package/dist/domain/task.js.map +1 -0
  182. package/dist/domain/taskstate.d.ts +37 -0
  183. package/dist/domain/taskstate.d.ts.map +1 -0
  184. package/dist/domain/taskstate.js +98 -0
  185. package/dist/domain/taskstate.js.map +1 -0
  186. package/dist/gates/dry.d.ts +14 -0
  187. package/dist/gates/dry.d.ts.map +1 -0
  188. package/dist/gates/dry.js +71 -0
  189. package/dist/gates/dry.js.map +1 -0
  190. package/dist/gates/parsers.d.ts +34 -0
  191. package/dist/gates/parsers.d.ts.map +1 -0
  192. package/dist/gates/parsers.js +120 -0
  193. package/dist/gates/parsers.js.map +1 -0
  194. package/dist/index.d.ts +45 -0
  195. package/dist/index.d.ts.map +1 -0
  196. package/dist/index.js +207 -0
  197. package/dist/index.js.map +1 -0
  198. package/dist/options.d.ts +13 -0
  199. package/dist/options.d.ts.map +1 -0
  200. package/dist/options.js +27 -0
  201. package/dist/options.js.map +1 -0
  202. package/dist/panel.d.ts +5 -0
  203. package/dist/panel.d.ts.map +1 -0
  204. package/dist/panel.js +52 -0
  205. package/dist/panel.js.map +1 -0
  206. package/dist/ports/agent-runner.d.ts +51 -0
  207. package/dist/ports/agent-runner.d.ts.map +1 -0
  208. package/dist/ports/agent-runner.js +2 -0
  209. package/dist/ports/agent-runner.js.map +1 -0
  210. package/dist/ports/board-store.d.ts +7 -0
  211. package/dist/ports/board-store.d.ts.map +1 -0
  212. package/dist/ports/board-store.js +2 -0
  213. package/dist/ports/board-store.js.map +1 -0
  214. package/dist/ports/clock.d.ts +5 -0
  215. package/dist/ports/clock.d.ts.map +1 -0
  216. package/dist/ports/clock.js +2 -0
  217. package/dist/ports/clock.js.map +1 -0
  218. package/dist/ports/gate-runner.d.ts +34 -0
  219. package/dist/ports/gate-runner.d.ts.map +1 -0
  220. package/dist/ports/gate-runner.js +2 -0
  221. package/dist/ports/gate-runner.js.map +1 -0
  222. package/dist/ports/handoff-store.d.ts +39 -0
  223. package/dist/ports/handoff-store.d.ts.map +1 -0
  224. package/dist/ports/handoff-store.js +2 -0
  225. package/dist/ports/handoff-store.js.map +1 -0
  226. package/dist/ports/isolation.d.ts +43 -0
  227. package/dist/ports/isolation.d.ts.map +1 -0
  228. package/dist/ports/isolation.js +2 -0
  229. package/dist/ports/isolation.js.map +1 -0
  230. package/dist/ports/notifier.d.ts +28 -0
  231. package/dist/ports/notifier.d.ts.map +1 -0
  232. package/dist/ports/notifier.js +2 -0
  233. package/dist/ports/notifier.js.map +1 -0
  234. package/dist/ports/task-state-store.d.ts +10 -0
  235. package/dist/ports/task-state-store.d.ts.map +1 -0
  236. package/dist/ports/task-state-store.js +2 -0
  237. package/dist/ports/task-state-store.js.map +1 -0
  238. package/dist/refs.d.ts +10 -0
  239. package/dist/refs.d.ts.map +1 -0
  240. package/dist/refs.js +19 -0
  241. package/dist/refs.js.map +1 -0
  242. package/dist/resources.d.ts +55 -0
  243. package/dist/resources.d.ts.map +1 -0
  244. package/dist/resources.js +255 -0
  245. package/dist/resources.js.map +1 -0
  246. package/dist/status.d.ts +18 -0
  247. package/dist/status.d.ts.map +1 -0
  248. package/dist/status.js +60 -0
  249. package/dist/status.js.map +1 -0
  250. package/dist/storage.d.ts +18 -0
  251. package/dist/storage.d.ts.map +1 -0
  252. package/dist/storage.js +79 -0
  253. package/dist/storage.js.map +1 -0
  254. package/dist/toolchains/profile.d.ts +21 -0
  255. package/dist/toolchains/profile.d.ts.map +1 -0
  256. package/dist/toolchains/profile.js +60 -0
  257. package/dist/toolchains/profile.js.map +1 -0
  258. package/dist/toolchains/thresholds.d.ts +29 -0
  259. package/dist/toolchains/thresholds.d.ts.map +1 -0
  260. package/dist/toolchains/thresholds.js +45 -0
  261. package/dist/toolchains/thresholds.js.map +1 -0
  262. package/dist/version.d.ts +2 -0
  263. package/dist/version.d.ts.map +1 -0
  264. package/dist/version.js +3 -0
  265. package/dist/version.js.map +1 -0
  266. package/package.json +51 -3
@@ -0,0 +1,420 @@
1
+ import { existsSync } from "node:fs";
2
+ import { mkdir, readdir, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { FsBoardStore } from "../adapters/fs-board-store.js";
5
+ import { FsHandoffStore } from "../adapters/fs-handoff-store.js";
6
+ import { FsTaskStateStore } from "../adapters/fs-task-state-store.js";
7
+ import { deriveAttention } from "../domain/attention.js";
8
+ import { validateProjectName } from "../domain/identifiers.js";
9
+ import { parsePack, roleIds } from "../domain/pack.js";
10
+ import { entryRole } from "../domain/pipeline.js";
11
+ import { systemClock } from "../ports/clock.js";
12
+ import { silentNotifier } from "../ports/notifier.js";
13
+ import { listShippedPacks, loadShippedPack } from "../resources.js";
14
+ import { atomicWrite, ensureIgnoreEntries, Mutex, readText, resolveContained } from "../storage.js";
15
+ import { UsageMeter } from "./budget.js";
16
+ import { claimPidfile, releasePidfile } from "./pidfile.js";
17
+ import { MAX_TASK_TEXT, ProjectRuntime } from "./project.js";
18
+ const packNamePattern = /^[a-z0-9][a-z0-9-]{0,47}$/;
19
+ const githubPattern = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}\/[A-Za-z0-9._-]{1,100}$/;
20
+ export const DEFAULT_PACK = "two-pack";
21
+ function validateState(value) {
22
+ const record = value;
23
+ if (!record ||
24
+ typeof record !== "object" ||
25
+ record.schemaVersion !== 1 ||
26
+ !Array.isArray(record.projects)) {
27
+ throw new Error("forge.json is corrupt or has an unsupported schemaVersion");
28
+ }
29
+ const projects = record.projects.map((raw) => {
30
+ const entry = raw;
31
+ validateProjectName(entry.name);
32
+ if (typeof entry.pack !== "string" || !packNamePattern.test(entry.pack)) {
33
+ throw new Error("forge.json has an invalid pack name");
34
+ }
35
+ if (typeof entry.createdAt !== "string" || typeof entry.open !== "boolean") {
36
+ throw new Error("forge.json has an invalid project entry");
37
+ }
38
+ return {
39
+ name: entry.name,
40
+ pack: entry.pack,
41
+ createdAt: entry.createdAt,
42
+ open: entry.open,
43
+ };
44
+ });
45
+ return { schemaVersion: 1, projects };
46
+ }
47
+ /** The forge: `<workspace>/.alisio/swarm` with its projects, packs and open runtimes. */
48
+ export class Forge {
49
+ deps;
50
+ dir;
51
+ clock;
52
+ notifier;
53
+ runtimes = new Map();
54
+ opening = new Map();
55
+ stateLock = new Mutex();
56
+ meter;
57
+ constructor(deps) {
58
+ this.deps = deps;
59
+ this.dir = join(deps.workspace, ".alisio", "swarm");
60
+ this.clock = deps.clock ?? systemClock;
61
+ this.notifier = deps.notifier ?? silentNotifier;
62
+ }
63
+ get statePath() {
64
+ return join(this.dir, "forge.json");
65
+ }
66
+ get projectsDir() {
67
+ return join(this.dir, "projects");
68
+ }
69
+ get packsDir() {
70
+ return join(this.dir, "packs");
71
+ }
72
+ async init() {
73
+ await mkdir(this.projectsDir, { recursive: true, mode: 0o700 });
74
+ await mkdir(this.packsDir, { recursive: true, mode: 0o700 });
75
+ const created = (await readText(this.statePath)) === undefined;
76
+ if (created) {
77
+ await atomicWrite(this.statePath, `${JSON.stringify({ schemaVersion: 1, projects: [] }, null, 2)}\n`);
78
+ }
79
+ const root = this.deps.workspace;
80
+ if (existsSync(join(root, ".git")) || existsSync(join(root, ".gitignore"))) {
81
+ await ensureIgnoreEntries(join(root, ".gitignore"), [".alisio/swarm/"]);
82
+ }
83
+ return { created };
84
+ }
85
+ async readState() {
86
+ const raw = await readText(this.statePath);
87
+ if (raw === undefined)
88
+ throw new Error("The swarm forge is not initialised; run /swarm:init first");
89
+ try {
90
+ return validateState(JSON.parse(raw));
91
+ }
92
+ catch (error) {
93
+ throw new Error(error instanceof Error ? error.message : "forge.json is corrupt");
94
+ }
95
+ }
96
+ mutateState(change) {
97
+ return this.stateLock.run(async () => {
98
+ const state = await this.readState();
99
+ const result = change(state);
100
+ await atomicWrite(this.statePath, `${JSON.stringify(state, null, 2)}\n`);
101
+ return result;
102
+ });
103
+ }
104
+ // ---- packs ----
105
+ async scanLocalPacks() {
106
+ const packs = [];
107
+ const invalid = [];
108
+ let names = [];
109
+ try {
110
+ names = (await readdir(this.packsDir)).filter((file) => file.endsWith(".json")).sort();
111
+ }
112
+ catch (error) {
113
+ if (error.code !== "ENOENT")
114
+ throw error;
115
+ }
116
+ for (const file of names) {
117
+ try {
118
+ const pack = parsePack(JSON.parse((await readText(join(this.packsDir, file)))));
119
+ if (`${pack.name}.json` !== file)
120
+ throw new Error("The pack name must match its file name");
121
+ packs.push({ pack });
122
+ }
123
+ catch (error) {
124
+ invalid.push({ file, error: error instanceof Error ? error.message : String(error) });
125
+ }
126
+ }
127
+ return { packs, invalid };
128
+ }
129
+ async invalidPacks() {
130
+ return (await this.scanLocalPacks()).invalid;
131
+ }
132
+ async listPacks() {
133
+ const byName = new Map();
134
+ for (const name of await listShippedPacks()) {
135
+ const pack = await loadShippedPack(name);
136
+ byName.set(name, {
137
+ name,
138
+ description: pack.description,
139
+ roles: roleIds(pack),
140
+ source: "shipped",
141
+ });
142
+ }
143
+ for (const { pack } of (await this.scanLocalPacks()).packs) {
144
+ byName.set(pack.name, {
145
+ name: pack.name,
146
+ description: pack.description,
147
+ roles: roleIds(pack),
148
+ source: "workspace",
149
+ });
150
+ }
151
+ return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
152
+ }
153
+ /** A workspace-local pack shadows a shipped pack of the same name. */
154
+ async loadPack(name) {
155
+ if (!packNamePattern.test(name))
156
+ throw new Error("Invalid pack name");
157
+ const local = (await this.scanLocalPacks()).packs.find((entry) => entry.pack.name === name);
158
+ if (local)
159
+ return local.pack;
160
+ if ((await listShippedPacks()).includes(name))
161
+ return loadShippedPack(name);
162
+ throw new Error(`Unknown pack: ${name}`);
163
+ }
164
+ // ---- projects ----
165
+ async isInitialised() {
166
+ return (await readText(this.statePath)) !== undefined;
167
+ }
168
+ /** Everything the status views need, including closed projects (read from their files). */
169
+ async snapshot(only) {
170
+ const state = await this.readState();
171
+ if (only !== undefined && !state.projects.some((entry) => entry.name === only)) {
172
+ throw new Error(`Unknown project: ${only}`);
173
+ }
174
+ const out = [];
175
+ for (const entry of state.projects) {
176
+ if (only !== undefined && entry.name !== only)
177
+ continue;
178
+ const runtime = this.runtimes.get(entry.name);
179
+ const dir = await resolveContained(this.projectsDir, entry.name);
180
+ let pack = runtime?.pack;
181
+ if (!pack) {
182
+ try {
183
+ pack = parsePack(JSON.parse((await readText(join(dir, ".alisio", "swarm", "pack.json")))));
184
+ }
185
+ catch {
186
+ pack = undefined;
187
+ }
188
+ }
189
+ let board = runtime?.board();
190
+ if (!board) {
191
+ try {
192
+ board = await new FsBoardStore(dir).read();
193
+ }
194
+ catch {
195
+ board = undefined;
196
+ }
197
+ }
198
+ let attention = [];
199
+ if (runtime)
200
+ attention = runtime.attention();
201
+ else if (board) {
202
+ const states = new Map();
203
+ for (const saved of await new FsTaskStateStore(dir).list())
204
+ states.set(saved.taskId, saved);
205
+ attention = deriveAttention(entry.name, board, states);
206
+ }
207
+ out.push({
208
+ name: entry.name,
209
+ open: entry.open,
210
+ running: Boolean(runtime),
211
+ pack,
212
+ board,
213
+ attention,
214
+ });
215
+ }
216
+ return out;
217
+ }
218
+ async listProjects() {
219
+ const state = await this.readState();
220
+ return state.projects.map((entry) => ({
221
+ name: entry.name,
222
+ pack: entry.pack,
223
+ open: entry.open,
224
+ running: this.runtimes.has(entry.name),
225
+ }));
226
+ }
227
+ runtime(name) {
228
+ return this.runtimes.get(name);
229
+ }
230
+ /** Every running project, for synchronous views (the TUI panel). */
231
+ runningRuntimes() {
232
+ return [...this.runtimes.values()];
233
+ }
234
+ /** The mission text of a known project, open or closed. */
235
+ async mission(name) {
236
+ validateProjectName(name);
237
+ const state = await this.readState();
238
+ if (!state.projects.some((entry) => entry.name === name)) {
239
+ throw new Error(`Unknown project: ${name}`);
240
+ }
241
+ const dir = await resolveContained(this.projectsDir, name);
242
+ return (await readText(join(dir, ".alisio", "swarm", "mission.md"))) ?? "";
243
+ }
244
+ async newProject(input) {
245
+ const name = validateProjectName(input.name);
246
+ const mission = input.mission.trim();
247
+ if (!mission)
248
+ throw new Error("A project needs a mission");
249
+ if (mission.length > MAX_TASK_TEXT)
250
+ throw new Error("The mission is too long");
251
+ if (input.github !== undefined &&
252
+ (!githubPattern.test(input.github) || input.github.includes(".."))) {
253
+ throw new Error("Invalid GitHub repository: expected owner/repo");
254
+ }
255
+ const pack = input.packDefinition !== undefined
256
+ ? parsePack(input.packDefinition)
257
+ : await this.loadPack(input.pack ?? DEFAULT_PACK);
258
+ const state = await this.readState();
259
+ const dir = await resolveContained(this.projectsDir, name);
260
+ if (state.projects.some((entry) => entry.name === name) || existsSync(dir)) {
261
+ throw new Error(`Project ${name} already exists`);
262
+ }
263
+ const masterRole = entryRole(pack);
264
+ try {
265
+ if (input.github !== undefined) {
266
+ const url = (this.deps.cloneUrl ?? ((repo) => `https://github.com/${repo}.git`))(input.github);
267
+ await this.deps.isolation.cloneProject(url, dir, { masterRole });
268
+ }
269
+ else {
270
+ await this.deps.isolation.initProject(dir, { mission, masterRole });
271
+ }
272
+ await atomicWrite(join(dir, ".alisio", "swarm", "pack.json"), `${JSON.stringify(pack, null, 2)}\n`);
273
+ await atomicWrite(join(dir, ".alisio", "swarm", "mission.md"), `${mission}\n`);
274
+ await this.mutateState((current) => {
275
+ current.projects.push({
276
+ name,
277
+ pack: pack.name,
278
+ createdAt: this.clock.now().toISOString(),
279
+ open: false,
280
+ });
281
+ });
282
+ }
283
+ catch (error) {
284
+ await rm(dir, { recursive: true, force: true });
285
+ throw error;
286
+ }
287
+ return this.openProject(name);
288
+ }
289
+ async openProject(name) {
290
+ validateProjectName(name);
291
+ const existing = this.runtimes.get(name);
292
+ if (existing)
293
+ return existing;
294
+ const pending = this.opening.get(name);
295
+ if (pending)
296
+ return pending;
297
+ const work = this.doOpen(name).finally(() => this.opening.delete(name));
298
+ this.opening.set(name, work);
299
+ return work;
300
+ }
301
+ async doOpen(name) {
302
+ const state = await this.readState();
303
+ if (!state.projects.some((entry) => entry.name === name))
304
+ throw new Error(`Unknown project: ${name}`);
305
+ const dir = await resolveContained(this.projectsDir, name);
306
+ const raw = await readText(join(dir, ".alisio", "swarm", "pack.json"));
307
+ if (raw === undefined)
308
+ throw new Error(`Project ${name} has no pack.json`);
309
+ const pack = parsePack(JSON.parse(raw));
310
+ const meter = await this.usageMeter();
311
+ await this.claimPid();
312
+ const runtime = await ProjectRuntime.open({
313
+ name,
314
+ dir,
315
+ pack,
316
+ isolation: this.deps.isolation,
317
+ runner: this.deps.runner,
318
+ handoffs: new FsHandoffStore(dir, this.clock),
319
+ boards: new FsBoardStore(dir),
320
+ states: new FsTaskStateStore(dir),
321
+ clock: this.clock,
322
+ notifier: this.notifier,
323
+ maxConcurrent: this.deps.maxConcurrent ?? 3,
324
+ autoStart: this.deps.autoStart ?? true,
325
+ meter,
326
+ ...(this.deps.gates ? { gates: this.deps.gates } : {}),
327
+ });
328
+ this.runtimes.set(name, runtime);
329
+ await this.mutateState((current) => {
330
+ const entry = current.projects.find((candidate) => candidate.name === name);
331
+ if (entry)
332
+ entry.open = true;
333
+ });
334
+ return runtime;
335
+ }
336
+ get pidPath() {
337
+ return join(this.dir, "swarm.pid");
338
+ }
339
+ /** The first open project claims the pidfile; a dead previous owner is reaped and reported. */
340
+ async claimPid() {
341
+ if (this.runtimes.size > 0)
342
+ return;
343
+ const claim = await claimPidfile(this.pidPath).catch(() => ({}));
344
+ const notify = (message) => this.notifier.notify({ type: "error", project: "-", message });
345
+ if ("stale" in claim && claim.stale !== undefined) {
346
+ notify(`A previous swarm process (pid ${claim.stale}) ended without cleaning up; its state was replayed`);
347
+ }
348
+ else if ("other" in claim && claim.other !== undefined) {
349
+ notify(`Another process (pid ${claim.other}) is running this swarm forge`);
350
+ }
351
+ }
352
+ async releasePid() {
353
+ if (this.runtimes.size === 0)
354
+ await releasePidfile(this.pidPath).catch(() => undefined);
355
+ }
356
+ async usageMeter() {
357
+ this.meter ??= await UsageMeter.open({
358
+ file: join(this.dir, "usage.json"),
359
+ ...(this.deps.tokenBudget !== undefined ? { limit: this.deps.tokenBudget } : {}),
360
+ });
361
+ return this.meter;
362
+ }
363
+ /** The swarm-wide token meter (spec 8.4). */
364
+ budget() {
365
+ return {
366
+ total: this.meter?.total ?? 0,
367
+ limit: this.meter?.limit ?? this.deps.tokenBudget,
368
+ exceeded: this.meter?.exceeded ?? false,
369
+ };
370
+ }
371
+ /** Raise the soft cap and wake every pump that paused for it. */
372
+ async raiseBudget(extra) {
373
+ const meter = await this.usageMeter();
374
+ if (meter.limit === undefined)
375
+ throw new Error("No token budget is configured");
376
+ await meter.raise(extra);
377
+ for (const runtime of this.runtimes.values())
378
+ runtime.pump.wake();
379
+ }
380
+ /** Stop a project's agents and pump but keep it registered as open (it can be reopened). */
381
+ async stopProject(name) {
382
+ validateProjectName(name);
383
+ const state = await this.readState();
384
+ if (!state.projects.some((entry) => entry.name === name))
385
+ throw new Error(`Unknown project: ${name}`);
386
+ const runtime = this.runtimes.get(name);
387
+ if (!runtime)
388
+ return;
389
+ await runtime.close();
390
+ this.runtimes.delete(name);
391
+ await this.releasePid();
392
+ }
393
+ /** Stop the pump and cancel sessions. Never touches project directories. */
394
+ async closeProject(name) {
395
+ validateProjectName(name);
396
+ const state = await this.readState();
397
+ if (!state.projects.some((entry) => entry.name === name))
398
+ throw new Error(`Unknown project: ${name}`);
399
+ const runtime = this.runtimes.get(name);
400
+ if (runtime) {
401
+ await runtime.close();
402
+ this.runtimes.delete(name);
403
+ await this.releasePid();
404
+ }
405
+ await this.mutateState((current) => {
406
+ const entry = current.projects.find((candidate) => candidate.name === name);
407
+ if (entry)
408
+ entry.open = false;
409
+ });
410
+ }
411
+ /** Stop every running project (dispose, teardown). Registry flags are left as they were. */
412
+ async stopAll() {
413
+ const open = [...this.runtimes.values()];
414
+ this.runtimes.clear();
415
+ await Promise.allSettled(open.map((runtime) => runtime.close()));
416
+ this.deps.gates?.cancelAll?.();
417
+ await this.releasePid();
418
+ }
419
+ }
420
+ //# sourceMappingURL=forge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forge.js","sourceRoot":"","sources":["../../src/app/forge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { Pack } from "../domain/pack.js";
2
+ import type { TaskCard } from "../domain/task.js";
3
+ import type { Clock } from "../ports/clock.js";
4
+ import type { HandoffStore } from "../ports/handoff-store.js";
5
+ import type { Isolation } from "../ports/isolation.js";
6
+ import type { TaskStateStore } from "../ports/task-state-store.js";
7
+ import type { Pump } from "./pump.js";
8
+ /** What the operator actions need from their project (implemented by `ProjectRuntime`). */
9
+ export interface OperatorHost {
10
+ readonly name: string;
11
+ readonly dir: string;
12
+ readonly pack: Pack;
13
+ readonly isolation: Isolation;
14
+ readonly handoffs: HandoffStore;
15
+ readonly state: TaskStateStore;
16
+ readonly clock: Clock;
17
+ readonly pump: Pump;
18
+ workdir(role: string): string;
19
+ cardByName(name: string): TaskCard;
20
+ updateCard(taskId: string, patch: Partial<Pick<TaskCard, "lane" | "status" | "auditCount">>): Promise<void>;
21
+ removeCard(taskId: string): Promise<void>;
22
+ }
23
+ export type RejectAction = "retry" | "delete" | "accept";
24
+ export declare const rejectActions: readonly RejectAction[];
25
+ /**
26
+ * Human decisions on a task (approve, reject, retry, delete, accept, comments). One implementation
27
+ * behind the commands, the tools and the dashboard (AD-10).
28
+ */
29
+ export declare class Operator {
30
+ private readonly host;
31
+ constructor(host: OperatorHost);
32
+ private pendingApproval;
33
+ approve(name: string): Promise<void>;
34
+ reject(name: string, action: RejectAction, comments?: string): Promise<void>;
35
+ /** Retry: snapshot the rejected commit, restore the base, count the audit and re-run the role. */
36
+ private retryRejected;
37
+ /** Retry a held task (blocked, gate-failed or clarifying) with a fresh allowance. */
38
+ retry(name: string): Promise<void>;
39
+ /** Accept the work as it is: an approval gate or a gate failure the operator overrides. */
40
+ accept(name: string): Promise<void>;
41
+ /** Delete: archive the task, then remove its card, handoffs and state. */
42
+ delete(name: string): Promise<void>;
43
+ addComment(name: string, doc: string, text: string): Promise<void>;
44
+ clearComments(name: string): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=operator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../../src/app/operator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,2FAA2F;AAC3F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,UAAU,CACR,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC,CAAC,GAC/D,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AACzD,eAAO,MAAM,aAAa,EAAE,SAAS,YAAY,EAAkC,CAAC;AAEpF;;;GAGG;AACH,qBAAa,QAAQ;IACP,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,YAAY,EAAI;YAErC,eAAe;IAUvB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWzC;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAc7E;IAED,kGAAkG;YACpF,aAAa;IAuD3B,qFAAqF;IAC/E,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvC;IAED,2FAA2F;IACrF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIxC;IAED,0EAA0E;IACpE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BxC;IAEK,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBvE;IAEK,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/C;CACF"}
@@ -0,0 +1,168 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { join } from "node:path";
3
+ import { PHANTOM_SENDER } from "../domain/handoff.js";
4
+ import { MAX_HOLD_TEXT } from "../domain/taskstate.js";
5
+ import { assertRelativePath, atomicWrite } from "../storage.js";
6
+ import { retryBody } from "./prompts.js";
7
+ export const rejectActions = ["retry", "delete", "accept"];
8
+ /**
9
+ * Human decisions on a task (approve, reject, retry, delete, accept, comments). One implementation
10
+ * behind the commands, the tools and the dashboard (AD-10).
11
+ */
12
+ export class Operator {
13
+ host;
14
+ constructor(host) {
15
+ this.host = host;
16
+ }
17
+ async pendingApproval(card) {
18
+ const { records } = await this.host.handoffs.scan();
19
+ const record = records.find((candidate) => candidate.location.kind === "pending_approval" && candidate.handoff.taskId === card.taskId);
20
+ if (!record)
21
+ throw new Error(`Task ${card.name} is not waiting for approval`);
22
+ return record;
23
+ }
24
+ async approve(name) {
25
+ const card = this.host.cardByName(name);
26
+ const record = await this.pendingApproval(card);
27
+ const state = await this.host.state.get(card.taskId);
28
+ if (state && state.comments.length > 0) {
29
+ throw new Error(`Resolve the ${state.comments.length} comment(s) on the documents before approving, or reject the task`);
30
+ }
31
+ await this.host.pump.deliverParked(record, { approve: true });
32
+ this.host.pump.wake();
33
+ }
34
+ async reject(name, action, comments = "") {
35
+ if (!rejectActions.includes(action)) {
36
+ throw new Error("Reject needs one of: retry, delete, accept");
37
+ }
38
+ if (action === "delete")
39
+ return this.delete(name);
40
+ if (action === "accept") {
41
+ const card = this.host.cardByName(name);
42
+ const record = await this.pendingApproval(card);
43
+ await this.clearComments(name);
44
+ await this.host.pump.deliverParked(record, { approve: true });
45
+ this.host.pump.wake();
46
+ return;
47
+ }
48
+ return this.retryRejected(name, comments);
49
+ }
50
+ /** Retry: snapshot the rejected commit, restore the base, count the audit and re-run the role. */
51
+ async retryRejected(name, findings) {
52
+ const card = this.host.cardByName(name);
53
+ const record = await this.pendingApproval(card);
54
+ const role = record.location.role;
55
+ const workdir = this.host.workdir(role);
56
+ const state = await this.host.state.get(card.taskId);
57
+ const base = state?.bases[role];
58
+ const ref = `refs/swarm/rejected/${card.name}`;
59
+ if (record.handoff.commit)
60
+ await this.host.isolation.snapshotRef(workdir, ref, record.handoff.commit);
61
+ // Restoring can refuse (uncommitted changes): do it before anything is discarded.
62
+ if (base)
63
+ await this.host.isolation.restoreTo(workdir, base);
64
+ const { records } = await this.host.handoffs.scan();
65
+ const original = records
66
+ .filter((r) => r.handoff.taskId === card.taskId &&
67
+ r.handoff.type === "note" &&
68
+ r.handoff.from === PHANTOM_SENDER)
69
+ .sort((a, b) => a.handoff.createdAt.localeCompare(b.handoff.createdAt))[0];
70
+ const comments = state?.comments ?? [];
71
+ const note = {
72
+ id: randomUUID(),
73
+ from: PHANTOM_SENDER,
74
+ to: [role],
75
+ priority: record.handoff.priority,
76
+ type: "note",
77
+ task: card.name,
78
+ taskId: card.taskId,
79
+ approved: false,
80
+ nonForwarding: false,
81
+ createdAt: this.host.clock.now().toISOString(),
82
+ body: retryBody({
83
+ original: original?.handoff.body ?? `Task ${card.name}`,
84
+ ref,
85
+ findings: findings.slice(0, MAX_HOLD_TEXT),
86
+ comments,
87
+ }),
88
+ };
89
+ await this.host.handoffs.discard(record);
90
+ await this.host.handoffs.inject(note);
91
+ await this.host.state.update(card.taskId, card.name, (current) => {
92
+ current.rejections += 1;
93
+ current.comments = [];
94
+ current.hold = undefined;
95
+ });
96
+ await this.host.updateCard(card.taskId, {
97
+ lane: role,
98
+ status: "queued",
99
+ auditCount: card.auditCount + 1,
100
+ });
101
+ this.host.pump.wake();
102
+ }
103
+ /** Retry a held task (blocked, gate-failed or clarifying) with a fresh allowance. */
104
+ async retry(name) {
105
+ const card = this.host.cardByName(name);
106
+ await this.host.pump.releaseHold(card.taskId);
107
+ }
108
+ /** Accept the work as it is: an approval gate or a gate failure the operator overrides. */
109
+ async accept(name) {
110
+ const card = this.host.cardByName(name);
111
+ if (card.status === "waiting_approval")
112
+ return this.reject(name, "accept");
113
+ await this.host.pump.acceptHold(card.taskId);
114
+ }
115
+ /** Delete: archive the task, then remove its card, handoffs and state. */
116
+ async delete(name) {
117
+ const card = this.host.cardByName(name);
118
+ if (this.host.pump.isTaskRunning(card.taskId)) {
119
+ throw new Error(`Task ${card.name} is running; stop the project before deleting it`);
120
+ }
121
+ this.host.pump.forget(card.taskId);
122
+ const { records } = await this.host.handoffs.scan();
123
+ const mine = records.filter((record) => record.handoff.taskId === card.taskId);
124
+ await atomicWrite(join(this.host.dir, ".alisio", "swarm", "archive", `${card.taskId}.json`), `${JSON.stringify({
125
+ schemaVersion: 1,
126
+ archivedAt: this.host.clock.now().toISOString(),
127
+ card,
128
+ state: (await this.host.state.get(card.taskId)) ?? null,
129
+ handoffs: mine.map((record) => ({
130
+ location: record.location,
131
+ fileName: record.fileName,
132
+ handoff: record.handoff,
133
+ })),
134
+ }, null, 2)}\n`);
135
+ await this.host.handoffs.purge(card.taskId);
136
+ await this.host.state.remove(card.taskId);
137
+ await this.host.removeCard(card.taskId);
138
+ }
139
+ async addComment(name, doc, text) {
140
+ const card = this.host.cardByName(name);
141
+ if (card.status !== "waiting_approval") {
142
+ throw new Error(`Task ${card.name} is not waiting for approval`);
143
+ }
144
+ const path = assertRelativePath(doc);
145
+ const body = text.trim();
146
+ if (!body)
147
+ throw new Error("A comment needs text");
148
+ if (body.length > MAX_HOLD_TEXT)
149
+ throw new Error("The comment is too long");
150
+ await this.host.state.update(card.taskId, card.name, (state) => {
151
+ state.comments.push({
152
+ doc: path,
153
+ text: body,
154
+ createdAt: this.host.clock.now().toISOString(),
155
+ });
156
+ });
157
+ }
158
+ async clearComments(name) {
159
+ const card = this.host.cardByName(name);
160
+ const state = await this.host.state.get(card.taskId);
161
+ if (!state || state.comments.length === 0)
162
+ return;
163
+ await this.host.state.update(card.taskId, card.name, (current) => {
164
+ current.comments = [];
165
+ });
166
+ }
167
+ }
168
+ //# sourceMappingURL=operator.js.map