@hacksmith/doraval 0.2.43 → 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 +12 -1
- package/bin/doraval.js +103 -16
- 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
|
|
|
@@ -168,7 +179,7 @@ Exits with code `1` when errors are found. Pipe `--format json` output to `jq` o
|
|
|
168
179
|
|
|
169
180
|
## Providers
|
|
170
181
|
|
|
171
|
-
Claude Code
|
|
182
|
+
Claude Code, Cursor, Codex, and Copilot CLI validators and scaffolding built in. OpenCode support is experimental.
|
|
172
183
|
|
|
173
184
|
## Links
|
|
174
185
|
|
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",
|
|
@@ -1719,19 +1719,17 @@ var init_list = __esm(() => {
|
|
|
1719
1719
|
if (!args.all) {
|
|
1720
1720
|
allEntries = allEntries.filter((e) => e.status === "active");
|
|
1721
1721
|
}
|
|
1722
|
-
|
|
1722
|
+
let staged = [];
|
|
1723
1723
|
try {
|
|
1724
1724
|
const pdir = getPendingProjectDir(project);
|
|
1725
1725
|
if (existsSync4(pdir)) {
|
|
1726
1726
|
const files = readdirSync(pdir).filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
1727
|
-
|
|
1727
|
+
const stagedResults = await Promise.all(files.map(async (f) => {
|
|
1728
1728
|
const txt = await Bun.file(join3(pdir, f)).text();
|
|
1729
1729
|
const parsed = parseJournalEntries(txt);
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1730
|
+
return parsed.map((e) => ({ ...e, _staged: true }));
|
|
1731
|
+
}));
|
|
1732
|
+
staged = stagedResults.flat();
|
|
1735
1733
|
}
|
|
1736
1734
|
} catch {}
|
|
1737
1735
|
if (args.format === "json") {
|
|
@@ -4369,7 +4367,7 @@ var exports_ui = {};
|
|
|
4369
4367
|
__export(exports_ui, {
|
|
4370
4368
|
default: () => ui_default
|
|
4371
4369
|
});
|
|
4372
|
-
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";
|
|
4373
4371
|
import { join as join18 } from "path";
|
|
4374
4372
|
import { spawn } from "child_process";
|
|
4375
4373
|
function slugify2(title) {
|
|
@@ -4459,6 +4457,34 @@ async function killPort(port) {
|
|
|
4459
4457
|
await new Promise((r) => setTimeout(r, 400));
|
|
4460
4458
|
} catch {}
|
|
4461
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
|
+
}
|
|
4462
4488
|
async function getDashboardHtml() {
|
|
4463
4489
|
const isSource = import.meta.url.includes("/src/");
|
|
4464
4490
|
const htmlPath = isSource ? new URL("../../ui/index.html", import.meta.url) : new URL("./ui/index.html", import.meta.url);
|
|
@@ -4469,7 +4495,7 @@ async function getDashboardHtml() {
|
|
|
4469
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>`;
|
|
4470
4496
|
}
|
|
4471
4497
|
}
|
|
4472
|
-
var import_picocolors16, DEFAULT_PORT = 3737, ui_default;
|
|
4498
|
+
var import_picocolors16, DEFAULT_PORT = 3737, getPidFile = () => join18(getDoravalDir(), "ui.pid"), ui_default;
|
|
4473
4499
|
var init_ui = __esm(() => {
|
|
4474
4500
|
init_journal_config();
|
|
4475
4501
|
init_journal_parse();
|
|
@@ -4481,7 +4507,42 @@ var init_ui = __esm(() => {
|
|
|
4481
4507
|
const port = Number(args.port) || DEFAULT_PORT;
|
|
4482
4508
|
const host = args.host || "127.0.0.1";
|
|
4483
4509
|
const shouldOpen = args.open !== false;
|
|
4484
|
-
|
|
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
|
+
}
|
|
4485
4546
|
const config = await readConfig();
|
|
4486
4547
|
let project = resolveProjectName(config) ?? undefined;
|
|
4487
4548
|
if (project) {
|
|
@@ -4590,6 +4651,7 @@ var init_ui = __esm(() => {
|
|
|
4590
4651
|
}
|
|
4591
4652
|
});
|
|
4592
4653
|
const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${server.port}`;
|
|
4654
|
+
writePid(process.pid);
|
|
4593
4655
|
const msg = `
|
|
4594
4656
|
${import_picocolors16.default.blue("\u25C9")} dora local dashboard
|
|
4595
4657
|
${import_picocolors16.default.dim("Project:")} ${project ? import_picocolors16.default.white(project) : import_picocolors16.default.yellow("none (run dora init)")}
|
|
@@ -4606,12 +4668,15 @@ var init_ui = __esm(() => {
|
|
|
4606
4668
|
console.error(import_picocolors16.default.dim(` Could not auto-open. Visit ${url}`));
|
|
4607
4669
|
}
|
|
4608
4670
|
}
|
|
4609
|
-
|
|
4671
|
+
const cleanup = () => {
|
|
4672
|
+
removePid();
|
|
4610
4673
|
console.error(`
|
|
4611
4674
|
Stopping dashboard...`);
|
|
4612
4675
|
server.stop();
|
|
4613
4676
|
process.exit(0);
|
|
4614
|
-
}
|
|
4677
|
+
};
|
|
4678
|
+
process.on("SIGINT", cleanup);
|
|
4679
|
+
process.on("SIGTERM", cleanup);
|
|
4615
4680
|
}
|
|
4616
4681
|
};
|
|
4617
4682
|
});
|
|
@@ -7735,7 +7800,7 @@ var exports_completion = {};
|
|
|
7735
7800
|
__export(exports_completion, {
|
|
7736
7801
|
default: () => completion_default
|
|
7737
7802
|
});
|
|
7738
|
-
var commands, subCommands, completion_default;
|
|
7803
|
+
var commands, uiFlags, subCommands, completion_default;
|
|
7739
7804
|
var init_completion = __esm(() => {
|
|
7740
7805
|
init_dist();
|
|
7741
7806
|
commands = [
|
|
@@ -7746,11 +7811,13 @@ var init_completion = __esm(() => {
|
|
|
7746
7811
|
"providers",
|
|
7747
7812
|
"skill",
|
|
7748
7813
|
"journal",
|
|
7814
|
+
"ui",
|
|
7749
7815
|
"claude",
|
|
7750
7816
|
"codex",
|
|
7751
7817
|
"cursor",
|
|
7752
7818
|
"copilot"
|
|
7753
7819
|
];
|
|
7820
|
+
uiFlags = ["--port", "--open", "--no-open", "--host", "--status", "--force"];
|
|
7754
7821
|
subCommands = {
|
|
7755
7822
|
skill: ["validate", "drift", "judge"],
|
|
7756
7823
|
journal: ["init", "list", "context", "hook", "update", "add", "sync"],
|
|
@@ -7789,6 +7856,7 @@ _doraval_completions() {
|
|
|
7789
7856
|
skill) COMPREPLY=( $(compgen -W "${subCommands.skill.join(" ")}" -- "$cur") ) ;;
|
|
7790
7857
|
journal) COMPREPLY=( $(compgen -W "${subCommands.journal.join(" ")}" -- "$cur") ) ;;
|
|
7791
7858
|
hook) COMPREPLY=( $(compgen -W "${subCommands.hook.join(" ")}" -- "$cur") ) ;;
|
|
7859
|
+
ui) COMPREPLY=( $(compgen -W "${uiFlags.join(" ")}" -- "$cur") ) ;;
|
|
7792
7860
|
claude|codex|cursor|copilot) COMPREPLY=( $(compgen -W "${subCommands.claude.join(" ")}" -- "$cur") ) ;;
|
|
7793
7861
|
esac
|
|
7794
7862
|
fi
|
|
@@ -7801,7 +7869,7 @@ complete -F _doraval_completions doraval
|
|
|
7801
7869
|
|
|
7802
7870
|
_doraval() {
|
|
7803
7871
|
local -a commands sub
|
|
7804
|
-
commands=(validate init bump update providers skill journal claude codex cursor copilot)
|
|
7872
|
+
commands=(validate init bump update providers skill journal ui claude codex cursor copilot)
|
|
7805
7873
|
_arguments -C \\
|
|
7806
7874
|
'1: :->cmd' \\
|
|
7807
7875
|
'*::arg:->args'
|
|
@@ -7821,6 +7889,9 @@ _doraval() {
|
|
|
7821
7889
|
hook)
|
|
7822
7890
|
_describe 'subcommand' (enable disable status)
|
|
7823
7891
|
;;
|
|
7892
|
+
ui)
|
|
7893
|
+
_describe 'flag' (${uiFlags})
|
|
7894
|
+
;;
|
|
7824
7895
|
claude|codex|cursor|copilot)
|
|
7825
7896
|
_describe 'subcommand' (new bump)
|
|
7826
7897
|
;;
|
|
@@ -7834,11 +7905,17 @@ _doraval "$@"
|
|
|
7834
7905
|
} else if (shell === "fish") {
|
|
7835
7906
|
console.log(`# doraval fish completion
|
|
7836
7907
|
complete -c doraval -f
|
|
7837
|
-
complete -c doraval -n '__fish_use_subcommand' -a 'validate init bump update providers skill journal claude codex cursor copilot'
|
|
7908
|
+
complete -c doraval -n '__fish_use_subcommand' -a 'validate init bump update providers skill journal ui claude codex cursor copilot'
|
|
7838
7909
|
|
|
7839
7910
|
complete -c doraval -n '__fish_seen_subcommand_from skill' -a 'validate drift judge'
|
|
7840
7911
|
complete -c doraval -n '__fish_seen_subcommand_from journal' -a 'init list context hook update add sync'
|
|
7841
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'
|
|
7842
7919
|
complete -c doraval -n '__fish_seen_subcommand_from claude codex cursor copilot' -a 'new bump'
|
|
7843
7920
|
`);
|
|
7844
7921
|
} else {
|
|
@@ -7976,6 +8053,16 @@ var ui2 = defineCommand({
|
|
|
7976
8053
|
type: "string",
|
|
7977
8054
|
description: "Host to bind (default 127.0.0.1 for local only)",
|
|
7978
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
|
|
7979
8066
|
}
|
|
7980
8067
|
},
|
|
7981
8068
|
async run({ args }) {
|