@nwire/cli 0.7.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/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/__tests__/doctor.test.d.ts +10 -0
- package/dist/__tests__/doctor.test.d.ts.map +1 -0
- package/dist/__tests__/doctor.test.js +105 -0
- package/dist/__tests__/doctor.test.js.map +1 -0
- package/dist/cache-runner.d.ts +2 -0
- package/dist/cache-runner.d.ts.map +1 -0
- package/dist/cache-runner.js +58 -0
- package/dist/cache-runner.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +67 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/build.d.ts +13 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +74 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/cache.d.ts +6 -0
- package/dist/commands/cache.d.ts.map +1 -0
- package/dist/commands/cache.js +27 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/check.d.ts +6 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +21 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/dev.d.ts +11 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +165 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +59 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +399 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/fmt.d.ts +13 -0
- package/dist/commands/fmt.d.ts.map +1 -0
- package/dist/commands/fmt.js +33 -0
- package/dist/commands/fmt.js.map +1 -0
- package/dist/commands/greeting.d.ts +6 -0
- package/dist/commands/greeting.d.ts.map +1 -0
- package/dist/commands/greeting.js +25 -0
- package/dist/commands/greeting.js.map +1 -0
- package/dist/commands/infra.d.ts +14 -0
- package/dist/commands/infra.d.ts.map +1 -0
- package/dist/commands/infra.js +146 -0
- package/dist/commands/infra.js.map +1 -0
- package/dist/commands/lint.d.ts +12 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +32 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/logs.d.ts +21 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +73 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/ls.d.ts +5 -0
- package/dist/commands/ls.d.ts.map +1 -0
- package/dist/commands/ls.js +26 -0
- package/dist/commands/ls.js.map +1 -0
- package/dist/commands/please.d.ts +13 -0
- package/dist/commands/please.d.ts.map +1 -0
- package/dist/commands/please.js +46 -0
- package/dist/commands/please.js.map +1 -0
- package/dist/commands/ps.d.ts +6 -0
- package/dist/commands/ps.d.ts.map +1 -0
- package/dist/commands/ps.js +21 -0
- package/dist/commands/ps.js.map +1 -0
- package/dist/commands/run.d.ts +19 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +112 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/studio.d.ts +9 -0
- package/dist/commands/studio.d.ts.map +1 -0
- package/dist/commands/studio.js +46 -0
- package/dist/commands/studio.js.map +1 -0
- package/dist/commands/test.d.ts +26 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +143 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel-instance.d.ts +8 -0
- package/dist/kernel-instance.d.ts.map +1 -0
- package/dist/kernel-instance.js +13 -0
- package/dist/kernel-instance.js.map +1 -0
- package/dist/lib/colors.d.ts +19 -0
- package/dist/lib/colors.d.ts.map +1 -0
- package/dist/lib/colors.js +18 -0
- package/dist/lib/colors.js.map +1 -0
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.d.ts.map +1 -0
- package/dist/lib/exec.js +58 -0
- package/dist/lib/exec.js.map +1 -0
- package/dist/lib/process-state.d.ts +30 -0
- package/dist/lib/process-state.d.ts.map +1 -0
- package/dist/lib/process-state.js +68 -0
- package/dist/lib/process-state.js.map +1 -0
- package/dist/lib/project.d.ts +15 -0
- package/dist/lib/project.d.ts.map +1 -0
- package/dist/lib/project.js +52 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/run-task.d.ts +32 -0
- package/dist/lib/run-task.d.ts.map +1 -0
- package/dist/lib/run-task.js +70 -0
- package/dist/lib/run-task.js.map +1 -0
- package/dist/lib/vite-node.d.ts +10 -0
- package/dist/lib/vite-node.d.ts.map +1 -0
- package/dist/lib/vite-node.js +14 -0
- package/dist/lib/vite-node.js.map +1 -0
- package/dist/load-config.d.ts +27 -0
- package/dist/load-config.d.ts.map +1 -0
- package/dist/load-config.js +38 -0
- package/dist/load-config.js.map +1 -0
- package/dist/ls-runner.d.ts +2 -0
- package/dist/ls-runner.d.ts.map +1 -0
- package/dist/ls-runner.js +55 -0
- package/dist/ls-runner.js.map +1 -0
- package/dist/ui/dev-dashboard.d.ts +23 -0
- package/dist/ui/dev-dashboard.d.ts.map +1 -0
- package/dist/ui/dev-dashboard.js +53 -0
- package/dist/ui/dev-dashboard.js.map +1 -0
- package/dist/ui/greeting.d.ts +16 -0
- package/dist/ui/greeting.d.ts.map +1 -0
- package/dist/ui/greeting.js +16 -0
- package/dist/ui/greeting.js.map +1 -0
- package/dist/ui/process-table.d.ts +13 -0
- package/dist/ui/process-table.d.ts.map +1 -0
- package/dist/ui/process-table.js +26 -0
- package/dist/ui/process-table.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nwire dev` — boots the project's wire under vite-node --watch with
|
|
3
|
+
* stdio passthrough. Prints a branded banner before spawning so the
|
|
4
|
+
* user sees what's about to run + the project context; the child's
|
|
5
|
+
* stdout/stderr flow through unmodified afterwards.
|
|
6
|
+
*
|
|
7
|
+
* Also writes a state file under `.nwire/processes/` so `nwire ps`
|
|
8
|
+
* sees the dev session from any other shell.
|
|
9
|
+
*/
|
|
10
|
+
import { defineCommand } from "citty";
|
|
11
|
+
import { resolve } from "node:path";
|
|
12
|
+
import { appendFileSync, closeSync, existsSync, openSync } from "node:fs";
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
import { randomUUID } from "node:crypto";
|
|
15
|
+
import { palette } from "../lib/colors.js";
|
|
16
|
+
import { detectProject } from "../lib/project.js";
|
|
17
|
+
import { ensureDir as ensureProcDir, logPath as procLogPath, removeRecord, writeRecord, } from "../lib/process-state.js";
|
|
18
|
+
export const devCommand = defineCommand({
|
|
19
|
+
meta: {
|
|
20
|
+
name: "dev",
|
|
21
|
+
description: "Boot the dev-all topology with watch mode",
|
|
22
|
+
},
|
|
23
|
+
async run() {
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
// Resolve in order:
|
|
26
|
+
// 1. apps/dev-all/run.ts — explicit multi-wire dev topology
|
|
27
|
+
// 2. apps/<single-wire>/{run,main}.ts — the obvious single-wire case
|
|
28
|
+
const candidates = [resolve(cwd, "apps/dev-all/run.ts")];
|
|
29
|
+
const project = detectProject(cwd);
|
|
30
|
+
if (project.wires.length === 1) {
|
|
31
|
+
const only = project.wires[0];
|
|
32
|
+
candidates.push(resolve(cwd, "apps", only, "run.ts"), resolve(cwd, "apps", only, "main.ts"));
|
|
33
|
+
}
|
|
34
|
+
const entry = candidates.find((p) => existsSync(p));
|
|
35
|
+
if (!entry) {
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.error(palette.err("nwire dev:") +
|
|
38
|
+
` no dev entry found in ${cwd} (looked for ${candidates
|
|
39
|
+
.map((p) => p.replace(cwd + "/", ""))
|
|
40
|
+
.join(", ")})`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const subtitle = entry.includes("/dev-all/") ? "dev-all" : (project.wires[0] ?? "wire");
|
|
44
|
+
const entryRel = entry.replace(cwd + "/", "");
|
|
45
|
+
// ── Banner ──────────────────────────────────────────────────────
|
|
46
|
+
// Single block before stdio passthrough takes over. The child's
|
|
47
|
+
// boot logs (runApp's "ready" banner, ports, etc.) flow through
|
|
48
|
+
// immediately after.
|
|
49
|
+
// eslint-disable-next-line no-console
|
|
50
|
+
console.log([
|
|
51
|
+
"",
|
|
52
|
+
` ${palette.brand(palette.bold("Nwire dev"))} ${palette.dim(project.name)}`,
|
|
53
|
+
` ${palette.dim("entry ")} ${entryRel}`,
|
|
54
|
+
` ${palette.dim("wire ")} ${subtitle}`,
|
|
55
|
+
` ${palette.dim("mode ")} ${palette.accent("watch")}`,
|
|
56
|
+
` ${palette.dim("Ctrl+C ")} stop`,
|
|
57
|
+
"",
|
|
58
|
+
].join("\n"));
|
|
59
|
+
// ── Spawn child with stdio inherited ────────────────────────────
|
|
60
|
+
// Inherit means logs go straight to the user's terminal — no ink
|
|
61
|
+
// capture, no log buffering. The trade-off: `nwire logs <id>`
|
|
62
|
+
// can't tail the live stream (only what we tee to disk). For dev
|
|
63
|
+
// sessions that's fine — the user is watching the terminal.
|
|
64
|
+
const child = spawn("pnpm", ["exec", "vite-node", "--watch", entry], {
|
|
65
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
66
|
+
cwd,
|
|
67
|
+
});
|
|
68
|
+
// Tee child stdio through to BOTH the user's terminal AND the
|
|
69
|
+
// per-process log file so `nwire logs <id>` works from another
|
|
70
|
+
// shell. Direct passthrough to stdout to keep ordering intact.
|
|
71
|
+
const id = randomUUID();
|
|
72
|
+
const startedAt = new Date().toISOString();
|
|
73
|
+
ensureProcDir(cwd);
|
|
74
|
+
const logFile = procLogPath(cwd, id);
|
|
75
|
+
const logFd = openSync(logFile, "a");
|
|
76
|
+
let port;
|
|
77
|
+
let currentStatus = "starting";
|
|
78
|
+
const persistRecord = () => {
|
|
79
|
+
const record = {
|
|
80
|
+
id,
|
|
81
|
+
name: `dev:${subtitle}`,
|
|
82
|
+
pid: child.pid ?? -1,
|
|
83
|
+
status: currentStatus,
|
|
84
|
+
port,
|
|
85
|
+
startedAt,
|
|
86
|
+
cwd,
|
|
87
|
+
command: `vite-node --watch ${entryRel}`,
|
|
88
|
+
logPath: logFile,
|
|
89
|
+
lastUpdated: new Date().toISOString(),
|
|
90
|
+
};
|
|
91
|
+
writeRecord(cwd, record);
|
|
92
|
+
};
|
|
93
|
+
persistRecord();
|
|
94
|
+
const READY_RE = /listening on http[s]?:\/\/[^:]+:(\d+)|nwire app.*ready in|Local:\s+http/i;
|
|
95
|
+
const handleStream = (out) => (data) => {
|
|
96
|
+
const text = data.toString();
|
|
97
|
+
try {
|
|
98
|
+
appendFileSync(logFd, text);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// log file gone — keep streaming to user
|
|
102
|
+
}
|
|
103
|
+
out.write(text);
|
|
104
|
+
if (currentStatus !== "running" && READY_RE.test(text)) {
|
|
105
|
+
// Try to capture the port from "Local: http://...:<port>"
|
|
106
|
+
const match = /:(\d+)\b/.exec(text);
|
|
107
|
+
if (match)
|
|
108
|
+
port = Number(match[1]);
|
|
109
|
+
currentStatus = "running";
|
|
110
|
+
persistRecord();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
child.stdout?.on("data", handleStream(process.stdout));
|
|
114
|
+
child.stderr?.on("data", handleStream(process.stderr));
|
|
115
|
+
// ── Shutdown ────────────────────────────────────────────────────
|
|
116
|
+
let stopping = false;
|
|
117
|
+
const stop = (signal) => {
|
|
118
|
+
if (stopping)
|
|
119
|
+
return;
|
|
120
|
+
stopping = true;
|
|
121
|
+
currentStatus = "stopping";
|
|
122
|
+
persistRecord();
|
|
123
|
+
try {
|
|
124
|
+
child.kill(signal);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// gone
|
|
128
|
+
}
|
|
129
|
+
setTimeout(() => {
|
|
130
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
131
|
+
try {
|
|
132
|
+
child.kill("SIGKILL");
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// gone
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}, 4000).unref();
|
|
139
|
+
setTimeout(() => process.exit(0), 6000).unref();
|
|
140
|
+
};
|
|
141
|
+
process.on("SIGINT", () => stop("SIGINT"));
|
|
142
|
+
process.on("SIGTERM", () => stop("SIGTERM"));
|
|
143
|
+
const exitCode = await new Promise((resolveExit) => {
|
|
144
|
+
child.on("exit", (code, signal) => {
|
|
145
|
+
if (stopping || signal === "SIGINT" || signal === "SIGTERM") {
|
|
146
|
+
resolveExit(0);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
resolveExit(code ?? 0);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
try {
|
|
154
|
+
closeSync(logFd);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// already closed
|
|
158
|
+
}
|
|
159
|
+
removeRecord(cwd, id);
|
|
160
|
+
// eslint-disable-next-line no-console
|
|
161
|
+
console.log(palette.dim("\nDev stopped."));
|
|
162
|
+
process.exit(exitCode);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
//# sourceMappingURL=dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nwire doctor` — preflight diagnostic for a Nwire workspace.
|
|
3
|
+
*
|
|
4
|
+
* Runs a battery of named checks and prints a single colored table with
|
|
5
|
+
* pass / warn / fail per check plus a remediation hint. Exits 0 if no
|
|
6
|
+
* failures (warnings still allow boot), 1 otherwise.
|
|
7
|
+
*
|
|
8
|
+
* Born from the Phase F dev-loop bugs: lightship port collisions, missing
|
|
9
|
+
* `api.inspect(app)`, stale `.nwire/` cache, wrong probe paths. Each
|
|
10
|
+
* check here exists because Alex hit the bug live; the doctor exists so
|
|
11
|
+
* the next team member doesn't.
|
|
12
|
+
*
|
|
13
|
+
* Flags
|
|
14
|
+
* --json machine-readable output
|
|
15
|
+
* --check=<name> run only the matching check (substring match)
|
|
16
|
+
*
|
|
17
|
+
* Adding a new check: append a `Check` to the `CHECKS` array. The
|
|
18
|
+
* function returns `{ status, message, hint? }`; the table renderer
|
|
19
|
+
* does the rest.
|
|
20
|
+
*/
|
|
21
|
+
type Status = "pass" | "warn" | "fail" | "info";
|
|
22
|
+
interface CheckResult {
|
|
23
|
+
status: Status;
|
|
24
|
+
message: string;
|
|
25
|
+
hint?: string;
|
|
26
|
+
}
|
|
27
|
+
interface Check {
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
run: (ctx: DoctorCtx) => Promise<CheckResult> | CheckResult;
|
|
31
|
+
}
|
|
32
|
+
interface DoctorCtx {
|
|
33
|
+
cwd: string;
|
|
34
|
+
}
|
|
35
|
+
export declare const CHECKS: readonly Check[];
|
|
36
|
+
/**
|
|
37
|
+
* Run all (or filtered) checks. Pure: no console output, no process exit.
|
|
38
|
+
* The CLI command wraps this with rendering and exit-code handling.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runDoctor(opts: {
|
|
41
|
+
cwd: string;
|
|
42
|
+
filter?: string;
|
|
43
|
+
}): Promise<Array<{
|
|
44
|
+
check: Check;
|
|
45
|
+
result: CheckResult;
|
|
46
|
+
}>>;
|
|
47
|
+
export type { Check, CheckResult, Status };
|
|
48
|
+
export declare const doctorCommand: import("citty").CommandDef<{
|
|
49
|
+
json: {
|
|
50
|
+
type: "boolean";
|
|
51
|
+
description: string;
|
|
52
|
+
default: false;
|
|
53
|
+
};
|
|
54
|
+
check: {
|
|
55
|
+
type: "string";
|
|
56
|
+
description: string;
|
|
57
|
+
};
|
|
58
|
+
}>;
|
|
59
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAChD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC;CAC7D;AAED,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAuND,eAAO,MAAM,MAAM,EAAE,SAAS,KAAK,EAWlC,CAAC;AAsFF;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC,CAmBxD;AAED,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AAI3C,eAAO,MAAM,aAAa;;;;;;;;;;EAkCxB,CAAC"}
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nwire doctor` — preflight diagnostic for a Nwire workspace.
|
|
3
|
+
*
|
|
4
|
+
* Runs a battery of named checks and prints a single colored table with
|
|
5
|
+
* pass / warn / fail per check plus a remediation hint. Exits 0 if no
|
|
6
|
+
* failures (warnings still allow boot), 1 otherwise.
|
|
7
|
+
*
|
|
8
|
+
* Born from the Phase F dev-loop bugs: lightship port collisions, missing
|
|
9
|
+
* `api.inspect(app)`, stale `.nwire/` cache, wrong probe paths. Each
|
|
10
|
+
* check here exists because Alex hit the bug live; the doctor exists so
|
|
11
|
+
* the next team member doesn't.
|
|
12
|
+
*
|
|
13
|
+
* Flags
|
|
14
|
+
* --json machine-readable output
|
|
15
|
+
* --check=<name> run only the matching check (substring match)
|
|
16
|
+
*
|
|
17
|
+
* Adding a new check: append a `Check` to the `CHECKS` array. The
|
|
18
|
+
* function returns `{ status, message, hint? }`; the table renderer
|
|
19
|
+
* does the rest.
|
|
20
|
+
*/
|
|
21
|
+
import { defineCommand } from "citty";
|
|
22
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import { createServer } from "node:net";
|
|
25
|
+
import { palette } from "../lib/colors.js";
|
|
26
|
+
// ─── individual checks ──────────────────────────────────────────────
|
|
27
|
+
const nodeVersionCheck = {
|
|
28
|
+
name: "node-version",
|
|
29
|
+
description: "Node.js runtime is supported",
|
|
30
|
+
run: () => {
|
|
31
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
32
|
+
if (major >= 22)
|
|
33
|
+
return { status: "pass", message: `Node ${process.versions.node}` };
|
|
34
|
+
return {
|
|
35
|
+
status: "fail",
|
|
36
|
+
message: `Node ${process.versions.node} (need ≥22)`,
|
|
37
|
+
hint: "install Node 22 LTS or 24 — `nvm install 24`",
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
const pkgManagerCheck = {
|
|
42
|
+
name: "package-manager",
|
|
43
|
+
description: "pnpm is available",
|
|
44
|
+
run: async () => {
|
|
45
|
+
try {
|
|
46
|
+
const { spawnSync } = await import("node:child_process");
|
|
47
|
+
const r = spawnSync("pnpm", ["--version"], { encoding: "utf8" });
|
|
48
|
+
if (r.status === 0)
|
|
49
|
+
return { status: "pass", message: `pnpm ${r.stdout.trim()}` };
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
/* fall through */
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
status: "fail",
|
|
56
|
+
message: "pnpm not on PATH",
|
|
57
|
+
hint: "install with `npm i -g pnpm@10` — Nwire pins to pnpm in package.json",
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const workspaceCheck = {
|
|
62
|
+
name: "workspace",
|
|
63
|
+
description: "Working dir looks like a Nwire workspace",
|
|
64
|
+
run: (ctx) => {
|
|
65
|
+
const hasPkg = existsSync(join(ctx.cwd, "package.json"));
|
|
66
|
+
if (!hasPkg) {
|
|
67
|
+
return {
|
|
68
|
+
status: "fail",
|
|
69
|
+
message: "no package.json",
|
|
70
|
+
hint: "run from your project root, or `pnpm create nwire <name>` first",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const hasApps = existsSync(join(ctx.cwd, "apps"));
|
|
74
|
+
const hasConfig = existsSync(join(ctx.cwd, "nwire.config.ts"));
|
|
75
|
+
const hasSrc = existsSync(join(ctx.cwd, "src"));
|
|
76
|
+
if (!hasApps && !hasConfig && !hasSrc) {
|
|
77
|
+
return {
|
|
78
|
+
status: "warn",
|
|
79
|
+
message: "no apps/, src/, or nwire.config.ts",
|
|
80
|
+
hint: "if this is a L1/L2 starter that's fine; for L4 add apps/<name>/main.ts",
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return { status: "pass", message: `apps:${hasApps} src:${hasSrc} config:${hasConfig}` };
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const cacheCheck = {
|
|
87
|
+
name: "nwire-cache",
|
|
88
|
+
description: "`.nwire/` cache is present and fresh",
|
|
89
|
+
run: (ctx) => {
|
|
90
|
+
const manifest = join(ctx.cwd, ".nwire", "manifest.json");
|
|
91
|
+
if (!existsSync(manifest)) {
|
|
92
|
+
return {
|
|
93
|
+
status: "warn",
|
|
94
|
+
message: ".nwire/manifest.json missing",
|
|
95
|
+
hint: "`nwire cache` builds it; `nwire dev` builds it on boot",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const ageMs = Date.now() - statSync(manifest).mtimeMs;
|
|
99
|
+
const ageH = Math.round(ageMs / 36e5);
|
|
100
|
+
if (ageH > 24) {
|
|
101
|
+
return {
|
|
102
|
+
status: "warn",
|
|
103
|
+
message: `manifest is ${ageH}h old`,
|
|
104
|
+
hint: "run `nwire cache` to rebuild — Studio renders stale data otherwise",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return { status: "pass", message: `manifest fresh (${ageH}h old)` };
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
const probePortCheck = {
|
|
111
|
+
name: "probe-port",
|
|
112
|
+
description: "Default lightship port (9_400) is free",
|
|
113
|
+
run: async () => {
|
|
114
|
+
const free = await portIsFree(9_400);
|
|
115
|
+
if (free)
|
|
116
|
+
return { status: "pass", message: ":9400 is free" };
|
|
117
|
+
return {
|
|
118
|
+
status: "warn",
|
|
119
|
+
message: ":9400 is in use",
|
|
120
|
+
hint: "another endpoint is running OR a service squatted the port — override with `endpoint(name, { probes: { port: 9_500 } })`",
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
const studioPortCheck = {
|
|
125
|
+
name: "studio-port",
|
|
126
|
+
description: "Studio default port (7777) is free",
|
|
127
|
+
run: async () => {
|
|
128
|
+
const free = await portIsFree(7_777);
|
|
129
|
+
if (free)
|
|
130
|
+
return { status: "pass", message: ":7777 is free" };
|
|
131
|
+
return {
|
|
132
|
+
status: "warn",
|
|
133
|
+
message: ":7777 is in use",
|
|
134
|
+
hint: "Studio is probably already running — visit http://localhost:7777",
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
const composeCollisionCheck = {
|
|
139
|
+
name: "compose-port-collisions",
|
|
140
|
+
description: "docker-compose.yml doesn't shadow probe/Studio ports",
|
|
141
|
+
run: (ctx) => {
|
|
142
|
+
const path = join(ctx.cwd, "docker-compose.yml");
|
|
143
|
+
if (!existsSync(path))
|
|
144
|
+
return { status: "info", message: "no docker-compose.yml" };
|
|
145
|
+
const text = readFileSync(path, "utf8");
|
|
146
|
+
const reserved = [9_400, 7_777];
|
|
147
|
+
const hits = [];
|
|
148
|
+
for (const p of reserved) {
|
|
149
|
+
// crude regex — `"PORT:..."` or `PORT:PORT`. Matches the docker-compose YAML shape.
|
|
150
|
+
const re = new RegExp(`["\\s]${p}:`, "g");
|
|
151
|
+
if (re.test(text))
|
|
152
|
+
hits.push(p);
|
|
153
|
+
}
|
|
154
|
+
if (hits.length === 0)
|
|
155
|
+
return { status: "pass", message: "no collisions with 9400/7777" };
|
|
156
|
+
return {
|
|
157
|
+
status: "fail",
|
|
158
|
+
message: `compose binds ${hits.join(", ")} — collides with Nwire defaults`,
|
|
159
|
+
hint: `move the conflicting service OR override Nwire's defaults (9_400=probes, 7_777=Studio)`,
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
const inspectMountCheck = {
|
|
164
|
+
name: "inspect-mount",
|
|
165
|
+
description: "Every L4 example calls `api.inspect(app)`",
|
|
166
|
+
run: (ctx) => {
|
|
167
|
+
// Scan apps/*/main.ts (or apps/*/<name>/main.ts) for createApp + missing .inspect().
|
|
168
|
+
// Best-effort grep — produces warnings not failures, since not every app
|
|
169
|
+
// wants the introspection surface in production wires.
|
|
170
|
+
const appsDir = join(ctx.cwd, "apps");
|
|
171
|
+
if (!existsSync(appsDir))
|
|
172
|
+
return { status: "info", message: "no apps/ folder" };
|
|
173
|
+
const offenders = [];
|
|
174
|
+
for (const entry of walk(appsDir, 3)) {
|
|
175
|
+
if (!entry.endsWith("main.ts") && !entry.endsWith("main.js"))
|
|
176
|
+
continue;
|
|
177
|
+
const text = readFileSync(entry, "utf8");
|
|
178
|
+
const looksLikeL4 = /createApp|app\.start\(\)/.test(text);
|
|
179
|
+
const hasInspect = /\.inspect\(/.test(text);
|
|
180
|
+
if (looksLikeL4 && !hasInspect) {
|
|
181
|
+
offenders.push(entry.replace(ctx.cwd + "/", ""));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (offenders.length === 0)
|
|
185
|
+
return { status: "pass", message: "all L4 mains mount inspect" };
|
|
186
|
+
return {
|
|
187
|
+
status: "warn",
|
|
188
|
+
message: `${offenders.length} app${offenders.length === 1 ? "" : "s"} missing api.inspect(app)`,
|
|
189
|
+
hint: `Studio's Live/Trace pages will 404 against:\n - ${offenders.join("\n - ")}`,
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
const tsconfigCheck = {
|
|
194
|
+
name: "tsconfig",
|
|
195
|
+
description: "tsconfig uses Bundler module resolution",
|
|
196
|
+
run: (ctx) => {
|
|
197
|
+
const path = join(ctx.cwd, "tsconfig.json");
|
|
198
|
+
if (!existsSync(path))
|
|
199
|
+
return { status: "info", message: "no tsconfig.json" };
|
|
200
|
+
const text = readFileSync(path, "utf8");
|
|
201
|
+
if (/Bundler/i.test(text))
|
|
202
|
+
return { status: "pass", message: 'moduleResolution: "Bundler"' };
|
|
203
|
+
if (/NodeNext|node16/i.test(text)) {
|
|
204
|
+
return {
|
|
205
|
+
status: "warn",
|
|
206
|
+
message: "moduleResolution is NodeNext/node16",
|
|
207
|
+
hint: "Nwire source uses Bundler resolution (no .js in imports). Use Bundler in apps and ship a postbuild .js patcher (see scripts/fix-dist-extensions.mjs).",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return { status: "info", message: "moduleResolution not set explicitly (defaults apply)" };
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
const envFileCheck = {
|
|
214
|
+
name: "env-files",
|
|
215
|
+
description: "No .env files contain obvious secrets in plain text",
|
|
216
|
+
run: (ctx) => {
|
|
217
|
+
const candidates = [".env", ".env.local", ".env.production"];
|
|
218
|
+
const offenders = [];
|
|
219
|
+
for (const f of candidates) {
|
|
220
|
+
const p = join(ctx.cwd, f);
|
|
221
|
+
if (!existsSync(p))
|
|
222
|
+
continue;
|
|
223
|
+
const text = readFileSync(p, "utf8");
|
|
224
|
+
// Crude — any non-empty value that looks like a real key (length>20, alphanumeric)
|
|
225
|
+
// for *_SECRET, *_KEY, *_PASSWORD, *_TOKEN names.
|
|
226
|
+
const lines = text.split("\n");
|
|
227
|
+
for (const line of lines) {
|
|
228
|
+
const m = /^([A-Z_]+(SECRET|KEY|PASSWORD|TOKEN))=(.+)$/.exec(line);
|
|
229
|
+
if (m && m[3] && m[3].length > 20 && !/^(dev|test|changeme)/.test(m[3])) {
|
|
230
|
+
offenders.push(`${f} contains ${m[1]}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (offenders.length === 0)
|
|
235
|
+
return { status: "pass", message: "no plaintext secrets detected" };
|
|
236
|
+
return {
|
|
237
|
+
status: "warn",
|
|
238
|
+
message: `possible secrets in ${offenders.length} location${offenders.length === 1 ? "" : "s"}`,
|
|
239
|
+
hint: `${offenders.join(", ")} — consider doppler/1password/sealed-secrets in production`,
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
export const CHECKS = [
|
|
244
|
+
nodeVersionCheck,
|
|
245
|
+
pkgManagerCheck,
|
|
246
|
+
workspaceCheck,
|
|
247
|
+
cacheCheck,
|
|
248
|
+
probePortCheck,
|
|
249
|
+
studioPortCheck,
|
|
250
|
+
composeCollisionCheck,
|
|
251
|
+
inspectMountCheck,
|
|
252
|
+
tsconfigCheck,
|
|
253
|
+
envFileCheck,
|
|
254
|
+
];
|
|
255
|
+
// ─── helpers ────────────────────────────────────────────────────────
|
|
256
|
+
/** Walk a directory tree up to `depth` deep, yielding absolute file paths. */
|
|
257
|
+
function* walk(dir, depth) {
|
|
258
|
+
if (depth < 0)
|
|
259
|
+
return;
|
|
260
|
+
let entries;
|
|
261
|
+
try {
|
|
262
|
+
entries = readdirSync(dir);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
for (const name of entries) {
|
|
268
|
+
if (name === "node_modules" || name.startsWith("."))
|
|
269
|
+
continue;
|
|
270
|
+
const full = join(dir, name);
|
|
271
|
+
let st;
|
|
272
|
+
try {
|
|
273
|
+
st = statSync(full);
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (st.isDirectory())
|
|
279
|
+
yield* walk(full, depth - 1);
|
|
280
|
+
else
|
|
281
|
+
yield full;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/** Non-destructive port probe — try to bind ephemerally, close immediately. */
|
|
285
|
+
function portIsFree(port) {
|
|
286
|
+
return new Promise((res) => {
|
|
287
|
+
const srv = createServer();
|
|
288
|
+
srv.once("error", () => res(false));
|
|
289
|
+
srv.once("listening", () => {
|
|
290
|
+
srv.close(() => res(true));
|
|
291
|
+
});
|
|
292
|
+
srv.listen(port, "127.0.0.1");
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// ─── output formatters ──────────────────────────────────────────────
|
|
296
|
+
const STATUS_ICON = {
|
|
297
|
+
pass: "✓",
|
|
298
|
+
warn: "⚠",
|
|
299
|
+
fail: "✗",
|
|
300
|
+
info: "·",
|
|
301
|
+
};
|
|
302
|
+
const STATUS_COLOR = {
|
|
303
|
+
pass: palette.ok,
|
|
304
|
+
warn: palette.warn,
|
|
305
|
+
fail: palette.err,
|
|
306
|
+
info: palette.dim,
|
|
307
|
+
};
|
|
308
|
+
function renderHuman(results) {
|
|
309
|
+
const nameW = Math.max(...results.map((r) => r.check.name.length));
|
|
310
|
+
for (const { check, result } of results) {
|
|
311
|
+
const icon = STATUS_COLOR[result.status](STATUS_ICON[result.status]);
|
|
312
|
+
const name = check.name.padEnd(nameW);
|
|
313
|
+
console.log(` ${icon} ${palette.bold(name)} ${result.message}`);
|
|
314
|
+
if (result.hint) {
|
|
315
|
+
// wrap multi-line hints (from inspect-mount listing files)
|
|
316
|
+
for (const line of result.hint.split("\n")) {
|
|
317
|
+
console.log(palette.hint(` ${line}`));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const pass = results.filter((r) => r.result.status === "pass").length;
|
|
322
|
+
const warn = results.filter((r) => r.result.status === "warn").length;
|
|
323
|
+
const fail = results.filter((r) => r.result.status === "fail").length;
|
|
324
|
+
const info = results.filter((r) => r.result.status === "info").length;
|
|
325
|
+
console.log("");
|
|
326
|
+
console.log(` ${palette.ok(`${pass} pass`)} ${palette.warn(`${warn} warn`)} ${palette.err(`${fail} fail`)} ${palette.dim(`${info} info`)}`);
|
|
327
|
+
}
|
|
328
|
+
function renderJson(results) {
|
|
329
|
+
const out = results.map(({ check, result }) => ({
|
|
330
|
+
name: check.name,
|
|
331
|
+
description: check.description,
|
|
332
|
+
...result,
|
|
333
|
+
}));
|
|
334
|
+
console.log(JSON.stringify(out, null, 2));
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Run all (or filtered) checks. Pure: no console output, no process exit.
|
|
338
|
+
* The CLI command wraps this with rendering and exit-code handling.
|
|
339
|
+
*/
|
|
340
|
+
export async function runDoctor(opts) {
|
|
341
|
+
const filter = (opts.filter ?? "").toLowerCase();
|
|
342
|
+
const selected = filter ? CHECKS.filter((c) => c.name.toLowerCase().includes(filter)) : CHECKS;
|
|
343
|
+
const results = [];
|
|
344
|
+
for (const check of selected) {
|
|
345
|
+
try {
|
|
346
|
+
const result = await check.run({ cwd: opts.cwd });
|
|
347
|
+
results.push({ check, result });
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
results.push({
|
|
351
|
+
check,
|
|
352
|
+
result: {
|
|
353
|
+
status: "fail",
|
|
354
|
+
message: `check threw: ${err.message}`,
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return results;
|
|
360
|
+
}
|
|
361
|
+
// ─── command ───────────────────────────────────────────────────────
|
|
362
|
+
export const doctorCommand = defineCommand({
|
|
363
|
+
meta: {
|
|
364
|
+
name: "doctor",
|
|
365
|
+
description: "Preflight diagnostic for the current workspace",
|
|
366
|
+
},
|
|
367
|
+
args: {
|
|
368
|
+
json: {
|
|
369
|
+
type: "boolean",
|
|
370
|
+
description: "Emit JSON instead of human-readable output",
|
|
371
|
+
default: false,
|
|
372
|
+
},
|
|
373
|
+
check: {
|
|
374
|
+
type: "string",
|
|
375
|
+
description: "Substring filter — run only checks whose name matches",
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
async run({ args }) {
|
|
379
|
+
const cwd = process.cwd();
|
|
380
|
+
const filter = typeof args.check === "string" ? args.check : undefined;
|
|
381
|
+
if (!args.json) {
|
|
382
|
+
console.log("");
|
|
383
|
+
console.log(` ${palette.brand("nwire doctor")} ${palette.dim(cwd)}`);
|
|
384
|
+
console.log("");
|
|
385
|
+
}
|
|
386
|
+
const results = await runDoctor({ cwd, filter });
|
|
387
|
+
if (results.length === 0) {
|
|
388
|
+
console.error(palette.err(`nwire doctor: no checks match "${filter}"`));
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
if (args.json)
|
|
392
|
+
renderJson(results);
|
|
393
|
+
else
|
|
394
|
+
renderHuman(results);
|
|
395
|
+
const hasFail = results.some((r) => r.result.status === "fail");
|
|
396
|
+
process.exit(hasFail ? 1 : 0);
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|