@krapht/ork 0.3.0 → 0.4.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.
- package/dist/__build_info__-CtSVVuZE.mjs +691 -0
- package/dist/bin.mjs +826 -526
- package/dist/clean-Dcr807be.mjs +88 -0
- package/dist/{context-BFGC_C02.mjs → context-C_bksb0C.mjs} +45 -129
- package/dist/{find-BcvhT6UN.mjs → find-DptmbhGd.mjs} +1 -1
- package/dist/{format-DqpObyMl.mjs → format-J-a21Yvn.mjs} +3 -163
- package/dist/{in-a-run-BbLhZOFW.mjs → in-a-run-D1Qc5Mit.mjs} +1 -1
- package/dist/{limits-BKYAmqCR.mjs → limits-BDZCmGEu.mjs} +1 -1
- package/dist/list-ZvY2OcLq.mjs +110 -0
- package/dist/{mcp-BWsdQyri.mjs → mcp-CHVKKg3B.mjs} +6 -6
- package/dist/{output-Q2EdeVUt.mjs → output-CXSJO00X.mjs} +68 -24
- package/dist/{pause-DKACDfV1.mjs → pause-BPSmg4yz.mjs} +4 -4
- package/dist/{relay-CbK-Wme9.mjs → relay-Do-aNbSD.mjs} +2 -2
- package/dist/remove-AwaMMaHf.mjs +194 -0
- package/dist/{send-C6yr04Fe.mjs → send-DhGBkowy.mjs} +3 -3
- package/dist/{src-CZOVF2yU.mjs → src-BHnxpJyH.mjs} +1 -1
- package/dist/{src-Cz1yOUTg.mjs → src-CGqMati3.mjs} +1411 -747
- package/dist/{src-D5ruZFgD.mjs → src-CpDKIulI.mjs} +1200 -55
- package/dist/{src-DtN1k-B3.mjs → src-UWkk1sl9.mjs} +1 -1
- package/dist/ui/assets/app-BgVDC_5l.js +67 -0
- package/dist/ui/assets/{app-C722xNZ3.css → app-DVf68fj5.css} +1 -1
- package/dist/ui/assets/{index-BoG6O-Lp.js → index-MQNNgsyT.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/ui-DhutUMgQ.mjs +472 -0
- package/dist/{usage-BIjf9Xdt.mjs → usage-CT7Z-yjr.mjs} +5 -4
- package/dist/{watch-B8o4Szd_.mjs → watch-0Qr2UfCQ.mjs} +6 -6
- package/dist/worktrees-DHl80k96.mjs +212 -0
- package/package.json +4 -4
- package/dist/__build_info__-CXXMLvjt.mjs +0 -104
- package/dist/ui/assets/app-BlDdP396.js +0 -61
- package/dist/ui-CZS1XKla.mjs +0 -160
package/dist/ui/index.html
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
href="/favicon.svg"
|
|
21
21
|
type="image/svg+xml"
|
|
22
22
|
/>
|
|
23
|
-
<script type="module" crossorigin src="/assets/index-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-MQNNgsyT.js"></script>
|
|
24
24
|
<link rel="modulepreload" crossorigin href="/assets/theme-3xH5jxKs.js">
|
|
25
25
|
<link rel="stylesheet" crossorigin href="/assets/index-BiO54L90.css">
|
|
26
26
|
</head>
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { n as ORK_VERSION, t as ORK_NAME } from "./__build_info__-CtSVVuZE.mjs";
|
|
2
|
+
import { a as write, i as style, o as writeErr } from "./output-CXSJO00X.mjs";
|
|
3
|
+
import { i as uiFilePath, l as newToken, n as startServer, r as runningServer, t as DEFAULT_PORT } from "./src-CpDKIulI.mjs";
|
|
4
|
+
import { a as mayShowSignIn } from "./in-a-run-D1Qc5Mit.mjs";
|
|
5
|
+
import { defineCommand } from "citty";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { constants } from "node:os";
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
// src/browser/open.ts
|
|
11
|
+
/**
|
|
12
|
+
* @file Opening a link in the user's browser, for `ork ui`. Each way is an
|
|
13
|
+
* opener in a registry, tried in order when it applies to this platform:
|
|
14
|
+
* `open` on macOS, `wslview` then `xdg-open` under WSL, `xdg-open` on Linux.
|
|
15
|
+
* Adding a platform is one more entry. When none starts, the caller prints
|
|
16
|
+
* the link instead.
|
|
17
|
+
*/
|
|
18
|
+
const wsl = (env) => env["WSL_DISTRO_NAME"] !== void 0;
|
|
19
|
+
const OPENERS = [
|
|
20
|
+
{
|
|
21
|
+
id: "macos",
|
|
22
|
+
applies: (platform) => platform === "darwin",
|
|
23
|
+
program: "open"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "wslview",
|
|
27
|
+
applies: (platform, env) => platform === "linux" && wsl(env),
|
|
28
|
+
program: "wslview"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "xdg-open",
|
|
32
|
+
applies: (platform) => platform === "linux" || platform === "freebsd",
|
|
33
|
+
program: "xdg-open"
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
/** Starts one program with the link; false when it cannot be started. */
|
|
37
|
+
const start = (program, url) => new Promise((resolve) => {
|
|
38
|
+
const child = spawn(program, [url], {
|
|
39
|
+
detached: true,
|
|
40
|
+
stdio: "ignore"
|
|
41
|
+
});
|
|
42
|
+
child.once("error", () => {
|
|
43
|
+
resolve(false);
|
|
44
|
+
});
|
|
45
|
+
child.once("spawn", () => {
|
|
46
|
+
child.unref();
|
|
47
|
+
resolve(true);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
/** Opens `url` with the first opener that starts; false when none did. */
|
|
51
|
+
const openInBrowser = async (url, options = {}) => {
|
|
52
|
+
const platform = options.platform ?? process.platform;
|
|
53
|
+
const env = options.env ?? process.env;
|
|
54
|
+
for (const opener of options.openers ?? OPENERS) {
|
|
55
|
+
if (!opener.applies(platform, env)) continue;
|
|
56
|
+
if (await start(opener.program, url)) return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
// src/browser/folder.ts
|
|
61
|
+
/**
|
|
62
|
+
* @file Where `ork ui` finds the built UI: `dist/ui` beside the published
|
|
63
|
+
* bundle, or, run from source, `packages/ui/dist` once it is built (`pnpm
|
|
64
|
+
* --filter @krapht/ork-ui build`). The CLI takes the UI's built files, never
|
|
65
|
+
* its source; without them the server shows its placeholder page.
|
|
66
|
+
*/
|
|
67
|
+
/** The UI package's built folder in the workspace, or null outside it. */
|
|
68
|
+
const workspaceUi = () => {
|
|
69
|
+
try {
|
|
70
|
+
const manifest = fileURLToPath(import.meta.resolve("@krapht/ork-ui/package.json"));
|
|
71
|
+
return path.join(path.dirname(manifest), "dist");
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
/** The folders that may hold the built UI, in the order they are tried. */
|
|
77
|
+
const uiFolders = () => {
|
|
78
|
+
const workspace = workspaceUi();
|
|
79
|
+
return [path.join(import.meta.dirname, "ui"), ...workspace === null ? [] : [workspace]];
|
|
80
|
+
};
|
|
81
|
+
// src/browser/ui-protocol.ts
|
|
82
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
83
|
+
const TYPES = /* @__PURE__ */ new Set([
|
|
84
|
+
"ork-ui-hello",
|
|
85
|
+
"ork-ui-ready",
|
|
86
|
+
"ork-ui-failed",
|
|
87
|
+
"ork-ui-restart"
|
|
88
|
+
]);
|
|
89
|
+
/** A message from the child, or `null` for anything else. */
|
|
90
|
+
const childMessage = (value) => {
|
|
91
|
+
if (!isRecord(value) || !TYPES.has(value["type"])) return null;
|
|
92
|
+
const { type, port, version, error } = value;
|
|
93
|
+
if (type === "ork-ui-ready") return typeof port === "number" && typeof version === "string" ? {
|
|
94
|
+
type,
|
|
95
|
+
port,
|
|
96
|
+
version
|
|
97
|
+
} : null;
|
|
98
|
+
if (type === "ork-ui-failed") return {
|
|
99
|
+
type,
|
|
100
|
+
error: typeof error === "string" ? error : "It failed."
|
|
101
|
+
};
|
|
102
|
+
return type === "ork-ui-hello" ? { type } : { type: "ork-ui-restart" };
|
|
103
|
+
};
|
|
104
|
+
/** The supervisor's `start`, or `null` for anything else. */
|
|
105
|
+
const startMessage = (value) => isRecord(value) && value["type"] === "ork-ui-start" && typeof value["port"] === "number" && typeof value["token"] === "string" ? {
|
|
106
|
+
type: "ork-ui-start",
|
|
107
|
+
port: value["port"],
|
|
108
|
+
token: value["token"]
|
|
109
|
+
} : null;
|
|
110
|
+
// src/browser/serve.ts
|
|
111
|
+
/**
|
|
112
|
+
* @file The server's side of `ork ui` (ADR-060): `ork ui --serve`, which only
|
|
113
|
+
* `ork ui` starts. It says hello over its IPC channel, takes the port and the
|
|
114
|
+
* token from the supervisor, serves, and says it's ready. A restart asked by
|
|
115
|
+
* the page tells the supervisor, then closes and exits, so the supervisor
|
|
116
|
+
* starts the installed `ork` in its place. Ctrl-C, SIGTERM, or losing the
|
|
117
|
+
* supervisor closes it too, so no server is left behind; an upgrade still
|
|
118
|
+
* running is waited for first.
|
|
119
|
+
*/
|
|
120
|
+
const NOT_SUPERVISED = "`ork ui --serve` is how `ork ui` starts its server; run `ork ui`.";
|
|
121
|
+
const send = (message) => new Promise((resolve) => {
|
|
122
|
+
if (!process.connected || process.send === void 0) {
|
|
123
|
+
resolve();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
process.send(message, void 0, {}, () => {
|
|
127
|
+
resolve();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
/** The supervisor's `start`, after saying hello. */
|
|
131
|
+
const started = () => new Promise((resolve) => {
|
|
132
|
+
const listen = (raw) => {
|
|
133
|
+
const message = startMessage(raw);
|
|
134
|
+
if (message === null) return;
|
|
135
|
+
process.off("message", listen);
|
|
136
|
+
resolve(message);
|
|
137
|
+
};
|
|
138
|
+
process.on("message", listen);
|
|
139
|
+
send({ type: "ork-ui-hello" });
|
|
140
|
+
});
|
|
141
|
+
const ignore = () => {};
|
|
142
|
+
/** What the terminal says while an upgrade holds the stop up. */
|
|
143
|
+
const WAITING_FOR_UPGRADE = "Waiting for the upgrade to finish… Press Ctrl-C again to stop now.";
|
|
144
|
+
/**
|
|
145
|
+
* Ends on Ctrl-C, SIGTERM, the supervisor's channel closing, or `end`. Each
|
|
146
|
+
* Ctrl-C reaches the child twice (from the terminal, and passed on by the
|
|
147
|
+
* supervisor), so while the supervisor is there, forcing a stop is its job: it
|
|
148
|
+
* kills the child on the second. Without it, a signal after the first stop
|
|
149
|
+
* exits at once.
|
|
150
|
+
*/
|
|
151
|
+
const stopper = () => {
|
|
152
|
+
let end = ignore;
|
|
153
|
+
let stopped = false;
|
|
154
|
+
const promise = new Promise((resolve) => {
|
|
155
|
+
end = () => {
|
|
156
|
+
stopped = true;
|
|
157
|
+
resolve();
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
const onSignal = (signal) => {
|
|
161
|
+
if (stopped && !process.connected) process.exit(128 + constants.signals[signal]);
|
|
162
|
+
end();
|
|
163
|
+
};
|
|
164
|
+
process.on("SIGINT", onSignal);
|
|
165
|
+
process.on("SIGTERM", onSignal);
|
|
166
|
+
process.once("disconnect", () => {
|
|
167
|
+
end();
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
promise,
|
|
171
|
+
end: () => {
|
|
172
|
+
end();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Waits for an upgrade still running before the server closes, saying so on the
|
|
178
|
+
* terminal: exiting mid-install could leave `ork` half-installed. The
|
|
179
|
+
* installer's output is read to its end meanwhile.
|
|
180
|
+
*/
|
|
181
|
+
const upgradeFinished = async (server, say) => {
|
|
182
|
+
const running = server.upgrading();
|
|
183
|
+
if (running === null) return;
|
|
184
|
+
say(WAITING_FOR_UPGRADE);
|
|
185
|
+
await running.catch(ignore);
|
|
186
|
+
};
|
|
187
|
+
const serve = async (start, end) => {
|
|
188
|
+
try {
|
|
189
|
+
return await startServer({
|
|
190
|
+
version: ORK_VERSION,
|
|
191
|
+
port: start.port,
|
|
192
|
+
token: start.token,
|
|
193
|
+
ui: uiFolders(),
|
|
194
|
+
update: { name: ORK_NAME },
|
|
195
|
+
restart: () => {
|
|
196
|
+
send({ type: "ork-ui-restart" }).then(end);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
} catch (error) {
|
|
200
|
+
await send({
|
|
201
|
+
type: "ork-ui-failed",
|
|
202
|
+
error: error instanceof Error ? error.message : String(error)
|
|
203
|
+
});
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
/** `ork ui --serve`: serves until stopped; exits when it closes. */
|
|
208
|
+
const serveForSupervisor = async () => {
|
|
209
|
+
if (process.send === void 0) {
|
|
210
|
+
writeErr(NOT_SUPERVISED);
|
|
211
|
+
process.exitCode = 1;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const stop = stopper();
|
|
215
|
+
const start = await Promise.race([started(), stop.promise.then(() => null)]);
|
|
216
|
+
const server = start === null ? null : await serve(start, stop.end);
|
|
217
|
+
if (server !== null) {
|
|
218
|
+
await send({
|
|
219
|
+
type: "ork-ui-ready",
|
|
220
|
+
port: server.port,
|
|
221
|
+
version: ORK_VERSION
|
|
222
|
+
});
|
|
223
|
+
await stop.promise;
|
|
224
|
+
await upgradeFinished(server, writeErr);
|
|
225
|
+
await server.close();
|
|
226
|
+
}
|
|
227
|
+
process.exit(server === null ? 1 : 0);
|
|
228
|
+
};
|
|
229
|
+
// src/browser/supervise.ts
|
|
230
|
+
/**
|
|
231
|
+
* @file `ork ui`'s process model (ADR-060): the command in the terminal only
|
|
232
|
+
* supervises; its server runs in a child, the launcher the user ran
|
|
233
|
+
* (`process.argv[1]` as given, so after an upgrade it is the new install's)
|
|
234
|
+
* with `ui --serve`. The port and the token go over the child's IPC channel.
|
|
235
|
+
* When the page asks for a restart, the child says so and exits, and the
|
|
236
|
+
* supervisor starts the launcher again on the same port with the same token,
|
|
237
|
+
* so the open tab stays signed in. There is only ever one child; Ctrl-C (or
|
|
238
|
+
* SIGTERM) stops it and then the supervisor, which exits with its code. The
|
|
239
|
+
* child may wait for an upgrade to finish first; a second Ctrl-C (or SIGTERM)
|
|
240
|
+
* kills it and exits at once.
|
|
241
|
+
*/
|
|
242
|
+
/**
|
|
243
|
+
* How long an exited child's channel may take to close before the supervisor
|
|
244
|
+
* decides without it; a child's channel closes with it, so this is only a
|
|
245
|
+
* backstop.
|
|
246
|
+
*/
|
|
247
|
+
const CHANNEL_CLOSE_MS = 2e3;
|
|
248
|
+
/** A shell's exit code for a process a signal stopped. */
|
|
249
|
+
const signalled = (signal) => 128 + constants.signals[signal];
|
|
250
|
+
/** Supervises the server until it stops; resolves the exit code. */
|
|
251
|
+
const supervise = (options) => new Promise((resolve) => {
|
|
252
|
+
const { token, say, sayErr } = options;
|
|
253
|
+
let port = options.port;
|
|
254
|
+
let stopping = false;
|
|
255
|
+
let ended = false;
|
|
256
|
+
let restarts = 0;
|
|
257
|
+
let current = null;
|
|
258
|
+
const end = (code) => {
|
|
259
|
+
if (ended) return;
|
|
260
|
+
ended = true;
|
|
261
|
+
resolve(code);
|
|
262
|
+
};
|
|
263
|
+
const start = () => {
|
|
264
|
+
let restarting = false;
|
|
265
|
+
let ready = false;
|
|
266
|
+
let exited = null;
|
|
267
|
+
let disconnected = false;
|
|
268
|
+
let backstop;
|
|
269
|
+
const child = options.spawnServer();
|
|
270
|
+
current = child;
|
|
271
|
+
const decide = () => {
|
|
272
|
+
clearTimeout(backstop);
|
|
273
|
+
if (exited === null || ended || current !== child) return;
|
|
274
|
+
const { code } = exited;
|
|
275
|
+
if (restarting && !stopping) {
|
|
276
|
+
restarts += 1;
|
|
277
|
+
say("Restarting Ork's UI from the installed `ork`…");
|
|
278
|
+
start();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (!ready && restarts > 0) sayErr(`Ork's UI did not start again (exit ${String(code)}). Start it with: ork ui --port ${String(port)}`);
|
|
282
|
+
else if (ready && code !== 0 && !stopping) sayErr(`Ork's UI stopped: its server exited with ${String(code)}.`);
|
|
283
|
+
if (ready) say("Ork's UI stopped.");
|
|
284
|
+
end(code ?? (stopping ? 0 : 1));
|
|
285
|
+
};
|
|
286
|
+
child.onMessage((raw) => {
|
|
287
|
+
const message = childMessage(raw);
|
|
288
|
+
if (message?.type === "ork-ui-hello") child.send({
|
|
289
|
+
type: "ork-ui-start",
|
|
290
|
+
port,
|
|
291
|
+
token
|
|
292
|
+
});
|
|
293
|
+
else if (message?.type === "ork-ui-ready") {
|
|
294
|
+
ready = true;
|
|
295
|
+
({port} = message);
|
|
296
|
+
options.onReady({
|
|
297
|
+
port,
|
|
298
|
+
version: message.version,
|
|
299
|
+
restarted: restarts > 0
|
|
300
|
+
});
|
|
301
|
+
} else if (message?.type === "ork-ui-failed") sayErr(message.error);
|
|
302
|
+
else if (message?.type === "ork-ui-restart") restarting = true;
|
|
303
|
+
});
|
|
304
|
+
child.onExit((code) => {
|
|
305
|
+
exited = { code };
|
|
306
|
+
if (disconnected) decide();
|
|
307
|
+
else backstop = setTimeout(decide, CHANNEL_CLOSE_MS);
|
|
308
|
+
});
|
|
309
|
+
child.onDisconnect(() => {
|
|
310
|
+
disconnected = true;
|
|
311
|
+
decide();
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
options.onStop((signal) => {
|
|
315
|
+
if (!stopping) {
|
|
316
|
+
stopping = true;
|
|
317
|
+
current?.kill(signal);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
current?.kill("SIGKILL");
|
|
321
|
+
say("Ork's UI stopped.");
|
|
322
|
+
end(signalled(signal));
|
|
323
|
+
});
|
|
324
|
+
start();
|
|
325
|
+
});
|
|
326
|
+
/**
|
|
327
|
+
* Starts `launcher ui --serve` with the same Node, on this terminal, with an
|
|
328
|
+
* IPC channel for the port and the token.
|
|
329
|
+
*/
|
|
330
|
+
const spawnServerFrom = (launcher) => () => {
|
|
331
|
+
const child = spawn(process.execPath, [
|
|
332
|
+
...process.execArgv,
|
|
333
|
+
launcher,
|
|
334
|
+
"ui",
|
|
335
|
+
"--serve"
|
|
336
|
+
], { stdio: [
|
|
337
|
+
"inherit",
|
|
338
|
+
"inherit",
|
|
339
|
+
"inherit",
|
|
340
|
+
"ipc"
|
|
341
|
+
] });
|
|
342
|
+
return {
|
|
343
|
+
send: (message) => {
|
|
344
|
+
if (child.connected) child.send(message);
|
|
345
|
+
},
|
|
346
|
+
kill: (signal) => {
|
|
347
|
+
child.kill(signal);
|
|
348
|
+
},
|
|
349
|
+
onMessage: (listener) => {
|
|
350
|
+
child.on("message", listener);
|
|
351
|
+
},
|
|
352
|
+
onExit: (listener) => {
|
|
353
|
+
let told = false;
|
|
354
|
+
const once = (code) => {
|
|
355
|
+
if (told) return;
|
|
356
|
+
told = true;
|
|
357
|
+
listener(code);
|
|
358
|
+
};
|
|
359
|
+
child.on("error", () => {
|
|
360
|
+
if (child.pid === void 0) once(1);
|
|
361
|
+
});
|
|
362
|
+
child.on("exit", once);
|
|
363
|
+
},
|
|
364
|
+
onDisconnect: (listener) => {
|
|
365
|
+
let told = false;
|
|
366
|
+
const once = () => {
|
|
367
|
+
if (told) return;
|
|
368
|
+
told = true;
|
|
369
|
+
listener();
|
|
370
|
+
};
|
|
371
|
+
child.on("error", () => {
|
|
372
|
+
if (child.pid === void 0) once();
|
|
373
|
+
});
|
|
374
|
+
child.on("disconnect", once);
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
/** Ctrl-C and SIGTERM, for {@link SuperviseOptions.onStop}. */
|
|
379
|
+
const onStopSignals = (stop) => {
|
|
380
|
+
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => {
|
|
381
|
+
stop(signal);
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
// src/commands/ui.ts
|
|
385
|
+
/**
|
|
386
|
+
* @file `ork ui`: starts the local server (ADR-039) on loopback and opens it in
|
|
387
|
+
* the browser, signed in with the server's token; or, when one is already
|
|
388
|
+
* running (`~/.ork/ui.json`), opens that one. The command supervises the
|
|
389
|
+
* server in a child process, so the page can restart it onto a newly
|
|
390
|
+
* installed `ork` (ADR-060). The server runs nothing: runs it starts keep
|
|
391
|
+
* running when it stops, and the CLI works without it.
|
|
392
|
+
*/
|
|
393
|
+
/** The link that signs the browser in; the server swaps it for a cookie. */
|
|
394
|
+
const signInLink = (port, token) => `http://127.0.0.1:${String(port)}/?token=${token}`;
|
|
395
|
+
/** `--port`: 0 to 65535 (0 picks a free port); `null` when invalid. */
|
|
396
|
+
const portArg = (value) => {
|
|
397
|
+
if (value === void 0) return DEFAULT_PORT;
|
|
398
|
+
const port = Number(value);
|
|
399
|
+
return Number.isInteger(port) && port >= 0 && port <= 65535 ? port : null;
|
|
400
|
+
};
|
|
401
|
+
/** Opens the link, or prints it when there is no browser to open. */
|
|
402
|
+
const show = async (link, open) => {
|
|
403
|
+
if (!mayShowSignIn()) {
|
|
404
|
+
writeErr("A program or an agent in a run does not get the sign-in link, which acts as you. Run `ork ui` in your own terminal.");
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (!(open && process.stdout.isTTY && await openInBrowser(link))) write(`Open it with this link, which signs you in: ${link}`);
|
|
408
|
+
};
|
|
409
|
+
/** What `ork ui` says once its server serves, the first time or again. */
|
|
410
|
+
const ready = async ({ port, version, restarted }, token, open) => {
|
|
411
|
+
const url = `http://127.0.0.1:${String(port)}`;
|
|
412
|
+
if (restarted) {
|
|
413
|
+
write(`Ork's UI restarted: Ork ${version} at ${url}`);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
write(`Ork's UI is at ${url}`);
|
|
417
|
+
write(style("dim", "Runs keep running when it stops, and every ork command works without it. Ctrl-C stops it."));
|
|
418
|
+
await show(signInLink(port, token), open);
|
|
419
|
+
};
|
|
420
|
+
const ui = defineCommand({
|
|
421
|
+
meta: {
|
|
422
|
+
name: "ui",
|
|
423
|
+
description: "Start Ork's local UI and open it, or open the running one"
|
|
424
|
+
},
|
|
425
|
+
args: {
|
|
426
|
+
port: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description: `The port to serve on (default ${String(DEFAULT_PORT)})`
|
|
429
|
+
},
|
|
430
|
+
open: {
|
|
431
|
+
type: "boolean",
|
|
432
|
+
description: "Open the browser (--no-open only prints the address)",
|
|
433
|
+
default: true
|
|
434
|
+
},
|
|
435
|
+
serve: {
|
|
436
|
+
type: "boolean",
|
|
437
|
+
description: "Only for `ork ui` itself: be the server it supervises",
|
|
438
|
+
default: false
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
run: async ({ args }) => {
|
|
442
|
+
const port = portArg(args.port);
|
|
443
|
+
if (port === null) {
|
|
444
|
+
writeErr(`--port must be a number from 0 to 65535, not \`${args.port ?? ""}\`.`);
|
|
445
|
+
process.exitCode = 1;
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
if (args.serve) {
|
|
449
|
+
await serveForSupervisor();
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const running = runningServer(uiFilePath());
|
|
453
|
+
if (running !== null) {
|
|
454
|
+
write(`Ork's UI is already running at http://127.0.0.1:${String(running.port)} (process ${String(running.pid)}).`);
|
|
455
|
+
await show(signInLink(running.port, running.token), args.open);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const token = newToken();
|
|
459
|
+
process.exitCode = await supervise({
|
|
460
|
+
port,
|
|
461
|
+
token,
|
|
462
|
+
spawnServer: spawnServerFrom(process.argv[1] ?? ""),
|
|
463
|
+
onReady: (answer) => ready(answer, token, args.open),
|
|
464
|
+
onStop: onStopSignals,
|
|
465
|
+
say: (line) => {
|
|
466
|
+
write(style("dim", line));
|
|
467
|
+
},
|
|
468
|
+
sayErr: writeErr
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
export { ui };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as write, c as openStore, i as style, n as cost, o as writeErr, t as confirm } from "./output-
|
|
3
|
-
import {
|
|
1
|
+
import { c as usd, fn as placeFor, lt as liveStatus, mn as runDirOf } from "./src-CGqMati3.mjs";
|
|
2
|
+
import { a as write, c as openStore, i as style, n as cost, o as writeErr, t as confirm } from "./output-CXSJO00X.mjs";
|
|
3
|
+
import { n as listOrkWorktrees, t as createdWorktrees } from "./list-ZvY2OcLq.mjs";
|
|
4
4
|
import { n as usageReport, t as USAGE_DIMENSIONS } from "./report-DK4LGqwF.mjs";
|
|
5
|
-
import
|
|
5
|
+
import "./format-J-a21Yvn.mjs";
|
|
6
|
+
import { n as limitsHere } from "./limits-BDZCmGEu.mjs";
|
|
6
7
|
import { defineCommand } from "citty";
|
|
7
8
|
import { existsSync, rmSync } from "node:fs";
|
|
8
9
|
// ../core/src/store/prune.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as newRunId } from "./find-
|
|
3
|
-
import { a as write, c as openStore, i as style, o as writeErr, r as plain, t as confirm } from "./output-
|
|
4
|
-
import { i as runLimits, r as limitsRefusal } from "./limits-
|
|
5
|
-
import { c as toolExecutor, o as spawnTool, s as mcpCallExecutor } from "./src-
|
|
6
|
-
import { t as acceptRefusal } from "./in-a-run-
|
|
1
|
+
import { C as watchingPid, Mn as CheckReportSchema, S as takeWatchLock, Un as timeoutMs, Vn as isToolNode, _ as createWatcher, b as readProjectTriggers, dn as placeFiles, g as triggersReport, ht as stillTheSameProcess, lt as liveStatus, rt as detachRun, v as triggerStanding, y as declaredTriggers } from "./src-CGqMati3.mjs";
|
|
2
|
+
import { n as newRunId } from "./find-DptmbhGd.mjs";
|
|
3
|
+
import { a as write, c as openStore, i as style, o as writeErr, r as plain, t as confirm } from "./output-CXSJO00X.mjs";
|
|
4
|
+
import { i as runLimits, r as limitsRefusal } from "./limits-BDZCmGEu.mjs";
|
|
5
|
+
import { c as toolExecutor, o as spawnTool, s as mcpCallExecutor } from "./src-UWkk1sl9.mjs";
|
|
6
|
+
import { t as acceptRefusal } from "./in-a-run-D1Qc5Mit.mjs";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { mkdirSync } from "node:fs";
|