@hacksmith/doraval 0.2.44 → 0.2.45
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/README.md +11 -0
- package/bin/doraval.js +95 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,17 @@ doraval journal update # pull latest from remote
|
|
|
144
144
|
|
|
145
145
|
Requires the GitHub CLI (`gh`). Journal lives in a private GitHub repo you control.
|
|
146
146
|
|
|
147
|
+
### `ui` — Local dashboard (avoid typing repetitive commands)
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
doraval ui # start the web dashboard (opens browser)
|
|
151
|
+
doraval ui --port 4921 # different port
|
|
152
|
+
doraval ui --status # check if running + show URL
|
|
153
|
+
doraval ui --force # force restart
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Re-running `doraval ui` is now idempotent (uses PID tracking). Use `--force` to restart.
|
|
157
|
+
|
|
147
158
|
doraval update # self-update doraval to the latest version
|
|
148
159
|
doraval claude new # interactive wizard for skills/plugins (follows official table)
|
|
149
160
|
|
package/bin/doraval.js
CHANGED
|
@@ -599,7 +599,7 @@ var init_dist = __esm(() => {
|
|
|
599
599
|
var require_package = __commonJS((exports, module) => {
|
|
600
600
|
module.exports = {
|
|
601
601
|
name: "@hacksmith/doraval",
|
|
602
|
-
version: "0.2.
|
|
602
|
+
version: "0.2.45",
|
|
603
603
|
author: "Saif",
|
|
604
604
|
repository: {
|
|
605
605
|
type: "git",
|
|
@@ -4367,7 +4367,7 @@ var exports_ui = {};
|
|
|
4367
4367
|
__export(exports_ui, {
|
|
4368
4368
|
default: () => ui_default
|
|
4369
4369
|
});
|
|
4370
|
-
import { existsSync as existsSync19, readdirSync as readdirSync9 } from "fs";
|
|
4370
|
+
import { existsSync as existsSync19, readdirSync as readdirSync9, writeFileSync as writeFileSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync2 } from "fs";
|
|
4371
4371
|
import { join as join18 } from "path";
|
|
4372
4372
|
import { spawn } from "child_process";
|
|
4373
4373
|
function slugify2(title) {
|
|
@@ -4457,6 +4457,34 @@ async function killPort(port) {
|
|
|
4457
4457
|
await new Promise((r) => setTimeout(r, 400));
|
|
4458
4458
|
} catch {}
|
|
4459
4459
|
}
|
|
4460
|
+
function readPid() {
|
|
4461
|
+
const file = getPidFile();
|
|
4462
|
+
if (!existsSync19(file))
|
|
4463
|
+
return null;
|
|
4464
|
+
try {
|
|
4465
|
+
const raw = readFileSync2(file, "utf8").trim();
|
|
4466
|
+
const pid = parseInt(raw, 10);
|
|
4467
|
+
if (isNaN(pid))
|
|
4468
|
+
return null;
|
|
4469
|
+
process.kill(pid, 0);
|
|
4470
|
+
return pid;
|
|
4471
|
+
} catch {
|
|
4472
|
+
try {
|
|
4473
|
+
unlinkSync2(file);
|
|
4474
|
+
} catch {}
|
|
4475
|
+
return null;
|
|
4476
|
+
}
|
|
4477
|
+
}
|
|
4478
|
+
function writePid(pid) {
|
|
4479
|
+
ensureDoravalDirs();
|
|
4480
|
+
writeFileSync6(getPidFile(), String(pid) + `
|
|
4481
|
+
`);
|
|
4482
|
+
}
|
|
4483
|
+
function removePid() {
|
|
4484
|
+
try {
|
|
4485
|
+
unlinkSync2(getPidFile());
|
|
4486
|
+
} catch {}
|
|
4487
|
+
}
|
|
4460
4488
|
async function getDashboardHtml() {
|
|
4461
4489
|
const isSource = import.meta.url.includes("/src/");
|
|
4462
4490
|
const htmlPath = isSource ? new URL("../../ui/index.html", import.meta.url) : new URL("./ui/index.html", import.meta.url);
|
|
@@ -4467,7 +4495,7 @@ async function getDashboardHtml() {
|
|
|
4467
4495
|
return `<!doctype html><meta charset="utf-8"><body style="font-family:monospace;background:#111;color:#ddd;padding:2rem"><h1>doraval ui</h1><p>Dashboard HTML missing.</p><pre>${String(err)}</pre></body>`;
|
|
4468
4496
|
}
|
|
4469
4497
|
}
|
|
4470
|
-
var import_picocolors16, DEFAULT_PORT = 3737, ui_default;
|
|
4498
|
+
var import_picocolors16, DEFAULT_PORT = 3737, getPidFile = () => join18(getDoravalDir(), "ui.pid"), ui_default;
|
|
4471
4499
|
var init_ui = __esm(() => {
|
|
4472
4500
|
init_journal_config();
|
|
4473
4501
|
init_journal_parse();
|
|
@@ -4479,7 +4507,42 @@ var init_ui = __esm(() => {
|
|
|
4479
4507
|
const port = Number(args.port) || DEFAULT_PORT;
|
|
4480
4508
|
const host = args.host || "127.0.0.1";
|
|
4481
4509
|
const shouldOpen = args.open !== false;
|
|
4482
|
-
|
|
4510
|
+
const showStatusOnly = !!args.status;
|
|
4511
|
+
const force = !!args.force;
|
|
4512
|
+
ensureDoravalDirs();
|
|
4513
|
+
const existingPid = readPid();
|
|
4514
|
+
if (showStatusOnly) {
|
|
4515
|
+
if (existingPid) {
|
|
4516
|
+
const url2 = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
|
|
4517
|
+
console.error(` Dashboard running (pid ${existingPid})`);
|
|
4518
|
+
console.error(` URL: ${import_picocolors16.default.underline(import_picocolors16.default.cyan(url2))}`);
|
|
4519
|
+
} else {
|
|
4520
|
+
console.error(` No dashboard running.`);
|
|
4521
|
+
}
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4524
|
+
if (existingPid && !force) {
|
|
4525
|
+
const url2 = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
|
|
4526
|
+
console.error(` Dashboard already running (pid ${existingPid}).`);
|
|
4527
|
+
console.error(` URL: ${import_picocolors16.default.underline(import_picocolors16.default.cyan(url2))}`);
|
|
4528
|
+
if (shouldOpen && process.stdout.isTTY) {
|
|
4529
|
+
try {
|
|
4530
|
+
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
4531
|
+
spawn(opener, [url2], { stdio: "ignore", detached: true }).unref();
|
|
4532
|
+
} catch {}
|
|
4533
|
+
}
|
|
4534
|
+
return;
|
|
4535
|
+
}
|
|
4536
|
+
if (existingPid && force) {
|
|
4537
|
+
console.error(` Force restarting (killing pid ${existingPid})...`);
|
|
4538
|
+
try {
|
|
4539
|
+
process.kill(existingPid, "SIGTERM");
|
|
4540
|
+
} catch {}
|
|
4541
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
4542
|
+
removePid();
|
|
4543
|
+
} else if (!existingPid) {
|
|
4544
|
+
await killPort(port);
|
|
4545
|
+
}
|
|
4483
4546
|
const config = await readConfig();
|
|
4484
4547
|
let project = resolveProjectName(config) ?? undefined;
|
|
4485
4548
|
if (project) {
|
|
@@ -4588,6 +4651,7 @@ var init_ui = __esm(() => {
|
|
|
4588
4651
|
}
|
|
4589
4652
|
});
|
|
4590
4653
|
const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${server.port}`;
|
|
4654
|
+
writePid(process.pid);
|
|
4591
4655
|
const msg = `
|
|
4592
4656
|
${import_picocolors16.default.blue("\u25C9")} dora local dashboard
|
|
4593
4657
|
${import_picocolors16.default.dim("Project:")} ${project ? import_picocolors16.default.white(project) : import_picocolors16.default.yellow("none (run dora init)")}
|
|
@@ -4604,12 +4668,15 @@ var init_ui = __esm(() => {
|
|
|
4604
4668
|
console.error(import_picocolors16.default.dim(` Could not auto-open. Visit ${url}`));
|
|
4605
4669
|
}
|
|
4606
4670
|
}
|
|
4607
|
-
|
|
4671
|
+
const cleanup = () => {
|
|
4672
|
+
removePid();
|
|
4608
4673
|
console.error(`
|
|
4609
4674
|
Stopping dashboard...`);
|
|
4610
4675
|
server.stop();
|
|
4611
4676
|
process.exit(0);
|
|
4612
|
-
}
|
|
4677
|
+
};
|
|
4678
|
+
process.on("SIGINT", cleanup);
|
|
4679
|
+
process.on("SIGTERM", cleanup);
|
|
4613
4680
|
}
|
|
4614
4681
|
};
|
|
4615
4682
|
});
|
|
@@ -7733,7 +7800,7 @@ var exports_completion = {};
|
|
|
7733
7800
|
__export(exports_completion, {
|
|
7734
7801
|
default: () => completion_default
|
|
7735
7802
|
});
|
|
7736
|
-
var commands, subCommands, completion_default;
|
|
7803
|
+
var commands, uiFlags, subCommands, completion_default;
|
|
7737
7804
|
var init_completion = __esm(() => {
|
|
7738
7805
|
init_dist();
|
|
7739
7806
|
commands = [
|
|
@@ -7750,6 +7817,7 @@ var init_completion = __esm(() => {
|
|
|
7750
7817
|
"cursor",
|
|
7751
7818
|
"copilot"
|
|
7752
7819
|
];
|
|
7820
|
+
uiFlags = ["--port", "--open", "--no-open", "--host", "--status", "--force"];
|
|
7753
7821
|
subCommands = {
|
|
7754
7822
|
skill: ["validate", "drift", "judge"],
|
|
7755
7823
|
journal: ["init", "list", "context", "hook", "update", "add", "sync"],
|
|
@@ -7788,6 +7856,7 @@ _doraval_completions() {
|
|
|
7788
7856
|
skill) COMPREPLY=( $(compgen -W "${subCommands.skill.join(" ")}" -- "$cur") ) ;;
|
|
7789
7857
|
journal) COMPREPLY=( $(compgen -W "${subCommands.journal.join(" ")}" -- "$cur") ) ;;
|
|
7790
7858
|
hook) COMPREPLY=( $(compgen -W "${subCommands.hook.join(" ")}" -- "$cur") ) ;;
|
|
7859
|
+
ui) COMPREPLY=( $(compgen -W "${uiFlags.join(" ")}" -- "$cur") ) ;;
|
|
7791
7860
|
claude|codex|cursor|copilot) COMPREPLY=( $(compgen -W "${subCommands.claude.join(" ")}" -- "$cur") ) ;;
|
|
7792
7861
|
esac
|
|
7793
7862
|
fi
|
|
@@ -7820,6 +7889,9 @@ _doraval() {
|
|
|
7820
7889
|
hook)
|
|
7821
7890
|
_describe 'subcommand' (enable disable status)
|
|
7822
7891
|
;;
|
|
7892
|
+
ui)
|
|
7893
|
+
_describe 'flag' (${uiFlags})
|
|
7894
|
+
;;
|
|
7823
7895
|
claude|codex|cursor|copilot)
|
|
7824
7896
|
_describe 'subcommand' (new bump)
|
|
7825
7897
|
;;
|
|
@@ -7838,6 +7910,12 @@ complete -c doraval -n '__fish_use_subcommand' -a 'validate init bump update pro
|
|
|
7838
7910
|
complete -c doraval -n '__fish_seen_subcommand_from skill' -a 'validate drift judge'
|
|
7839
7911
|
complete -c doraval -n '__fish_seen_subcommand_from journal' -a 'init list context hook update add sync'
|
|
7840
7912
|
complete -c doraval -n '__fish_seen_subcommand_from hook' -a 'enable disable status'
|
|
7913
|
+
complete -c doraval -n '__fish_seen_subcommand_from ui' -l port -d 'Port'
|
|
7914
|
+
complete -c doraval -n '__fish_seen_subcommand_from ui' -l open -d 'Open browser'
|
|
7915
|
+
complete -c doraval -n '__fish_seen_subcommand_from ui' -l no-open -d 'Do not open browser'
|
|
7916
|
+
complete -c doraval -n '__fish_seen_subcommand_from ui' -l host -d 'Host'
|
|
7917
|
+
complete -c doraval -n '__fish_seen_subcommand_from ui' -l status -d 'Show status only'
|
|
7918
|
+
complete -c doraval -n '__fish_seen_subcommand_from ui' -l force -d 'Force restart'
|
|
7841
7919
|
complete -c doraval -n '__fish_seen_subcommand_from claude codex cursor copilot' -a 'new bump'
|
|
7842
7920
|
`);
|
|
7843
7921
|
} else {
|
|
@@ -7975,6 +8053,16 @@ var ui2 = defineCommand({
|
|
|
7975
8053
|
type: "string",
|
|
7976
8054
|
description: "Host to bind (default 127.0.0.1 for local only)",
|
|
7977
8055
|
default: "127.0.0.1"
|
|
8056
|
+
},
|
|
8057
|
+
status: {
|
|
8058
|
+
type: "boolean",
|
|
8059
|
+
description: "Check if a dashboard is running and print its URL (no start)",
|
|
8060
|
+
default: false
|
|
8061
|
+
},
|
|
8062
|
+
force: {
|
|
8063
|
+
type: "boolean",
|
|
8064
|
+
description: "Force start/restart even if one is already running",
|
|
8065
|
+
default: false
|
|
7978
8066
|
}
|
|
7979
8067
|
},
|
|
7980
8068
|
async run({ args }) {
|