@devflow-tools/cli 0.18.3 → 0.18.5

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 (42) hide show
  1. package/README.md +19 -4
  2. package/dist/commands/doctor.d.ts.map +1 -1
  3. package/dist/commands/doctor.js +12 -10
  4. package/dist/commands/doctor.js.map +1 -1
  5. package/dist/commands/server.d.ts +19 -5
  6. package/dist/commands/server.d.ts.map +1 -1
  7. package/dist/commands/server.js +31 -116
  8. package/dist/commands/server.js.map +1 -1
  9. package/dist/commands/start.d.ts +4 -2
  10. package/dist/commands/start.d.ts.map +1 -1
  11. package/dist/commands/start.js +29 -56
  12. package/dist/commands/start.js.map +1 -1
  13. package/dist/commands/status.d.ts +4 -1
  14. package/dist/commands/status.d.ts.map +1 -1
  15. package/dist/commands/status.js +17 -9
  16. package/dist/commands/status.js.map +1 -1
  17. package/dist/commands/stop.d.ts.map +1 -1
  18. package/dist/commands/stop.js +3 -2
  19. package/dist/commands/stop.js.map +1 -1
  20. package/dist/index.js +63 -18
  21. package/dist/index.js.map +1 -1
  22. package/dist/lib/messages.d.ts +38 -0
  23. package/dist/lib/messages.d.ts.map +1 -0
  24. package/dist/lib/messages.js +42 -0
  25. package/dist/lib/messages.js.map +1 -0
  26. package/dist/lib/with-server.d.ts.map +1 -1
  27. package/dist/lib/with-server.js +22 -8
  28. package/dist/lib/with-server.js.map +1 -1
  29. package/dist/plugin-files/.claude-plugin/plugin.json +1 -1
  30. package/dist/plugin-files/dist/command-registry.json +5 -5
  31. package/dist/plugin-files/dist/hooks/hook-daemon.js +28 -27
  32. package/dist/plugin-files/dist/hooks/post-tool-use-failure.js +2 -2
  33. package/dist/plugin-files/dist/hooks/post-tool-use.js +6 -6
  34. package/dist/plugin-files/dist/hooks/pre-compact.js +3 -3
  35. package/dist/plugin-files/dist/hooks/pre-tool-use.js +4 -4
  36. package/dist/plugin-files/dist/hooks/server-bootstrap.js +1 -109
  37. package/dist/plugin-files/dist/hooks/session-end.js +5 -5
  38. package/dist/plugin-files/dist/hooks/stop.js +9 -9
  39. package/dist/plugin-files/dist/hooks/user-prompt-submit.js +8 -8
  40. package/dist/plugin-files/package.json +13 -13
  41. package/dist/plugin-files/skills/start/SKILL.md +20 -34
  42. package/package.json +27 -27
@@ -1,16 +1,30 @@
1
+ import { type EnsureRuntimeInput, type RuntimeStateV2 } from '@devflow-tools/sdk';
1
2
  export declare const DEFAULT_SERVER_PORT = 13337;
2
- declare function readPort(pidFile: string): number | null;
3
- declare function readPid(pidFile: string): number | null;
4
- export { readPort as readPortFromFile, readPid as readPidFromFile };
5
- export declare function startServer(opts: {
6
- port: number;
3
+ export declare function resolveServerLaunch(projectRoot?: string): EnsureRuntimeInput['server'];
4
+ export declare function getRuntimeManager(): import("@devflow-tools/sdk").RuntimeManager;
5
+ export interface CliRuntimeOptions {
6
+ reason: EnsureRuntimeInput['reason'];
7
+ projectRoot: string;
8
+ port?: number;
9
+ explicitPort?: boolean;
10
+ noStart?: boolean;
11
+ }
12
+ export declare function ensureCliRuntime(options: CliRuntimeOptions): Promise<import("@devflow-tools/sdk").EnsureRuntimeResult>;
13
+ export declare function startServer(options?: {
14
+ port?: number;
15
+ projectRoot?: string;
16
+ explicitPort?: boolean;
7
17
  }): Promise<{
8
18
  pid: number;
19
+ port: number;
20
+ state: RuntimeStateV2;
21
+ reused: boolean;
9
22
  }>;
10
23
  export declare function stopServer(): Promise<boolean>;
11
24
  export declare function serverStatus(): Promise<{
12
25
  running: boolean;
13
26
  pid?: number;
14
27
  port?: number;
28
+ state?: RuntimeStateV2 | null;
15
29
  }>;
16
30
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,mBAAmB,QAA8B,CAAC;AAE/D,iBAAS,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhD;AAED,iBAAS,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO/C;AAED,OAAO,EAAE,QAAQ,IAAI,gBAAgB,EAAE,OAAO,IAAI,eAAe,EAAE,CAAC;AAEpE,wBAAsB,WAAW,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BlF;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAgBnD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB/F"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAG5B,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,wBAAgB,mBAAmB,CAAC,WAAW,SAAgB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAU7F;AAED,wBAAgB,iBAAiB,gDAAqC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,6DAShE;AAED,wBAAsB,WAAW,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAI/L;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAAuD;AAE3G,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,CAAC,CAG9H"}
@@ -1,126 +1,41 @@
1
- import { spawn } from "child_process";
2
- import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync } from "fs";
3
- import { join } from "path";
4
- import { createRequire } from "module";
5
- import { randomUUID } from "node:crypto";
6
- import { DEFAULT_DEVFLOW_SERVER_PORT, readRuntimeEndpointState, resolveRuntimeEndpoint, updateRuntimeEndpointStatus, writeRuntimeEndpointState, } from "@devflow-tools/sdk";
1
+ import { createRequire } from 'node:module';
2
+ import { join } from 'node:path';
3
+ import { createRuntimeManager, } from '@devflow-tools/sdk';
7
4
  const require = createRequire(import.meta.url);
8
- function getPidFile(projectRoot) {
9
- const dotdev = join(projectRoot, ".devflow");
10
- if (!existsSync(dotdev))
11
- mkdirSync(dotdev, { recursive: true });
12
- return join(dotdev, "server.pid");
13
- }
14
- function getServerScript() {
15
- // Prefer bundled server.js distributed alongside the CLI
16
- try {
17
- return require.resolve("./server.js");
18
- }
19
- catch {
20
- // Fallback: separate npm package
5
+ export const DEFAULT_SERVER_PORT = 13337;
6
+ export function resolveServerLaunch(projectRoot = process.cwd()) {
7
+ const candidates = [
8
+ () => require.resolve('@devflow-tools/server/dist/main.js'),
9
+ () => join(projectRoot, 'node_modules', '@devflow-tools', 'server', 'dist', 'main.js'),
10
+ () => join(projectRoot, 'apps', 'server', 'dist', 'main.js'),
11
+ ];
12
+ for (const candidate of candidates) {
21
13
  try {
22
- return require.resolve("@devflow-tools/server/dist/main.js");
23
- }
24
- catch {
25
- return join(process.cwd(), "apps", "server", "dist", "main.js");
14
+ return { command: process.execPath, args: [candidate()], cwd: projectRoot };
26
15
  }
16
+ catch { }
27
17
  }
28
- }
29
- export const DEFAULT_SERVER_PORT = DEFAULT_DEVFLOW_SERVER_PORT;
30
- function readPort(pidFile) {
31
- if (!existsSync(pidFile))
32
- return null;
33
- const lines = readFileSync(pidFile, "utf-8").trim().split("\n");
34
- if (lines.length >= 2) {
35
- const port = parseInt(lines[0], 10);
36
- if (!isNaN(port))
37
- return port;
38
- }
39
- return null;
40
- }
41
- function readPid(pidFile) {
42
- if (!existsSync(pidFile))
43
- return null;
44
- const lines = readFileSync(pidFile, "utf-8").trim().split("\n");
45
- // New format: port\npid (2 lines). Old format: just pid (1 line).
46
- const pidLine = lines.length >= 2 ? lines[1] : lines[0];
47
- const pid = parseInt(pidLine, 10);
48
- return isNaN(pid) ? null : pid;
49
- }
50
- export { readPort as readPortFromFile, readPid as readPidFromFile };
51
- export async function startServer(opts) {
52
- const script = getServerScript();
53
- const pidFile = getPidFile(process.cwd());
54
- const ownerToken = randomUUID();
55
- const child = spawn(process.execPath, [script, '--devflow-instance-token', ownerToken], {
56
- env: { ...process.env, PORT: String(opts.port) },
57
- stdio: "ignore",
58
- detached: true,
59
- });
60
- writeFileSync(pidFile, `${opts.port}\n${child.pid ?? 0}`);
61
- writeRuntimeEndpointState({
62
- url: `http://127.0.0.1:${opts.port}`,
63
- port: opts.port,
64
- pid: child.pid ?? 0,
65
- ownerToken,
66
- status: 'launching',
18
+ throw new Error('DevFlow server entry point is not installed or built');
19
+ }
20
+ export function getRuntimeManager() { return createRuntimeManager(); }
21
+ export async function ensureCliRuntime(options) {
22
+ return getRuntimeManager().ensureRunning({
23
+ reason: options.reason,
24
+ projectRoot: options.projectRoot,
25
+ port: options.port,
26
+ explicitPort: options.explicitPort,
27
+ noStart: options.noStart,
28
+ server: resolveServerLaunch(options.projectRoot),
67
29
  });
68
- child.unref();
69
- const healthy = await waitForHealth(`http://127.0.0.1:${opts.port}`, 5_000);
70
- updateRuntimeEndpointStatus(healthy ? 'healthy' : 'degraded');
71
- return { pid: child.pid ?? 0 };
72
30
  }
73
- export async function stopServer() {
74
- const pidFile = getPidFile(process.cwd());
75
- const pid = readPid(pidFile);
76
- if (pid === null)
77
- return false;
78
- try {
79
- process.kill(pid);
80
- unlinkSync(pidFile);
81
- const endpoint = readRuntimeEndpointState();
82
- if (endpoint?.pid === pid)
83
- updateRuntimeEndpointStatus('stopped');
84
- return true;
85
- }
86
- catch {
87
- unlinkSync(pidFile);
88
- const endpoint = readRuntimeEndpointState();
89
- if (endpoint?.pid === pid)
90
- updateRuntimeEndpointStatus('stopped');
91
- return false;
92
- }
31
+ export async function startServer(options = {}) {
32
+ const root = options.projectRoot ?? process.cwd();
33
+ const result = await ensureCliRuntime({ reason: 'cli-start', projectRoot: root, port: options.port, explicitPort: options.explicitPort });
34
+ return { pid: result.state.pid, port: result.state.port, state: result.state, reused: result.reused };
93
35
  }
36
+ export async function stopServer() { return (await getRuntimeManager().stop()).stopped; }
94
37
  export async function serverStatus() {
95
- const pidFile = getPidFile(process.cwd());
96
- const resolved = resolveRuntimeEndpoint();
97
- const port = readPort(pidFile) ?? resolved.port;
98
- const { DevFlowApiClient } = await import("@devflow-tools/sdk");
99
- const client = new DevFlowApiClient({ baseUrl: `http://127.0.0.1:${port}`, projectRoot: process.cwd() });
100
- const reachable = await client.ping();
101
- if (reachable) {
102
- const pid = readPid(pidFile) ?? undefined;
103
- const state = readRuntimeEndpointState();
104
- if (state && (!pid || state.pid === pid))
105
- updateRuntimeEndpointStatus('healthy');
106
- return { running: true, pid, port };
107
- }
108
- const state = readRuntimeEndpointState();
109
- if (state && (!readPid(pidFile) || state.pid === readPid(pidFile)))
110
- updateRuntimeEndpointStatus('degraded');
111
- return { running: false, port };
112
- }
113
- async function waitForHealth(url, timeoutMs) {
114
- const deadline = Date.now() + timeoutMs;
115
- while (Date.now() < deadline) {
116
- try {
117
- const response = await fetch(new URL('/api/health', url), { signal: AbortSignal.timeout(500) });
118
- if (response.ok)
119
- return true;
120
- }
121
- catch { }
122
- await new Promise(resolve => setTimeout(resolve, 100));
123
- }
124
- return false;
38
+ const state = await getRuntimeManager().status();
39
+ return { running: Boolean(state?.status === 'ready' && state.dashboardAvailable), pid: state?.pid, port: state?.port, state };
125
40
  }
126
41
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,oBAAoB,GAGrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAEzC,MAAM,UAAU,mBAAmB,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;IAC7D,MAAM,UAAU,GAAG;QACjB,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,oCAAoC,CAAC;QAC3D,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;QACtF,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;KAC7D,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IAC/F,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,iBAAiB,KAAK,OAAO,oBAAoB,EAAE,CAAC,CAAC,CAAC;AAUtE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAA0B;IAC/D,OAAO,iBAAiB,EAAE,CAAC,aAAa,CAAC;QACvC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC;KACjD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAA2E,EAAE;IAC7G,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC1I,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AACxG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,KAAuB,OAAO,CAAC,MAAM,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAE3G,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,KAAK,GAAG,MAAM,iBAAiB,EAAE,CAAC,MAAM,EAAE,CAAC;IACjD,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,IAAI,KAAK,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAChI,CAAC"}
@@ -1,5 +1,7 @@
1
- export declare function startAll(opts: {
2
- port: number;
1
+ export declare function startAll(options: {
2
+ port?: number;
3
3
  background: boolean;
4
+ explicitPort?: boolean;
5
+ projectRoot?: string;
4
6
  }): Promise<void>;
5
7
  //# sourceMappingURL=start.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAgBA,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0ChB"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAIA,wBAAsB,QAAQ,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB3I"}
@@ -1,58 +1,31 @@
1
- import chalk from "chalk";
2
- import { startServer, stopServer } from "./server.js";
3
- async function waitForServer(port, timeoutMs = 15000) {
4
- const start = Date.now();
5
- while (Date.now() - start < timeoutMs) {
6
- try {
7
- const res = await fetch(`http://127.0.0.1:${port}/api/health`);
8
- if (res.ok)
9
- return true;
10
- }
11
- catch { }
12
- await new Promise((r) => setTimeout(r, 500));
13
- }
14
- return false;
15
- }
16
- export async function startAll(opts) {
17
- // 1. Start server (serves both API and dashboard static files)
18
- console.log(chalk.blue("Starting DevFlow server..."));
19
- const { pid: serverPid } = await startServer({ port: opts.port });
20
- console.log(chalk.green(` Server started (PID: ${serverPid})`));
21
- // 2. Wait for server to be ready
22
- console.log(chalk.blue(" Waiting for server..."));
23
- const ready = await waitForServer(opts.port);
24
- if (!ready) {
25
- console.log(chalk.yellow(" Server started but health check timed out"));
26
- }
27
- else {
28
- console.log(chalk.green(" Server ready"));
29
- }
30
- // 3. Print status
31
- console.log("");
32
- console.log(chalk.green("╔═══════════════════════════════════════════════════════════╗"));
33
- console.log(chalk.green("║") + " DevFlow Started! " + chalk.green("║"));
34
- console.log(chalk.green("╠═══════════════════════════════════════════════════════════╣"));
35
- console.log(chalk.green("║") + ` Server + Dashboard: http://localhost:${opts.port}`.padEnd(57) + chalk.green("║"));
36
- console.log(chalk.green("║") + ` API: http://localhost:${opts.port}/api`.padEnd(57) + chalk.green("║"));
37
- console.log(chalk.green("║") + " " + chalk.green("║"));
38
- console.log(chalk.green("║") + " Press Ctrl+C to stop " + chalk.green("║"));
39
- console.log(chalk.green("╚═══════════════════════════════════════════════════════════╝"));
40
- // 4. If not background, wait for Ctrl+C
41
- if (!opts.background) {
42
- await new Promise((resolve) => {
43
- let cleaned = false;
44
- const cleanup = async () => {
45
- if (cleaned)
46
- return;
47
- cleaned = true;
48
- console.log(chalk.blue("\nShutting down..."));
49
- await stopServer();
50
- console.log(chalk.green("Server stopped."));
51
- resolve();
52
- };
53
- process.on("SIGINT", cleanup);
54
- process.on("SIGTERM", cleanup);
55
- });
56
- }
1
+ import chalk from 'chalk';
2
+ import { getRuntimeManager, startServer } from './server.js';
3
+ import { runtimeMessage } from '../lib/messages.js';
4
+ export async function startAll(options) {
5
+ const projectRoot = options.projectRoot ?? process.cwd();
6
+ console.log(chalk.blue(runtimeMessage('starting')));
7
+ const result = await startServer({ port: options.port, projectRoot, explicitPort: options.explicitPort });
8
+ console.log(chalk.green(runtimeMessage('ready', { url: result.state.url })));
9
+ if (result.reused)
10
+ console.log(chalk.dim(runtimeMessage('reused')));
11
+ if (options.background)
12
+ return;
13
+ await new Promise(resolve => {
14
+ let finished = false;
15
+ const cleanup = async () => {
16
+ if (finished)
17
+ return;
18
+ finished = true;
19
+ process.off('SIGINT', cleanup);
20
+ process.off('SIGTERM', cleanup);
21
+ const current = getRuntimeManager().readState();
22
+ if (!result.reused && current?.generation === result.state.generation && current.ownerToken === result.state.ownerToken) {
23
+ await getRuntimeManager().stop().catch(() => undefined);
24
+ }
25
+ resolve();
26
+ };
27
+ process.once('SIGINT', cleanup);
28
+ process.once('SIGTERM', cleanup);
29
+ });
57
30
  }
58
31
  //# sourceMappingURL=start.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtD,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,SAAS,GAAG,KAAK;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,aAAa,CAAC,CAAC;YAC/D,IAAI,GAAG,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAG9B;IACC,+DAA+D;IAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,SAAS,GAAG,CAAC,CAAC,CAAC;IAEjE,iCAAiC;IACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,6CAA6C,CAAC,CAAC,CAAC;IAC3E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,kBAAkB;IAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,0DAA0D,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,0CAA0C,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACpH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,2BAA2B,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACzG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,6DAA6D,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACjH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,2DAA2D,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC,CAAC;IAE1F,wCAAwC;IACxC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACrB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBACzB,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBAC9C,MAAM,UAAU,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBAC5C,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAA6F;IAC1H,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC1G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7E,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,OAAO,CAAC,UAAU;QAAE,OAAO;IAE/B,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;QAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;YACxC,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChC,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC,SAAS,EAAE,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,EAAE,UAAU,KAAK,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;gBACxH,MAAM,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC1D,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -1,2 +1,5 @@
1
- export declare function showStatus(): Promise<void>;
1
+ export declare function showStatus(options?: {
2
+ json?: boolean;
3
+ projectRoot?: string;
4
+ }): Promise<void>;
2
5
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAuBA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAgDhD"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAwBA,wBAAsB,UAAU,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDtG"}
@@ -1,11 +1,12 @@
1
1
  import { existsSync, statSync } from "fs";
2
2
  import chalk from "chalk";
3
- import { serverStatus, DEFAULT_SERVER_PORT } from "./server.js";
3
+ import { serverStatus } from "./server.js";
4
4
  import { getGlobalDevFlowDbPath } from "@devflow-tools/database";
5
5
  import { join } from "path";
6
6
  import { DatabaseSync } from "node:sqlite";
7
7
  import { homedir } from "node:os";
8
8
  import { resolveActivePlugin, scanClaudeSkillShadowing } from "../lib/plugin-setup.js";
9
+ import { runtimeMessage } from "../lib/messages.js";
9
10
  function hasDevFlowTables(path) {
10
11
  if (!existsSync(path))
11
12
  return false;
@@ -22,19 +23,26 @@ function hasDevFlowTables(path) {
22
23
  return true;
23
24
  }
24
25
  }
25
- export async function showStatus() {
26
- console.log(chalk.blue("DevFlow Status"));
26
+ export async function showStatus(options = {}) {
27
+ const server = await serverStatus();
28
+ const projectRoot = options.projectRoot ?? process.cwd();
29
+ if (options.json) {
30
+ console.log(JSON.stringify({
31
+ runtime: server.state ?? null,
32
+ running: server.running,
33
+ project: { root: projectRoot, initialized: existsSync(join(projectRoot, '.devflow')) },
34
+ }));
35
+ return;
36
+ }
37
+ console.log(chalk.blue(runtimeMessage('statusHeader')));
27
38
  console.log(chalk.dim("──────────────"));
28
39
  // Server status
29
- const server = await serverStatus();
30
- const serverPort = server.port ?? DEFAULT_SERVER_PORT;
31
40
  if (server.running) {
32
- console.log(`Server: ${chalk.green("✓")} running (port ${serverPort}${server.pid ? `, PID ${server.pid}` : ""})`);
33
- console.log(`Dashboard: ${chalk.green("✓")} served at http://localhost:${serverPort}`);
41
+ const state = server.state;
42
+ console.log(chalk.green(runtimeMessage('running', { url: state.url, pid: state.pid, generation: state.generation })));
34
43
  }
35
44
  else {
36
- console.log(`Server: ${chalk.yellow("○")} not running`);
37
- console.log(`Dashboard: ${chalk.yellow("○")} not running`);
45
+ console.log(chalk.yellow(runtimeMessage(server.state ? 'dashboardUnavailable' : 'notRunning', { status: server.state?.status ?? 'stopped' })));
38
46
  }
39
47
  const home = homedir();
40
48
  const activePlugin = resolveActivePlugin(home);
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAGA,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAO7C"}
1
+ {"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAIA,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAO7C"}
@@ -1,12 +1,13 @@
1
1
  import chalk from "chalk";
2
2
  import { stopServer } from "./server.js";
3
+ import { runtimeMessage } from "../lib/messages.js";
3
4
  export async function stopAll() {
4
5
  const stopped = await stopServer();
5
6
  if (stopped) {
6
- console.log(chalk.green("Server stopped"));
7
+ console.log(chalk.green(runtimeMessage('stopped')));
7
8
  }
8
9
  else {
9
- console.log(chalk.dim("No DevFlow services running"));
10
+ console.log(chalk.dim(runtimeMessage('notRunning')));
10
11
  }
11
12
  }
12
13
  //# sourceMappingURL=stop.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACxD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;AACH,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import fs from "fs";
5
5
  import path from "path";
6
6
  import { detectMode } from "./mode.js";
7
7
  import { createRequire } from "module";
8
+ import { execFile } from "node:child_process";
8
9
  const require = createRequire(import.meta.url);
9
10
  // Read version from package.json at runtime
10
11
  // Installed: dist/cli.js → ../package.json = packages/devflow/package.json
@@ -22,6 +23,19 @@ catch {
22
23
  }
23
24
  }
24
25
  const program = new Command();
26
+ function openDashboardUrl(url) {
27
+ const parsed = new URL(url);
28
+ if (parsed.protocol !== 'http:' || parsed.hostname !== '127.0.0.1')
29
+ return Promise.reject(new Error('Only loopback Dashboard URLs can be opened.'));
30
+ const [command, args] = process.platform === 'darwin'
31
+ ? ['/usr/bin/open', [url]]
32
+ : process.platform === 'win32'
33
+ ? ['cmd.exe', ['/c', 'start', '', url]]
34
+ : ['xdg-open', [url]];
35
+ return new Promise((resolve, reject) => {
36
+ execFile(command, args, error => error ? reject(error) : resolve());
37
+ });
38
+ }
25
39
  program
26
40
  .name("devflow")
27
41
  .description("Developer Intelligence Platform for AI Coding Agents")
@@ -821,43 +835,71 @@ serverCmd
821
835
  .command("start")
822
836
  .description("Start the DevFlow REST server")
823
837
  .option("--port <n>", "Port number", "13337")
824
- .action(async (opts) => {
825
- console.log(chalk.blue("Starting DevFlow server..."));
838
+ .action(async (opts, command) => {
826
839
  const { startServer } = await import("./commands/server.js");
827
- const result = await startServer({ port: parseInt(opts.port, 10) });
828
- console.log(chalk.green(`Server started (pid: ${result.pid}) on port ${opts.port}`));
840
+ const { runtimeMessage } = await import('./lib/messages.js');
841
+ console.log(chalk.blue(runtimeMessage('starting')));
842
+ const result = await startServer({ port: Number(opts.port), explicitPort: command.getOptionValueSource('port') === 'cli' });
843
+ console.log(chalk.green(runtimeMessage('ready', { url: result.state.url })));
844
+ if (result.reused)
845
+ console.log(chalk.dim(runtimeMessage('reused')));
829
846
  });
830
847
  serverCmd
831
848
  .command("stop")
832
849
  .description("Stop the DevFlow REST server")
833
850
  .action(async () => {
834
851
  const { stopServer } = await import("./commands/server.js");
852
+ const { runtimeMessage } = await import('./lib/messages.js');
835
853
  const ok = await stopServer();
836
854
  if (ok)
837
- console.log(chalk.green("Server stopped"));
855
+ console.log(chalk.green(runtimeMessage('stopped')));
838
856
  else
839
- console.log(chalk.dim("No server running"));
857
+ console.log(chalk.dim(runtimeMessage('notRunning')));
840
858
  });
841
859
  serverCmd
842
860
  .command("status")
843
861
  .description("Show server status")
844
862
  .action(async () => {
845
863
  const { serverStatus } = await import("./commands/server.js");
864
+ const { runtimeMessage } = await import('./lib/messages.js');
846
865
  const status = await serverStatus();
847
- if (status.running)
848
- console.log(chalk.green(`Running (pid: ${status.pid})`));
866
+ if (status.running && status.state)
867
+ console.log(chalk.green(runtimeMessage('running', { url: status.state.url, pid: status.state.pid, generation: status.state.generation })));
849
868
  else
850
- console.log(chalk.yellow("Not running"));
869
+ console.log(chalk.yellow(runtimeMessage(status.state ? 'dashboardUnavailable' : 'notRunning', { status: status.state?.status ?? 'stopped' })));
851
870
  });
852
871
  // --- dashboard ---
853
872
  program
854
873
  .command("dashboard")
855
874
  .description("Open DevFlow Dashboard")
856
- .action(async () => {
857
- const { resolveRuntimeEndpoint } = await import("@devflow-tools/sdk");
858
- console.log(chalk.blue("The Dashboard is served by the DevFlow server."));
859
- console.log(chalk.dim("Run: devflow start"));
860
- console.log(chalk.dim(`Then open: ${resolveRuntimeEndpoint().url}`));
875
+ .option('--open', 'Open the ready Dashboard URL in the default browser')
876
+ .option('--no-start', 'Return an error when no ready runtime exists')
877
+ .option('--json', 'Print a stable JSON result')
878
+ .option('--project <path>', 'Project root', process.cwd())
879
+ .option('--port <n>', 'Runtime port')
880
+ .action(async (opts, command) => {
881
+ const { ensureCliRuntime } = await import('./commands/server.js');
882
+ const { runtimeMessage } = await import('./lib/messages.js');
883
+ const projectRoot = path.resolve(opts.project);
884
+ if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory())
885
+ throw new Error(runtimeMessage('projectRequired'));
886
+ const result = await ensureCliRuntime({ reason: 'cli-dashboard', projectRoot, port: opts.port === undefined ? undefined : Number(opts.port), explicitPort: command.getOptionValueSource('port') === 'cli', noStart: opts.start === false });
887
+ const document = { url: result.state.url, projectId: result.projectId, runtime: result.state, reused: result.reused };
888
+ if (opts.json)
889
+ console.log(JSON.stringify(document));
890
+ else {
891
+ console.log(chalk.green(runtimeMessage('ready', { url: result.state.url })));
892
+ if (result.reused)
893
+ console.log(chalk.dim(runtimeMessage('reused')));
894
+ }
895
+ if (opts.open) {
896
+ try {
897
+ await openDashboardUrl(result.state.url);
898
+ }
899
+ catch (error) {
900
+ console.error(chalk.yellow(runtimeMessage('openingFailed', { message: error instanceof Error ? error.message : String(error) })));
901
+ }
902
+ }
861
903
  });
862
904
  // --- start ---
863
905
  program
@@ -865,11 +907,12 @@ program
865
907
  .description("Start DevFlow server (API + Dashboard)")
866
908
  .option("--port <n>", "Server port", "13337")
867
909
  .option("-d, --background", "Run in background (detached)")
868
- .action(async (opts) => {
910
+ .action(async (opts, command) => {
869
911
  const { startAll } = await import("./commands/start.js");
870
912
  await startAll({
871
- port: parseInt(opts.port, 10),
913
+ port: Number(opts.port),
872
914
  background: !!opts.background,
915
+ explicitPort: command.getOptionValueSource('port') === 'cli',
873
916
  });
874
917
  });
875
918
  // --- stop ---
@@ -884,9 +927,11 @@ program
884
927
  program
885
928
  .command("status")
886
929
  .description("Show DevFlow services status")
887
- .action(async () => {
930
+ .option('--json', 'Print a stable JSON result')
931
+ .option('--project <path>', 'Project root', process.cwd())
932
+ .action(async (opts) => {
888
933
  const { showStatus } = await import("./commands/status.js");
889
- await showStatus();
934
+ await showStatus({ json: Boolean(opts.json), projectRoot: path.resolve(opts.project) });
890
935
  });
891
936
  // --- setup ---
892
937
  program