@infinitedusky/indusk-mcp 1.25.1 → 1.26.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/bin/cli.js +9 -0
- package/dist/bin/commands/ui.d.ts +22 -0
- package/dist/bin/commands/ui.js +118 -0
- package/package.json +10 -2
package/dist/bin/cli.js
CHANGED
|
@@ -344,4 +344,13 @@ program
|
|
|
344
344
|
const { startServer } = await import("../server/index.js");
|
|
345
345
|
await startServer();
|
|
346
346
|
});
|
|
347
|
+
program
|
|
348
|
+
.command("ui")
|
|
349
|
+
.description("Open the InDusk admin UI (sidebar of plans, trajectory states, scorecards)")
|
|
350
|
+
.option("--port <port>", "Port to listen on (0 = pick free)", "3939")
|
|
351
|
+
.option("--no-open", "Don't auto-open the browser when the server is ready")
|
|
352
|
+
.action(async (opts) => {
|
|
353
|
+
const { ui } = await import("./commands/ui.js");
|
|
354
|
+
await ui(rootOrExit(), { port: opts.port, open: opts.open });
|
|
355
|
+
});
|
|
347
356
|
program.parse();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface UiOptions {
|
|
2
|
+
port: string;
|
|
3
|
+
open: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Spawn the indusk-admin Next.js dev server in the user's project root.
|
|
7
|
+
*
|
|
8
|
+
* - Runs `pnpm exec next dev` from `apps/indusk-admin/` so admin-ui's deps
|
|
9
|
+
* resolve correctly via the workspace.
|
|
10
|
+
* - Sets `INDUSK_PROJECT_ROOT` to the project root so the admin app's
|
|
11
|
+
* server components read the right `.indusk/planning/` regardless of
|
|
12
|
+
* `process.cwd()` inside the spawned process. (For now, admin-ui reads
|
|
13
|
+
* from `process.cwd()` directly — child process inherits cwd from the
|
|
14
|
+
* indusk CLI's invocation.)
|
|
15
|
+
* - Auto-bumps the port if the requested one is taken.
|
|
16
|
+
* - Optionally opens the browser when stdout reports "ready".
|
|
17
|
+
*
|
|
18
|
+
* v1 ships the source tree (admin-ui as a workspace app, dev mode). v2 may
|
|
19
|
+
* switch to a built static export if startup latency or package size become
|
|
20
|
+
* pain points.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ui(projectRoot: string, opts: UiOptions): Promise<void>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { createServer } from "node:net";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
/**
|
|
7
|
+
* Spawn the indusk-admin Next.js dev server in the user's project root.
|
|
8
|
+
*
|
|
9
|
+
* - Runs `pnpm exec next dev` from `apps/indusk-admin/` so admin-ui's deps
|
|
10
|
+
* resolve correctly via the workspace.
|
|
11
|
+
* - Sets `INDUSK_PROJECT_ROOT` to the project root so the admin app's
|
|
12
|
+
* server components read the right `.indusk/planning/` regardless of
|
|
13
|
+
* `process.cwd()` inside the spawned process. (For now, admin-ui reads
|
|
14
|
+
* from `process.cwd()` directly — child process inherits cwd from the
|
|
15
|
+
* indusk CLI's invocation.)
|
|
16
|
+
* - Auto-bumps the port if the requested one is taken.
|
|
17
|
+
* - Optionally opens the browser when stdout reports "ready".
|
|
18
|
+
*
|
|
19
|
+
* v1 ships the source tree (admin-ui as a workspace app, dev mode). v2 may
|
|
20
|
+
* switch to a built static export if startup latency or package size become
|
|
21
|
+
* pain points.
|
|
22
|
+
*/
|
|
23
|
+
export async function ui(projectRoot, opts) {
|
|
24
|
+
const requestedPort = Number.parseInt(opts.port, 10);
|
|
25
|
+
if (!Number.isFinite(requestedPort) || requestedPort < 0 || requestedPort > 65535) {
|
|
26
|
+
console.error(`Invalid --port value: ${opts.port}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const adminDir = resolveAdminDir();
|
|
30
|
+
if (!existsSync(adminDir)) {
|
|
31
|
+
console.error(`indusk-admin app not found at ${adminDir}. ` +
|
|
32
|
+
"If running from a published package, ensure indusk-admin is bundled.");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const port = requestedPort === 0 ? await findFreePort() : await ensureFreePort(requestedPort);
|
|
36
|
+
if (port !== requestedPort && requestedPort !== 0) {
|
|
37
|
+
console.warn(`Port ${requestedPort} is in use; using ${port} instead.`);
|
|
38
|
+
}
|
|
39
|
+
console.info(`Starting indusk-admin on http://localhost:${port}/`);
|
|
40
|
+
console.info(`Project root: ${projectRoot}`);
|
|
41
|
+
const child = spawn("pnpm", ["exec", "next", "dev", "--port", String(port)], {
|
|
42
|
+
cwd: adminDir,
|
|
43
|
+
env: {
|
|
44
|
+
...process.env,
|
|
45
|
+
INDUSK_PROJECT_ROOT: projectRoot,
|
|
46
|
+
},
|
|
47
|
+
stdio: ["inherit", "pipe", "inherit"],
|
|
48
|
+
});
|
|
49
|
+
let opened = false;
|
|
50
|
+
child.stdout.on("data", (chunk) => {
|
|
51
|
+
const text = chunk.toString();
|
|
52
|
+
process.stdout.write(text);
|
|
53
|
+
if (!opened && opts.open && /\bReady\b|\bready in\b|started server/i.test(text)) {
|
|
54
|
+
opened = true;
|
|
55
|
+
openBrowser(`http://localhost:${port}/`);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
child.on("close", (code) => {
|
|
59
|
+
process.exit(code ?? 0);
|
|
60
|
+
});
|
|
61
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
62
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the admin app directory. In the source repo, that's the sibling
|
|
66
|
+
* `apps/indusk-admin/`. When indusk-mcp is npm-installed, this needs to
|
|
67
|
+
* resolve to the bundled path (decided in Phase 6 — for now only the source
|
|
68
|
+
* layout is supported).
|
|
69
|
+
*/
|
|
70
|
+
function resolveAdminDir() {
|
|
71
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
72
|
+
// here = apps/indusk-mcp/dist/bin/commands/ (or .../src/bin/commands/ in dev)
|
|
73
|
+
// Walk up to apps/, then into indusk-admin
|
|
74
|
+
const candidates = [
|
|
75
|
+
resolve(here, "../../../../indusk-admin"),
|
|
76
|
+
resolve(here, "../../../indusk-admin"),
|
|
77
|
+
];
|
|
78
|
+
for (const c of candidates) {
|
|
79
|
+
if (existsSync(join(c, "package.json")))
|
|
80
|
+
return c;
|
|
81
|
+
}
|
|
82
|
+
return candidates[0];
|
|
83
|
+
}
|
|
84
|
+
async function ensureFreePort(port) {
|
|
85
|
+
if (await isPortFree(port))
|
|
86
|
+
return port;
|
|
87
|
+
return findFreePort();
|
|
88
|
+
}
|
|
89
|
+
function isPortFree(port) {
|
|
90
|
+
return new Promise((resolveProm) => {
|
|
91
|
+
const server = createServer();
|
|
92
|
+
server.once("error", () => resolveProm(false));
|
|
93
|
+
server.once("listening", () => {
|
|
94
|
+
server.close(() => resolveProm(true));
|
|
95
|
+
});
|
|
96
|
+
server.listen(port);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function findFreePort() {
|
|
100
|
+
return new Promise((resolveProm, rejectProm) => {
|
|
101
|
+
const server = createServer();
|
|
102
|
+
server.once("error", rejectProm);
|
|
103
|
+
server.listen(0, () => {
|
|
104
|
+
const addr = server.address();
|
|
105
|
+
if (typeof addr === "object" && addr !== null) {
|
|
106
|
+
const port = addr.port;
|
|
107
|
+
server.close(() => resolveProm(port));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
rejectProm(new Error("Could not determine free port"));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function openBrowser(url) {
|
|
116
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
117
|
+
spawn(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
118
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infinitedusky/indusk-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "InDusk development system — skills, MCP tools, and CLI for structured AI-assisted development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -18,7 +18,15 @@
|
|
|
18
18
|
"dev-system": "dist/bin/cli.js"
|
|
19
19
|
},
|
|
20
20
|
"exports": {
|
|
21
|
-
".": "./dist/server/index.js"
|
|
21
|
+
".": "./dist/server/index.js",
|
|
22
|
+
"./trajectory/parser": {
|
|
23
|
+
"types": "./dist/lib/trajectory/parser.d.ts",
|
|
24
|
+
"default": "./dist/lib/trajectory/parser.js"
|
|
25
|
+
},
|
|
26
|
+
"./falsification/log": {
|
|
27
|
+
"types": "./dist/lib/falsification/log.d.ts",
|
|
28
|
+
"default": "./dist/lib/falsification/log.js"
|
|
29
|
+
}
|
|
22
30
|
},
|
|
23
31
|
"scripts": {
|
|
24
32
|
"dev": "tsx watch src/server/index.ts",
|