@loompad/cli 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 (177) hide show
  1. package/ARCHITECTURE.md +211 -0
  2. package/CHANGELOG.md +470 -0
  3. package/LICENSE +21 -0
  4. package/README.md +630 -0
  5. package/dist/adapters/base.d.ts +71 -0
  6. package/dist/adapters/base.js +187 -0
  7. package/dist/adapters/base.js.map +1 -0
  8. package/dist/adapters/bridges/antigravity.d.ts +53 -0
  9. package/dist/adapters/bridges/antigravity.js +106 -0
  10. package/dist/adapters/bridges/antigravity.js.map +1 -0
  11. package/dist/adapters/bridges/cdp.d.ts +82 -0
  12. package/dist/adapters/bridges/cdp.js +222 -0
  13. package/dist/adapters/bridges/cdp.js.map +1 -0
  14. package/dist/adapters/bridges/gui-chat.d.ts +113 -0
  15. package/dist/adapters/bridges/gui-chat.js +498 -0
  16. package/dist/adapters/bridges/gui-chat.js.map +1 -0
  17. package/dist/adapters/bridges/kiro.d.ts +19 -0
  18. package/dist/adapters/bridges/kiro.js +22 -0
  19. package/dist/adapters/bridges/kiro.js.map +1 -0
  20. package/dist/adapters/bridges/profiles.d.ts +82 -0
  21. package/dist/adapters/bridges/profiles.js +125 -0
  22. package/dist/adapters/bridges/profiles.js.map +1 -0
  23. package/dist/adapters/claude-code.d.ts +26 -0
  24. package/dist/adapters/claude-code.js +209 -0
  25. package/dist/adapters/claude-code.js.map +1 -0
  26. package/dist/adapters/codex.d.ts +51 -0
  27. package/dist/adapters/codex.js +291 -0
  28. package/dist/adapters/codex.js.map +1 -0
  29. package/dist/adapters/echo.d.ts +20 -0
  30. package/dist/adapters/echo.js +79 -0
  31. package/dist/adapters/echo.js.map +1 -0
  32. package/dist/adapters/grok.d.ts +61 -0
  33. package/dist/adapters/grok.js +217 -0
  34. package/dist/adapters/grok.js.map +1 -0
  35. package/dist/adapters/index.d.ts +9 -0
  36. package/dist/adapters/index.js +33 -0
  37. package/dist/adapters/index.js.map +1 -0
  38. package/dist/adapters/opencode.d.ts +64 -0
  39. package/dist/adapters/opencode.js +426 -0
  40. package/dist/adapters/opencode.js.map +1 -0
  41. package/dist/cli/common.d.ts +11 -0
  42. package/dist/cli/common.js +40 -0
  43. package/dist/cli/common.js.map +1 -0
  44. package/dist/cli/doctor.d.ts +12 -0
  45. package/dist/cli/doctor.js +181 -0
  46. package/dist/cli/doctor.js.map +1 -0
  47. package/dist/cli/index.d.ts +8 -0
  48. package/dist/cli/index.js +641 -0
  49. package/dist/cli/index.js.map +1 -0
  50. package/dist/cli/tui-model.d.ts +73 -0
  51. package/dist/cli/tui-model.js +312 -0
  52. package/dist/cli/tui-model.js.map +1 -0
  53. package/dist/cli/tui.d.ts +15 -0
  54. package/dist/cli/tui.js +451 -0
  55. package/dist/cli/tui.js.map +1 -0
  56. package/dist/cli/ui.d.ts +10 -0
  57. package/dist/cli/ui.js +135 -0
  58. package/dist/cli/ui.js.map +1 -0
  59. package/dist/core/ades.d.ts +79 -0
  60. package/dist/core/ades.js +130 -0
  61. package/dist/core/ades.js.map +1 -0
  62. package/dist/core/baton.d.ts +37 -0
  63. package/dist/core/baton.js +92 -0
  64. package/dist/core/baton.js.map +1 -0
  65. package/dist/core/brain-extract.d.ts +111 -0
  66. package/dist/core/brain-extract.js +248 -0
  67. package/dist/core/brain-extract.js.map +1 -0
  68. package/dist/core/brain-index.d.ts +128 -0
  69. package/dist/core/brain-index.js +338 -0
  70. package/dist/core/brain-index.js.map +1 -0
  71. package/dist/core/brain.d.ts +214 -0
  72. package/dist/core/brain.js +425 -0
  73. package/dist/core/brain.js.map +1 -0
  74. package/dist/core/claude-cli.d.ts +12 -0
  75. package/dist/core/claude-cli.js +47 -0
  76. package/dist/core/claude-cli.js.map +1 -0
  77. package/dist/core/distill.d.ts +19 -0
  78. package/dist/core/distill.js +88 -0
  79. package/dist/core/distill.js.map +1 -0
  80. package/dist/core/eventlog.d.ts +43 -0
  81. package/dist/core/eventlog.js +211 -0
  82. package/dist/core/eventlog.js.map +1 -0
  83. package/dist/core/git.d.ts +203 -0
  84. package/dist/core/git.js +460 -0
  85. package/dist/core/git.js.map +1 -0
  86. package/dist/core/logbook.d.ts +59 -0
  87. package/dist/core/logbook.js +118 -0
  88. package/dist/core/logbook.js.map +1 -0
  89. package/dist/core/memory.d.ts +34 -0
  90. package/dist/core/memory.js +124 -0
  91. package/dist/core/memory.js.map +1 -0
  92. package/dist/core/notify.d.ts +11 -0
  93. package/dist/core/notify.js +30 -0
  94. package/dist/core/notify.js.map +1 -0
  95. package/dist/core/projection.d.ts +20 -0
  96. package/dist/core/projection.js +96 -0
  97. package/dist/core/projection.js.map +1 -0
  98. package/dist/core/registry.d.ts +76 -0
  99. package/dist/core/registry.js +147 -0
  100. package/dist/core/registry.js.map +1 -0
  101. package/dist/core/router.d.ts +42 -0
  102. package/dist/core/router.js +99 -0
  103. package/dist/core/router.js.map +1 -0
  104. package/dist/core/routes.d.ts +93 -0
  105. package/dist/core/routes.js +399 -0
  106. package/dist/core/routes.js.map +1 -0
  107. package/dist/core/search.d.ts +63 -0
  108. package/dist/core/search.js +0 -0
  109. package/dist/core/search.js.map +1 -0
  110. package/dist/core/setup.d.ts +70 -0
  111. package/dist/core/setup.js +250 -0
  112. package/dist/core/setup.js.map +1 -0
  113. package/dist/core/suggestions.d.ts +15 -0
  114. package/dist/core/suggestions.js +38 -0
  115. package/dist/core/suggestions.js.map +1 -0
  116. package/dist/core/worktree.d.ts +32 -0
  117. package/dist/core/worktree.js +83 -0
  118. package/dist/core/worktree.js.map +1 -0
  119. package/dist/daemon/app-page.d.ts +32 -0
  120. package/dist/daemon/app-page.js +6363 -0
  121. package/dist/daemon/app-page.js.map +1 -0
  122. package/dist/daemon/auth.d.ts +51 -0
  123. package/dist/daemon/auth.js +135 -0
  124. package/dist/daemon/auth.js.map +1 -0
  125. package/dist/daemon/board.d.ts +117 -0
  126. package/dist/daemon/board.js +202 -0
  127. package/dist/daemon/board.js.map +1 -0
  128. package/dist/daemon/brand-icons.d.ts +29 -0
  129. package/dist/daemon/brand-icons.js +44 -0
  130. package/dist/daemon/brand-icons.js.map +1 -0
  131. package/dist/daemon/client.d.ts +127 -0
  132. package/dist/daemon/client.js +237 -0
  133. package/dist/daemon/client.js.map +1 -0
  134. package/dist/daemon/geist-font.d.ts +10 -0
  135. package/dist/daemon/geist-font.js +783 -0
  136. package/dist/daemon/geist-font.js.map +1 -0
  137. package/dist/daemon/guards.d.ts +18 -0
  138. package/dist/daemon/guards.js +40 -0
  139. package/dist/daemon/guards.js.map +1 -0
  140. package/dist/daemon/linear.d.ts +59 -0
  141. package/dist/daemon/linear.js +117 -0
  142. package/dist/daemon/linear.js.map +1 -0
  143. package/dist/daemon/push.d.ts +22 -0
  144. package/dist/daemon/push.js +58 -0
  145. package/dist/daemon/push.js.map +1 -0
  146. package/dist/daemon/runtime.d.ts +299 -0
  147. package/dist/daemon/runtime.js +1016 -0
  148. package/dist/daemon/runtime.js.map +1 -0
  149. package/dist/daemon/server.d.ts +125 -0
  150. package/dist/daemon/server.js +1728 -0
  151. package/dist/daemon/server.js.map +1 -0
  152. package/dist/daemon/tasks.d.ts +153 -0
  153. package/dist/daemon/tasks.js +264 -0
  154. package/dist/daemon/tasks.js.map +1 -0
  155. package/dist/daemon/terminals.d.ts +82 -0
  156. package/dist/daemon/terminals.js +372 -0
  157. package/dist/daemon/terminals.js.map +1 -0
  158. package/dist/index.d.ts +20 -0
  159. package/dist/index.js +20 -0
  160. package/dist/index.js.map +1 -0
  161. package/dist/sdk.d.ts +17 -0
  162. package/dist/sdk.js +17 -0
  163. package/dist/sdk.js.map +1 -0
  164. package/dist/types.d.ts +236 -0
  165. package/dist/types.js +18 -0
  166. package/dist/types.js.map +1 -0
  167. package/docs/SETUP.md +265 -0
  168. package/docs/adapters.md +132 -0
  169. package/docs/design-system.md +245 -0
  170. package/docs/img/board-linear.png +0 -0
  171. package/docs/img/board-projects.png +0 -0
  172. package/docs/img/brain.png +0 -0
  173. package/docs/img/settings.png +0 -0
  174. package/docs/img/workspace.png +0 -0
  175. package/docs/integration-notes.md +76 -0
  176. package/docs/proposals/brain.md +262 -0
  177. package/package.json +84 -0
@@ -0,0 +1,426 @@
1
+ /**
2
+ * OpenCode adapter — manages an `opencode serve` process per project and
3
+ * speaks its HTTP + SSE API.
4
+ *
5
+ * create session : POST /api/session → { data: { id: "ses…" } }
6
+ * send prompt : POST /api/session/:id/prompt { prompt: { text } }
7
+ * wait for idle : POST /api/session/:id/wait
8
+ * interrupt : POST /api/session/:id/interrupt
9
+ * live events : GET /event (SSE)
10
+ *
11
+ * Surface verified against opencode 1.17.20 — see docs/integration-notes.md.
12
+ */
13
+ import { execFile, spawn } from "node:child_process";
14
+ import { readProjectState, writeProjectState } from "../core/registry.js";
15
+ import { AdapterBase, agentEnv, cliAvailable, fetchJson, frameBriefing, freePort, waitFor } from "./base.js";
16
+ /** "providerID/modelID" → ModelRef body for session create ({providerID, id}). */
17
+ export function parseModelRef(model) {
18
+ const idx = model.indexOf("/");
19
+ if (idx <= 0 || idx === model.length - 1)
20
+ return null;
21
+ return { providerID: model.slice(0, idx), id: model.slice(idx + 1) };
22
+ }
23
+ export class OpenCodeAdapter extends AdapterBase {
24
+ child = null;
25
+ baseUrl = null;
26
+ sseAbort = null;
27
+ options;
28
+ started = false;
29
+ /** text parts per in-flight assistant message */
30
+ textParts = new Map();
31
+ roles = new Map();
32
+ /** assistant messages whose text already went to the log (SSE path) */
33
+ emittedText = new Set();
34
+ constructor(id, projectDir, options = {}) {
35
+ super(id, "opencode", projectDir);
36
+ this.options = options;
37
+ }
38
+ get sessionId() {
39
+ return readProjectState(this.projectDir).agents[this.id]?.sessionId;
40
+ }
41
+ set sessionId(value) {
42
+ const state = readProjectState(this.projectDir);
43
+ state.agents[this.id] = { ...state.agents[this.id], sessionId: value };
44
+ writeProjectState(this.projectDir, state);
45
+ }
46
+ async available() {
47
+ if (this.options.baseUrl)
48
+ return true;
49
+ return cliAvailable("opencode");
50
+ }
51
+ /** Kill a serve child left behind by a previous daemon (verified by cmdline). */
52
+ async reapOrphanServe() {
53
+ const state = readProjectState(this.projectDir);
54
+ const pid = Number(state.agents[this.id]?.servePid ?? 0);
55
+ if (!pid)
56
+ return;
57
+ const cmd = await new Promise((resolve) => {
58
+ execFile("ps", ["-p", String(pid), "-o", "command="], (err, stdout) => resolve(err ? "" : stdout.trim()));
59
+ });
60
+ if (/opencode serve/.test(cmd)) {
61
+ try {
62
+ process.kill(pid, "SIGTERM");
63
+ this.emit({ kind: "status", payload: { state: "reaped_orphan_serve", pid } });
64
+ }
65
+ catch {
66
+ // already gone
67
+ }
68
+ }
69
+ delete state.agents[this.id]?.servePid;
70
+ writeProjectState(this.projectDir, state);
71
+ }
72
+ recordServePid(pid) {
73
+ const state = readProjectState(this.projectDir);
74
+ state.agents[this.id] = { ...state.agents[this.id], servePid: pid };
75
+ writeProjectState(this.projectDir, state);
76
+ }
77
+ async start() {
78
+ if (this.started)
79
+ return;
80
+ if (this.options.baseUrl) {
81
+ this.baseUrl = this.options.baseUrl.replace(/\/$/, "");
82
+ }
83
+ else {
84
+ await this.reapOrphanServe();
85
+ const port = await freePort();
86
+ this.baseUrl = `http://127.0.0.1:${port}`;
87
+ const child = spawn("opencode", ["serve", "--port", String(port), "--hostname", "127.0.0.1", ...(this.options.extraArgs ?? [])], { cwd: this.projectDir, stdio: "ignore", env: agentEnv() });
88
+ this.child = child;
89
+ this.recordServePid(child.pid);
90
+ child.on("close", (code) => {
91
+ if (this.started) {
92
+ this.emit({ kind: "error", payload: { message: `opencode serve exited (${code})` } });
93
+ this.started = false;
94
+ }
95
+ });
96
+ }
97
+ await waitFor(async () => {
98
+ await fetchJson(`${this.baseUrl}/api/health`);
99
+ return true;
100
+ });
101
+ await this.assertModelAvailable();
102
+ await this.ensureSession();
103
+ this.startSse();
104
+ this.started = true;
105
+ this.emit({
106
+ kind: "status",
107
+ payload: { state: "ready", baseUrl: this.baseUrl, session: this.sessionId ?? null },
108
+ });
109
+ }
110
+ get sessionModel() {
111
+ return readProjectState(this.projectDir).agents[this.id]?.sessionModel;
112
+ }
113
+ set sessionModel(value) {
114
+ const state = readProjectState(this.projectDir);
115
+ state.agents[this.id] = { ...state.agents[this.id], sessionModel: value };
116
+ writeProjectState(this.projectDir, state);
117
+ }
118
+ /**
119
+ * A session whose model can't be resolved is a silent trap: opencode
120
+ * "admits" prompts and never runs them (ModelUnavailableError only shows
121
+ * in server logs). Validate against /api/model — the list of models the
122
+ * server can actually run — and fail loudly with suggestions instead.
123
+ */
124
+ async assertModelAvailable() {
125
+ if (!this.options.model)
126
+ return;
127
+ const res = await fetchJson(`${this.baseUrl}/api/model`).catch(() => null);
128
+ const models = Array.isArray(res?.data) ? res.data : [];
129
+ if (!models.length)
130
+ return; // endpoint unavailable — don't block
131
+ const ids = models.map((m) => `${String(m.providerID)}/${String(m.id)}`);
132
+ if (ids.includes(this.options.model))
133
+ return;
134
+ const base = this.options.model.split("/").pop().split("-")[0].toLowerCase();
135
+ const near = ids.filter((id) => id.toLowerCase().includes(base)).slice(0, 5);
136
+ const free = ids.filter((id) => id.endsWith("-free")).slice(0, 3);
137
+ throw new Error(`opencode cannot run model "${this.options.model}" (listed ≠ available). ` +
138
+ `Close matches: ${near.length ? near.join(", ") : "none"}. ` +
139
+ `Free options: ${free.join(", ")}. Fix .loom/config.json agent options.model.`);
140
+ }
141
+ async ensureSession() {
142
+ const existing = this.sessionId;
143
+ // Session model is fixed at creation — a changed config model means the
144
+ // old session must be replaced, or turns keep running on the old model.
145
+ const modelChanged = (this.options.model ?? undefined) !== this.sessionModel;
146
+ if (existing && !modelChanged) {
147
+ try {
148
+ await fetchJson(`${this.baseUrl}/api/session/${existing}`);
149
+ return existing;
150
+ }
151
+ catch {
152
+ // stale session (server state moved on) — create a fresh one
153
+ }
154
+ }
155
+ const body = {};
156
+ if (this.options.model) {
157
+ const ref = parseModelRef(this.options.model);
158
+ if (ref)
159
+ body.model = ref;
160
+ }
161
+ if (this.options.agent)
162
+ body.agent = this.options.agent;
163
+ const res = await fetchJson(`${this.baseUrl}/api/session`, {
164
+ method: "POST",
165
+ headers: { "content-type": "application/json" },
166
+ body: JSON.stringify(body),
167
+ });
168
+ const data = (res.data ?? res);
169
+ const id = String(data.id ?? "");
170
+ if (!id)
171
+ throw new Error("opencode: could not create session");
172
+ this.sessionId = id;
173
+ this.sessionModel = this.options.model ?? undefined;
174
+ return id;
175
+ }
176
+ startSse() {
177
+ const abort = new AbortController();
178
+ this.sseAbort = abort;
179
+ void (async () => {
180
+ while (!abort.signal.aborted) {
181
+ try {
182
+ const res = await fetch(`${this.baseUrl}/event`, {
183
+ signal: abort.signal,
184
+ headers: { accept: "text/event-stream" },
185
+ });
186
+ if (!res.ok || !res.body)
187
+ throw new Error(`SSE ${res.status}`);
188
+ let buffer = "";
189
+ for await (const chunk of res.body) {
190
+ buffer += Buffer.from(chunk).toString("utf8");
191
+ let idx;
192
+ while ((idx = buffer.indexOf("\n")) >= 0) {
193
+ const line = buffer.slice(0, idx).trim();
194
+ buffer = buffer.slice(idx + 1);
195
+ if (!line.startsWith("data:"))
196
+ continue;
197
+ try {
198
+ this.handleSse(JSON.parse(line.slice(5).trim()));
199
+ }
200
+ catch {
201
+ // Unparseable SSE payloads are skipped, never fatal.
202
+ }
203
+ }
204
+ }
205
+ }
206
+ catch {
207
+ if (abort.signal.aborted)
208
+ return;
209
+ await new Promise((r) => setTimeout(r, 1000)); // reconnect
210
+ }
211
+ }
212
+ })();
213
+ }
214
+ handleSse(evt) {
215
+ const type = String(evt.type ?? "");
216
+ // Payload wrapping varies across opencode builds: {properties} or {data}.
217
+ const props = (evt.properties ?? evt.data ?? evt);
218
+ const mySession = this.sessionId;
219
+ if (type === "message.part.updated") {
220
+ const part = (props.part ?? {});
221
+ if (part.sessionID && part.sessionID !== mySession)
222
+ return;
223
+ const partType = String(part.type ?? "");
224
+ const messageID = String(part.messageID ?? "");
225
+ if (partType === "text" && typeof part.text === "string") {
226
+ if (!this.textParts.has(messageID))
227
+ this.textParts.set(messageID, new Map());
228
+ this.textParts.get(messageID).set(String(part.id ?? "p"), part.text);
229
+ }
230
+ else if (partType === "tool") {
231
+ const state = (part.state ?? {});
232
+ if (String(state.status ?? "") === "completed") {
233
+ this.emit({
234
+ kind: "tool_call",
235
+ payload: {
236
+ tool: String(part.tool ?? "tool"),
237
+ summary: String(state.title ?? part.tool ?? "tool"),
238
+ },
239
+ });
240
+ }
241
+ }
242
+ else if (partType === "patch") {
243
+ const files = Array.isArray(part.files) ? part.files : [];
244
+ for (const f of files) {
245
+ this.emit({ kind: "file_edit", payload: { path: String(f) } });
246
+ }
247
+ }
248
+ return;
249
+ }
250
+ if (type === "message.updated") {
251
+ const info = (props.info ?? props.message ?? {});
252
+ if (info.sessionID && info.sessionID !== mySession)
253
+ return;
254
+ const messageID = String(info.id ?? "");
255
+ const role = String(info.role ?? "");
256
+ if (role)
257
+ this.roles.set(messageID, role);
258
+ const time = (info.time ?? {});
259
+ if (role === "assistant" && time.completed) {
260
+ const parts = this.textParts.get(messageID);
261
+ if (parts && parts.size) {
262
+ const text = [...parts.values()].join("").trim();
263
+ if (text) {
264
+ this.emit({ kind: "message", payload: { text } });
265
+ this.emittedText.add(messageID);
266
+ }
267
+ }
268
+ this.textParts.delete(messageID);
269
+ // Best-effort per-turn cost (present on opencode assistant messages).
270
+ const cost = Number(info.cost ?? 0);
271
+ if (cost > 0) {
272
+ this.emit({ kind: "status", payload: { state: "turn_cost", costUsd: cost } });
273
+ }
274
+ }
275
+ return;
276
+ }
277
+ if (/^(permission|question)(\.v2)?\.asked$/.test(type)) {
278
+ if (props.sessionID && props.sessionID !== mySession)
279
+ return;
280
+ const detail = props.title ??
281
+ props.text ??
282
+ props.permission?.title ??
283
+ type;
284
+ this.emit({ kind: "needs_input", payload: { question: String(detail).slice(0, 500) } });
285
+ }
286
+ }
287
+ /** All messages in the session, oldest first (info objects). */
288
+ async listMessages(sid) {
289
+ const res = await fetchJson(`${this.baseUrl}/api/session/${sid}/message`);
290
+ const data = (res.data ?? res);
291
+ const items = Array.isArray(data) ? data : [];
292
+ return items
293
+ .map((m) => (m.info ?? m))
294
+ .sort((a, b) => Number(a.time?.created ?? 0) -
295
+ Number(b.time?.created ?? 0));
296
+ }
297
+ /**
298
+ * Wait until the TURN is over — not just the first assistant message.
299
+ * opencode runs a turn as a sequence of assistant messages (one per step),
300
+ * so completion = the newest message is a completed assistant AND that
301
+ * fact holds across two consecutive polls (nothing new started).
302
+ * `/wait` is tried first but returns 503 on 1.17.
303
+ */
304
+ async waitForTurn(sid, baseline, timeoutMs) {
305
+ try {
306
+ await fetchJson(`${this.baseUrl}/api/session/${sid}/wait`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" }, timeoutMs);
307
+ }
308
+ catch {
309
+ // 503 "not available yet" on 1.17 — fall through to polling.
310
+ }
311
+ const deadline = Date.now() + timeoutMs;
312
+ let stableId = null;
313
+ while (Date.now() < deadline) {
314
+ const messages = await this.listMessages(sid).catch(() => []);
315
+ const newest = messages[messages.length - 1];
316
+ const newAssistants = messages.filter((m) => (m.type ?? m.role) === "assistant" &&
317
+ !baseline.has(String(m.id)) &&
318
+ m.time?.completed);
319
+ const turnLooksDone = newest &&
320
+ (newest.type ?? newest.role) === "assistant" &&
321
+ newest.time?.completed &&
322
+ newAssistants.length > 0;
323
+ if (turnLooksDone) {
324
+ // Errors are terminal immediately; otherwise require stability
325
+ // across two polls so multi-step turns aren't cut short.
326
+ if (newest.finish === "error" || newest.error)
327
+ return newest;
328
+ if (stableId === String(newest.id))
329
+ return newest;
330
+ stableId = String(newest.id);
331
+ }
332
+ else {
333
+ stableId = null;
334
+ }
335
+ await new Promise((r) => setTimeout(r, 3000));
336
+ }
337
+ return null;
338
+ }
339
+ async send(input) {
340
+ if (!this.started)
341
+ await this.start();
342
+ if (this._busy)
343
+ throw new Error(`opencode agent "${this.id}" is busy`);
344
+ this._busy = true;
345
+ const started = Date.now();
346
+ const timeoutMs = 60 * 60 * 1000;
347
+ try {
348
+ const sid = await this.ensureSession();
349
+ const baseline = new Set((await this.listMessages(sid).catch(() => [])).map((m) => String(m.id)));
350
+ // No per-prompt system field in the API, so the handoff briefing rides in
351
+ // the prompt — framed as an unmissable authoritative block (frameBriefing)
352
+ // rather than a loose preamble.
353
+ const text = input.briefing ? `${frameBriefing(input.briefing)}\n\n${input.text}` : input.text;
354
+ await fetchJson(`${this.baseUrl}/api/session/${sid}/prompt`, {
355
+ method: "POST",
356
+ headers: { "content-type": "application/json" },
357
+ body: JSON.stringify({ prompt: { text } }),
358
+ });
359
+ const turn = await this.waitForTurn(sid, baseline, timeoutMs);
360
+ if (!turn) {
361
+ this.emit({ kind: "error", payload: { message: "turn timed out waiting for opencode" } });
362
+ }
363
+ else {
364
+ const turnId = String(turn.id);
365
+ // Fetch the full message: parts (in case SSE missed them) + errors.
366
+ const detail = await fetchJson(`${this.baseUrl}/api/session/${sid}/message/${turnId}`).catch(() => null);
367
+ const info = (detail?.data ?? detail ?? turn) ?? turn;
368
+ if (info.finish === "error" || info.error) {
369
+ const err = (info.error ?? {});
370
+ this.emit({
371
+ kind: "error",
372
+ payload: {
373
+ message: String(err.message ?? "opencode turn failed").slice(0, 500),
374
+ },
375
+ });
376
+ }
377
+ else if (!this.emittedText.has(turnId)) {
378
+ const content = Array.isArray(info.content) ? info.content : [];
379
+ const text = content
380
+ .filter((p) => p.type === "text" && typeof p.text === "string")
381
+ .map((p) => String(p.text))
382
+ .join("")
383
+ .trim();
384
+ if (text) {
385
+ this.emit({ kind: "message", payload: { text } });
386
+ this.emittedText.add(turnId);
387
+ }
388
+ }
389
+ const cost = Number(info.cost ?? 0);
390
+ if (cost > 0) {
391
+ this.emit({ kind: "status", payload: { state: "turn_cost", costUsd: cost } });
392
+ }
393
+ }
394
+ this.emit({ kind: "run_complete", payload: { durationMs: Date.now() - started } });
395
+ }
396
+ finally {
397
+ this._busy = false;
398
+ }
399
+ }
400
+ async interrupt() {
401
+ const sid = this.sessionId;
402
+ if (!sid || !this.baseUrl)
403
+ return;
404
+ try {
405
+ await fetchJson(`${this.baseUrl}/api/session/${sid}/interrupt`, {
406
+ method: "POST",
407
+ headers: { "content-type": "application/json" },
408
+ body: "{}",
409
+ });
410
+ }
411
+ catch {
412
+ // If the server is gone there is nothing to interrupt.
413
+ }
414
+ }
415
+ async stop() {
416
+ this.started = false;
417
+ this.sseAbort?.abort();
418
+ this.sseAbort = null;
419
+ if (this.child) {
420
+ this.child.kill("SIGTERM");
421
+ this.child = null;
422
+ }
423
+ this.emit({ kind: "status", payload: { state: "stopped" } });
424
+ }
425
+ }
426
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared CLI plumbing: resolving "the project I'm standing in".
3
+ */
4
+ import type { ProjectStatus } from "../types.js";
5
+ import type { DaemonClient } from "../daemon/client.js";
6
+ /** Walk up from cwd to the nearest directory containing .loom/config.json. */
7
+ export declare function currentProjectDir(): string | null;
8
+ export declare class NoProjectError extends Error {
9
+ constructor();
10
+ }
11
+ export declare function resolveCurrentProject(client: DaemonClient): Promise<ProjectStatus>;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared CLI plumbing: resolving "the project I'm standing in".
3
+ */
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { findProject } from "../core/registry.js";
7
+ /** Walk up from cwd to the nearest directory containing .loom/config.json. */
8
+ export function currentProjectDir() {
9
+ let dir = process.cwd();
10
+ for (;;) {
11
+ if (fs.existsSync(path.join(dir, ".loom", "config.json")))
12
+ return dir;
13
+ const parent = path.dirname(dir);
14
+ if (parent === dir)
15
+ return null;
16
+ dir = parent;
17
+ }
18
+ }
19
+ export class NoProjectError extends Error {
20
+ constructor() {
21
+ super("no Loom project here — run `loom init` in your project directory");
22
+ this.name = "NoProjectError";
23
+ }
24
+ }
25
+ export async function resolveCurrentProject(client) {
26
+ const dir = currentProjectDir();
27
+ if (!dir)
28
+ throw new NoProjectError();
29
+ let info = findProject(dir);
30
+ if (!info) {
31
+ // Has .loom but isn't registered (e.g. a cloned repo) — register it.
32
+ await client.addProject(dir);
33
+ info = findProject(dir);
34
+ }
35
+ if (!info)
36
+ throw new Error(`could not register project at ${dir}`);
37
+ const { project } = await client.project(info.id);
38
+ return project;
39
+ }
40
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/cli/common.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB;IAC/B,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IACxB,SAAS,CAAC;QACR,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC;QACE,KAAK,CAAC,kEAAkE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAoB;IAC9D,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,cAAc,EAAE,CAAC;IACrC,IAAI,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,qEAAqE;QACrE,MAAM,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;IACnE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * loom doctor — one command that answers "why is nothing working?".
3
+ * Checks the environment (node, agent CLIs, tailscale), the daemon (health,
4
+ * build freshness, binding), and the current project's config.
5
+ */
6
+ export interface Check {
7
+ name: string;
8
+ status: "ok" | "warn" | "fail";
9
+ detail: string;
10
+ }
11
+ export declare function projectChecks(dir: string): Check[];
12
+ export declare function envChecks(): Promise<Check[]>;