koppler 0.0.0-stage → 0.0.2

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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -2
  3. package/bin/run-logged +16 -0
  4. package/bin/secret-list +7 -0
  5. package/bin/secret-psql +41 -0
  6. package/bin/secret-set +17 -0
  7. package/bin/secret-store +82 -0
  8. package/bin/secret-test +10 -0
  9. package/bin/with-secrets +25 -0
  10. package/dist/.built +1 -0
  11. package/dist/cli/agent.js +144 -0
  12. package/dist/cli/agent.js.map +1 -0
  13. package/dist/cli/doctor.js +173 -0
  14. package/dist/cli/doctor.js.map +1 -0
  15. package/dist/cli/mcp.js +204 -0
  16. package/dist/cli/mcp.js.map +1 -0
  17. package/dist/cli/output.js +37 -0
  18. package/dist/cli/output.js.map +1 -0
  19. package/dist/cli/records.js +121 -0
  20. package/dist/cli/records.js.map +1 -0
  21. package/dist/cli/running.js +270 -0
  22. package/dist/cli/running.js.map +1 -0
  23. package/dist/cli/shell.js +43 -0
  24. package/dist/cli/shell.js.map +1 -0
  25. package/dist/cli/wait.js +59 -0
  26. package/dist/cli/wait.js.map +1 -0
  27. package/dist/core/addresses.js +55 -0
  28. package/dist/core/addresses.js.map +1 -0
  29. package/dist/core/arrange.js +329 -0
  30. package/dist/core/arrange.js.map +1 -0
  31. package/dist/core/cables.js +158 -0
  32. package/dist/core/cables.js.map +1 -0
  33. package/dist/core/expressions.js +72 -0
  34. package/dist/core/expressions.js.map +1 -0
  35. package/dist/core/frameworks.js +13 -0
  36. package/dist/core/frameworks.js.map +1 -0
  37. package/dist/core/kinds.js +244 -0
  38. package/dist/core/kinds.js.map +1 -0
  39. package/dist/core/launch.js +181 -0
  40. package/dist/core/launch.js.map +1 -0
  41. package/dist/core/logfmt.js +144 -0
  42. package/dist/core/logfmt.js.map +1 -0
  43. package/dist/core/mock.js +27 -0
  44. package/dist/core/mock.js.map +1 -0
  45. package/dist/core/plan.js +147 -0
  46. package/dist/core/plan.js.map +1 -0
  47. package/dist/core/ports.js +155 -0
  48. package/dist/core/ports.js.map +1 -0
  49. package/dist/core/presets.js +186 -0
  50. package/dist/core/presets.js.map +1 -0
  51. package/dist/core/secret-types.js +3 -0
  52. package/dist/core/secret-types.js.map +1 -0
  53. package/dist/core/sign-in.js +30 -0
  54. package/dist/core/sign-in.js.map +1 -0
  55. package/dist/core/stack-path.js +64 -0
  56. package/dist/core/stack-path.js.map +1 -0
  57. package/dist/core/stack.js +509 -0
  58. package/dist/core/stack.js.map +1 -0
  59. package/dist/core/terraform.js +393 -0
  60. package/dist/core/terraform.js.map +1 -0
  61. package/dist/data.js +37 -0
  62. package/dist/data.js.map +1 -0
  63. package/dist/engine/actions.js +99 -0
  64. package/dist/engine/actions.js.map +1 -0
  65. package/dist/engine/app-commands.js +106 -0
  66. package/dist/engine/app-commands.js.map +1 -0
  67. package/dist/engine/app-start.js +167 -0
  68. package/dist/engine/app-start.js.map +1 -0
  69. package/dist/engine/app-state.js +43 -0
  70. package/dist/engine/app-state.js.map +1 -0
  71. package/dist/engine/boards.js +219 -0
  72. package/dist/engine/boards.js.map +1 -0
  73. package/dist/engine/branch.js +194 -0
  74. package/dist/engine/branch.js.map +1 -0
  75. package/dist/engine/browser-console.js +45 -0
  76. package/dist/engine/browser-console.js.map +1 -0
  77. package/dist/engine/calls.js +97 -0
  78. package/dist/engine/calls.js.map +1 -0
  79. package/dist/engine/checks.js +270 -0
  80. package/dist/engine/checks.js.map +1 -0
  81. package/dist/engine/clones.js +67 -0
  82. package/dist/engine/clones.js.map +1 -0
  83. package/dist/engine/config.js +26 -0
  84. package/dist/engine/config.js.map +1 -0
  85. package/dist/engine/deployed.js +488 -0
  86. package/dist/engine/deployed.js.map +1 -0
  87. package/dist/engine/devices.js +81 -0
  88. package/dist/engine/devices.js.map +1 -0
  89. package/dist/engine/discover.js +236 -0
  90. package/dist/engine/discover.js.map +1 -0
  91. package/dist/engine/down.js +253 -0
  92. package/dist/engine/down.js.map +1 -0
  93. package/dist/engine/history.js +215 -0
  94. package/dist/engine/history.js.map +1 -0
  95. package/dist/engine/investigate.js +278 -0
  96. package/dist/engine/investigate.js.map +1 -0
  97. package/dist/engine/libraries.js +129 -0
  98. package/dist/engine/libraries.js.map +1 -0
  99. package/dist/engine/linked.js +146 -0
  100. package/dist/engine/linked.js.map +1 -0
  101. package/dist/engine/listen.js +223 -0
  102. package/dist/engine/listen.js.map +1 -0
  103. package/dist/engine/locks.js +38 -0
  104. package/dist/engine/locks.js.map +1 -0
  105. package/dist/engine/messages.js +177 -0
  106. package/dist/engine/messages.js.map +1 -0
  107. package/dist/engine/needs.js +363 -0
  108. package/dist/engine/needs.js.map +1 -0
  109. package/dist/engine/processes.js +350 -0
  110. package/dist/engine/processes.js.map +1 -0
  111. package/dist/engine/query.js +241 -0
  112. package/dist/engine/query.js.map +1 -0
  113. package/dist/engine/queues.js +100 -0
  114. package/dist/engine/queues.js.map +1 -0
  115. package/dist/engine/recipes.js +248 -0
  116. package/dist/engine/recipes.js.map +1 -0
  117. package/dist/engine/reload.js +32 -0
  118. package/dist/engine/reload.js.map +1 -0
  119. package/dist/engine/repos.js +214 -0
  120. package/dist/engine/repos.js.map +1 -0
  121. package/dist/engine/research.js +134 -0
  122. package/dist/engine/research.js.map +1 -0
  123. package/dist/engine/run-logs.js +79 -0
  124. package/dist/engine/run-logs.js.map +1 -0
  125. package/dist/engine/run.js +54 -0
  126. package/dist/engine/run.js.map +1 -0
  127. package/dist/engine/runs.js +223 -0
  128. package/dist/engine/runs.js.map +1 -0
  129. package/dist/engine/session.js +130 -0
  130. package/dist/engine/session.js.map +1 -0
  131. package/dist/engine/share.js +124 -0
  132. package/dist/engine/share.js.map +1 -0
  133. package/dist/engine/stack-file.js +206 -0
  134. package/dist/engine/stack-file.js.map +1 -0
  135. package/dist/engine/stack-share.js +86 -0
  136. package/dist/engine/stack-share.js.map +1 -0
  137. package/dist/engine/stacks.js +143 -0
  138. package/dist/engine/stacks.js.map +1 -0
  139. package/dist/engine/sync.js +214 -0
  140. package/dist/engine/sync.js.map +1 -0
  141. package/dist/engine/traces.js +65 -0
  142. package/dist/engine/traces.js.map +1 -0
  143. package/dist/engine/up.js +621 -0
  144. package/dist/engine/up.js.map +1 -0
  145. package/dist/engine/watch.js +71 -0
  146. package/dist/engine/watch.js.map +1 -0
  147. package/dist/engine/wire.js +120 -0
  148. package/dist/engine/wire.js.map +1 -0
  149. package/dist/failure.js +16 -0
  150. package/dist/failure.js.map +1 -0
  151. package/dist/github.js +95 -0
  152. package/dist/github.js.map +1 -0
  153. package/dist/ids.js +6 -0
  154. package/dist/ids.js.map +1 -0
  155. package/dist/json-files.js +36 -0
  156. package/dist/json-files.js.map +1 -0
  157. package/dist/koppler.mjs +840 -0
  158. package/dist/koppler.mjs.map +1 -0
  159. package/dist/lambda-local.mjs +250 -0
  160. package/dist/lambda-local.mjs.map +1 -0
  161. package/dist/lambda-secrets-proxy.go +31 -0
  162. package/dist/mock-server.mjs +23 -0
  163. package/dist/mock-server.mjs.map +1 -0
  164. package/dist/page/assets/JetBrainsMono-cyrillic-D2jMJ_bk.woff2 +0 -0
  165. package/dist/page/assets/JetBrainsMono-greek-D2nYnAec.woff2 +0 -0
  166. package/dist/page/assets/JetBrainsMono-latin-Db4Uuiha.woff2 +0 -0
  167. package/dist/page/assets/JetBrainsMono-latin-ext-Bnd2h4Br.woff2 +0 -0
  168. package/dist/page/assets/JetBrainsMono-vietnamese-CNlsqbWb.woff2 +0 -0
  169. package/dist/page/assets/SchibstedGrotesk-latin-DxefFeRw.woff2 +0 -0
  170. package/dist/page/assets/SchibstedGrotesk-latin-ext-CnpJE18X.woff2 +0 -0
  171. package/dist/page/assets/index-Bkj_pX35.js +42 -0
  172. package/dist/page/assets/index-Dq45jswH.css +1 -0
  173. package/dist/page/index.html +14 -0
  174. package/dist/page/theme.js +8 -0
  175. package/dist/paths.js +19 -0
  176. package/dist/paths.js.map +1 -0
  177. package/dist/safe-env.js +73 -0
  178. package/dist/safe-env.js.map +1 -0
  179. package/dist/sam-local.mjs +135 -0
  180. package/dist/sam-local.mjs.map +1 -0
  181. package/dist/scrub.js +87 -0
  182. package/dist/scrub.js.map +1 -0
  183. package/dist/secret-check.mjs +262 -0
  184. package/dist/secret-check.mjs.map +1 -0
  185. package/dist/server/browser-console.js +117 -0
  186. package/dist/server/browser-console.js.map +1 -0
  187. package/dist/server/cable-test.js +365 -0
  188. package/dist/server/cable-test.js.map +1 -0
  189. package/dist/server/choices.js +51 -0
  190. package/dist/server/choices.js.map +1 -0
  191. package/dist/server/files.js +107 -0
  192. package/dist/server/files.js.map +1 -0
  193. package/dist/server/gate.js +128 -0
  194. package/dist/server/gate.js.map +1 -0
  195. package/dist/server/logs.js +76 -0
  196. package/dist/server/logs.js.map +1 -0
  197. package/dist/server/mobile.js +113 -0
  198. package/dist/server/mobile.js.map +1 -0
  199. package/dist/server/routes.js +326 -0
  200. package/dist/server/routes.js.map +1 -0
  201. package/dist/server/runs.js +111 -0
  202. package/dist/server/runs.js.map +1 -0
  203. package/dist/server/sanitize.js +242 -0
  204. package/dist/server/sanitize.js.map +1 -0
  205. package/dist/server/secrets.js +111 -0
  206. package/dist/server/secrets.js.map +1 -0
  207. package/dist/server/status.js +321 -0
  208. package/dist/server/status.js.map +1 -0
  209. package/dist/server/token.js +38 -0
  210. package/dist/server/token.js.map +1 -0
  211. package/dist/server/waiting.js +79 -0
  212. package/dist/server/waiting.js.map +1 -0
  213. package/dist/status-watch.mjs +63 -0
  214. package/dist/status-watch.mjs.map +1 -0
  215. package/package.json +74 -4
  216. package/skills/koppler-run/SKILL.md +169 -0
  217. package/skills/koppler-run/VERSION +1 -0
  218. package/skills/koppler-run/references/action-log.md +50 -0
  219. package/skills/koppler-run/references/permissions.md +25 -0
  220. package/skills/koppler-run/references/preparing-nodes.md +62 -0
  221. package/skills/koppler-run/references/reporting-bugs.md +76 -0
  222. package/skills/koppler-run/references/research.md +40 -0
  223. package/skills/koppler-run/references/secrets.md +56 -0
  224. package/skills/koppler-run/references/stack.md +197 -0
  225. package/skills/koppler-run/references/status.md +92 -0
@@ -0,0 +1,326 @@
1
+ // What the page can ask the server to do: one function per address, each given the request's JSON body and answering
2
+ // with a status and, usually, a JSON body.
3
+ import { runs } from "../engine/history.js";
4
+ import { pin } from "../engine/run-logs.js";
5
+ import { hotReload } from "../engine/reload.js";
6
+ import { spawn } from 'node:child_process';
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import { readStack, writeData } from "../data.js";
10
+ import { applyFindings, current as currentFindingsStack, discover } from "../engine/discover.js";
11
+ import { editDone } from "../engine/boards.js";
12
+ import { discardChanges, linkStack, proposeChanges, updateStack } from "../engine/linked.js";
13
+ import { listenerPid } from "../engine/listen.js";
14
+ import { setLock } from "../engine/locks.js";
15
+ import { appendAnswer, clearMessages, readMessages } from "../engine/messages.js";
16
+ import { appendNote } from "../engine/history.js";
17
+ import { addApps, addOutside, editStack, removeApp, refreshRegistry, replaceStack, saveStack, stackSource, } from "../engine/stack-file.js";
18
+ import { shareBoard, shareTarget } from "../engine/share.js";
19
+ import { newToken, pageToken, writePageUrl } from "./token.js";
20
+ import { createStack, currentStack, forgetStacks, useStack } from "../engine/stacks.js";
21
+ import { CODE, tempDir } from "../paths.js";
22
+ import { cableTest } from "./cable-test.js";
23
+ import { appendDebugLog, clearDebugLog } from "./logs.js";
24
+ import { fetchPresets, sanitizeLayout } from "./sanitize.js";
25
+ import { secretRequest } from "./secrets.js";
26
+ import { drop } from "./waiting.js";
27
+ import { koppler, prompted, reload } from "./runs.js";
28
+ import { APP_ID } from "../ids.js";
29
+ // Never starts with a dash: an id is passed to `koppler` as an argument, and must not read as a flag.
30
+ const isApp = (value) => typeof value === 'string' && APP_ID.test(value);
31
+ /** What a failed result says, as the answer; undefined when the result is not a failure. */
32
+ const refused = (result) => result.error === undefined ? undefined : { status: 400, body: result };
33
+ /** The linked stack in use: bring in GitHub's changes, drop this copy's, or propose them as a pull request. */
34
+ const linked = (work, thenReload) => async () => {
35
+ // With no stack in use there is nothing linked: the work fails on the missing folder, and the request with it.
36
+ const result = await work(currentStack());
37
+ if (result.error !== undefined || !thenReload)
38
+ return { status: result.error === undefined ? 200 : 400, body: result };
39
+ await koppler(['sync'], 120000);
40
+ return { status: 200, body: result };
41
+ };
42
+ /** Findings are worked out again here, so only what Koppler itself found can be written, and only what the user ticked. */
43
+ const found = (apply) => async (body) => {
44
+ const stack = currentFindingsStack();
45
+ if (!stack)
46
+ return { status: 400, body: { error: 'No stack is in use.' } };
47
+ let findings;
48
+ try {
49
+ findings = discover(stack.stack, stack.clones);
50
+ }
51
+ catch {
52
+ return { status: 500, body: { error: 'Looking through the repos failed. Run koppler discover to see why.' } };
53
+ }
54
+ if (!apply)
55
+ return { status: 200, body: { findings } };
56
+ const ids = Array.isArray(body['ids']) ? body['ids'].filter(id => typeof id === 'string') : [];
57
+ const applied = applyFindings(stack.stack, findings, ids);
58
+ if (applied.error !== undefined)
59
+ return { status: 400, body: applied };
60
+ const refused = saveStack(stack.source, JSON.parse(fs.readFileSync(stack.source, 'utf8')), applied.stack);
61
+ if (refused)
62
+ return { status: 400, body: refused };
63
+ forgetStacks();
64
+ await koppler(['sync'], 120000);
65
+ return { status: 200, body: { applied: applied.applied } };
66
+ };
67
+ // Tests of the same tunnel wait for each other: a tunnel drops connections when several open at once.
68
+ const tunnelLanes = new Map();
69
+ const secret = (action) => async (body) => {
70
+ const { status, body: answer } = await secretRequest(action, body);
71
+ return { status, body: answer };
72
+ };
73
+ export const ROUTES = {
74
+ '/state': body => {
75
+ const layout = sanitizeLayout(body);
76
+ if (!layout)
77
+ return { status: 400 };
78
+ writeData('state', layout);
79
+ return { status: 204 };
80
+ },
81
+ '/board-edit-done': body => {
82
+ editDone(body['id']);
83
+ return { status: 204 };
84
+ },
85
+ '/prompt': prompted,
86
+ '/preset': async (body) => {
87
+ const result = await fetchPresets(typeof body['url'] === 'string' ? body['url'].slice(0, 500) : '');
88
+ return { status: result.error === undefined ? 200 : 400, body: result };
89
+ },
90
+ '/discover': found(false),
91
+ '/discover-apply': found(true),
92
+ '/stack': async (body) => {
93
+ const { link, use } = body;
94
+ if (typeof link === 'string') {
95
+ const result = await linkStack(link.slice(0, 500));
96
+ forgetStacks();
97
+ return refused(result) ?? reload('The stack was linked, but could not be loaded. Run koppler sync.');
98
+ }
99
+ // A new stack from the canvas: only a name and environment names; it is created empty and loaded.
100
+ const result = typeof use === 'string' ? useStack(use) : createStack(body);
101
+ return refused(result) ?? reload('The stack was created, but could not be loaded. Run koppler sync.');
102
+ },
103
+ '/stack-update': linked(dir => updateStack(dir), true),
104
+ '/stack-discard': linked(dir => Promise.resolve(discardChanges(dir)), true),
105
+ '/stack-pr': linked(dir => proposeChanges(dir), false),
106
+ // Clones the user picked on the canvas join stack.json as apps that are not set up yet; then the stack is loaded again.
107
+ '/apps': body => {
108
+ const result = addApps(body['apps']);
109
+ forgetStacks();
110
+ if (result.error !== undefined || !result.added.length)
111
+ return { status: 400, body: { error: result.error ?? 'Pick at least one repo that is not in the stack yet.' } };
112
+ return reload('The apps were added, but the stack could not be loaded again. Run koppler sync.', result);
113
+ },
114
+ // One field of the stack, set or taken out, checked as the terminal's koppler stack set is.
115
+ // A new address for the page: every address given out before stops working. The page moves to the new one.
116
+ '/new-address': body => {
117
+ newToken();
118
+ const port = typeof body['port'] === 'string' && /^\d{2,5}$/.test(body['port']) ? body['port'] : '';
119
+ const page = port ? writePageUrl(port) : '';
120
+ return { status: 200, body: { path: page ? new URL(page).pathname : `/s/${pageToken()}/` } };
121
+ },
122
+ // A board of the user's own, proposed to the team: `check` says where it would go before anything is sent.
123
+ '/board-share': async (body) => {
124
+ const dir = currentStack();
125
+ const preset = body['preset'];
126
+ if (!dir)
127
+ return { status: 400, body: { error: 'No stack is in use.' } };
128
+ if (!preset || typeof preset.name !== 'string')
129
+ return { status: 400, body: { error: 'No board to share.' } };
130
+ if (body['check'] === true) {
131
+ const target = await shareTarget(dir);
132
+ return { status: 200, body: target.error === undefined ? { repo: target.repo } : { local: true } };
133
+ }
134
+ const shared = await shareBoard(dir, preset);
135
+ return { status: shared.error === undefined ? 200 : 400, body: shared };
136
+ },
137
+ '/stack-edit': body => {
138
+ const at = typeof body['path'] === 'string' ? body['path'] : '';
139
+ const result = editStack(at, body['unset'] === true ? undefined : [body['value']]);
140
+ if (result.error !== undefined)
141
+ return { status: 400, body: result };
142
+ // One field: the registry is copied again on the spot, without a full sync.
143
+ refreshRegistry();
144
+ forgetStacks();
145
+ return { status: 200, body: result };
146
+ },
147
+ // A settings panel's Save: the whole edited stack, checked and written at once, or refused with each problem.
148
+ '/stack-save': body => {
149
+ const result = replaceStack(body['stack']);
150
+ if (result.error !== undefined)
151
+ return { status: 400, body: result };
152
+ refreshRegistry();
153
+ forgetStacks();
154
+ return { status: 200, body: { ok: true } };
155
+ },
156
+ // The canvas's lock on a field: the person's own click, so it locks and unlocks.
157
+ '/stack-lock': body => {
158
+ const source = stackSource();
159
+ if (!source || typeof body['path'] !== 'string')
160
+ return { status: 400, body: { error: 'No stack or no field given' } };
161
+ const done = setLock(source, body['path'], body['on'] === true);
162
+ return done.error === undefined ? { status: 200, body: { ok: true } } : { status: 400, body: done };
163
+ },
164
+ // One of an app's commands from the stack: `koppler do` runs it, refuses what is not allowed, and says how it ended.
165
+ '/app-command': body => {
166
+ const { app, command, args } = body;
167
+ const given = args && typeof args === 'object' && !Array.isArray(args) ? Object.entries(args) : [];
168
+ const plain = (value) => typeof value === 'string' && /^[a-z0-9][a-z0-9-]{0,63}$/.test(value);
169
+ if (!plain(app) || !plain(command))
170
+ return { status: 400, body: { error: 'Which command of which app?' } };
171
+ if (given.some(([name, value]) => !/^[A-Za-z][A-Za-z0-9_]{0,31}$/.test(name) || typeof value !== 'string'))
172
+ return { status: 400, body: { error: 'Each value is text, under its name.' } };
173
+ const values = given.flatMap(([name, value]) => ['--arg', `${name}=${String(value)}`]);
174
+ spawn(process.execPath, [path.join(CODE, 'koppler.mjs'), 'do', String(app), String(command), '--from-canvas', '--yes', ...values], { detached: true, stdio: 'ignore' }).unref();
175
+ return { status: 200, body: { started: true } };
176
+ },
177
+ // A terminal window from a card: a shell in the app's clone, or psql on its database. The command runs in the user's
178
+ // own terminal, so a protected environment's secret is asked for there.
179
+ '/open-terminal': body => {
180
+ const { app, env, query } = body;
181
+ const id = (value) => typeof value === 'string' && /^[a-z0-9][a-z0-9-]{0,63}$/.test(value);
182
+ if (!id(app) || !id(env))
183
+ return { status: 400, body: { error: 'Which app, on which environment?' } };
184
+ const words = ['shell', String(app), '--env', String(env), ...(query === true ? ['--query'] : [])];
185
+ const command = `koppler ${words.join(' ')}`;
186
+ if (process.platform !== 'darwin')
187
+ return { status: 400, body: { error: `Open a terminal and run: ${command}`, command } };
188
+ const quote = (word) => `'${word.replaceAll("'", `'\\''`)}'`;
189
+ const script = path.join(tempDir(), 'terminal', `${String(app)}.command`);
190
+ fs.mkdirSync(path.dirname(script), { recursive: true, mode: 0o700 });
191
+ fs.writeFileSync(script, `#!/bin/sh\nexec ${[process.execPath, path.join(CODE, 'koppler.mjs'), ...words].map(quote).join(' ')}\n`, { mode: 0o700 });
192
+ spawn('open', [script], { detached: true, stdio: 'ignore' }).unref();
193
+ return { status: 200, body: { opened: true, command } };
194
+ },
195
+ // The trace collector, started or stopped by Koppler itself; the status says when it answers.
196
+ '/traces': body => {
197
+ spawn(process.execPath, [path.join(CODE, 'koppler.mjs'), 'traces', body['on'] === false ? 'stop' : 'start'], {
198
+ detached: true,
199
+ stdio: 'ignore',
200
+ }).unref();
201
+ return { status: 200, body: { asked: true } };
202
+ },
203
+ '/reload': body => {
204
+ const app = typeof body['app'] === 'string' ? body['app'] : '';
205
+ try {
206
+ return { status: 200, body: { said: hotReload(app, body['restart'] === true) } };
207
+ }
208
+ catch (error) {
209
+ return { status: 400, body: { error: error.message } };
210
+ }
211
+ },
212
+ '/run-pin': body => {
213
+ const id = body['id'];
214
+ if (typeof id !== 'string' || !runs().some(run => run.id === id))
215
+ return { status: 400, body: { error: 'No such run.' } };
216
+ pin(id, body['on'] === true);
217
+ return { status: 200, body: { pinned: body['on'] === true } };
218
+ },
219
+ '/apps-outside': body => {
220
+ const result = addOutside(body);
221
+ forgetStacks();
222
+ return (refused(result) ??
223
+ reload('The outside system was added, but the stack could not be loaded again. Run koppler sync.', result));
224
+ },
225
+ '/apps-remove': body => {
226
+ const result = isApp(body['id']) ? removeApp(body['id']) : { error: 'No app given' };
227
+ forgetStacks();
228
+ return refused(result) ?? reload('The stack changed, but reloading it failed: run koppler sync', result);
229
+ },
230
+ // Looks through the user's folders for clones again, as `koppler sync --rescan` does.
231
+ '/rescan': async () => {
232
+ const { failed, said } = await koppler(['sync', '--rescan'], 120000);
233
+ const why = said
234
+ .trim()
235
+ .split('\n')
236
+ .pop()
237
+ ?.replace(/^koppler: /, '') || 'The scan did not finish.';
238
+ return failed ? { status: 500, body: { error: why } } : { status: 200, body: { ok: true } };
239
+ },
240
+ // What the user has to do before these apps run on this environment, worked out live by `koppler doctor`.
241
+ '/needs': async (body) => {
242
+ const ids = (Array.isArray(body['apps']) ? body['apps'] : []).filter(isApp).slice(0, 50);
243
+ const env = typeof body['env'] === 'string' && /^[a-z0-9-]{1,16}$/.test(body['env']) ? body['env'] : null;
244
+ if (!ids.length || !env)
245
+ return { status: 400, body: { error: 'No apps or environment given' } };
246
+ const asked = Array.isArray(body['noTunnels']) ? body['noTunnels'] : [];
247
+ const off = ids.filter(id => asked.includes(id));
248
+ const { out } = await koppler(['doctor', ...ids, '--env', env, ...(off.length ? ['--no-tunnels', off.join(',')] : []), '--json'], 30000);
249
+ try {
250
+ return { status: 200, body: JSON.parse(out) };
251
+ }
252
+ catch {
253
+ return { status: 200, body: { error: 'Could not work out what is needed: run koppler doctor in a terminal' } };
254
+ }
255
+ },
256
+ '/secret': secret('set'),
257
+ '/secret-remove': secret('remove'),
258
+ '/secret-test': secret('test'),
259
+ '/cable-test': async (body) => {
260
+ const { host, port } = body;
261
+ const named = typeof host === 'string' && /^[\w.-]{1,253}$/.test(host) && Number.isInteger(port);
262
+ const lane = named ? `${host}:${String(port)}` : null;
263
+ const before = (lane && tunnelLanes.get(lane)) || Promise.resolve();
264
+ const test = before.then(() => cableTest(readStack(), body));
265
+ if (lane) {
266
+ const settled = test.catch(() => undefined);
267
+ tunnelLanes.set(lane, settled);
268
+ void settled.then(() => {
269
+ if (tunnelLanes.get(lane) === settled)
270
+ tunnelLanes.delete(lane);
271
+ });
272
+ }
273
+ return { status: 200, body: await test };
274
+ },
275
+ '/messages-clear': () => ({ status: 200, body: clearMessages() }),
276
+ // A request no agent took yet is taken out of the queue.
277
+ '/prompt-drop': body => drop(typeof body['key'] === 'string' ? body['key'] : '')
278
+ ? { status: 200, body: { ok: true } }
279
+ : { status: 409, body: { error: 'That request is no longer waiting.' } },
280
+ '/message-dismiss': body => {
281
+ const open = readMessages(200).find(one => one.id === body['id'] && one.kind === 'question' && !one.answered);
282
+ if (open)
283
+ appendAnswer(open.id, { via: 'dismissed' });
284
+ return { status: open ? 204 : 409 };
285
+ },
286
+ '/debug-log': body => ({ status: 200, body: appendDebugLog(body['entries']) }),
287
+ '/debug-clear': () => ({ status: 200, body: clearDebugLog() }),
288
+ // Stop apps, keep changes: everything Koppler runs except this canvas; branches and code changes stay for a later Revert.
289
+ // With an app, only that one.
290
+ '/stop-apps': async (body) => {
291
+ const app = body['app'];
292
+ // A name that could not be one of Koppler's processes stops nothing.
293
+ if (app !== undefined && !isApp(app))
294
+ return { status: 200, body: { stopped: [] } };
295
+ const { failed, out } = await koppler(app ? ['stop', app] : ['stop', '--all', '--yes'], 60000);
296
+ const stopped = out
297
+ .trim()
298
+ .split('\n')
299
+ .filter(line => / stopped/.test(line));
300
+ return { status: failed ? 500 : 200, body: { stopped: stopped.map(line => line.split(':')[0]) } };
301
+ },
302
+ // Shut down: the agent's listener, then this server through koppler (so its record goes too). Apps and tunnels keep
303
+ // running.
304
+ '/shutdown': () => ({
305
+ status: 204,
306
+ after: () => {
307
+ appendNote('canvas-closed');
308
+ const listener = path.join(tempDir(), 'listener.json');
309
+ try {
310
+ const pid = listenerPid(JSON.parse(fs.readFileSync(listener, 'utf8')));
311
+ if (pid)
312
+ process.kill(pid, 'SIGTERM');
313
+ }
314
+ catch {
315
+ // No agent session was listening.
316
+ }
317
+ fs.rmSync(listener, { force: true });
318
+ spawn(process.execPath, [path.join(CODE, 'koppler.mjs'), 'stop', 'canvas'], {
319
+ detached: true,
320
+ stdio: 'ignore',
321
+ }).unref();
322
+ setTimeout(() => process.exit(0), 3000).unref();
323
+ },
324
+ }),
325
+ };
326
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/server/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ // Runs from the canvas: a Send or a Stop is recorded, then carried out by Koppler itself (`koppler up` or `koppler down`),
2
+ // and whatever it cannot do alone is queued for the agent, as is anything the agent must handle.
3
+ import { execFile, spawn } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { appendRun, runRecord } from "../engine/history.js";
7
+ import { answerProposal } from "../engine/boards.js";
8
+ import { appendAnswer, appendMessage, readMessages, refusal } from "../engine/messages.js";
9
+ import { CODE, tempDir } from "../paths.js";
10
+ import { tail } from "./logs.js";
11
+ import { sanitizePrompt } from "./sanitize.js";
12
+ const PROMPTS = path.join(tempDir(), 'prompts.jsonl');
13
+ const stamp = () => new Date().toISOString();
14
+ const appendLine = (file, line) => {
15
+ fs.appendFileSync(file, JSON.stringify(line) + '\n', { mode: 0o600 });
16
+ };
17
+ /** Runs a koppler command of this same build; gives what it printed and whether it failed. */
18
+ export const koppler = (args, timeout) => new Promise(resolve => {
19
+ const options = { timeout, maxBuffer: 1 << 20 };
20
+ execFile(process.execPath, [path.join(CODE, 'koppler.mjs'), ...args], options, (error, out, said) => {
21
+ resolve({ failed: !!error, out, said });
22
+ });
23
+ });
24
+ /** Loads the stack again after it changed; `unloaded` is what to say when that fails. */
25
+ export async function reload(unloaded, done = { ok: true }) {
26
+ const { failed } = await koppler(['sync'], 120000);
27
+ return failed ? { status: 500, body: { error: unloaded } } : { status: 200, body: done };
28
+ }
29
+ /** A confirmed Send (koppler up) or Stop and revert (koppler down), carried out by Koppler itself; leftovers go to the agent. */
30
+ function startRun(prompt, record, command) {
31
+ const log = path.join(tempDir(), `up-${record.id}.log`);
32
+ const out = fs.openSync(log, 'w', 0o600);
33
+ appendLine(path.join(tempDir(), 'history.jsonl'), { id: record.id, event: 'picked', at: stamp() });
34
+ const entry = path.join(CODE, 'koppler.mjs');
35
+ const child = spawn(process.execPath, [entry, command, '--run', record.id], {
36
+ stdio: ['ignore', out, out],
37
+ env: process.env,
38
+ });
39
+ child.on('error', error => {
40
+ fs.closeSync(out);
41
+ appendMessage(refusal(record.id, record.kind, `Koppler could not start: ${error.message}`));
42
+ });
43
+ child.on('exit', code => {
44
+ fs.closeSync(out);
45
+ // A Stop from switching stacks switches once everything is stopped and reverted.
46
+ const switchTo = prompt.data['switchTo'];
47
+ if (code === 0 && record.kind === 'stop' && typeof switchTo === 'string')
48
+ void koppler(['use', switchTo], 60000);
49
+ if (code === 0)
50
+ return;
51
+ // The log may have gone with a Stop: the exit code still tells.
52
+ const said = tail(log, 64 * 1024, 40)?.trim() ?? '';
53
+ // Said on the canvas too: with no agent connected, the prompt below is read by nobody.
54
+ appendMessage(refusal(record.id, record.kind, said));
55
+ const finish = `koppler history done ${record.kind === 'stop' ? record.id : ''}`;
56
+ const text = `${prompt.text}\n\nKoppler already did what it could (koppler ${command} --run ${record.id}); finish the rest, then ${finish}:\n${said}`;
57
+ appendLine(PROMPTS, { ...prompt, text, data: { ...prompt.data, koppler: { exit: code, log } } });
58
+ });
59
+ }
60
+ /** A Send, a Stop, or an answer from the page. */
61
+ export function prompted(body) {
62
+ const prompt = sanitizePrompt(body);
63
+ if (!prompt)
64
+ return { status: 400 };
65
+ // An answer to a question on the canvas: only for a message that exists and has no answer yet.
66
+ if (prompt.tag === 'koppler-reply') {
67
+ const message = readMessages(200).find(one => one.id === prompt.data['message']);
68
+ if (!message || message.answered)
69
+ return { status: 409 };
70
+ const choice = message.choices?.find(one => one.id === prompt.data['choice']);
71
+ const said = typeof prompt.data['text'] === 'string' ? prompt.data['text'].slice(0, 2000) : '';
72
+ if (!choice && !said)
73
+ return { status: 400 };
74
+ prompt.data = {
75
+ message: message.id,
76
+ ...(message.run && { run: message.run }),
77
+ ...(choice && { choice: choice.id, label: choice.label }),
78
+ ...(said && { text: said }),
79
+ };
80
+ appendAnswer(message.id, { ...(choice && { choice: choice.id }), ...(said && { text: said }) });
81
+ // A board change the agent proposed: made as soon as the user says yes, so the agent only hears how it went.
82
+ if (choice) {
83
+ let done;
84
+ try {
85
+ done = answerProposal(message.id, choice.id === 'accept');
86
+ }
87
+ catch (error) {
88
+ done = `It could not be made: ${error.message}`;
89
+ appendMessage({ kind: 'failure', title: done.slice(0, 120) });
90
+ }
91
+ if (done)
92
+ prompt.data['result'] = done;
93
+ }
94
+ }
95
+ // Kept as a run from the moment it is sent, so a Send nobody picked up still shows on the canvas.
96
+ const record = runRecord(prompt);
97
+ if (record)
98
+ appendRun(record);
99
+ // A confirmed Send in auto mode: Koppler starts it itself. Only what it cannot do alone goes on to the agent.
100
+ const { mode, note, nodes } = prompt.data;
101
+ const noted = (Array.isArray(nodes) ? nodes : []).some(node => node?.['note']);
102
+ const byAgent = mode === 'manual' || !!note || noted;
103
+ if (record?.kind === 'run' && !byAgent)
104
+ startRun(prompt, record, 'up');
105
+ else if (record?.kind === 'stop')
106
+ startRun(prompt, record, 'down');
107
+ else
108
+ appendLine(PROMPTS, prompt);
109
+ return { status: 204 };
110
+ }
111
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/server/runs.ts"],"names":[],"mappings":"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"}