nomoreide 0.1.19 → 0.1.21

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 (35) hide show
  1. package/dist/core/config-files.d.ts +27 -0
  2. package/dist/core/config-files.js +154 -0
  3. package/dist/core/config-files.js.map +1 -0
  4. package/dist/core/env-file.d.ts +24 -0
  5. package/dist/core/env-file.js +122 -0
  6. package/dist/core/env-file.js.map +1 -0
  7. package/dist/web/client/assets/index-CBZsUFdB.js +23 -0
  8. package/dist/web/client/assets/index-y4GyM_JC.css +1 -0
  9. package/dist/web/client/index.html +2 -2
  10. package/dist/web/routes/agent-routes.d.ts +3 -0
  11. package/dist/web/routes/agent-routes.js +40 -0
  12. package/dist/web/routes/agent-routes.js.map +1 -0
  13. package/dist/web/routes/context.d.ts +39 -0
  14. package/dist/web/routes/context.js +48 -0
  15. package/dist/web/routes/context.js.map +1 -0
  16. package/dist/web/routes/dashboard-routes.d.ts +3 -0
  17. package/dist/web/routes/dashboard-routes.js +20 -0
  18. package/dist/web/routes/dashboard-routes.js.map +1 -0
  19. package/dist/web/routes/git-routes.d.ts +3 -0
  20. package/dist/web/routes/git-routes.js +125 -0
  21. package/dist/web/routes/git-routes.js.map +1 -0
  22. package/dist/web/routes/index.d.ts +10 -0
  23. package/dist/web/routes/index.js +20 -0
  24. package/dist/web/routes/index.js.map +1 -0
  25. package/dist/web/routes/service-routes.d.ts +3 -0
  26. package/dist/web/routes/service-routes.js +298 -0
  27. package/dist/web/routes/service-routes.js.map +1 -0
  28. package/dist/web/routes/shell-routes.d.ts +3 -0
  29. package/dist/web/routes/shell-routes.js +34 -0
  30. package/dist/web/routes/shell-routes.js.map +1 -0
  31. package/dist/web/server.js +21 -358
  32. package/dist/web/server.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/web/client/assets/index-CZxkTcFO.js +0 -23
  35. package/dist/web/client/assets/index-Di8-pWM4.css +0 -1
@@ -0,0 +1,298 @@
1
+ import { dirname } from "node:path";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { browseDirectory, ConfigFilePathError, detectConfigFiles, resolveConfigFile, validateJson, } from "../../core/config-files.js";
4
+ import { entriesFromLines, looksSecret, mergeEntries, readEnvFile, writeEnvFile, } from "../../core/env-file.js";
5
+ import { PortConflictError } from "../../core/process-manager.js";
6
+ import { testServiceCommand } from "../service-tester.js";
7
+ import { optionalFormValue, readForm, requiredFormValue, sendJson, } from "../http-utils.js";
8
+ import { errorMessage, patternRoute, route } from "./context.js";
9
+ /** Services, bundles, per-service config files, and the HTTP inspector toggle. */
10
+ export const serviceRoutes = [
11
+ route("POST", "/api/services", async ({ request, response, configStore }) => {
12
+ const form = await readForm(request);
13
+ const portValue = form.get("port")?.trim();
14
+ const port = portValue ? Number(portValue) : undefined;
15
+ const kind = (optionalFormValue(form, "kind") ?? "local");
16
+ const name = requiredFormValue(form, "name");
17
+ const description = optionalFormValue(form, "description");
18
+ const definition = kind === "docker-compose"
19
+ ? {
20
+ name,
21
+ kind: "docker-compose",
22
+ cwd: requiredFormValue(form, "cwd"),
23
+ composeFile: optionalFormValue(form, "composeFile"),
24
+ composeService: requiredFormValue(form, "composeService"),
25
+ port,
26
+ description,
27
+ }
28
+ : kind === "ssh"
29
+ ? {
30
+ name,
31
+ kind: "ssh",
32
+ host: requiredFormValue(form, "host"),
33
+ cwd: requiredFormValue(form, "cwd"),
34
+ command: requiredFormValue(form, "command"),
35
+ port,
36
+ description,
37
+ }
38
+ : {
39
+ name,
40
+ command: requiredFormValue(form, "command"),
41
+ cwd: requiredFormValue(form, "cwd"),
42
+ port,
43
+ description,
44
+ };
45
+ const config = await configStore.registerService(definition);
46
+ sendJson(response, { ok: true, config });
47
+ }),
48
+ route("POST", "/api/services/test", async ({ request, response }) => {
49
+ const form = await readForm(request);
50
+ const portValue = form.get("port")?.trim();
51
+ sendJson(response, await testServiceCommand({
52
+ command: requiredFormValue(form, "command"),
53
+ cwd: requiredFormValue(form, "cwd"),
54
+ port: portValue ? Number(portValue) : undefined,
55
+ }));
56
+ }),
57
+ route("POST", "/api/bundles", async ({ request, response, configStore }) => {
58
+ const form = await readForm(request);
59
+ const services = requiredFormValue(form, "services")
60
+ .split(",")
61
+ .map((service) => service.trim())
62
+ .filter(Boolean);
63
+ const config = await configStore.registerBundle({ name: requiredFormValue(form, "name"), services }, optionalFormValue(form, "originalName"));
64
+ sendJson(response, { ok: true, config });
65
+ }),
66
+ patternRoute(/^\/api\/services\/([^/]+)\/config-files$/, ["name"], async ({ request, response, configStore, params }) => {
67
+ if (request.method !== "GET") {
68
+ sendJson(response, { ok: false, error: "Method not allowed" }, 405);
69
+ return;
70
+ }
71
+ const name = decodeURIComponent(params.name);
72
+ const serviceCwd = await getServiceCwd(configStore, name);
73
+ if (!serviceCwd) {
74
+ sendJson(response, { ok: false, error: `Service "${name}" has no working directory.` }, 400);
75
+ return;
76
+ }
77
+ const files = await detectConfigFiles(serviceCwd);
78
+ sendJson(response, { ok: true, cwd: serviceCwd, files });
79
+ }),
80
+ patternRoute(/^\/api\/services\/([^/]+)\/config-browse$/, ["name"], async ({ request, response, url, configStore, params }) => {
81
+ if (request.method !== "GET") {
82
+ sendJson(response, { ok: false, error: "Method not allowed" }, 405);
83
+ return;
84
+ }
85
+ const name = decodeURIComponent(params.name);
86
+ const serviceCwd = await getServiceCwd(configStore, name);
87
+ if (!serviceCwd) {
88
+ sendJson(response, { ok: false, error: `Service "${name}" has no working directory.` }, 400);
89
+ return;
90
+ }
91
+ try {
92
+ const result = await browseDirectory(serviceCwd, url.searchParams.get("path")?.trim() || undefined);
93
+ sendJson(response, { ok: true, ...result });
94
+ }
95
+ catch (error) {
96
+ sendJson(response, { ok: false, error: errorMessage(error) }, error instanceof ConfigFilePathError ? 400 : 500);
97
+ }
98
+ }),
99
+ patternRoute(/^\/api\/services\/([^/]+)\/config-file$/, ["name"], async ({ request, response, url, configStore, params }) => {
100
+ const name = decodeURIComponent(params.name);
101
+ const serviceCwd = await getServiceCwd(configStore, name);
102
+ if (!serviceCwd) {
103
+ sendJson(response, { ok: false, error: `Service "${name}" has no working directory.` }, 400);
104
+ return;
105
+ }
106
+ const requested = url.searchParams.get("path")?.trim();
107
+ if (!requested) {
108
+ sendJson(response, { ok: false, error: "path is required" }, 400);
109
+ return;
110
+ }
111
+ let file;
112
+ try {
113
+ file = resolveConfigFile(serviceCwd, requested);
114
+ }
115
+ catch (error) {
116
+ sendJson(response, { ok: false, error: errorMessage(error) }, error instanceof ConfigFilePathError ? 400 : 500);
117
+ return;
118
+ }
119
+ if (request.method === "GET") {
120
+ if (file.format === "env") {
121
+ const { exists, lines } = await readEnvFile(file.path);
122
+ const entries = entriesFromLines(lines).map((entry) => ({
123
+ key: entry.key,
124
+ value: entry.value,
125
+ secret: looksSecret(entry.key),
126
+ }));
127
+ sendJson(response, { ok: true, exists, format: file.format, path: file.path, relativePath: file.relativePath, entries });
128
+ return;
129
+ }
130
+ const { content, exists } = await readTextFile(file.path);
131
+ sendJson(response, { ok: true, exists, format: file.format, path: file.path, relativePath: file.relativePath, content });
132
+ return;
133
+ }
134
+ if (request.method === "PUT") {
135
+ const body = await readJsonBody(request);
136
+ if (file.format === "env") {
137
+ const parsed = parseEnvEntries(body);
138
+ const { lines } = await readEnvFile(file.path);
139
+ const merged = mergeEntries(lines, parsed);
140
+ await writeEnvFile(file.path, merged);
141
+ const entries = entriesFromLines(merged).map((entry) => ({
142
+ key: entry.key,
143
+ value: entry.value,
144
+ secret: looksSecret(entry.key),
145
+ }));
146
+ sendJson(response, { ok: true, exists: true, format: file.format, path: file.path, relativePath: file.relativePath, entries });
147
+ return;
148
+ }
149
+ const content = body?.content;
150
+ if (typeof content !== "string") {
151
+ sendJson(response, { ok: false, error: "content must be a string" }, 400);
152
+ return;
153
+ }
154
+ if (file.format === "json") {
155
+ try {
156
+ validateJson(content);
157
+ }
158
+ catch (error) {
159
+ sendJson(response, { ok: false, error: errorMessage(error) }, 400);
160
+ return;
161
+ }
162
+ }
163
+ await mkdir(dirname(file.path), { recursive: true });
164
+ await writeFile(file.path, content);
165
+ sendJson(response, { ok: true, exists: true, format: file.format, path: file.path, relativePath: file.relativePath, content });
166
+ return;
167
+ }
168
+ sendJson(response, { ok: false, error: "Method not allowed" }, 405);
169
+ }),
170
+ patternRoute(/^\/api\/services\/([^/]+)\/inspector$/, ["name"], async ({ request, response, manager, params }) => {
171
+ if (request.method !== "POST") {
172
+ sendJson(response, { ok: false, error: "Method not allowed" }, 405);
173
+ return;
174
+ }
175
+ const name = decodeURIComponent(params.name);
176
+ const form = await readForm(request);
177
+ const enabled = form.get("enabled") === "true" || form.get("enabled") === "1";
178
+ const status = await manager.setInspectorEnabled(name, enabled);
179
+ sendJson(response, { ok: true, status });
180
+ }),
181
+ patternRoute(/^\/api\/services\/([^/]+)\/(start|stop|restart|logs)$/, ["name", "action"], async ({ request, response, manager, logStore, params }) => {
182
+ const name = decodeURIComponent(params.name);
183
+ const action = params.action;
184
+ if (request.method === "GET" && action === "logs") {
185
+ sendJson(response, { ok: true, logs: logStore.read(name, 200) });
186
+ return;
187
+ }
188
+ if (request.method !== "POST") {
189
+ sendJson(response, { ok: false, error: "Method not allowed" }, 405);
190
+ return;
191
+ }
192
+ try {
193
+ let startOptions = {};
194
+ if (action === "start" || action === "restart") {
195
+ const form = await readForm(request).catch(() => new URLSearchParams());
196
+ if (form.get("strategy") === "killHolder") {
197
+ startOptions = { killHolder: true };
198
+ }
199
+ }
200
+ const status = action === "start"
201
+ ? await manager.startService(name, startOptions)
202
+ : action === "stop"
203
+ ? await manager.stopService(name)
204
+ : await manager.restartService(name, startOptions);
205
+ sendJson(response, { ok: true, status });
206
+ }
207
+ catch (error) {
208
+ if (error instanceof PortConflictError) {
209
+ sendJson(response, {
210
+ ok: false,
211
+ error: error.message,
212
+ conflict: { code: error.code, port: error.port, holder: error.holder },
213
+ }, 409);
214
+ return;
215
+ }
216
+ throw error;
217
+ }
218
+ }),
219
+ patternRoute(/^\/api\/bundles\/([^/]+)\/(start|stop|restart)$/, ["name", "action"], async ({ request, response, manager, params }) => {
220
+ if (request.method !== "POST") {
221
+ sendJson(response, { ok: false, error: "Method not allowed" }, 405);
222
+ return;
223
+ }
224
+ const name = decodeURIComponent(params.name);
225
+ const action = params.action;
226
+ const statuses = action === "start"
227
+ ? await manager.startBundle(name)
228
+ : action === "stop"
229
+ ? await manager.stopBundle(name)
230
+ : await manager.restartBundle(name);
231
+ sendJson(response, { ok: true, statuses });
232
+ }),
233
+ ];
234
+ async function readJsonBody(request) {
235
+ const chunks = [];
236
+ for await (const chunk of request) {
237
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
238
+ }
239
+ const text = Buffer.concat(chunks).toString("utf8");
240
+ if (!text)
241
+ return undefined;
242
+ try {
243
+ return JSON.parse(text);
244
+ }
245
+ catch {
246
+ throw new Error("Request body must be valid JSON.");
247
+ }
248
+ }
249
+ function parseEnvEntries(body) {
250
+ if (!body || typeof body !== "object") {
251
+ throw new Error("entries array is required.");
252
+ }
253
+ const raw = body.entries;
254
+ if (!Array.isArray(raw)) {
255
+ throw new Error("entries must be an array.");
256
+ }
257
+ const seen = new Set();
258
+ const result = [];
259
+ for (const item of raw) {
260
+ if (!item || typeof item !== "object") {
261
+ throw new Error("each entry must be { key, value }.");
262
+ }
263
+ const { key, value } = item;
264
+ if (typeof key !== "string" || !/^[A-Za-z_][A-Za-z0-9_.]*$/.test(key)) {
265
+ throw new Error(`invalid env key: ${JSON.stringify(key)}`);
266
+ }
267
+ if (typeof value !== "string") {
268
+ throw new Error(`value for "${key}" must be a string.`);
269
+ }
270
+ if (seen.has(key)) {
271
+ throw new Error(`duplicate env key: ${key}`);
272
+ }
273
+ seen.add(key);
274
+ result.push({ key, value });
275
+ }
276
+ return result;
277
+ }
278
+ async function getServiceCwd(configStore, name) {
279
+ const config = await configStore.load();
280
+ const service = config.services.find((item) => item.name === name);
281
+ if (!service) {
282
+ throw new Error(`Service "${name}" not found.`);
283
+ }
284
+ return service.cwd;
285
+ }
286
+ async function readTextFile(path) {
287
+ try {
288
+ const content = await readFile(path, "utf8");
289
+ return { content, exists: true };
290
+ }
291
+ catch (error) {
292
+ if (error.code === "ENOENT") {
293
+ return { content: "", exists: false };
294
+ }
295
+ throw error;
296
+ }
297
+ }
298
+ //# sourceMappingURL=service-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-routes.js","sourceRoot":"","sources":["../../../src/web/routes/service-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Route } from "./context.js";
2
+ /** Static assets and the SPA shell. Registered last so /api/* wins first. */
3
+ export declare const shellRoutes: Route[];
@@ -0,0 +1,34 @@
1
+ import { sendHead, sendHtml } from "../http-utils.js";
2
+ import { readWebAppShell, sendStaticAsset } from "../static-assets.js";
3
+ import { prefixRoute } from "./context.js";
4
+ /** Paths that serve the SPA shell (client-side routing handles the rest). */
5
+ const shellPaths = new Set(["/", "/git", "/agent"]);
6
+ /** Static assets and the SPA shell. Registered last so /api/* wins first. */
7
+ export const shellRoutes = [
8
+ {
9
+ match(method, url) {
10
+ if (method !== "HEAD")
11
+ return null;
12
+ return shellPaths.has(url.pathname) ? {} : null;
13
+ },
14
+ handle({ response }) {
15
+ sendHead(response, "text/html; charset=utf-8");
16
+ },
17
+ },
18
+ prefixRoute("GET", "/assets/", async ({ response, url }) => {
19
+ if (await sendStaticAsset(response, url.pathname))
20
+ return;
21
+ sendHtml(response, "Not found", 404);
22
+ }),
23
+ {
24
+ match(method, url) {
25
+ if (method !== "GET")
26
+ return null;
27
+ return shellPaths.has(url.pathname) ? {} : null;
28
+ },
29
+ async handle({ response }) {
30
+ sendHtml(response, await readWebAppShell());
31
+ },
32
+ },
33
+ ];
34
+ //# sourceMappingURL=shell-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-routes.js","sourceRoot":"","sources":["../../../src/web/routes/shell-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAc,MAAM,cAAc,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEpD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC;QACE,KAAK,CAAC,MAAM,EAAE,GAAG;YACf,IAAI,MAAM,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAC;YACnC,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAClD,CAAC;QACD,MAAM,CAAC,EAAE,QAAQ,EAAE;YACjB,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC,CAAC;QACjD,CAAC;KACF;IAED,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE;QACzD,IAAI,MAAM,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC1D,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC,CAAC;IAEF;QACE,KAAK,CAAC,MAAM,EAAE,GAAG;YACf,IAAI,MAAM,KAAK,KAAK;gBAAE,OAAO,IAAI,CAAC;YAClC,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAClD,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE;YACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,eAAe,EAAE,CAAC,CAAC;QAC9C,CAAC;KACF;CACF,CAAC"}