feat(cli): make --port the user-facing port flag (#737)
* feat(cli): add --port flag as the user-facing port knob
Introduces --port (and KANDEV_PORT) as the primary, command-aware port
flag: in start/run it sets the Go backend port (the proxy front door
the browser actually hits), and in dev it sets the Next dev server port.
--backend-port and --web-port still work but emit a one-time stderr
deprecation note pointing at --port and --web-internal-port respectively.
* feat(cli): print labelled "open:" URL on startup
Replaces the ambiguous "[kandev] url:" / "ready at" lines with a
labelled block that always shows the user-facing URL first, plus the
backend (api) and web (internal) URLs when they differ. Each command
now declares its own publicUrl: backend in start/run (where the Go
server reverse-proxies Next.js), web in dev (browser hits Next direct).
* style(cli): apply prettier formatting to args.test.ts
* refactor(cli): tighten arg parsing per review feedback
- Validate value-taking flags (--port, --backend-port, --web-internal-port,
--web-port, --version) and reject missing/non-numeric values with a clear
ParseError instead of leaking NaN into the port validator.
- Drop the test-only _resetWarnedFlagsForTest export and the module-level
warned-flag set; parseArgs now returns deduped deprecatedFlags and cli.ts
emits warnings command-aware (e.g. --backend-port → KANDEV_BACKEND_PORT
in dev, where --port maps to web).
- Stop double-printing the "open:" URL: logStartupInfo now lists labelled
backend (api) / web (internal) URLs only, leaving the post-readiness
open: line as the single source of truth.
- Fix help text: --web-internal-port works in dev too.
- Drop multi-line JSDoc blocks per CLAUDE.md style guide.
* fix(cli): validate env-var ports and collapse comment to one-liner
Catches non-numeric KANDEV_PORT / KANDEV_BACKEND_PORT / KANDEV_WEB_PORT in
envPort with a clear ParseError instead of letting NaN reach
ensureValidPort. Drops a multi-line comment per CLAUDE.md style.
* fix(cli): reject non-integer port values
Number.isFinite accepts floats like 3000.5 which then fail downstream
in ensureValidPort with a generic message. Tighten parsePort and
envPort to require integers and add float tests for both flag and
env-var paths.
* fix(cli): reject out-of-range port values with flag-named errors
Adds 1-65535 range checks to parsePort and envPort so values like 0,
-1, or 65536 fail with a flag/env-var-named ParseError instead of
reaching ensureValidPort with a generic 'backend port' label.
* test(cli): cover KANDEV_WEB_PORT happy path and range validation
* test(cli): cover KANDEV_WEB_PORT in run/start mode too
* fix(cli): explicit CLI flag wins over env var for port resolution
Previously KANDEV_BACKEND_PORT silently overrode --port because each
process port resolved its own env var before the generic --port
fallback. New precedence per process: explicit CLI flag > generic
--port flag > explicit env var > generic KANDEV_PORT. Also relabel
the startup info from "backend (api)" / "web (internal)" to plain
"backend" / "web" — "internal" was misleading in dev where the web
URL is what users open.
* style(cli): collapse resolvePorts comment to one line
* fix(cli): reject empty --version= and empty port env vars
- --version= (no value after =) now throws ParseError instead of
silently storing the empty string as the version tag.
- envPort distinguishes unset (undefined) from empty (""); an empty
KANDEV_PORT / KANDEV_BACKEND_PORT / KANDEV_WEB_PORT is now treated
as misconfiguration and fails fast.
* refactor(cli): make --port a plain alias for --backend-port
Drops the command-aware split where --port mapped to web in dev and
backend in run/start. --port and --backend-port now both set
options.backendPort regardless of command, and KANDEV_PORT is a plain
fallback for KANDEV_BACKEND_PORT. The whole point of the original
fix was that the *backend port* is the URL users actually open in
run/start (because the Go server reverse-proxies Next.js); a single
flag that always means "the backend port" matches that mental model
without per-command surprises.
Removes deprecationReplacement and the command-aware warning logic
since the two flags are now interchangeable. --web-port → --web-internal-port
deprecation stays.
* test(cli): re-add KANDEV_WEB_PORT run-mode coverage dropped in refactor
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { parseArgs, ParseError, resolvePorts } from "./args";
|
||||
|
||||
describe("parseArgs", () => {
|
||||
it("defaults to the run command with no args", () => {
|
||||
const { options, showHelp, deprecatedFlags } = parseArgs([]);
|
||||
expect(options.command).toBe("run");
|
||||
expect(showHelp).toBe(false);
|
||||
expect(deprecatedFlags).toEqual([]);
|
||||
});
|
||||
|
||||
it("parses --port and --port=<n> as the backend port", () => {
|
||||
expect(parseArgs(["--port", "3000"]).options.backendPort).toBe(3000);
|
||||
expect(parseArgs(["--port=3000"]).options.backendPort).toBe(3000);
|
||||
});
|
||||
|
||||
it("parses --backend-port the same as --port (no deprecation note)", () => {
|
||||
expect(parseArgs(["--backend-port=3447"]).options.backendPort).toBe(3447);
|
||||
expect(parseArgs(["--backend-port=3447"]).deprecatedFlags).toEqual([]);
|
||||
});
|
||||
|
||||
it("parses --web-internal-port without a deprecation note", () => {
|
||||
const r = parseArgs(["--web-internal-port", "12345"]);
|
||||
expect(r.options.webPort).toBe(12345);
|
||||
expect(r.deprecatedFlags).toEqual([]);
|
||||
});
|
||||
|
||||
it("records --web-port as deprecated", () => {
|
||||
const r = parseArgs(["--web-port=8080"]);
|
||||
expect(r.options.webPort).toBe(8080);
|
||||
expect(r.deprecatedFlags).toEqual(["--web-port"]);
|
||||
});
|
||||
|
||||
it("dedupes deprecated flags across repeats", () => {
|
||||
const r = parseArgs(["--web-port=1", "--web-port=2"]);
|
||||
expect(r.deprecatedFlags).toEqual(["--web-port"]);
|
||||
});
|
||||
|
||||
it("reports --help via showHelp without exiting", () => {
|
||||
expect(parseArgs(["--help"]).showHelp).toBe(true);
|
||||
});
|
||||
|
||||
it("throws ParseError when a value-taking flag has no value", () => {
|
||||
expect(() => parseArgs(["--port"])).toThrow(ParseError);
|
||||
expect(() => parseArgs(["--port"])).toThrow(/--port requires a value/);
|
||||
});
|
||||
|
||||
it("throws ParseError when the next token is another flag", () => {
|
||||
expect(() => parseArgs(["--port", "--debug"])).toThrow(/--port requires a value/);
|
||||
});
|
||||
|
||||
it("throws ParseError on a non-numeric port value", () => {
|
||||
expect(() => parseArgs(["--port=abc"])).toThrow(/--port value must be an integer/);
|
||||
});
|
||||
|
||||
it("throws ParseError on a non-integer port value", () => {
|
||||
expect(() => parseArgs(["--port=3000.5"])).toThrow(/--port value must be an integer/);
|
||||
});
|
||||
|
||||
it.each(["0", "-1", "65536"])("throws ParseError on out-of-range port %s", (val) => {
|
||||
expect(() => parseArgs([`--port=${val}`])).toThrow(/--port value must be an integer between/);
|
||||
});
|
||||
|
||||
it("throws ParseError on empty --port=", () => {
|
||||
expect(() => parseArgs(["--port="])).toThrow(/--port value must be an integer/);
|
||||
});
|
||||
|
||||
it("throws ParseError on empty --version=", () => {
|
||||
expect(() => parseArgs(["--version="])).toThrow(/--version requires a value/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolvePorts", () => {
|
||||
it("returns undefined for both ports when nothing is set", () => {
|
||||
const r = resolvePorts({ command: "run" }, {} as NodeJS.ProcessEnv);
|
||||
expect(r).toEqual({ backendPort: undefined, webPort: undefined });
|
||||
});
|
||||
|
||||
it("CLI backendPort wins over env vars", () => {
|
||||
const r = resolvePorts({ command: "start", backendPort: 3000 }, {
|
||||
KANDEV_BACKEND_PORT: "4000",
|
||||
KANDEV_PORT: "5000",
|
||||
} as NodeJS.ProcessEnv);
|
||||
expect(r.backendPort).toBe(3000);
|
||||
});
|
||||
|
||||
it("KANDEV_BACKEND_PORT wins over KANDEV_PORT (more specific env wins)", () => {
|
||||
const r = resolvePorts({ command: "run" }, {
|
||||
KANDEV_PORT: "5555",
|
||||
KANDEV_BACKEND_PORT: "6666",
|
||||
} as NodeJS.ProcessEnv);
|
||||
expect(r.backendPort).toBe(6666);
|
||||
});
|
||||
|
||||
it("falls back to KANDEV_PORT when KANDEV_BACKEND_PORT is not set", () => {
|
||||
const r = resolvePorts({ command: "run" }, { KANDEV_PORT: "5555" } as NodeJS.ProcessEnv);
|
||||
expect(r.backendPort).toBe(5555);
|
||||
});
|
||||
|
||||
it("KANDEV_WEB_PORT sets the internal web port in dev", () => {
|
||||
const r = resolvePorts({ command: "dev" }, { KANDEV_WEB_PORT: "8080" } as NodeJS.ProcessEnv);
|
||||
expect(r.webPort).toBe(8080);
|
||||
});
|
||||
|
||||
it("KANDEV_WEB_PORT sets the internal web port in run/start (backend stays undefined)", () => {
|
||||
const r = resolvePorts({ command: "run" }, { KANDEV_WEB_PORT: "8080" } as NodeJS.ProcessEnv);
|
||||
expect(r).toEqual({ backendPort: undefined, webPort: 8080 });
|
||||
});
|
||||
|
||||
it("--port maps to backend in every command (including dev)", () => {
|
||||
const r = resolvePorts({ command: "dev", backendPort: 3447 }, {} as NodeJS.ProcessEnv);
|
||||
expect(r).toEqual({ backendPort: 3447, webPort: undefined });
|
||||
});
|
||||
|
||||
it("throws ParseError when KANDEV_PORT is not a number", () => {
|
||||
expect(() =>
|
||||
resolvePorts({ command: "run" }, { KANDEV_PORT: "abc" } as NodeJS.ProcessEnv),
|
||||
).toThrow(ParseError);
|
||||
});
|
||||
|
||||
it("throws ParseError when KANDEV_PORT is a float", () => {
|
||||
expect(() =>
|
||||
resolvePorts({ command: "run" }, { KANDEV_PORT: "3000.5" } as NodeJS.ProcessEnv),
|
||||
).toThrow(/KANDEV_PORT must be an integer/);
|
||||
});
|
||||
|
||||
it.each(["0", "-1", "65536"])("throws ParseError when KANDEV_PORT is out-of-range %s", (val) => {
|
||||
expect(() =>
|
||||
resolvePorts({ command: "run" }, { KANDEV_PORT: val } as NodeJS.ProcessEnv),
|
||||
).toThrow(/KANDEV_PORT must be an integer between/);
|
||||
});
|
||||
|
||||
it.each(["KANDEV_PORT", "KANDEV_BACKEND_PORT", "KANDEV_WEB_PORT"])(
|
||||
"throws ParseError when %s is set to empty string",
|
||||
(name) => {
|
||||
expect(() => resolvePorts({ command: "run" }, { [name]: "" } as NodeJS.ProcessEnv)).toThrow(
|
||||
new RegExp(`${name} must be an integer`),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
export type Command = "run" | "dev" | "start";
|
||||
|
||||
export type CliOptions = {
|
||||
command: Command;
|
||||
version?: string;
|
||||
backendPort?: number;
|
||||
webPort?: number;
|
||||
verbose?: boolean;
|
||||
debug?: boolean;
|
||||
};
|
||||
|
||||
export type ParseResult = {
|
||||
options: CliOptions;
|
||||
showHelp: boolean;
|
||||
/** Deprecated flags seen on the command line. cli.ts emits warnings after parsing. */
|
||||
deprecatedFlags: string[];
|
||||
};
|
||||
|
||||
export class ParseError extends Error {}
|
||||
|
||||
export function parseArgs(argv: string[]): ParseResult {
|
||||
const opts: CliOptions = { command: "run" };
|
||||
let showHelp = false;
|
||||
const deprecatedFlags: string[] = [];
|
||||
const noteDeprecated = (flag: string) => {
|
||||
if (!deprecatedFlags.includes(flag)) deprecatedFlags.push(flag);
|
||||
};
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
const arg = argv[i];
|
||||
if (arg === "--help" || arg === "-h") {
|
||||
showHelp = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "dev" || arg === "run" || arg === "start") {
|
||||
opts.command = arg;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--version") {
|
||||
opts.version = takeValue(argv, i, "--version");
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--version=")) {
|
||||
const value = arg.slice("--version=".length);
|
||||
if (value.length === 0) throw new ParseError("--version requires a value");
|
||||
opts.version = value;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--dev") {
|
||||
opts.command = "dev";
|
||||
continue;
|
||||
}
|
||||
// --port is an alias for --backend-port (the user-facing port in run/start).
|
||||
if (arg === "--port" || arg === "--backend-port") {
|
||||
opts.backendPort = parsePort(takeValue(argv, i, arg), arg);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--port=") || arg.startsWith("--backend-port=")) {
|
||||
const flag = arg.startsWith("--port=") ? "--port" : "--backend-port";
|
||||
opts.backendPort = parsePort(arg.slice(flag.length + 1), flag);
|
||||
continue;
|
||||
}
|
||||
if (arg === "--web-internal-port") {
|
||||
opts.webPort = parsePort(takeValue(argv, i, "--web-internal-port"), "--web-internal-port");
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--web-internal-port=")) {
|
||||
opts.webPort = parsePort(arg.slice("--web-internal-port=".length), "--web-internal-port");
|
||||
continue;
|
||||
}
|
||||
if (arg === "--web-port") {
|
||||
opts.webPort = parsePort(takeValue(argv, i, "--web-port"), "--web-port");
|
||||
noteDeprecated("--web-port");
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--web-port=")) {
|
||||
opts.webPort = parsePort(arg.slice("--web-port=".length), "--web-port");
|
||||
noteDeprecated("--web-port");
|
||||
continue;
|
||||
}
|
||||
if (arg === "--verbose" || arg === "-v") {
|
||||
opts.verbose = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--debug") {
|
||||
opts.debug = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return { options: opts, showHelp, deprecatedFlags };
|
||||
}
|
||||
|
||||
function takeValue(argv: string[], i: number, flag: string): string {
|
||||
const v = argv[i + 1];
|
||||
if (v === undefined || v.startsWith("-")) {
|
||||
throw new ParseError(`${flag} requires a value`);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
function parsePort(raw: string, flag: string): number {
|
||||
const n = Number(raw);
|
||||
if (raw === "" || !Number.isInteger(n) || n < 1 || n > 65535) {
|
||||
throw new ParseError(`${flag} value must be an integer between 1 and 65535, got "${raw}"`);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
export type ResolvedPorts = {
|
||||
backendPort?: number;
|
||||
webPort?: number;
|
||||
};
|
||||
|
||||
// CLI flags beat env vars; KANDEV_PORT is an alias for KANDEV_BACKEND_PORT.
|
||||
export function resolvePorts(options: CliOptions, env: NodeJS.ProcessEnv): ResolvedPorts {
|
||||
return {
|
||||
backendPort:
|
||||
options.backendPort ?? envPort(env, "KANDEV_BACKEND_PORT") ?? envPort(env, "KANDEV_PORT"),
|
||||
webPort: options.webPort ?? envPort(env, "KANDEV_WEB_PORT"),
|
||||
};
|
||||
}
|
||||
|
||||
function envPort(env: NodeJS.ProcessEnv, name: string): number | undefined {
|
||||
const val = env[name];
|
||||
if (val === undefined) return undefined;
|
||||
const n = Number(val);
|
||||
if (val === "" || !Number.isInteger(n) || n < 1 || n > 65535) {
|
||||
throw new ParseError(`${name} must be an integer between 1 and 65535, got "${val}"`);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
+50
-94
@@ -2,32 +2,22 @@ import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
|
||||
import pkg from "../package.json";
|
||||
import { parseArgs, ParseError, resolvePorts } from "./args";
|
||||
import { runDev } from "./dev";
|
||||
import { runRelease } from "./run";
|
||||
import { runStart } from "./start";
|
||||
import { ensureValidPort } from "./ports";
|
||||
import { maybePromptForUpdate } from "./update";
|
||||
|
||||
type Command = "run" | "dev" | "start";
|
||||
|
||||
type CliOptions = {
|
||||
command: Command;
|
||||
version?: string;
|
||||
backendPort?: number;
|
||||
webPort?: number;
|
||||
verbose?: boolean;
|
||||
debug?: boolean;
|
||||
};
|
||||
|
||||
function printHelp() {
|
||||
console.log(`kandev launcher
|
||||
|
||||
Usage:
|
||||
kandev run [--version <tag>] [--backend-port <port>] [--web-port <port>] [--verbose] [--debug]
|
||||
kandev dev [--backend-port <port>] [--web-port <port>]
|
||||
kandev start [--backend-port <port>] [--web-port <port>] [--verbose] [--debug]
|
||||
kandev [--version <tag>] [--backend-port <port>] [--web-port <port>] [--verbose] [--debug]
|
||||
kandev --dev [--backend-port <port>] [--web-port <port>]
|
||||
kandev run [--version <tag>] [--port <port>] [--verbose] [--debug]
|
||||
kandev dev [--port <port>]
|
||||
kandev start [--port <port>] [--verbose] [--debug]
|
||||
kandev [--version <tag>] [--port <port>] [--verbose] [--debug]
|
||||
kandev --dev [--port <port>]
|
||||
|
||||
Examples:
|
||||
kandev
|
||||
@@ -36,83 +26,31 @@ Examples:
|
||||
kandev dev
|
||||
kandev start
|
||||
kandev --version v0.1.0
|
||||
kandev --backend-port 18080 --web-port 13000
|
||||
kandev --port 3000
|
||||
kandev --debug
|
||||
|
||||
Options:
|
||||
dev Use local repo for dev (make dev + next dev) if available.
|
||||
start Use local production build (make build + next start).
|
||||
run Use release bundles (default).
|
||||
dev Use local repo for dev (make dev + next dev) if available.
|
||||
start Use local production build (make build + next start).
|
||||
run Use release bundles (default).
|
||||
--dev Alias for "dev".
|
||||
--version Release tag to install (default: latest).
|
||||
--backend-port Override backend port (or KANDEV_BACKEND_PORT env var).
|
||||
--web-port Override web port (or KANDEV_WEB_PORT env var).
|
||||
--port Port for the Go backend (the URL kandev opens on in
|
||||
start/run). Alias for --backend-port. Also reads
|
||||
KANDEV_PORT or KANDEV_BACKEND_PORT.
|
||||
--verbose, -v Show info logs from backend + web.
|
||||
--debug Show debug logs + agent message dumps.
|
||||
--help, -h Show help.
|
||||
|
||||
Advanced:
|
||||
--backend-port Same as --port.
|
||||
--web-internal-port Override the internal Next.js port. The Go backend
|
||||
reverse-proxies to it; users hit the backend port.
|
||||
Also reads KANDEV_WEB_PORT.
|
||||
--web-port Deprecated alias for --web-internal-port.
|
||||
`);
|
||||
}
|
||||
|
||||
function parseArgs(argv: string[]): CliOptions {
|
||||
const opts: CliOptions = { command: "run" };
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
const arg = argv[i];
|
||||
if (arg === "--help" || arg === "-h") {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
if (arg === "dev" || arg === "run" || arg === "start") {
|
||||
opts.command = arg;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--version") {
|
||||
opts.version = argv[i + 1];
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--version=")) {
|
||||
opts.version = arg.split("=")[1];
|
||||
continue;
|
||||
}
|
||||
if (arg === "--dev") {
|
||||
opts.command = "dev";
|
||||
continue;
|
||||
}
|
||||
if (arg === "--backend-port") {
|
||||
opts.backendPort = Number(argv[i + 1]);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--backend-port=")) {
|
||||
opts.backendPort = Number(arg.split("=")[1]);
|
||||
continue;
|
||||
}
|
||||
if (arg === "--web-port") {
|
||||
opts.webPort = Number(argv[i + 1]);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("--web-port=")) {
|
||||
opts.webPort = Number(arg.split("=")[1]);
|
||||
continue;
|
||||
}
|
||||
if (arg === "--verbose" || arg === "-v") {
|
||||
opts.verbose = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--debug") {
|
||||
opts.debug = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
function envPort(name: string): number | undefined {
|
||||
const val = process.env[name];
|
||||
return val ? Number(val) : undefined;
|
||||
}
|
||||
|
||||
function findRepoRoot(startDir: string): string | null {
|
||||
let current = path.resolve(startDir);
|
||||
while (true) {
|
||||
@@ -137,14 +75,21 @@ function findRepoRoot(startDir: string): string | null {
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const raw = parseArgs(process.argv.slice(2));
|
||||
const backendPort = ensureValidPort(
|
||||
raw.backendPort ?? envPort("KANDEV_BACKEND_PORT"),
|
||||
"backend port",
|
||||
);
|
||||
const webPort = ensureValidPort(raw.webPort ?? envPort("KANDEV_WEB_PORT"), "web port");
|
||||
const { options, showHelp, deprecatedFlags } = parseArgs(process.argv.slice(2));
|
||||
if (showHelp) {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (raw.command === "dev") {
|
||||
for (const flag of deprecatedFlags) {
|
||||
process.stderr.write(`[kandev] ${flag} is deprecated; use --web-internal-port\n`);
|
||||
}
|
||||
|
||||
const resolved = resolvePorts(options, process.env);
|
||||
const backendPort = ensureValidPort(resolved.backendPort, "backend port");
|
||||
const webPort = ensureValidPort(resolved.webPort, "web port");
|
||||
|
||||
if (options.command === "dev") {
|
||||
const repoRoot = findRepoRoot(process.cwd());
|
||||
if (!repoRoot) {
|
||||
throw new Error("Unable to locate repo root for dev. Run from the repo.");
|
||||
@@ -153,26 +98,37 @@ async function main(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (raw.command === "start") {
|
||||
if (options.command === "start") {
|
||||
const repoRoot = findRepoRoot(process.cwd());
|
||||
if (!repoRoot) {
|
||||
throw new Error("Unable to locate repo root for start. Run from the repo.");
|
||||
}
|
||||
await runStart({ repoRoot, backendPort, webPort, verbose: raw.verbose, debug: raw.debug });
|
||||
await runStart({
|
||||
repoRoot,
|
||||
backendPort,
|
||||
webPort,
|
||||
verbose: options.verbose,
|
||||
debug: options.debug,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await maybePromptForUpdate(pkg.version, process.argv.slice(2));
|
||||
await runRelease({
|
||||
version: raw.version,
|
||||
version: options.version,
|
||||
backendPort,
|
||||
webPort,
|
||||
verbose: raw.verbose,
|
||||
debug: raw.debug,
|
||||
verbose: options.verbose,
|
||||
debug: options.debug,
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
if (err instanceof ParseError) {
|
||||
console.error(`[kandev] ${err.message}`);
|
||||
console.error("[kandev] run --help for usage");
|
||||
process.exit(2);
|
||||
}
|
||||
console.error(`[kandev] ${err instanceof Error ? err.message : String(err)}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
+2
-2
@@ -27,6 +27,7 @@ export async function runDev({ repoRoot, backendPort, webPort }: DevOptions): Pr
|
||||
const webEnv = buildWebEnv({ ports, debug: true });
|
||||
const logLevel =
|
||||
process.env.KANDEV_LOGGING_LEVEL?.trim() || process.env.KANDEV_LOG_LEVEL?.trim() || "info";
|
||||
const webUrl = `http://localhost:${ports.webPort}`;
|
||||
|
||||
logStartupInfo({
|
||||
header: "dev mode: using local repo",
|
||||
@@ -52,7 +53,6 @@ export async function runDev({ repoRoot, backendPort, webPort }: DevOptions): Pr
|
||||
await waitForHealth(ports.backendUrl, backendProc, healthTimeoutMs);
|
||||
console.log(`[kandev] backend ready at ${ports.backendUrl}`);
|
||||
|
||||
const webUrl = `http://localhost:${ports.webPort}`;
|
||||
console.log("[kandev] starting web...");
|
||||
const webProc = launchWebApp({
|
||||
command: "pnpm",
|
||||
@@ -63,7 +63,7 @@ export async function runDev({ repoRoot, backendPort, webPort }: DevOptions): Pr
|
||||
label: "web",
|
||||
});
|
||||
await waitForUrlReady(webUrl, webProc, healthTimeoutMs);
|
||||
console.log(`[kandev] web ready at ${webUrl}`);
|
||||
console.log(`[kandev] open: ${webUrl}`);
|
||||
openBrowser(webUrl);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -318,6 +318,6 @@ export async function runRelease({
|
||||
quiet: !prepared.showOutput,
|
||||
});
|
||||
await waitForUrlReady(webUrl, webProc, healthTimeoutMs);
|
||||
console.log("[kandev] ready at " + prepared.backendUrl);
|
||||
console.log("[kandev] open: " + prepared.backendUrl);
|
||||
openBrowser(prepared.backendUrl);
|
||||
}
|
||||
|
||||
@@ -120,10 +120,13 @@ export type StartupInfoOptions = {
|
||||
*/
|
||||
export function logStartupInfo(options: StartupInfoOptions): void {
|
||||
const { header, ports, dbPath, logLevel } = options;
|
||||
const backendUrl = ports.backendUrl;
|
||||
const webUrl = `http://localhost:${ports.webPort}`;
|
||||
console.log(`[kandev] ${header}`);
|
||||
console.log("[kandev] url: http://localhost:" + ports.backendPort);
|
||||
console.log("[kandev] backend:", backendUrl);
|
||||
console.log("[kandev] web:", webUrl);
|
||||
console.log("[kandev] agentctl port:", ports.agentctlPort);
|
||||
console.log("[kandev] mcp url:", `http://localhost:${ports.backendPort}/mcp`);
|
||||
console.log("[kandev] mcp url:", `${backendUrl}/mcp`);
|
||||
if (dbPath) {
|
||||
console.log("[kandev] db path:", dbPath);
|
||||
}
|
||||
|
||||
@@ -207,6 +207,6 @@ export async function runStart({
|
||||
});
|
||||
|
||||
await waitForUrlReady(webUrl, webProc, healthTimeoutMs);
|
||||
console.log("[kandev] ready at " + ports.backendUrl);
|
||||
console.log("[kandev] open: " + ports.backendUrl);
|
||||
openBrowser(ports.backendUrl);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user