@songsid/agend 0.0.1

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 (232) hide show
  1. package/README.md +210 -0
  2. package/README.zh-TW.md +134 -0
  3. package/dist/access-path.d.ts +10 -0
  4. package/dist/access-path.js +32 -0
  5. package/dist/access-path.js.map +1 -0
  6. package/dist/adapter-world.d.ts +25 -0
  7. package/dist/adapter-world.js +41 -0
  8. package/dist/adapter-world.js.map +1 -0
  9. package/dist/agent-cli-instructions.md +50 -0
  10. package/dist/agent-cli.d.ts +2 -0
  11. package/dist/agent-cli.js +200 -0
  12. package/dist/agent-cli.js.map +1 -0
  13. package/dist/agent-endpoint.d.ts +25 -0
  14. package/dist/agent-endpoint.js +162 -0
  15. package/dist/agent-endpoint.js.map +1 -0
  16. package/dist/backend/antigravity.d.ts +17 -0
  17. package/dist/backend/antigravity.js +98 -0
  18. package/dist/backend/antigravity.js.map +1 -0
  19. package/dist/backend/claude-code.d.ts +23 -0
  20. package/dist/backend/claude-code.js +171 -0
  21. package/dist/backend/claude-code.js.map +1 -0
  22. package/dist/backend/codex.d.ts +18 -0
  23. package/dist/backend/codex.js +160 -0
  24. package/dist/backend/codex.js.map +1 -0
  25. package/dist/backend/factory.d.ts +2 -0
  26. package/dist/backend/factory.js +28 -0
  27. package/dist/backend/factory.js.map +1 -0
  28. package/dist/backend/gemini-cli.d.ts +17 -0
  29. package/dist/backend/gemini-cli.js +163 -0
  30. package/dist/backend/gemini-cli.js.map +1 -0
  31. package/dist/backend/index.d.ts +7 -0
  32. package/dist/backend/index.js +7 -0
  33. package/dist/backend/index.js.map +1 -0
  34. package/dist/backend/kiro.d.ts +17 -0
  35. package/dist/backend/kiro.js +147 -0
  36. package/dist/backend/kiro.js.map +1 -0
  37. package/dist/backend/marker-utils.d.ts +13 -0
  38. package/dist/backend/marker-utils.js +64 -0
  39. package/dist/backend/marker-utils.js.map +1 -0
  40. package/dist/backend/mock.d.ts +25 -0
  41. package/dist/backend/mock.js +85 -0
  42. package/dist/backend/mock.js.map +1 -0
  43. package/dist/backend/opencode.d.ts +16 -0
  44. package/dist/backend/opencode.js +136 -0
  45. package/dist/backend/opencode.js.map +1 -0
  46. package/dist/backend/types.d.ts +86 -0
  47. package/dist/backend/types.js +33 -0
  48. package/dist/backend/types.js.map +1 -0
  49. package/dist/channel/access-manager.d.ts +18 -0
  50. package/dist/channel/access-manager.js +153 -0
  51. package/dist/channel/access-manager.js.map +1 -0
  52. package/dist/channel/adapters/telegram.d.ts +63 -0
  53. package/dist/channel/adapters/telegram.js +646 -0
  54. package/dist/channel/adapters/telegram.js.map +1 -0
  55. package/dist/channel/attachment-handler.d.ts +15 -0
  56. package/dist/channel/attachment-handler.js +88 -0
  57. package/dist/channel/attachment-handler.js.map +1 -0
  58. package/dist/channel/factory.d.ts +12 -0
  59. package/dist/channel/factory.js +67 -0
  60. package/dist/channel/factory.js.map +1 -0
  61. package/dist/channel/ipc-bridge.d.ts +26 -0
  62. package/dist/channel/ipc-bridge.js +220 -0
  63. package/dist/channel/ipc-bridge.js.map +1 -0
  64. package/dist/channel/mcp-server.d.ts +10 -0
  65. package/dist/channel/mcp-server.js +288 -0
  66. package/dist/channel/mcp-server.js.map +1 -0
  67. package/dist/channel/mcp-tools.d.ts +17 -0
  68. package/dist/channel/mcp-tools.js +110 -0
  69. package/dist/channel/mcp-tools.js.map +1 -0
  70. package/dist/channel/message-bus.d.ts +17 -0
  71. package/dist/channel/message-bus.js +86 -0
  72. package/dist/channel/message-bus.js.map +1 -0
  73. package/dist/channel/message-queue.d.ts +39 -0
  74. package/dist/channel/message-queue.js +253 -0
  75. package/dist/channel/message-queue.js.map +1 -0
  76. package/dist/channel/tool-router.d.ts +6 -0
  77. package/dist/channel/tool-router.js +75 -0
  78. package/dist/channel/tool-router.js.map +1 -0
  79. package/dist/channel/tool-tracker.d.ts +13 -0
  80. package/dist/channel/tool-tracker.js +58 -0
  81. package/dist/channel/tool-tracker.js.map +1 -0
  82. package/dist/channel/types.d.ts +118 -0
  83. package/dist/channel/types.js +2 -0
  84. package/dist/channel/types.js.map +1 -0
  85. package/dist/chat-export.d.ts +4 -0
  86. package/dist/chat-export.js +91 -0
  87. package/dist/chat-export.js.map +1 -0
  88. package/dist/classic-channel-manager.d.ts +59 -0
  89. package/dist/classic-channel-manager.js +193 -0
  90. package/dist/classic-channel-manager.js.map +1 -0
  91. package/dist/cli.d.ts +2 -0
  92. package/dist/cli.js +1833 -0
  93. package/dist/cli.js.map +1 -0
  94. package/dist/config.d.ts +9 -0
  95. package/dist/config.js +118 -0
  96. package/dist/config.js.map +1 -0
  97. package/dist/context-guardian.d.ts +26 -0
  98. package/dist/context-guardian.js +73 -0
  99. package/dist/context-guardian.js.map +1 -0
  100. package/dist/cost-guard.d.ts +36 -0
  101. package/dist/cost-guard.js +147 -0
  102. package/dist/cost-guard.js.map +1 -0
  103. package/dist/daemon-entry.d.ts +1 -0
  104. package/dist/daemon-entry.js +29 -0
  105. package/dist/daemon-entry.js.map +1 -0
  106. package/dist/daemon.d.ts +152 -0
  107. package/dist/daemon.js +1714 -0
  108. package/dist/daemon.js.map +1 -0
  109. package/dist/daily-summary.d.ts +13 -0
  110. package/dist/daily-summary.js +55 -0
  111. package/dist/daily-summary.js.map +1 -0
  112. package/dist/event-log.d.ts +36 -0
  113. package/dist/event-log.js +100 -0
  114. package/dist/event-log.js.map +1 -0
  115. package/dist/export-import.d.ts +2 -0
  116. package/dist/export-import.js +162 -0
  117. package/dist/export-import.js.map +1 -0
  118. package/dist/fleet-context.d.ts +61 -0
  119. package/dist/fleet-context.js +4 -0
  120. package/dist/fleet-context.js.map +1 -0
  121. package/dist/fleet-dashboard-html.d.ts +6 -0
  122. package/dist/fleet-dashboard-html.js +443 -0
  123. package/dist/fleet-dashboard-html.js.map +1 -0
  124. package/dist/fleet-health-server.d.ts +35 -0
  125. package/dist/fleet-health-server.js +290 -0
  126. package/dist/fleet-health-server.js.map +1 -0
  127. package/dist/fleet-instructions.d.ts +5 -0
  128. package/dist/fleet-instructions.js +161 -0
  129. package/dist/fleet-instructions.js.map +1 -0
  130. package/dist/fleet-manager.d.ts +212 -0
  131. package/dist/fleet-manager.js +3655 -0
  132. package/dist/fleet-manager.js.map +1 -0
  133. package/dist/fleet-rpc-handlers.d.ts +42 -0
  134. package/dist/fleet-rpc-handlers.js +356 -0
  135. package/dist/fleet-rpc-handlers.js.map +1 -0
  136. package/dist/fleet-system-prompt.d.ts +11 -0
  137. package/dist/fleet-system-prompt.js +61 -0
  138. package/dist/fleet-system-prompt.js.map +1 -0
  139. package/dist/general-knowledge/skills.md +177 -0
  140. package/dist/hang-detector.d.ts +16 -0
  141. package/dist/hang-detector.js +53 -0
  142. package/dist/hang-detector.js.map +1 -0
  143. package/dist/index.d.ts +8 -0
  144. package/dist/index.js +6 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/instance-lifecycle.d.ts +90 -0
  147. package/dist/instance-lifecycle.js +592 -0
  148. package/dist/instance-lifecycle.js.map +1 -0
  149. package/dist/instructions.d.ts +15 -0
  150. package/dist/instructions.js +90 -0
  151. package/dist/instructions.js.map +1 -0
  152. package/dist/logger.d.ts +7 -0
  153. package/dist/logger.js +84 -0
  154. package/dist/logger.js.map +1 -0
  155. package/dist/outbound-handlers.d.ts +51 -0
  156. package/dist/outbound-handlers.js +739 -0
  157. package/dist/outbound-handlers.js.map +1 -0
  158. package/dist/outbound-schemas.d.ts +238 -0
  159. package/dist/outbound-schemas.js +248 -0
  160. package/dist/outbound-schemas.js.map +1 -0
  161. package/dist/paths.d.ts +10 -0
  162. package/dist/paths.js +42 -0
  163. package/dist/paths.js.map +1 -0
  164. package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
  165. package/dist/quickstart.d.ts +1 -0
  166. package/dist/quickstart.js +595 -0
  167. package/dist/quickstart.js.map +1 -0
  168. package/dist/routing-engine.d.ts +22 -0
  169. package/dist/routing-engine.js +44 -0
  170. package/dist/routing-engine.js.map +1 -0
  171. package/dist/safe-async.d.ts +6 -0
  172. package/dist/safe-async.js +20 -0
  173. package/dist/safe-async.js.map +1 -0
  174. package/dist/scheduler/db.d.ts +37 -0
  175. package/dist/scheduler/db.js +360 -0
  176. package/dist/scheduler/db.js.map +1 -0
  177. package/dist/scheduler/db.test.d.ts +1 -0
  178. package/dist/scheduler/db.test.js +92 -0
  179. package/dist/scheduler/db.test.js.map +1 -0
  180. package/dist/scheduler/index.d.ts +4 -0
  181. package/dist/scheduler/index.js +4 -0
  182. package/dist/scheduler/index.js.map +1 -0
  183. package/dist/scheduler/scheduler.d.ts +44 -0
  184. package/dist/scheduler/scheduler.js +197 -0
  185. package/dist/scheduler/scheduler.js.map +1 -0
  186. package/dist/scheduler/scheduler.test.d.ts +1 -0
  187. package/dist/scheduler/scheduler.test.js +119 -0
  188. package/dist/scheduler/scheduler.test.js.map +1 -0
  189. package/dist/scheduler/types.d.ts +107 -0
  190. package/dist/scheduler/types.js +7 -0
  191. package/dist/scheduler/types.js.map +1 -0
  192. package/dist/service-installer.d.ts +17 -0
  193. package/dist/service-installer.js +182 -0
  194. package/dist/service-installer.js.map +1 -0
  195. package/dist/setup-wizard.d.ts +48 -0
  196. package/dist/setup-wizard.js +701 -0
  197. package/dist/setup-wizard.js.map +1 -0
  198. package/dist/statusline-watcher.d.ts +34 -0
  199. package/dist/statusline-watcher.js +73 -0
  200. package/dist/statusline-watcher.js.map +1 -0
  201. package/dist/stt.d.ts +10 -0
  202. package/dist/stt.js +33 -0
  203. package/dist/stt.js.map +1 -0
  204. package/dist/tmux-control.d.ts +52 -0
  205. package/dist/tmux-control.js +207 -0
  206. package/dist/tmux-control.js.map +1 -0
  207. package/dist/tmux-manager.d.ts +44 -0
  208. package/dist/tmux-manager.js +218 -0
  209. package/dist/tmux-manager.js.map +1 -0
  210. package/dist/topic-archiver.d.ts +40 -0
  211. package/dist/topic-archiver.js +103 -0
  212. package/dist/topic-archiver.js.map +1 -0
  213. package/dist/topic-commands.d.ts +28 -0
  214. package/dist/topic-commands.js +359 -0
  215. package/dist/topic-commands.js.map +1 -0
  216. package/dist/transcript-monitor.d.ts +23 -0
  217. package/dist/transcript-monitor.js +164 -0
  218. package/dist/transcript-monitor.js.map +1 -0
  219. package/dist/types.d.ts +211 -0
  220. package/dist/types.js +2 -0
  221. package/dist/types.js.map +1 -0
  222. package/dist/ui/dashboard.html +719 -0
  223. package/dist/web-api.d.ts +101 -0
  224. package/dist/web-api.js +648 -0
  225. package/dist/web-api.js.map +1 -0
  226. package/dist/webhook-emitter.d.ts +15 -0
  227. package/dist/webhook-emitter.js +41 -0
  228. package/dist/webhook-emitter.js.map +1 -0
  229. package/dist/workflow-templates/default.md +35 -0
  230. package/package.json +76 -0
  231. package/templates/launchd.plist.ejs +31 -0
  232. package/templates/systemd.service.ejs +16 -0
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Health / dashboard HTTP server for the daemon.
3
+ *
4
+ * Exposes:
5
+ * - GET /health (public, no auth)
6
+ * - GET /status (basic per-instance snapshot)
7
+ * - GET /api/fleet (enriched fleet snapshot for the UI)
8
+ * - GET /api/activity (event log entries; ?since= ?limit=)
9
+ * - GET /activity (HTML viewer; served from fleet-dashboard-html.ts)
10
+ * - POST /api/instance/:name/start
11
+ * - POST /restart/:name
12
+ * - POST /agent (forwarded to handleAgentRequest)
13
+ * - GET /ui/* (forwarded to handleWebRequest)
14
+ *
15
+ * All endpoints except /health require a Bearer / ?token= match against
16
+ * the per-process web token written to <dataDir>/web.token (mode 0600).
17
+ *
18
+ * Extracted from fleet-manager.ts (P4.1 step 4 of 4).
19
+ */
20
+ import { existsSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
21
+ import { createServer } from "node:http";
22
+ import { randomBytes } from "node:crypto";
23
+ import { join } from "node:path";
24
+ import { ACTIVITY_VIEWER_HTML } from "./fleet-dashboard-html.js";
25
+ import { handleAgentRequest } from "./agent-endpoint.js";
26
+ import { handleWebRequest } from "./web-api.js";
27
+ /**
28
+ * Extract a web token from a request, accepting (in order):
29
+ * 1. `?token=` query string
30
+ * 2. `Authorization: Bearer <token>` header (standard)
31
+ * 3. `X-Agend-Token: <token>` header (legacy compatibility)
32
+ */
33
+ export function extractWebToken(parsedUrl, headers) {
34
+ const queryToken = parsedUrl.searchParams.get("token");
35
+ if (queryToken)
36
+ return queryToken;
37
+ const auth = headers["authorization"];
38
+ const authStr = Array.isArray(auth) ? auth[0] : auth;
39
+ if (authStr && /^Bearer\s+/i.test(authStr)) {
40
+ return authStr.replace(/^Bearer\s+/i, "").trim();
41
+ }
42
+ const headerToken = headers["x-agend-token"];
43
+ if (typeof headerToken === "string")
44
+ return headerToken;
45
+ if (Array.isArray(headerToken) && headerToken.length > 0)
46
+ return headerToken[0];
47
+ return null;
48
+ }
49
+ export function startHealthServer(ctx, port) {
50
+ let server;
51
+ const startedAt = Date.now();
52
+ // Generate web token before server starts so auth is enforced from the first request.
53
+ const webToken = randomBytes(24).toString("hex");
54
+ const tokenPath = join(ctx.dataDir, "web.token");
55
+ writeFileSync(tokenPath, webToken, { mode: 0o600 });
56
+ // Defensive: if file existed previously with looser perms, tighten it.
57
+ try {
58
+ chmodSync(tokenPath, 0o600);
59
+ }
60
+ catch {
61
+ // best-effort
62
+ }
63
+ server = createServer((req, res) => {
64
+ res.setHeader("Content-Type", "application/json");
65
+ // Public health probe — no auth required.
66
+ if (req.method === "GET" && req.url === "/health") {
67
+ // fallthrough to existing handler below
68
+ }
69
+ else {
70
+ // All other endpoints require a valid token. Accepts ?token= query,
71
+ // Authorization: Bearer <token>, or legacy X-Agend-Token header.
72
+ // /ui/* will also re-check in web-api.ts, which is harmless.
73
+ const parsedUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
74
+ const providedToken = extractWebToken(parsedUrl, req.headers);
75
+ if (!webToken || providedToken !== webToken) {
76
+ res.writeHead(401);
77
+ res.end(JSON.stringify({ error: "Unauthorized" }));
78
+ return;
79
+ }
80
+ }
81
+ if (req.method === "GET" && req.url === "/health") {
82
+ const instanceCount = ctx.fleetConfig?.instances
83
+ ? Object.keys(ctx.fleetConfig.instances).length
84
+ : 0;
85
+ res.writeHead(200);
86
+ res.end(JSON.stringify({
87
+ status: "ok",
88
+ instances: instanceCount,
89
+ uptime: Math.floor((Date.now() - startedAt) / 1000),
90
+ }));
91
+ return;
92
+ }
93
+ if (req.method === "GET" && req.url === "/status") {
94
+ const instances = Object.keys(ctx.fleetConfig?.instances ?? {}).map(name => {
95
+ const statusFile = join(ctx.getInstanceDir(name), "statusline.json");
96
+ let context_pct = 0;
97
+ let cost = 0;
98
+ try {
99
+ const data = JSON.parse(readFileSync(statusFile, "utf-8"));
100
+ context_pct = data.context_window?.used_percentage ?? 0;
101
+ cost = data.cost?.total_cost_usd ?? 0;
102
+ }
103
+ catch (err) {
104
+ ctx.logger.debug({ err, name }, "statusline.json read failed (/status)");
105
+ }
106
+ return {
107
+ name,
108
+ status: ctx.getInstanceStatus(name),
109
+ context_pct,
110
+ cost,
111
+ };
112
+ });
113
+ res.writeHead(200);
114
+ res.end(JSON.stringify({ instances }));
115
+ return;
116
+ }
117
+ // Fleet API (enriched for agent board)
118
+ if (req.method === "GET" && req.url === "/api/fleet") {
119
+ const sysInfo = ctx.getSysInfo();
120
+ const enriched = sysInfo.instances.map(inst => {
121
+ const config = ctx.fleetConfig?.instances[inst.name];
122
+ // Find claimed tasks for this instance
123
+ let currentTask = null;
124
+ try {
125
+ const tasks = ctx.scheduler?.db.listTasks({ assignee: inst.name, status: "claimed" });
126
+ if (tasks?.length)
127
+ currentTask = tasks[0].title;
128
+ }
129
+ catch (err) {
130
+ ctx.logger.debug({ err, name: inst.name }, "Scheduler listTasks failed (/api/fleet)");
131
+ }
132
+ return {
133
+ ...inst,
134
+ description: config?.description ?? null,
135
+ backend: config?.backend ?? "claude-code",
136
+ tool_set: config?.tool_set ?? "full",
137
+ general_topic: config?.general_topic ?? false,
138
+ lastActivity: ctx.lastActivityMs(inst.name) || null,
139
+ currentTask,
140
+ };
141
+ });
142
+ // Same-origin only — token-bearing requests come from the dashboard
143
+ // served by this same daemon, so no CORS allowance is needed.
144
+ res.writeHead(200);
145
+ res.end(JSON.stringify({
146
+ ...sysInfo,
147
+ instances: enriched,
148
+ }));
149
+ return;
150
+ }
151
+ // Activity API
152
+ if (req.method === "GET" && req.url?.startsWith("/api/activity")) {
153
+ const url = new URL(req.url, `http://localhost:${port}`);
154
+ const sinceParam = url.searchParams.get("since") ?? "2h";
155
+ const limitParam = url.searchParams.get("limit") ?? "500";
156
+ const match = sinceParam.match(/^(\d+)(m|h|d)$/);
157
+ let sinceIso;
158
+ if (match) {
159
+ const val = parseInt(match[1], 10);
160
+ const unit = match[2] === "d" ? 86400000 : match[2] === "h" ? 3600000 : 60000;
161
+ sinceIso = new Date(Date.now() - val * unit).toISOString();
162
+ }
163
+ const rows = ctx.eventLog?.listActivity({ since: sinceIso, limit: parseInt(limitParam, 10) }) ?? [];
164
+ // Same-origin only — see /api/fleet rationale.
165
+ res.writeHead(200);
166
+ res.end(JSON.stringify(rows));
167
+ return;
168
+ }
169
+ // Activity viewer
170
+ if (req.method === "GET" && (req.url === "/activity" || req.url === "/activity/")) {
171
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
172
+ res.writeHead(200);
173
+ res.end(ACTIVITY_VIEWER_HTML);
174
+ return;
175
+ }
176
+ // Instance start via API
177
+ if (req.method === "POST" && req.url?.startsWith("/api/instance/") && req.url.endsWith("/start")) {
178
+ const name = decodeURIComponent(req.url.slice("/api/instance/".length, -"/start".length));
179
+ const config = ctx.fleetConfig?.instances[name];
180
+ if (!config) {
181
+ res.writeHead(404);
182
+ res.end(JSON.stringify({ error: `Instance not found: ${name}` }));
183
+ return;
184
+ }
185
+ (async () => {
186
+ try {
187
+ const topicMode = ctx.fleetConfig?.channel?.mode === "topic";
188
+ await ctx.startInstance(name, config, topicMode ?? false);
189
+ ctx.emitSseEvent("status", getUiStatus(ctx, startedAt));
190
+ res.writeHead(200);
191
+ res.end(JSON.stringify({ ok: true }));
192
+ }
193
+ catch (err) {
194
+ res.writeHead(500);
195
+ res.end(JSON.stringify({ error: `Start failed: ${err.message}` }));
196
+ }
197
+ })();
198
+ return;
199
+ }
200
+ // Instance restart (immediate, no idle wait)
201
+ if (req.method === "POST" && req.url?.startsWith("/restart/")) {
202
+ const name = decodeURIComponent(req.url.slice("/restart/".length));
203
+ ctx.logger.info({ name }, "Instance restart requested via HTTP");
204
+ (async () => {
205
+ try {
206
+ await ctx.restartSingleInstance(name);
207
+ ctx.logger.info({ name }, "Instance restarted");
208
+ ctx.emitSseEvent("status", getUiStatus(ctx, startedAt));
209
+ res.writeHead(200);
210
+ res.end(JSON.stringify({ restarted: name }));
211
+ }
212
+ catch (err) {
213
+ ctx.logger.error({ err, name }, "Instance restart failed");
214
+ const status = err.message.includes("not found") ? 404 : 500;
215
+ res.writeHead(status);
216
+ res.end(JSON.stringify({ error: `Restart failed: ${err.message}` }));
217
+ }
218
+ })();
219
+ return;
220
+ }
221
+ // ── Agent CLI endpoint ─────
222
+ if (req.url === "/agent" && req.method === "POST") {
223
+ handleAgentRequest(req, res, ctx);
224
+ return;
225
+ }
226
+ // ── Web UI endpoints (delegated to web-api.ts) ─────
227
+ const url = new URL(req.url ?? "/", `http://localhost:${port}`);
228
+ if (handleWebRequest(req, res, url, ctx))
229
+ return;
230
+ res.writeHead(404);
231
+ res.end(JSON.stringify({ error: "not found" }));
232
+ });
233
+ server.on("error", (err) => {
234
+ if (err.code === "EADDRINUSE") {
235
+ ctx.logger.warn({ port }, "Health port in use — attempting takeover");
236
+ const pidPath = join(ctx.dataDir, "fleet.pid");
237
+ try {
238
+ if (existsSync(pidPath)) {
239
+ const oldPid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
240
+ if (oldPid && oldPid !== process.pid) {
241
+ process.kill(oldPid, "SIGTERM");
242
+ ctx.logger.info({ oldPid }, "Killed old fleet process");
243
+ }
244
+ }
245
+ }
246
+ catch (err) {
247
+ ctx.logger.debug({ err }, "Old fleet process kill skipped (already gone or no permission)");
248
+ }
249
+ setTimeout(() => {
250
+ if (!server)
251
+ return;
252
+ server.listen(port, "127.0.0.1", () => {
253
+ ctx.logger.info({ port }, "Health endpoint listening (after takeover)");
254
+ }).on("error", () => {
255
+ ctx.logger.warn({ port }, "Health port still in use — skipping health endpoint");
256
+ });
257
+ }, 1500);
258
+ return;
259
+ }
260
+ ctx.logger.error({ err, port }, "Health server error");
261
+ });
262
+ server.listen(port, "127.0.0.1", () => {
263
+ ctx.logger.info({ port }, "Health endpoint listening");
264
+ });
265
+ ctx.logger.info({ url: `http://localhost:${port}/ui?token=${webToken}` }, "Web UI available");
266
+ return { server, webToken, startedAt };
267
+ }
268
+ export function getUiStatus(ctx, startedAt) {
269
+ const instances = Object.keys(ctx.fleetConfig?.instances ?? {}).map(name => {
270
+ const statusFile = join(ctx.getInstanceDir(name), "statusline.json");
271
+ let context_pct = 0;
272
+ let cost = 0;
273
+ let model = "";
274
+ try {
275
+ const data = JSON.parse(readFileSync(statusFile, "utf-8"));
276
+ context_pct = data.context_window?.used_percentage ?? 0;
277
+ cost = data.cost?.total_cost_usd ?? 0;
278
+ model = data.model?.display_name ?? "";
279
+ }
280
+ catch (err) {
281
+ ctx.logger.debug({ err, name }, "statusline.json read failed (getUiStatus)");
282
+ }
283
+ return { name, status: ctx.getInstanceStatus(name), context_pct, cost, model };
284
+ });
285
+ return {
286
+ instances,
287
+ uptime: Math.floor((Date.now() - startedAt) / 1000),
288
+ };
289
+ }
290
+ //# sourceMappingURL=fleet-health-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-health-server.js","sourceRoot":"","sources":["../src/fleet-health-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Logger } from "./logger.js";
2
+ export declare const INSTRUCTIONS_FILENAME: Record<string, string>;
3
+ export declare const GENERAL_INSTRUCTIONS = "# Fleet Coordinator\n\nYou are the fleet coordinator \u2014 the central entry point for this AgEnD fleet.\nYou route tasks, manage instances, enforce policies, and synthesize results.\nDo NOT modify project files directly \u2014 delegate file changes to the project's instance.\nYou CAN write code snippets, explain code, and answer technical questions directly.\n\n-----\n\n## Task Classification\n\nClassify every incoming request before acting.\n\n### Handle Directly (ALL conditions must be true)\n\n- No file system access needed\n- No external execution needed\n- Answerable from static knowledge\n- \u2264 2 reasoning steps\n\nExamples: Q&A, translation, fleet status queries, explaining a concept, writing code snippets.\n\n### Delegate to 1 Instance\n\n- Task scoped to a single project or repo\n- Requires file access, code changes, or execution\n\n### Coordinate Multiple Instances\n\n- Task spans multiple repos or domains\n- Requires outputs from one instance to feed into another\n- Benefits from parallel execution (max 3 instances per task)\n\n-----\n\n## Instance Discovery (in this order)\n1. list_teams() \u2192 reuse existing teams first\n2. list_instances() \u2192 find by working_directory, description, or tags\n3. describe_instance() \u2192 confirm capabilities before delegating\n4. create_instance() \u2192 only if no suitable instance exists\n\nRules: prefer reuse over creation. Do NOT create duplicates of running instances.\n\n-----\n\n## Delegation Protocol\n\nEvery delegation via send_to_instance() MUST include:\n\n1. Task scope \u2014 what exactly to do, bounded clearly\n2. Expected output \u2014 what to return and in what form\n3. Policy reminder \u2014 \"Follow Development Workflow policy\" (for code tasks)\n\n### Loop Prevention\n\n- Never re-delegate a task back to the instance that sent it to you\n- If a task has bounced 3 times, stop and solve locally or reduce scope\n\n### Execution Strategy\n\nParallel \u2014 use only when tasks are independent with no shared state\nSequential \u2014 use when one task's output feeds into the next\n\n-----\n\n## Result Handling\n\nWhen an instance reports back, classify the outcome:\n\n- Success \u2192 Summarize key results for user. Omit internal coordination noise.\n- Partial \u2192 State what succeeded, what remains, proposed next steps.\n- Failure \u2192 Retry up to 2 times. If still failing: try alternative instance, reduce scope, or return partial result clearly marked.\n- No response \u2192 Ping again after reasonable wait. If still silent: report to user with options.\n\n### Output to User\n\nEvery final response to the user should contain:\n\n- Result \u2014 the actual answer or deliverable\n- Gaps \u2014 anything incomplete or unresolved (omit if none)\n\n-----\n\n## Shared Decisions\n\nUse post_decision() / list_decisions() for any choice that affects more than 1 instance, changes an API contract, introduces a new dependency, or alters deployment process.\n\nWhen instances disagree, collect both viewpoints, make a decision, and record it via post_decision.\n\n-----\n\n## Context Rotation Bootstrap\n\nAfter your context rotates, run this sequence BEFORE processing any new messages:\n1. list_instances() \u2192 rebuild fleet awareness\n2. list_teams() \u2192 restore team structure\n3. list_decisions() \u2192 reload policies and conventions\n\nOnly then handle incoming requests.\n\n-----\n\n## Development Workflow Policy\n\nAll code changes across the fleet should follow this workflow.\nThe coordinator enforces compliance but does not perform these steps directly.\nRemind instances of this policy when delegating code tasks.\n\n### Workflow Stages\nDesign Proposed \u2192 Design Approved \u2192 Implementation \u2192 Submit for Review \u2192 Under Review \u2192 Approved \u2192 Merge\n\n### Policy Rules\n\n1. Design before code \u2014 developer sends design proposal to reviewer before implementation. Consensus required before proceeding.\n2. Challenger pairing \u2014 every code task should have a developer + reviewer. Reviewer actively questions decisions and finds risks.\n3. Verify by execution \u2014 backend/CLI changes must be tested by running them. Do not trust documentation alone.\n4. Independent review \u2014 every merge requires code review from someone other than the author.\n5. Root cause first \u2014 bug fixes require confirmed root cause before proposing a fix.\n6. Merge conditions: tests pass, reviewer approved, branch and worktree cleaned up.\n\n### Specialist Instance Rules\n\n- Execute within defined scope only\n- Return structured output: result, assumptions, uncertainties, verification status\n- Do NOT create new instances without coordinator approval\n\n-----\n\n## Team Management\n\n- Always check existing teams before creating new ones\n- Default to ephemeral teams (created for a specific task, dissolved after completion)\n- Clean up ephemeral teams and instances after task completion\n";
4
+ /** Ensure the general (coordinator) instance has its project instructions file. */
5
+ export declare function ensureGeneralInstructions(workDir: string, backendName?: string, logger?: Logger): void;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * General coordinator instance — system prompt + helpers for ensuring the
3
+ * coordinator's working directory has the per-backend instructions file.
4
+ * Extracted from fleet-manager.ts (P4.1).
5
+ */
6
+ import { mkdirSync, writeFileSync, existsSync } from "node:fs";
7
+ import { join, dirname } from "node:path";
8
+ export const INSTRUCTIONS_FILENAME = {
9
+ "claude-code": "CLAUDE.md",
10
+ "codex": "AGENTS.md",
11
+ "gemini-cli": "GEMINI.md",
12
+ "opencode": "AGENTS.md",
13
+ "kiro-cli": ".kiro/steering/project.md",
14
+ "mock": "CLAUDE.md",
15
+ };
16
+ export const GENERAL_INSTRUCTIONS = `# Fleet Coordinator
17
+
18
+ You are the fleet coordinator — the central entry point for this AgEnD fleet.
19
+ You route tasks, manage instances, enforce policies, and synthesize results.
20
+ Do NOT modify project files directly — delegate file changes to the project's instance.
21
+ You CAN write code snippets, explain code, and answer technical questions directly.
22
+
23
+ -----
24
+
25
+ ## Task Classification
26
+
27
+ Classify every incoming request before acting.
28
+
29
+ ### Handle Directly (ALL conditions must be true)
30
+
31
+ - No file system access needed
32
+ - No external execution needed
33
+ - Answerable from static knowledge
34
+ - ≤ 2 reasoning steps
35
+
36
+ Examples: Q&A, translation, fleet status queries, explaining a concept, writing code snippets.
37
+
38
+ ### Delegate to 1 Instance
39
+
40
+ - Task scoped to a single project or repo
41
+ - Requires file access, code changes, or execution
42
+
43
+ ### Coordinate Multiple Instances
44
+
45
+ - Task spans multiple repos or domains
46
+ - Requires outputs from one instance to feed into another
47
+ - Benefits from parallel execution (max 3 instances per task)
48
+
49
+ -----
50
+
51
+ ## Instance Discovery (in this order)
52
+ 1. list_teams() → reuse existing teams first
53
+ 2. list_instances() → find by working_directory, description, or tags
54
+ 3. describe_instance() → confirm capabilities before delegating
55
+ 4. create_instance() → only if no suitable instance exists
56
+
57
+ Rules: prefer reuse over creation. Do NOT create duplicates of running instances.
58
+
59
+ -----
60
+
61
+ ## Delegation Protocol
62
+
63
+ Every delegation via send_to_instance() MUST include:
64
+
65
+ 1. Task scope — what exactly to do, bounded clearly
66
+ 2. Expected output — what to return and in what form
67
+ 3. Policy reminder — "Follow Development Workflow policy" (for code tasks)
68
+
69
+ ### Loop Prevention
70
+
71
+ - Never re-delegate a task back to the instance that sent it to you
72
+ - If a task has bounced 3 times, stop and solve locally or reduce scope
73
+
74
+ ### Execution Strategy
75
+
76
+ Parallel — use only when tasks are independent with no shared state
77
+ Sequential — use when one task's output feeds into the next
78
+
79
+ -----
80
+
81
+ ## Result Handling
82
+
83
+ When an instance reports back, classify the outcome:
84
+
85
+ - Success → Summarize key results for user. Omit internal coordination noise.
86
+ - Partial → State what succeeded, what remains, proposed next steps.
87
+ - Failure → Retry up to 2 times. If still failing: try alternative instance, reduce scope, or return partial result clearly marked.
88
+ - No response → Ping again after reasonable wait. If still silent: report to user with options.
89
+
90
+ ### Output to User
91
+
92
+ Every final response to the user should contain:
93
+
94
+ - Result — the actual answer or deliverable
95
+ - Gaps — anything incomplete or unresolved (omit if none)
96
+
97
+ -----
98
+
99
+ ## Shared Decisions
100
+
101
+ Use post_decision() / list_decisions() for any choice that affects more than 1 instance, changes an API contract, introduces a new dependency, or alters deployment process.
102
+
103
+ When instances disagree, collect both viewpoints, make a decision, and record it via post_decision.
104
+
105
+ -----
106
+
107
+ ## Context Rotation Bootstrap
108
+
109
+ After your context rotates, run this sequence BEFORE processing any new messages:
110
+ 1. list_instances() → rebuild fleet awareness
111
+ 2. list_teams() → restore team structure
112
+ 3. list_decisions() → reload policies and conventions
113
+
114
+ Only then handle incoming requests.
115
+
116
+ -----
117
+
118
+ ## Development Workflow Policy
119
+
120
+ All code changes across the fleet should follow this workflow.
121
+ The coordinator enforces compliance but does not perform these steps directly.
122
+ Remind instances of this policy when delegating code tasks.
123
+
124
+ ### Workflow Stages
125
+ Design Proposed → Design Approved → Implementation → Submit for Review → Under Review → Approved → Merge
126
+
127
+ ### Policy Rules
128
+
129
+ 1. Design before code — developer sends design proposal to reviewer before implementation. Consensus required before proceeding.
130
+ 2. Challenger pairing — every code task should have a developer + reviewer. Reviewer actively questions decisions and finds risks.
131
+ 3. Verify by execution — backend/CLI changes must be tested by running them. Do not trust documentation alone.
132
+ 4. Independent review — every merge requires code review from someone other than the author.
133
+ 5. Root cause first — bug fixes require confirmed root cause before proposing a fix.
134
+ 6. Merge conditions: tests pass, reviewer approved, branch and worktree cleaned up.
135
+
136
+ ### Specialist Instance Rules
137
+
138
+ - Execute within defined scope only
139
+ - Return structured output: result, assumptions, uncertainties, verification status
140
+ - Do NOT create new instances without coordinator approval
141
+
142
+ -----
143
+
144
+ ## Team Management
145
+
146
+ - Always check existing teams before creating new ones
147
+ - Default to ephemeral teams (created for a specific task, dissolved after completion)
148
+ - Clean up ephemeral teams and instances after task completion
149
+ `;
150
+ /** Ensure the general (coordinator) instance has its project instructions file. */
151
+ export function ensureGeneralInstructions(workDir, backendName, logger) {
152
+ const backend = backendName ?? "claude-code";
153
+ const filename = INSTRUCTIONS_FILENAME[backend] ?? "CLAUDE.md";
154
+ const filePath = join(workDir, filename);
155
+ mkdirSync(dirname(filePath), { recursive: true });
156
+ if (!existsSync(filePath)) {
157
+ writeFileSync(filePath, GENERAL_INSTRUCTIONS, "utf-8");
158
+ logger?.info({ filePath }, "Created general instance instructions file");
159
+ }
160
+ }
161
+ //# sourceMappingURL=fleet-instructions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-instructions.js","sourceRoot":"","sources":["../src/fleet-instructions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D,aAAa,EAAE,WAAW;IAC1B,OAAO,EAAE,WAAW;IACpB,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,WAAW;IACvB,UAAU,EAAE,2BAA2B;IACvC,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqInC,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,yBAAyB,CACvC,OAAe,EACf,WAAoB,EACpB,MAAe;IAEf,MAAM,OAAO,GAAG,WAAW,IAAI,aAAa,CAAC;IAC7C,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,IAAI,WAAW,CAAC;IAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACzC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,aAAa,CAAC,QAAQ,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,4CAA4C,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC"}