@repo-os/repoos 0.5.58 → 0.5.59
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.json +2 -2
- package/dist/.build-stamp.json +1 -1
- package/dist/cli/index.js +1 -16
- package/dist/commands/serve-banner.test.d.ts +1 -0
- package/dist/commands/serve-banner.test.js +26 -0
- package/dist/commands/serve.d.ts +12 -0
- package/dist/commands/serve.js +58 -26
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.js +16 -0
- package/package.json +1 -1
package/dist/.build-info.json
CHANGED
package/dist/.build-stamp.json
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -23,9 +23,7 @@ import { checkBuild } from "../core/build.js";
|
|
|
23
23
|
import { loadConfig } from "../core/config.js";
|
|
24
24
|
import { reexecAfterStaleBuild, reexecUnderBunIfRequested } from "../core/runtime.js";
|
|
25
25
|
import { c } from "./colors.js";
|
|
26
|
-
import {
|
|
27
|
-
import { dirname, join } from "node:path";
|
|
28
|
-
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { readVersion } from "../core/version.js";
|
|
29
27
|
// node:sqlite (used by db.ts/auth-store.ts) is still marked experimental on
|
|
30
28
|
// supported Node versions and prints a warning the first time it's loaded.
|
|
31
29
|
// That's expected/stable usage here, not something a user needs to see —
|
|
@@ -40,19 +38,6 @@ process.on("warning", (warning) => {
|
|
|
40
38
|
return;
|
|
41
39
|
console.warn(warning);
|
|
42
40
|
});
|
|
43
|
-
/** Reads the version stamped into .build-info.json at build time; falls back for dev/source runs. */
|
|
44
|
-
function readVersion() {
|
|
45
|
-
try {
|
|
46
|
-
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
47
|
-
const info = JSON.parse(readFileSync(join(root, ".build-info.json"), "utf8"));
|
|
48
|
-
if (info.version)
|
|
49
|
-
return info.version;
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
/* fall through */
|
|
53
|
-
}
|
|
54
|
-
return "0.0.0-dev";
|
|
55
|
-
}
|
|
56
41
|
const VERSION = readVersion();
|
|
57
42
|
// Column where COMMANDS descriptions start, measured from the start of the
|
|
58
43
|
// command text (not counting the leading 4-space indent). Wide enough for
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { renderServeBanner } from "./serve.js";
|
|
3
|
+
describe("renderServeBanner", () => {
|
|
4
|
+
const rows = [
|
|
5
|
+
{ label: "Local", value: "http://127.0.0.1:7515" },
|
|
6
|
+
{ label: "Tailnet HTTPS", value: "x" },
|
|
7
|
+
];
|
|
8
|
+
it("shows the version and aligns labels", () => {
|
|
9
|
+
const out = renderServeBanner("1.2.3", rows);
|
|
10
|
+
expect(out).toContain("RepoOS v1.2.3");
|
|
11
|
+
expect(out).toContain("Local http://127.0.0.1:7515");
|
|
12
|
+
});
|
|
13
|
+
it("splits an HTTPS warning into problem, fix and link", () => {
|
|
14
|
+
const out = renderServeBanner("1.2.3", rows, "HTTPS certificates aren't enabled for your tailnet — turn on MagicDNS and HTTPS Certificates at https://login.tailscale.com/admin/dns");
|
|
15
|
+
expect(out).toContain("Tailscale HTTPS unavailable");
|
|
16
|
+
expect(out).toContain("HTTPS certificates aren't enabled for your tailnet");
|
|
17
|
+
expect(out).toContain("Fix: turn on MagicDNS and HTTPS Certificates at");
|
|
18
|
+
expect(out).toContain("https://login.tailscale.com/admin/dns");
|
|
19
|
+
expect(out).toContain("--no-tailscale-https");
|
|
20
|
+
});
|
|
21
|
+
it("handles a reason without a fix link", () => {
|
|
22
|
+
const out = renderServeBanner("1", rows, "all ports in use");
|
|
23
|
+
expect(out).toContain("all ports in use");
|
|
24
|
+
expect(out).not.toContain("Fix:");
|
|
25
|
+
});
|
|
26
|
+
});
|
package/dist/commands/serve.d.ts
CHANGED
|
@@ -59,6 +59,18 @@ export declare function resolvePreviewOverrides(args: readonly string[], env?: N
|
|
|
59
59
|
* processes keep working. Exported for the defense-in-depth tests (#0096).
|
|
60
60
|
*/
|
|
61
61
|
export declare function directServeBlockedByAgent(env?: NodeJS.ProcessEnv): boolean;
|
|
62
|
+
export interface BannerRow {
|
|
63
|
+
label: string;
|
|
64
|
+
/** May contain ANSI codes. */
|
|
65
|
+
value: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The startup banner: a title line with the running version, an aligned
|
|
69
|
+
* label/value table, and — when Tailscale HTTPS could not be set up — a
|
|
70
|
+
* highlighted warning block that separates the problem from its fix. Pure
|
|
71
|
+
* (returns a string) so tests can assert on it with colors off.
|
|
72
|
+
*/
|
|
73
|
+
export declare function renderServeBanner(version: string, rows: readonly BannerRow[], httpsWarning?: string): string;
|
|
62
74
|
export declare function cmdServe(args: string[], opts?: {
|
|
63
75
|
onShutdown?: () => void;
|
|
64
76
|
onReady?: (url: string) => void;
|
package/dist/commands/serve.js
CHANGED
|
@@ -8,6 +8,7 @@ import { PREVIEW_REQUEST_SIGNAL } from "../server/agents.js";
|
|
|
8
8
|
import { isBun } from "../core/runtime.js";
|
|
9
9
|
import { findRepoRoot } from "../core/config.js";
|
|
10
10
|
import { c, statusColor } from "../cli/colors.js";
|
|
11
|
+
import { readVersion } from "../core/version.js";
|
|
11
12
|
import { detectTailscaleIPv4, ensureTailscaleHttps } from "../core/tailscale.js";
|
|
12
13
|
/**
|
|
13
14
|
* The OS-visible process title for a `repoos serve` instance:
|
|
@@ -109,6 +110,39 @@ export function resolvePreviewOverrides(args, env = process.env) {
|
|
|
109
110
|
export function directServeBlockedByAgent(env = process.env) {
|
|
110
111
|
return env.REPOOS_AGENT === "1" && env.REPOOS_PREVIEW_CHILD !== "1" && env.REPOOS_RELOAD !== "1";
|
|
111
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* The startup banner: a title line with the running version, an aligned
|
|
115
|
+
* label/value table, and — when Tailscale HTTPS could not be set up — a
|
|
116
|
+
* highlighted warning block that separates the problem from its fix. Pure
|
|
117
|
+
* (returns a string) so tests can assert on it with colors off.
|
|
118
|
+
*/
|
|
119
|
+
export function renderServeBanner(version, rows, httpsWarning) {
|
|
120
|
+
const width = Math.max(...rows.map((r) => r.label.length));
|
|
121
|
+
const out = [
|
|
122
|
+
"",
|
|
123
|
+
` ${c.bold(c.cyan("◆ RepoOS"))} ${c.dim("v" + version)} ${c.green("● running")}`,
|
|
124
|
+
"",
|
|
125
|
+
];
|
|
126
|
+
for (const r of rows)
|
|
127
|
+
out.push(` ${c.dim(r.label.padEnd(width))} ${r.value}`);
|
|
128
|
+
if (httpsWarning) {
|
|
129
|
+
// Reasons read "<problem> — <fix> <url>": put the problem, the fix and the
|
|
130
|
+
// link on their own lines so the actionable part isn't buried.
|
|
131
|
+
const [problem, ...rest] = httpsWarning.split(" — ");
|
|
132
|
+
const fixText = rest.join(" — ");
|
|
133
|
+
const url = /https?:\/\/\S+/.exec(fixText)?.[0];
|
|
134
|
+
const fix = (url ? fixText.replace(url, "") : fixText).replace(/\s*\bat\s*$/, "").trim();
|
|
135
|
+
out.push("", ` ${c.yellow("▲")} ${c.bold(c.yellow("Tailscale HTTPS unavailable"))}`);
|
|
136
|
+
out.push(` ${c.dim(problem ?? "")}`);
|
|
137
|
+
if (fix)
|
|
138
|
+
out.push(` ${c.bold("Fix:")} ${fix}${url ? c.dim(" at") : ""}`);
|
|
139
|
+
if (url)
|
|
140
|
+
out.push(` ${c.cyan(url)}`);
|
|
141
|
+
out.push(` ${c.dim("or pass")} ${c.cyan("--no-tailscale-https")} ${c.dim("to silence this")}`);
|
|
142
|
+
}
|
|
143
|
+
out.push("", c.dim(" press ^C to stop"), "");
|
|
144
|
+
return out.join("\n");
|
|
145
|
+
}
|
|
112
146
|
export async function cmdServe(args, opts = {}) {
|
|
113
147
|
// Defense in depth (#0096): a managed agent process must never start its own
|
|
114
148
|
// `repoos serve`. An agent that ignores the mission and runs `repoos serve`
|
|
@@ -174,48 +208,46 @@ export async function cmdServe(args, opts = {}) {
|
|
|
174
208
|
return;
|
|
175
209
|
}
|
|
176
210
|
const snap = handle.index.snapshot();
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
c.cyan(handle.url + "/api/events"))
|
|
211
|
+
const rt = isBun()
|
|
212
|
+
? `Bun ${process.versions.bun ?? ""}`.trim()
|
|
213
|
+
: `Node ${process.versions.node}`;
|
|
214
|
+
const rows = [
|
|
215
|
+
{ label: "Local", value: c.cyan(c.bold(handle.url)) },
|
|
216
|
+
{ label: "Events", value: c.cyan(handle.url + "/api/events") + c.dim(" (SSE)") },
|
|
217
|
+
{ label: "Watching", value: `${snap.taskCount} tasks` },
|
|
218
|
+
{ label: "Runtime", value: rt },
|
|
219
|
+
];
|
|
183
220
|
// Report an active preview-only overlay and its effective keys (#0464), so a
|
|
184
221
|
// preview that deliberately differs from the base config is never silent.
|
|
185
222
|
if (handle.previewOverrides?.length) {
|
|
186
|
-
|
|
223
|
+
rows.push({ label: "Preview", value: c.yellow(handle.previewOverrides.join(", ")) });
|
|
187
224
|
}
|
|
188
|
-
const rt = isBun()
|
|
189
|
-
? `Bun ${process.versions.bun ?? ""}`.trim()
|
|
190
|
-
: `Node ${process.versions.node}`;
|
|
191
|
-
console.log(c.dim(" runtime ") + rt);
|
|
192
|
-
console.log(c.dim(" api: ") + c.dim("/api/tasks /api/tasks/:id /api/counts /api/index /api/docs"));
|
|
193
225
|
if (tailscaleDetected) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
c.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
226
|
+
rows.push({
|
|
227
|
+
label: "Tailnet",
|
|
228
|
+
value: c.cyan(`http://${tailscaleIP}:${handle.port}`) +
|
|
229
|
+
c.dim(" (all interfaces; ") +
|
|
230
|
+
c.cyan("--host 127.0.0.1") +
|
|
231
|
+
c.dim(" to restrict)"),
|
|
232
|
+
});
|
|
201
233
|
}
|
|
202
234
|
// HTTPS for tailnet devices (a plain-http IP isn't a secure context, so
|
|
203
235
|
// crypto.randomUUID etc. are missing). Skipped for managed previews, which
|
|
204
236
|
// must not touch the machine's `tailscale serve` config.
|
|
237
|
+
let httpsWarning;
|
|
205
238
|
if (tailscaleDetected && tailscaleHttps && process.env.REPOOS_PREVIEW_CHILD !== "1") {
|
|
206
239
|
const https = await ensureTailscaleHttps(handle.port);
|
|
207
240
|
if (https.url) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
c.
|
|
211
|
-
|
|
212
|
-
c.dim(" to skip)."));
|
|
241
|
+
rows.push({
|
|
242
|
+
label: "Tailnet HTTPS",
|
|
243
|
+
value: c.green(c.bold(https.url)) + c.dim(" (secure context)"),
|
|
244
|
+
});
|
|
213
245
|
}
|
|
214
246
|
else if (https.reason) {
|
|
215
|
-
|
|
247
|
+
httpsWarning = https.reason;
|
|
216
248
|
}
|
|
217
249
|
}
|
|
218
|
-
console.log(
|
|
250
|
+
console.log(renderServeBanner(readVersion(), rows, httpsWarning));
|
|
219
251
|
// Fires only now that the server is actually listening (handle.url is a
|
|
220
252
|
// live, bound address) — a caller opening a browser tab any earlier races
|
|
221
253
|
// the server's own startup and shows connection errors until a manual
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/** Reads the version stamped into .build-info.json at build time; falls back for dev/source runs. */
|
|
5
|
+
export function readVersion() {
|
|
6
|
+
try {
|
|
7
|
+
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
8
|
+
const info = JSON.parse(readFileSync(join(root, ".build-info.json"), "utf8"));
|
|
9
|
+
if (info.version)
|
|
10
|
+
return info.version;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
/* fall through */
|
|
14
|
+
}
|
|
15
|
+
return "0.0.0-dev";
|
|
16
|
+
}
|
package/package.json
CHANGED