@cavelang/cli 0.35.0 → 0.36.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/README.md +224 -12
- package/dist/internal/act/action.js +2 -1
- package/dist/internal/act/action.js.map +1 -1
- package/dist/internal/act/declare.d.ts.map +1 -1
- package/dist/internal/act/declare.js +82 -53
- package/dist/internal/act/declare.js.map +1 -1
- package/dist/internal/act/engine.d.ts +4 -3
- package/dist/internal/act/engine.d.ts.map +1 -1
- package/dist/internal/act/engine.js +121 -32
- package/dist/internal/act/engine.js.map +1 -1
- package/dist/internal/automate/cancellation.d.ts +3 -0
- package/dist/internal/automate/cancellation.d.ts.map +1 -0
- package/dist/internal/automate/cancellation.js +38 -0
- package/dist/internal/automate/cancellation.js.map +1 -0
- package/dist/internal/automate/declare.d.ts.map +1 -1
- package/dist/internal/automate/declare.js +49 -24
- package/dist/internal/automate/declare.js.map +1 -1
- package/dist/internal/automate/engine.d.ts +7 -3
- package/dist/internal/automate/engine.d.ts.map +1 -1
- package/dist/internal/automate/engine.js +196 -93
- package/dist/internal/automate/engine.js.map +1 -1
- package/dist/internal/automate/error-message.d.ts +3 -0
- package/dist/internal/automate/error-message.d.ts.map +1 -0
- package/dist/internal/automate/error-message.js +10 -0
- package/dist/internal/automate/error-message.js.map +1 -0
- package/dist/internal/automate/main.d.ts.map +1 -1
- package/dist/internal/automate/main.js +238 -35
- package/dist/internal/automate/main.js.map +1 -1
- package/dist/internal/automate/options.d.ts +4 -0
- package/dist/internal/automate/options.d.ts.map +1 -0
- package/dist/internal/automate/options.js +19 -0
- package/dist/internal/automate/options.js.map +1 -0
- package/dist/internal/connect/declared.d.ts +6 -27
- package/dist/internal/connect/declared.d.ts.map +1 -1
- package/dist/internal/connect/declared.js +165 -76
- package/dist/internal/connect/declared.js.map +1 -1
- package/dist/internal/connect/error-message.d.ts +3 -0
- package/dist/internal/connect/error-message.d.ts.map +1 -0
- package/dist/internal/connect/error-message.js +10 -0
- package/dist/internal/connect/error-message.js.map +1 -0
- package/dist/internal/connect/federation.d.ts +9 -0
- package/dist/internal/connect/federation.d.ts.map +1 -0
- package/dist/internal/connect/federation.js +19 -0
- package/dist/internal/connect/federation.js.map +1 -0
- package/dist/internal/connect/fetch-failure.d.ts +3 -0
- package/dist/internal/connect/fetch-failure.d.ts.map +1 -0
- package/dist/internal/connect/fetch-failure.js +36 -0
- package/dist/internal/connect/fetch-failure.js.map +1 -0
- package/dist/internal/connect/main.d.ts +1 -0
- package/dist/internal/connect/main.d.ts.map +1 -1
- package/dist/internal/connect/main.js +288 -114
- package/dist/internal/connect/main.js.map +1 -1
- package/dist/internal/connect/options.d.ts +3 -0
- package/dist/internal/connect/options.d.ts.map +1 -0
- package/dist/internal/connect/options.js +9 -0
- package/dist/internal/connect/options.js.map +1 -0
- package/dist/internal/connect/records.d.ts +3 -0
- package/dist/internal/connect/records.d.ts.map +1 -0
- package/dist/internal/connect/records.js +21 -0
- package/dist/internal/connect/records.js.map +1 -0
- package/dist/internal/connect/run.d.ts +1 -18
- package/dist/internal/connect/run.d.ts.map +1 -1
- package/dist/internal/connect/run.js +115 -55
- package/dist/internal/connect/run.js.map +1 -1
- package/dist/internal/connect/source.d.ts +3 -1
- package/dist/internal/connect/source.d.ts.map +1 -1
- package/dist/internal/connect/source.js +226 -47
- package/dist/internal/connect/source.js.map +1 -1
- package/dist/internal/connect/template.d.ts +2 -2
- package/dist/internal/connect/template.d.ts.map +1 -1
- package/dist/internal/connect/template.js +25 -9
- package/dist/internal/connect/template.js.map +1 -1
- package/dist/internal/connect/utf8.d.ts +3 -0
- package/dist/internal/connect/utf8.d.ts.map +1 -0
- package/dist/internal/connect/utf8.js +12 -0
- package/dist/internal/connect/utf8.js.map +1 -0
- package/dist/internal/eval/cleanup.d.ts +5 -0
- package/dist/internal/eval/cleanup.d.ts.map +1 -0
- package/dist/internal/eval/cleanup.js +50 -0
- package/dist/internal/eval/cleanup.js.map +1 -0
- package/dist/internal/eval/error-message.d.ts +3 -0
- package/dist/internal/eval/error-message.d.ts.map +1 -0
- package/dist/internal/eval/error-message.js +10 -0
- package/dist/internal/eval/error-message.js.map +1 -0
- package/dist/internal/eval/judge.d.ts.map +1 -1
- package/dist/internal/eval/judge.js +3 -31
- package/dist/internal/eval/judge.js.map +1 -1
- package/dist/internal/eval/loop.d.ts.map +1 -1
- package/dist/internal/eval/loop.js +18 -4
- package/dist/internal/eval/loop.js.map +1 -1
- package/dist/internal/eval/main.d.ts.map +1 -1
- package/dist/internal/eval/main.js +22 -10
- package/dist/internal/eval/main.js.map +1 -1
- package/dist/internal/eval/options.d.ts +6 -0
- package/dist/internal/eval/options.d.ts.map +1 -0
- package/dist/internal/eval/options.js +31 -0
- package/dist/internal/eval/options.js.map +1 -0
- package/dist/internal/eval/queries.d.ts.map +1 -1
- package/dist/internal/eval/queries.js +9 -6
- package/dist/internal/eval/queries.js.map +1 -1
- package/dist/internal/eval/run.d.ts.map +1 -1
- package/dist/internal/eval/run.js +112 -24
- package/dist/internal/eval/run.js.map +1 -1
- package/dist/internal/eval/score.d.ts.map +1 -1
- package/dist/internal/eval/score.js +9 -2
- package/dist/internal/eval/score.js.map +1 -1
- package/dist/internal/eval/suite.d.ts.map +1 -1
- package/dist/internal/eval/suite.js +14 -2
- package/dist/internal/eval/suite.js.map +1 -1
- package/dist/internal/ingest/cleanup.d.ts +5 -0
- package/dist/internal/ingest/cleanup.d.ts.map +1 -0
- package/dist/internal/ingest/cleanup.js +50 -0
- package/dist/internal/ingest/cleanup.js.map +1 -0
- package/dist/internal/ingest/content.d.ts +6 -0
- package/dist/internal/ingest/content.d.ts.map +1 -0
- package/dist/internal/ingest/content.js +25 -0
- package/dist/internal/ingest/content.js.map +1 -0
- package/dist/internal/ingest/context.d.ts.map +1 -1
- package/dist/internal/ingest/context.js +25 -7
- package/dist/internal/ingest/context.js.map +1 -1
- package/dist/internal/ingest/error-message.d.ts +3 -0
- package/dist/internal/ingest/error-message.d.ts.map +1 -0
- package/dist/internal/ingest/error-message.js +10 -0
- package/dist/internal/ingest/error-message.js.map +1 -0
- package/dist/internal/ingest/files.d.ts +4 -12
- package/dist/internal/ingest/files.d.ts.map +1 -1
- package/dist/internal/ingest/files.js +22 -10
- package/dist/internal/ingest/files.js.map +1 -1
- package/dist/internal/ingest/main.d.ts.map +1 -1
- package/dist/internal/ingest/main.js +46 -16
- package/dist/internal/ingest/main.js.map +1 -1
- package/dist/internal/ingest/options.d.ts +6 -0
- package/dist/internal/ingest/options.d.ts.map +1 -0
- package/dist/internal/ingest/options.js +27 -0
- package/dist/internal/ingest/options.js.map +1 -0
- package/dist/internal/ingest/prompt.d.ts.map +1 -1
- package/dist/internal/ingest/prompt.js +14 -10
- package/dist/internal/ingest/prompt.js.map +1 -1
- package/dist/internal/ingest/run.d.ts +9 -2
- package/dist/internal/ingest/run.d.ts.map +1 -1
- package/dist/internal/ingest/run.js +206 -62
- package/dist/internal/ingest/run.js.map +1 -1
- package/dist/internal/ingest/timeout.d.ts +3 -0
- package/dist/internal/ingest/timeout.d.ts.map +1 -0
- package/dist/internal/ingest/timeout.js +14 -0
- package/dist/internal/ingest/timeout.js.map +1 -0
- package/dist/internal/ingest/web.d.ts +2 -11
- package/dist/internal/ingest/web.d.ts.map +1 -1
- package/dist/internal/ingest/web.js +131 -25
- package/dist/internal/ingest/web.js.map +1 -1
- package/dist/internal/loop/budgets.d.ts +3 -0
- package/dist/internal/loop/budgets.d.ts.map +1 -0
- package/dist/internal/loop/budgets.js +10 -0
- package/dist/internal/loop/budgets.js.map +1 -0
- package/dist/internal/loop/index.d.ts +2 -0
- package/dist/internal/loop/index.d.ts.map +1 -1
- package/dist/internal/loop/index.js +2 -0
- package/dist/internal/loop/index.js.map +1 -1
- package/dist/internal/loop/json-answer.d.ts +7 -0
- package/dist/internal/loop/json-answer.d.ts.map +1 -0
- package/dist/internal/loop/json-answer.js +79 -0
- package/dist/internal/loop/json-answer.js.map +1 -0
- package/dist/internal/loop/json-spans.d.ts +3 -0
- package/dist/internal/loop/json-spans.d.ts.map +1 -0
- package/dist/internal/loop/json-spans.js +88 -0
- package/dist/internal/loop/json-spans.js.map +1 -0
- package/dist/internal/loop/llm.d.ts +3 -2
- package/dist/internal/loop/llm.d.ts.map +1 -1
- package/dist/internal/loop/llm.js +115 -32
- package/dist/internal/loop/llm.js.map +1 -1
- package/dist/internal/loop/process.d.ts +3 -1
- package/dist/internal/loop/process.d.ts.map +1 -1
- package/dist/internal/loop/process.js +159 -59
- package/dist/internal/loop/process.js.map +1 -1
- package/dist/internal/loop/read-snapshot.d.ts +4 -0
- package/dist/internal/loop/read-snapshot.d.ts.map +1 -0
- package/dist/internal/loop/read-snapshot.js +29 -0
- package/dist/internal/loop/read-snapshot.js.map +1 -0
- package/dist/internal/loop/reconstruct.d.ts +6 -5
- package/dist/internal/loop/reconstruct.d.ts.map +1 -1
- package/dist/internal/loop/reconstruct.js +19 -8
- package/dist/internal/loop/reconstruct.js.map +1 -1
- package/dist/internal/loop/score-settings.d.ts +5 -0
- package/dist/internal/loop/score-settings.d.ts.map +1 -0
- package/dist/internal/loop/score-settings.js +14 -0
- package/dist/internal/loop/score-settings.js.map +1 -0
- package/dist/internal/loop/sqlite.d.ts.map +1 -1
- package/dist/internal/loop/sqlite.js +15 -7
- package/dist/internal/loop/sqlite.js.map +1 -1
- package/dist/internal/loop/store.d.ts.map +1 -1
- package/dist/internal/loop/store.js +11 -7
- package/dist/internal/loop/store.js.map +1 -1
- package/dist/internal/loop/timeout.d.ts +3 -0
- package/dist/internal/loop/timeout.d.ts.map +1 -0
- package/dist/internal/loop/timeout.js +13 -0
- package/dist/internal/loop/timeout.js.map +1 -0
- package/dist/internal/mcp/error-message.d.ts +3 -0
- package/dist/internal/mcp/error-message.d.ts.map +1 -0
- package/dist/internal/mcp/error-message.js +10 -0
- package/dist/internal/mcp/error-message.js.map +1 -0
- package/dist/internal/mcp/main.d.ts.map +1 -1
- package/dist/internal/mcp/main.js +42 -27
- package/dist/internal/mcp/main.js.map +1 -1
- package/dist/internal/mcp/read-snapshot.d.ts +4 -0
- package/dist/internal/mcp/read-snapshot.d.ts.map +1 -0
- package/dist/internal/mcp/read-snapshot.js +22 -0
- package/dist/internal/mcp/read-snapshot.js.map +1 -0
- package/dist/internal/mcp/server.d.ts.map +1 -1
- package/dist/internal/mcp/server.js +181 -21
- package/dist/internal/mcp/server.js.map +1 -1
- package/dist/internal/mcp/source.d.ts +3 -0
- package/dist/internal/mcp/source.d.ts.map +1 -0
- package/dist/internal/mcp/source.js +13 -0
- package/dist/internal/mcp/source.js.map +1 -0
- package/dist/internal/mcp/tools.d.ts.map +1 -1
- package/dist/internal/mcp/tools.js +135 -72
- package/dist/internal/mcp/tools.js.map +1 -1
- package/dist/internal/rules/declarations.d.ts +6 -0
- package/dist/internal/rules/declarations.d.ts.map +1 -0
- package/dist/internal/rules/declarations.js +14 -0
- package/dist/internal/rules/declarations.js.map +1 -0
- package/dist/internal/rules/declare.d.ts.map +1 -1
- package/dist/internal/rules/declare.js +30 -16
- package/dist/internal/rules/declare.js.map +1 -1
- package/dist/internal/rules/engine.d.ts +8 -7
- package/dist/internal/rules/engine.d.ts.map +1 -1
- package/dist/internal/rules/engine.js +150 -44
- package/dist/internal/rules/engine.js.map +1 -1
- package/dist/internal/shape/alias-root.d.ts +3 -0
- package/dist/internal/shape/alias-root.d.ts.map +1 -0
- package/dist/internal/shape/alias-root.js +13 -0
- package/dist/internal/shape/alias-root.js.map +1 -0
- package/dist/internal/shape/check.d.ts +15 -3
- package/dist/internal/shape/check.d.ts.map +1 -1
- package/dist/internal/shape/check.js +230 -100
- package/dist/internal/shape/check.js.map +1 -1
- package/dist/internal/shape/client.d.ts.map +1 -1
- package/dist/internal/shape/client.js +42 -20
- package/dist/internal/shape/client.js.map +1 -1
- package/dist/internal/shape/constraints.d.ts +8 -0
- package/dist/internal/shape/constraints.d.ts.map +1 -0
- package/dist/internal/shape/constraints.js +17 -0
- package/dist/internal/shape/constraints.js.map +1 -0
- package/dist/internal/shape/edit-distance.d.ts +3 -0
- package/dist/internal/shape/edit-distance.d.ts.map +1 -0
- package/dist/internal/shape/edit-distance.js +33 -0
- package/dist/internal/shape/edit-distance.js.map +1 -0
- package/dist/internal/shape/gate.d.ts.map +1 -1
- package/dist/internal/shape/gate.js +0 -0
- package/dist/internal/shape/gate.js.map +1 -1
- package/dist/internal/shape/snapshot.d.ts +4 -0
- package/dist/internal/shape/snapshot.d.ts.map +1 -0
- package/dist/internal/shape/snapshot.js +20 -0
- package/dist/internal/shape/snapshot.js.map +1 -0
- package/dist/internal/shape/suggest.d.ts +8 -6
- package/dist/internal/shape/suggest.d.ts.map +1 -1
- package/dist/internal/shape/suggest.js +208 -92
- package/dist/internal/shape/suggest.js.map +1 -1
- package/dist/internal/sync/error-message.d.ts +3 -0
- package/dist/internal/sync/error-message.d.ts.map +1 -0
- package/dist/internal/sync/error-message.js +10 -0
- package/dist/internal/sync/error-message.js.map +1 -0
- package/dist/internal/sync/index.d.ts +3 -2
- package/dist/internal/sync/index.d.ts.map +1 -1
- package/dist/internal/sync/index.js +3 -2
- package/dist/internal/sync/index.js.map +1 -1
- package/dist/internal/sync/sync.d.ts +8 -5
- package/dist/internal/sync/sync.d.ts.map +1 -1
- package/dist/internal/sync/sync.js +322 -65
- package/dist/internal/sync/sync.js.map +1 -1
- package/dist/internal/view/api.d.ts +3 -1
- package/dist/internal/view/api.d.ts.map +1 -1
- package/dist/internal/view/api.js +154 -90
- package/dist/internal/view/api.js.map +1 -1
- package/dist/internal/view/error-message.d.ts +3 -0
- package/dist/internal/view/error-message.d.ts.map +1 -0
- package/dist/internal/view/error-message.js +10 -0
- package/dist/internal/view/error-message.js.map +1 -0
- package/dist/internal/view/main.d.ts.map +1 -1
- package/dist/internal/view/main.js +61 -8
- package/dist/internal/view/main.js.map +1 -1
- package/dist/internal/view/page.d.ts.map +1 -1
- package/dist/internal/view/page.js +119 -20
- package/dist/internal/view/page.js.map +1 -1
- package/dist/internal/view/report.d.ts.map +1 -1
- package/dist/internal/view/report.js +180 -145
- package/dist/internal/view/report.js.map +1 -1
- package/dist/internal/view/scope.d.ts +6 -2
- package/dist/internal/view/scope.d.ts.map +1 -1
- package/dist/internal/view/scope.js +107 -24
- package/dist/internal/view/scope.js.map +1 -1
- package/dist/internal/view/sensitivity.d.ts +4 -0
- package/dist/internal/view/sensitivity.d.ts.map +1 -0
- package/dist/internal/view/sensitivity.js +11 -0
- package/dist/internal/view/sensitivity.js.map +1 -0
- package/dist/internal/view/server.d.ts.map +1 -1
- package/dist/internal/view/server.js +57 -20
- package/dist/internal/view/server.js.map +1 -1
- package/dist/src/atomic-output.d.ts +3 -0
- package/dist/src/atomic-output.d.ts.map +1 -0
- package/dist/src/atomic-output.js +67 -0
- package/dist/src/atomic-output.js.map +1 -0
- package/dist/src/cli.d.ts +3 -2
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +188 -173
- package/dist/src/cli.js.map +1 -1
- package/dist/src/dispatch.d.ts.map +1 -1
- package/dist/src/dispatch.js +3 -2
- package/dist/src/dispatch.js.map +1 -1
- package/dist/src/doctor.d.ts.map +1 -1
- package/dist/src/doctor.js +178 -102
- package/dist/src/doctor.js.map +1 -1
- package/dist/src/error-message.d.ts +3 -0
- package/dist/src/error-message.d.ts.map +1 -0
- package/dist/src/error-message.js +20 -0
- package/dist/src/error-message.js.map +1 -0
- package/dist/src/hooks-config.d.ts +3 -0
- package/dist/src/hooks-config.d.ts.map +1 -0
- package/dist/src/hooks-config.js +23 -0
- package/dist/src/hooks-config.js.map +1 -0
- package/package.json +23 -20
- package/src/atomic-output.ts +47 -0
- package/src/cli.ts +170 -147
- package/src/dispatch.ts +3 -2
- package/src/doctor.ts +192 -111
- package/src/error-message.ts +13 -0
- package/src/hooks-config.ts +22 -0
package/dist/src/cli.js
CHANGED
|
@@ -34,13 +34,16 @@
|
|
|
34
34
|
* `file` defaults to stdin (`-`); `--db` defaults to `$CAVE_DB`, then
|
|
35
35
|
* `cave.db`. Every command answers `--help` with options and examples.
|
|
36
36
|
*/
|
|
37
|
-
import { readFileSync, readSync,
|
|
38
|
-
import {
|
|
37
|
+
import { readFileSync, readSync, realpathSync, statSync } from 'node:fs';
|
|
38
|
+
import { readHooks } from "./hooks-config.js";
|
|
39
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
39
40
|
import { parseArgs } from 'node:util';
|
|
40
|
-
import {
|
|
41
|
+
import { writeOutput } from "./atomic-output.js";
|
|
42
|
+
import { errorMessage } from "./error-message.js";
|
|
43
|
+
import { Time, Version } from '@cavelang/core';
|
|
41
44
|
import { parseDocument, Token } from '@cavelang/parser';
|
|
42
45
|
import { Registry, standardRegistry } from '@cavelang/canonical';
|
|
43
|
-
import { backup as backupStore, defaultDbPath, kindOf, LocateError, openAt, restoreBackup, Sensitivity, verifyBackup } from '@cavelang/store';
|
|
46
|
+
import { backup as backupStore, defaultDbPath, kindOf, LocateError, openAt, QuerySql, restoreBackup, Sensitivity, verifyBackup } from '@cavelang/store';
|
|
44
47
|
import { Declared, assemble as assembleSources } from '@cavelang/cli/connect';
|
|
45
48
|
import { defaultLimit as defaultQueryLimit, maxLimit as maxQueryLimit, page as caveQueryPage } from '@cavelang/query';
|
|
46
49
|
import { check as caveCheck, defaultMinScore, defaultStaleDays, gatedIngest, judgePrompt, parseJudgeReply, generateClient, suggestAliases, writeSuggestions } from '@cavelang/cli/shape';
|
|
@@ -487,7 +490,7 @@ Usage:
|
|
|
487
490
|
|
|
488
491
|
Options:
|
|
489
492
|
${dbHelp}
|
|
490
|
-
--out <file>
|
|
493
|
+
--out <file> atomically replace a file with the generated module
|
|
491
494
|
--version <n> generated-client format version (default and currently
|
|
492
495
|
supported: 1)
|
|
493
496
|
--no-prelude open the store without the standard verb registry
|
|
@@ -510,7 +513,7 @@ Usage:
|
|
|
510
513
|
Options:
|
|
511
514
|
${dbHelp}
|
|
512
515
|
--min <s> minimum evidence score, 0..1 or N% (default 60%)
|
|
513
|
-
--limit <n> at most n suggestions, strongest first
|
|
516
|
+
--limit <n> positive safe integer; at most n suggestions, strongest first
|
|
514
517
|
--agent <template> LLM judge filtering the candidates — the cave
|
|
515
518
|
ingest/eval shell contract: the prompt (each pair
|
|
516
519
|
with both sides' current claims) is piped to stdin
|
|
@@ -541,6 +544,10 @@ claim, so the opt-in §13.6 closure links it until reviewed:
|
|
|
541
544
|
claim identity, §9.2, so a plain @ 0% append would start a new series
|
|
542
545
|
and leave the suggested link standing).
|
|
543
546
|
|
|
547
|
+
Writes recheck pair history under their transaction reservation and skip
|
|
548
|
+
reviewed pairs. --json returns the selected suggestion array; --json --write
|
|
549
|
+
performs the write and returns { suggestions, appended }, with the actual count.
|
|
550
|
+
|
|
544
551
|
Examples:
|
|
545
552
|
cave suggest-alias --db k.db
|
|
546
553
|
cave suggest-alias --db k.db --min 80% --limit 10
|
|
@@ -596,7 +603,7 @@ Usage:
|
|
|
596
603
|
|
|
597
604
|
Options:
|
|
598
605
|
${dbHelp}
|
|
599
|
-
--out <file>
|
|
606
|
+
--out <file> atomically replace a file instead of stdout — refused when it
|
|
600
607
|
names the store's own database file
|
|
601
608
|
--current current beliefs only (skip superseded rows); compacting
|
|
602
609
|
view, not sanitization or selective erasure (spec §9.6)
|
|
@@ -612,6 +619,10 @@ Options:
|
|
|
612
619
|
Retention: claim history is permanent. Retraction and --current do not
|
|
613
620
|
guarantee erasure from the store, exports, peers, or backups (spec §9.6).
|
|
614
621
|
|
|
622
|
+
File output is staged and flushed before replacement. Existing permissions
|
|
623
|
+
and valid symlinks are preserved; hard-link aliases retain the previous file.
|
|
624
|
+
Dangling symlinks and non-regular output files are refused.
|
|
625
|
+
|
|
615
626
|
Examples:
|
|
616
627
|
cave export --db k.db
|
|
617
628
|
cave export --db k.db --out internal-export.cave
|
|
@@ -630,7 +641,7 @@ Usage:
|
|
|
630
641
|
|
|
631
642
|
Options:
|
|
632
643
|
${dbHelp}
|
|
633
|
-
--out <file>
|
|
644
|
+
--out <file> atomically replace a file with the rendered markdown
|
|
634
645
|
--aliases queries match through the alias closure (spec §13.6)
|
|
635
646
|
--resolve queries match resolved winners only (spec §26) — the fix
|
|
636
647
|
when an inline splice reports an ambiguous fact
|
|
@@ -724,6 +735,15 @@ Examples:
|
|
|
724
735
|
cave help query
|
|
725
736
|
cave help serve`
|
|
726
737
|
};
|
|
738
|
+
const decodeInput = (bytes, source) => {
|
|
739
|
+
try {
|
|
740
|
+
// Keep the existing BOM behavior of Buffer.toString while rejecting loss.
|
|
741
|
+
return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
742
|
+
}
|
|
743
|
+
catch (cause) {
|
|
744
|
+
throw new TypeError(`${source}: invalid UTF-8 input`, { cause });
|
|
745
|
+
}
|
|
746
|
+
};
|
|
727
747
|
const readStdin = () => {
|
|
728
748
|
const chunks = [];
|
|
729
749
|
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
@@ -732,7 +752,7 @@ const readStdin = () => {
|
|
|
732
752
|
try {
|
|
733
753
|
const size = readSync(0, buffer, 0, buffer.length, null);
|
|
734
754
|
if (size === 0)
|
|
735
|
-
return Buffer.concat(chunks)
|
|
755
|
+
return decodeInput(Buffer.concat(chunks), 'stdin');
|
|
736
756
|
chunks.push(Buffer.from(buffer.subarray(0, size)));
|
|
737
757
|
}
|
|
738
758
|
catch (error) {
|
|
@@ -759,6 +779,38 @@ const openDb = (values, intent) => openAt(values.db ?? defaultDbPath(), {
|
|
|
759
779
|
assemble: assembleSources,
|
|
760
780
|
...values['no-prelude'] === true ? { registry: Registry.empty } : {}
|
|
761
781
|
});
|
|
782
|
+
/** Retain command output and diagnostics when its owned store fails to close. */
|
|
783
|
+
const closeCommandStore = (store, output) => {
|
|
784
|
+
try {
|
|
785
|
+
store.close();
|
|
786
|
+
}
|
|
787
|
+
catch (error) {
|
|
788
|
+
const separator = output.err === '' || output.err.endsWith('\n') ? '' : '\n';
|
|
789
|
+
return { ...output, code: output.code === 0 ? 1 : output.code,
|
|
790
|
+
err: `${output.err}${separator}store close failed: ${errorMessage(error)}\n` };
|
|
791
|
+
}
|
|
792
|
+
return output;
|
|
793
|
+
};
|
|
794
|
+
const withCommandStore = (store, run) => {
|
|
795
|
+
let output;
|
|
796
|
+
try {
|
|
797
|
+
output = run();
|
|
798
|
+
}
|
|
799
|
+
catch (error) {
|
|
800
|
+
output = fail(`${errorMessage(error)}\n`);
|
|
801
|
+
}
|
|
802
|
+
return closeCommandStore(store, output);
|
|
803
|
+
};
|
|
804
|
+
const withAsyncCommandStore = async (store, run) => {
|
|
805
|
+
let output;
|
|
806
|
+
try {
|
|
807
|
+
output = await run();
|
|
808
|
+
}
|
|
809
|
+
catch (error) {
|
|
810
|
+
output = fail(`${errorMessage(error)}\n`);
|
|
811
|
+
}
|
|
812
|
+
return closeCommandStore(store, output);
|
|
813
|
+
};
|
|
762
814
|
const sourcesRollback = Symbol('cave query --sources rollback');
|
|
763
815
|
/**
|
|
764
816
|
* Runs `body` with the store's declared sources overlaid (spec §23.4): the
|
|
@@ -794,7 +846,7 @@ const withSources = (store, discovered, body) => {
|
|
|
794
846
|
};
|
|
795
847
|
const readInput = (files) => files.length === 0 || (files.length === 1 && files[0] === '-') ?
|
|
796
848
|
readStdin() :
|
|
797
|
-
files.map(file => readFileSync(file,
|
|
849
|
+
files.map(file => decodeInput(readFileSync(file), file)).join('\n');
|
|
798
850
|
export const parseCommand = (argv) => {
|
|
799
851
|
const { values, positionals } = parseArgs({
|
|
800
852
|
args: [...argv],
|
|
@@ -869,7 +921,7 @@ const ingestCommand = (name) => (argv) => {
|
|
|
869
921
|
});
|
|
870
922
|
const input = readInput(positionals);
|
|
871
923
|
const store = openDb(values, 'write');
|
|
872
|
-
|
|
924
|
+
return withCommandStore(store, () => {
|
|
873
925
|
const options = {
|
|
874
926
|
strict: values.strict === true,
|
|
875
927
|
...name === 'add' && values['no-src'] !== true ? { source: 'cli' } : {}
|
|
@@ -891,13 +943,7 @@ const ingestCommand = (name) => (argv) => {
|
|
|
891
943
|
out: `added ${outcome.result.ids.length} claim(s), ${outcome.result.edges} edge(s)\n`,
|
|
892
944
|
err: problems === '' ? '' : `${problems}\n`
|
|
893
945
|
};
|
|
894
|
-
}
|
|
895
|
-
catch (error) {
|
|
896
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
897
|
-
}
|
|
898
|
-
finally {
|
|
899
|
-
store.close();
|
|
900
|
-
}
|
|
946
|
+
});
|
|
901
947
|
};
|
|
902
948
|
export const addCommand = ingestCommand('add');
|
|
903
949
|
/**
|
|
@@ -959,7 +1005,7 @@ export const querySourcesCommand = async (argv, runtime = {}) => {
|
|
|
959
1005
|
// The overlay appends inside a transaction it rolls back: writable, but
|
|
960
1006
|
// never creating or migrating (spec §13.7).
|
|
961
1007
|
const store = openDb(values, 'scratch');
|
|
962
|
-
|
|
1008
|
+
return await withAsyncCommandStore(store, async () => {
|
|
963
1009
|
for (let attempt = 0; attempt < Declared.overlayAttempts; attempt += 1) {
|
|
964
1010
|
const discovered = await Declared.discovery(store, root, {
|
|
965
1011
|
// The overlay applies every source it loads (force), so discovery
|
|
@@ -974,13 +1020,7 @@ export const querySourcesCommand = async (argv, runtime = {}) => {
|
|
|
974
1020
|
}
|
|
975
1021
|
}
|
|
976
1022
|
throw Declared.staleOverlay();
|
|
977
|
-
}
|
|
978
|
-
catch (error) {
|
|
979
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
980
|
-
}
|
|
981
|
-
finally {
|
|
982
|
-
store.close();
|
|
983
|
-
}
|
|
1023
|
+
});
|
|
984
1024
|
};
|
|
985
1025
|
export const queryCommand = (argv) => {
|
|
986
1026
|
const parsed = parseQuery(argv);
|
|
@@ -994,15 +1034,9 @@ export const queryCommand = (argv) => {
|
|
|
994
1034
|
return fail('cave query: --sources loads the declared sources first and runs asynchronously — use querySourcesCommand\n');
|
|
995
1035
|
}
|
|
996
1036
|
const store = openDb(values, 'read');
|
|
997
|
-
|
|
1037
|
+
return withCommandStore(store, () => {
|
|
998
1038
|
return renderQueryPage(store, values, pattern, () => queryPage(store, values, pattern));
|
|
999
|
-
}
|
|
1000
|
-
catch (error) {
|
|
1001
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1002
|
-
}
|
|
1003
|
-
finally {
|
|
1004
|
-
store.close();
|
|
1005
|
-
}
|
|
1039
|
+
});
|
|
1006
1040
|
};
|
|
1007
1041
|
/** Every match of the overlay: the pages are followed here, inside the transaction that holds it. */
|
|
1008
1042
|
const wholeQuery = (store, values, pattern) => {
|
|
@@ -1090,7 +1124,7 @@ export const searchCommand = (argv) => {
|
|
|
1090
1124
|
return fail(`cave search: --limit must be an integer from 1 to ${maxQueryLimit}\n`);
|
|
1091
1125
|
}
|
|
1092
1126
|
const store = openDb(values, 'read');
|
|
1093
|
-
|
|
1127
|
+
return withCommandStore(store, () => {
|
|
1094
1128
|
const raw = values.raw === true;
|
|
1095
1129
|
const found = store.search(query, { raw, limit: limit + 1 });
|
|
1096
1130
|
const matches = found.slice(0, limit);
|
|
@@ -1114,13 +1148,7 @@ export const searchCommand = (argv) => {
|
|
|
1114
1148
|
lines.push(`more matches beyond ${limit}; raise --limit`);
|
|
1115
1149
|
}
|
|
1116
1150
|
return ok(`${lines.join('\n')}\n`);
|
|
1117
|
-
}
|
|
1118
|
-
catch (error) {
|
|
1119
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1120
|
-
}
|
|
1121
|
-
finally {
|
|
1122
|
-
store.close();
|
|
1123
|
-
}
|
|
1151
|
+
});
|
|
1124
1152
|
};
|
|
1125
1153
|
/**
|
|
1126
1154
|
* `cave resolve` — the human view of contradiction resolution (spec §26.4):
|
|
@@ -1139,15 +1167,22 @@ export const resolveCommand = (argv) => {
|
|
|
1139
1167
|
},
|
|
1140
1168
|
allowPositionals: false
|
|
1141
1169
|
});
|
|
1142
|
-
const percent = (value) =>
|
|
1170
|
+
const percent = (value) => {
|
|
1171
|
+
const rounded = Math.round(value * 1000) / 10;
|
|
1172
|
+
if (value > 0 && rounded === 0)
|
|
1173
|
+
return '<0.1%';
|
|
1174
|
+
if (value < 1 && rounded === 100)
|
|
1175
|
+
return '>99.9%';
|
|
1176
|
+
return `${rounded}%`;
|
|
1177
|
+
};
|
|
1143
1178
|
const store = openDb(values, 'read');
|
|
1144
|
-
|
|
1179
|
+
return withCommandStore(store, () => {
|
|
1145
1180
|
if (values.policy === true) {
|
|
1146
1181
|
const policy = store.resolutionPolicy();
|
|
1147
1182
|
if (values.json === true) {
|
|
1148
1183
|
return ok(`${JSON.stringify(policy, undefined, 2)}\n`);
|
|
1149
1184
|
}
|
|
1150
|
-
const width =
|
|
1185
|
+
const width = policy.reduce((maximum, entry) => Math.max(maximum, entry.prefix.length + 7), 0);
|
|
1151
1186
|
const lines = policy.map(entry => {
|
|
1152
1187
|
const subject = entry.prefix === '' ? 'source' : `source/${entry.prefix}`;
|
|
1153
1188
|
const dimensions = [
|
|
@@ -1167,13 +1202,7 @@ export const resolveCommand = (argv) => {
|
|
|
1167
1202
|
}
|
|
1168
1203
|
const lines = contested.flatMap(group => group.rows.map((row, at) => `${at === 0 ? '' : ' over '}${row.raw_line} ; class ${row.res_class}, effective ${percent(row.res_conf)}`));
|
|
1169
1204
|
return ok(`${lines.join('\n')}\n`);
|
|
1170
|
-
}
|
|
1171
|
-
catch (error) {
|
|
1172
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1173
|
-
}
|
|
1174
|
-
finally {
|
|
1175
|
-
store.close();
|
|
1176
|
-
}
|
|
1205
|
+
});
|
|
1177
1206
|
};
|
|
1178
1207
|
export const deriveCommand = (argv) => {
|
|
1179
1208
|
const { values, positionals } = parseArgs({
|
|
@@ -1199,15 +1228,15 @@ export const deriveCommand = (argv) => {
|
|
|
1199
1228
|
return fail(`cave derive: --min-conf expects a confidence in 0..1 or N%, got ${JSON.stringify(values['min-conf'])}\n`);
|
|
1200
1229
|
}
|
|
1201
1230
|
const maxPasses = values['max-passes'] === undefined ? undefined : Number(values['max-passes']);
|
|
1202
|
-
if (maxPasses !== undefined && (!Number.
|
|
1203
|
-
return fail(`cave derive: --max-passes expects a positive integer, got ${JSON.stringify(values['max-passes'])}\n`);
|
|
1231
|
+
if (maxPasses !== undefined && (!Number.isSafeInteger(maxPasses) || maxPasses < 1)) {
|
|
1232
|
+
return fail(`cave derive: --max-passes expects a positive safe integer, got ${JSON.stringify(values['max-passes'])}\n`);
|
|
1204
1233
|
}
|
|
1205
1234
|
// The intent follows the branch order below: listing reads, retracting
|
|
1206
1235
|
// writes, a dry run appends inside a rolled-back transaction.
|
|
1207
1236
|
const store = openDb(values, values.list === true ? 'read' :
|
|
1208
1237
|
values.retract !== undefined ? 'write' :
|
|
1209
1238
|
values['dry-run'] === true ? 'scratch' : 'write');
|
|
1210
|
-
|
|
1239
|
+
return withCommandStore(store, () => {
|
|
1211
1240
|
if (values.list === true) {
|
|
1212
1241
|
const rules = listRules(store);
|
|
1213
1242
|
if (values.json === true) {
|
|
@@ -1267,13 +1296,16 @@ export const deriveCommand = (argv) => {
|
|
|
1267
1296
|
report = derive(store, options);
|
|
1268
1297
|
}
|
|
1269
1298
|
if (declaration !== undefined) {
|
|
1270
|
-
|
|
1299
|
+
for (const problem of declaration.problems)
|
|
1300
|
+
err.push(`rules line ${problem.line}: ${problem.message}`);
|
|
1271
1301
|
out.push(`declared ${declaration.declared} rule(s)` +
|
|
1272
1302
|
(declaration.unchanged > 0 ? `, ${declaration.unchanged} unchanged` : '') +
|
|
1273
1303
|
(declaration.prelude > 0 ? `, +${declaration.prelude} prelude claim(s)` : ''));
|
|
1274
1304
|
}
|
|
1305
|
+
const hasProblems = (declaration?.problems.length ?? 0) > 0 || !report.complete ||
|
|
1306
|
+
report.problems.length > 0 || report.rules.some(rule => rule.problems.length > 0);
|
|
1275
1307
|
if (values.json === true) {
|
|
1276
|
-
return { code:
|
|
1308
|
+
return { code: hasProblems ? 1 : 0, out: `${stableJson(store, report)}\n`, err: err.join('\n') + (err.length > 0 ? '\n' : '') };
|
|
1277
1309
|
}
|
|
1278
1310
|
for (const problem of report.problems) {
|
|
1279
1311
|
err.push(`${problem.subject}: ${problem.problems.join('; ')}`);
|
|
@@ -1283,33 +1315,16 @@ export const deriveCommand = (argv) => {
|
|
|
1283
1315
|
`${rule.solutions} solution(s), +${rule.appended} appended, ${rule.updated} updated, ${rule.retracted} retracted, ${rule.unchanged} unchanged` :
|
|
1284
1316
|
'unchanged premises, skipped';
|
|
1285
1317
|
out.push(`${rule.subject}: ${state}${rule.label === undefined ? '' : ` ; ${rule.label}`}`);
|
|
1286
|
-
|
|
1318
|
+
for (const problem of rule.problems)
|
|
1319
|
+
err.push(`${rule.subject}: ${problem}`);
|
|
1287
1320
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1321
|
+
for (const note of report.notes)
|
|
1322
|
+
out.push(`note: ${note}`);
|
|
1323
|
+
out.push(`derived${report.complete ? '' : ' (incomplete)'}${values['dry-run'] === true ? ' (dry run)' : ''}: ` +
|
|
1290
1324
|
`+${report.appended} appended, ${report.updated} updated, ${report.retracted} retracted, ` +
|
|
1291
1325
|
`${report.unchanged} unchanged (${report.passes} pass(es))`);
|
|
1292
|
-
const hasProblems = !report.complete || report.problems.length > 0 || report.rules.some(rule => rule.problems.length > 0);
|
|
1293
1326
|
return { code: hasProblems ? 1 : 0, out: `${out.join('\n')}\n`, err: err.length === 0 ? '' : `${err.join('\n')}\n` };
|
|
1294
|
-
}
|
|
1295
|
-
catch (error) {
|
|
1296
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1297
|
-
}
|
|
1298
|
-
finally {
|
|
1299
|
-
store.close();
|
|
1300
|
-
}
|
|
1301
|
-
};
|
|
1302
|
-
/**
|
|
1303
|
-
* Loads a hooks configuration file (spec §25.4): a JSON object mapping
|
|
1304
|
-
* hook names to shell command templates.
|
|
1305
|
-
*/
|
|
1306
|
-
const readHooks = (path) => {
|
|
1307
|
-
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
1308
|
-
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed) ||
|
|
1309
|
-
Object.values(parsed).some(value => typeof value !== 'string')) {
|
|
1310
|
-
throw new Error(`${path}: hooks must be a JSON object of name → shell template strings`);
|
|
1311
|
-
}
|
|
1312
|
-
return parsed;
|
|
1327
|
+
});
|
|
1313
1328
|
};
|
|
1314
1329
|
/** Text rendering of a spec §25.2 execution report. */
|
|
1315
1330
|
const renderActReport = (report) => {
|
|
@@ -1328,17 +1343,16 @@ const renderActReport = (report) => {
|
|
|
1328
1343
|
];
|
|
1329
1344
|
let code = 0;
|
|
1330
1345
|
if (report.hook !== undefined) {
|
|
1331
|
-
if (
|
|
1332
|
-
|
|
1346
|
+
if (report.hook.error !== undefined) {
|
|
1347
|
+
// Effects may already be committed even when hook lookup failed before spawn.
|
|
1348
|
+
lines.push(`hook ${report.hook.name}: ${report.hook.error}`);
|
|
1349
|
+
code = 1;
|
|
1333
1350
|
}
|
|
1334
|
-
else if (report.hook.
|
|
1335
|
-
lines.push(`hook ${report.hook.name}:
|
|
1351
|
+
else if (!report.hook.fired) {
|
|
1352
|
+
lines.push(`hook ${report.hook.name}: not fired (${report.hook.note})`);
|
|
1336
1353
|
}
|
|
1337
1354
|
else {
|
|
1338
|
-
|
|
1339
|
-
// failure is reported, and the exit code carries it.
|
|
1340
|
-
lines.push(`hook ${report.hook.name}: ${report.hook.error}`);
|
|
1341
|
-
code = 1;
|
|
1355
|
+
lines.push(`hook ${report.hook.name}: ok`);
|
|
1342
1356
|
}
|
|
1343
1357
|
}
|
|
1344
1358
|
return { lines, code };
|
|
@@ -1367,7 +1381,7 @@ export const actCommand = (argv) => {
|
|
|
1367
1381
|
values.list === true ? 'read' :
|
|
1368
1382
|
values.retract !== undefined ? 'write' :
|
|
1369
1383
|
values['dry-run'] === true ? 'scratch' : 'write');
|
|
1370
|
-
|
|
1384
|
+
return withCommandStore(store, () => {
|
|
1371
1385
|
if (values.declare === true) {
|
|
1372
1386
|
const declaration = declareActions(store, readInput(positionals));
|
|
1373
1387
|
const err = declaration.problems.map(problem => `line ${problem.line}: ${problem.message}`);
|
|
@@ -1413,7 +1427,13 @@ export const actCommand = (argv) => {
|
|
|
1413
1427
|
if (at <= 0) {
|
|
1414
1428
|
return fail(`cave act: expected param=value, got ${JSON.stringify(pair)}\n`);
|
|
1415
1429
|
}
|
|
1416
|
-
|
|
1430
|
+
const parameter = pair.slice(0, at);
|
|
1431
|
+
if (Object.hasOwn(args, parameter)) {
|
|
1432
|
+
return fail(`cave act: duplicate parameter ${JSON.stringify(parameter)}\n`);
|
|
1433
|
+
}
|
|
1434
|
+
Object.defineProperty(args, parameter, {
|
|
1435
|
+
value: pair.slice(at + 1), enumerable: true, writable: true, configurable: true
|
|
1436
|
+
});
|
|
1417
1437
|
}
|
|
1418
1438
|
const hooksPath = values.hooks ?? process.env['CAVE_HOOKS'];
|
|
1419
1439
|
const report = act(store, name, args, {
|
|
@@ -1429,13 +1449,7 @@ export const actCommand = (argv) => {
|
|
|
1429
1449
|
return report.ok ?
|
|
1430
1450
|
{ code, out: `${lines.join('\n')}\n`, err: '' } :
|
|
1431
1451
|
{ code, out: '', err: `${lines.join('\n')}\n` };
|
|
1432
|
-
}
|
|
1433
|
-
catch (error) {
|
|
1434
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1435
|
-
}
|
|
1436
|
-
finally {
|
|
1437
|
-
store.close();
|
|
1438
|
-
}
|
|
1452
|
+
});
|
|
1439
1453
|
};
|
|
1440
1454
|
/** Text rendering of the §20.2 report: always shape + coverage, non-empty advisory sections. */
|
|
1441
1455
|
const renderReport = (report, staleDays) => {
|
|
@@ -1444,26 +1458,38 @@ const renderReport = (report, staleDays) => {
|
|
|
1444
1458
|
lines.push(`shape: ${coverage.expectations} expectation(s), ${coverage.instances} instance(s), ${coverage.satisfied}/${coverage.checks} satisfied`);
|
|
1445
1459
|
if (report.violations.length > 0) {
|
|
1446
1460
|
lines.push(`violations (${report.violations.length}):`);
|
|
1447
|
-
|
|
1461
|
+
for (const violation of report.violations)
|
|
1462
|
+
lines.push(` ${formatViolation(violation)}`);
|
|
1448
1463
|
}
|
|
1449
1464
|
if (report.stale.length > 0) {
|
|
1450
1465
|
lines.push(`stale (${report.stale.length}, older than ${staleDays} day(s)):`);
|
|
1451
|
-
|
|
1466
|
+
for (const { row, ageDays } of report.stale)
|
|
1467
|
+
lines.push(` ${row.raw_line} (${ageDays}d)`);
|
|
1452
1468
|
}
|
|
1453
1469
|
if (report.review.length > 0) {
|
|
1454
1470
|
lines.push(`review candidates (${report.review.length}, conf 0.3-0.7):`);
|
|
1455
|
-
|
|
1471
|
+
for (const row of report.review)
|
|
1472
|
+
lines.push(` ${row.raw_line}`);
|
|
1456
1473
|
}
|
|
1457
1474
|
if (report.disagreements.length > 0) {
|
|
1458
1475
|
lines.push(`alias disagreements (${report.disagreements.length}):`);
|
|
1459
1476
|
for (const disagreement of report.disagreements) {
|
|
1460
1477
|
lines.push(` ${disagreement.about} across ${disagreement.entities.join(', ')}:`);
|
|
1461
|
-
|
|
1478
|
+
for (const row of disagreement.rows)
|
|
1479
|
+
lines.push(` ${row.raw_line}`);
|
|
1462
1480
|
}
|
|
1463
1481
|
}
|
|
1482
|
+
const confidencePercent = (value) => {
|
|
1483
|
+
const rounded = Math.round(value * 100);
|
|
1484
|
+
if (value > 0 && rounded === 0)
|
|
1485
|
+
return '<1%';
|
|
1486
|
+
if (value < 1 && rounded === 100)
|
|
1487
|
+
return '>99%';
|
|
1488
|
+
return `${rounded}%`;
|
|
1489
|
+
};
|
|
1464
1490
|
const confidence = coverage.averageConfidence === null ?
|
|
1465
1491
|
'' :
|
|
1466
|
-
`; avg conf ${
|
|
1492
|
+
`; avg conf ${confidencePercent(coverage.averageConfidence)}, ${coverage.lowConfidence} low (< 0.3)`;
|
|
1467
1493
|
lines.push(`coverage: ${coverage.rows} row(s), ${coverage.facts} fact(s) — ` +
|
|
1468
1494
|
`${coverage.current} current, ${coverage.retracted} retracted, ${coverage.negated} negated` +
|
|
1469
1495
|
`${confidence}; ${coverage.entities} entities, ${coverage.typedEntities} typed`);
|
|
@@ -1485,17 +1511,14 @@ export const checkCommand = (argv) => {
|
|
|
1485
1511
|
return fail(`cave check: --stale expects a non-negative number of days, got ${JSON.stringify(values.stale)}\n`);
|
|
1486
1512
|
}
|
|
1487
1513
|
const store = openDb(values, 'read');
|
|
1488
|
-
|
|
1514
|
+
return withCommandStore(store, () => {
|
|
1489
1515
|
const report = caveCheck(store, { staleDays });
|
|
1490
1516
|
const out = values.json === true ?
|
|
1491
1517
|
`${stableJson(store, report)}\n` :
|
|
1492
1518
|
renderReport(report, staleDays);
|
|
1493
1519
|
// Violations fail the check (spec §20.2); the other sections are advisory.
|
|
1494
1520
|
return { code: report.violations.length > 0 ? 1 : 0, out, err: '' };
|
|
1495
|
-
}
|
|
1496
|
-
finally {
|
|
1497
|
-
store.close();
|
|
1498
|
-
}
|
|
1521
|
+
});
|
|
1499
1522
|
};
|
|
1500
1523
|
const snapshotLine = (action, snapshot) => `${action} exact backup (${snapshot.rows} row(s), schema v${snapshot.schemaVersion}, ` +
|
|
1501
1524
|
`${snapshot.bytes} bytes, sha256:${snapshot.sha256}) at ${snapshot.path}\n`;
|
|
@@ -1533,19 +1556,17 @@ export const backupCommand = (argv) => {
|
|
|
1533
1556
|
// the destination aliases the source: refuse before the file could be
|
|
1534
1557
|
// replaced by a SQLite snapshot of itself (a SQLite source is covered by
|
|
1535
1558
|
// the API's own check).
|
|
1536
|
-
if (
|
|
1559
|
+
if (sameStoreFile(dbPath, values.out)) {
|
|
1537
1560
|
return fail(`cave backup: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1538
1561
|
}
|
|
1562
|
+
const destination = values.out;
|
|
1539
1563
|
const store = openAt(dbPath, { intent: 'read', assemble: assembleSources });
|
|
1540
|
-
|
|
1541
|
-
return ok(snapshotLine('created', backupStore(store,
|
|
1542
|
-
}
|
|
1543
|
-
finally {
|
|
1544
|
-
store.close();
|
|
1545
|
-
}
|
|
1564
|
+
return withCommandStore(store, () => {
|
|
1565
|
+
return ok(snapshotLine('created', backupStore(store, destination, { force: values.force === true })));
|
|
1566
|
+
});
|
|
1546
1567
|
}
|
|
1547
1568
|
catch (error) {
|
|
1548
|
-
return fail(`${
|
|
1569
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1549
1570
|
}
|
|
1550
1571
|
};
|
|
1551
1572
|
/** `cave restore` — verify and atomically restore an exact snapshot (§13.2.2). */
|
|
@@ -1575,7 +1596,7 @@ export const restoreCommand = (argv) => {
|
|
|
1575
1596
|
})));
|
|
1576
1597
|
}
|
|
1577
1598
|
catch (error) {
|
|
1578
|
-
return fail(`${
|
|
1599
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1579
1600
|
}
|
|
1580
1601
|
};
|
|
1581
1602
|
/**
|
|
@@ -1610,15 +1631,15 @@ export const suggestAliasCommand = async (argv, runtime = {}) => {
|
|
|
1610
1631
|
return fail(`cave suggest-alias: --min expects a score in 0..1 or N%, got ${JSON.stringify(values.min)}\n`);
|
|
1611
1632
|
}
|
|
1612
1633
|
const limit = values.limit === undefined ? undefined : Number(values.limit);
|
|
1613
|
-
if (limit !== undefined && (!Number.
|
|
1614
|
-
return fail(`cave suggest-alias: --limit expects a positive integer, got ${JSON.stringify(values.limit)}\n`);
|
|
1634
|
+
if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 1)) {
|
|
1635
|
+
return fail(`cave suggest-alias: --limit expects a positive safe integer, got ${JSON.stringify(values.limit)}\n`);
|
|
1615
1636
|
}
|
|
1616
1637
|
const timeoutSeconds = values.timeout === undefined ? undefined : Number(values.timeout);
|
|
1617
1638
|
if (timeoutSeconds !== undefined && (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0)) {
|
|
1618
1639
|
return fail(`cave suggest-alias: --timeout must be a positive number of seconds, got '${values.timeout}'\n`);
|
|
1619
1640
|
}
|
|
1620
1641
|
const store = openDb(values, values.write === true ? 'write' : 'read');
|
|
1621
|
-
|
|
1642
|
+
return await withAsyncCommandStore(store, async () => {
|
|
1622
1643
|
let suggestions = suggestAliases(store, { minScore, ...limit === undefined ? {} : { limit } });
|
|
1623
1644
|
if (values.agent !== undefined && suggestions.length > 0) {
|
|
1624
1645
|
const reply = await shellComplete(values.agent, {
|
|
@@ -1628,7 +1649,9 @@ export const suggestAliasCommand = async (argv, runtime = {}) => {
|
|
|
1628
1649
|
suggestions = parseJudgeReply(reply, suggestions.length).map(index => suggestions[index]);
|
|
1629
1650
|
}
|
|
1630
1651
|
if (values.json === true) {
|
|
1631
|
-
|
|
1652
|
+
const result = values.write === true ?
|
|
1653
|
+
{ suggestions, ...writeSuggestions(store, suggestions) } : suggestions;
|
|
1654
|
+
return ok(`${JSON.stringify(result, undefined, 2)}\n`);
|
|
1632
1655
|
}
|
|
1633
1656
|
if (suggestions.length === 0) {
|
|
1634
1657
|
return ok('no alias suggestions\n');
|
|
@@ -1639,13 +1662,10 @@ export const suggestAliasCommand = async (argv, runtime = {}) => {
|
|
|
1639
1662
|
return ok(`${lines.join('\n')}\nappended ${appended} suggested alias claim(s)\n`);
|
|
1640
1663
|
}
|
|
1641
1664
|
return ok(`${lines.join('\n')}\n`);
|
|
1642
|
-
}
|
|
1643
|
-
finally {
|
|
1644
|
-
store.close();
|
|
1645
|
-
}
|
|
1665
|
+
});
|
|
1646
1666
|
}
|
|
1647
1667
|
catch (error) {
|
|
1648
|
-
return fail(`${
|
|
1668
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1649
1669
|
}
|
|
1650
1670
|
};
|
|
1651
1671
|
/**
|
|
@@ -1674,7 +1694,7 @@ export const syncCommand = (argv) => {
|
|
|
1674
1694
|
}
|
|
1675
1695
|
const dbPath = values.db ?? defaultDbPath();
|
|
1676
1696
|
const store = openDb(values, values['dry-run'] === true ? 'scratch' : 'write');
|
|
1677
|
-
|
|
1697
|
+
return withCommandStore(store, () => {
|
|
1678
1698
|
const options = {
|
|
1679
1699
|
into: values.into === undefined ? labelOf(dbPath) : sanitizeLabel(values.into),
|
|
1680
1700
|
record: values['no-record'] !== true,
|
|
@@ -1688,7 +1708,7 @@ export const syncCommand = (argv) => {
|
|
|
1688
1708
|
return { code: report.problems.length > 0 ? 1 : 0, out: `${JSON.stringify(report, undefined, 2)}\n`, err: '' };
|
|
1689
1709
|
}
|
|
1690
1710
|
if (report.problems.length > 0) {
|
|
1691
|
-
const detail = report.problems.map(problem => ` line ${problem.line}: ${problem.message}`).join('\n');
|
|
1711
|
+
const detail = report.problems.map(problem => ` ${problem.line === 0 ? '' : `line ${problem.line}: `}${problem.message}`).join('\n');
|
|
1692
1712
|
return fail(`cave sync: ${source}: ${report.problems.length} problem(s), nothing merged\n${detail}\n`);
|
|
1693
1713
|
}
|
|
1694
1714
|
const lines = [
|
|
@@ -1700,18 +1720,13 @@ export const syncCommand = (argv) => {
|
|
|
1700
1720
|
lines.push(`record: ${report.record}`);
|
|
1701
1721
|
}
|
|
1702
1722
|
return ok(`${lines.join('\n')}\n`);
|
|
1703
|
-
}
|
|
1704
|
-
catch (error) {
|
|
1705
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1706
|
-
}
|
|
1707
|
-
finally {
|
|
1708
|
-
store.close();
|
|
1709
|
-
}
|
|
1723
|
+
});
|
|
1710
1724
|
};
|
|
1711
1725
|
/**
|
|
1712
1726
|
* `cave report` — the §31 deliverable: a markdown template's cave-q
|
|
1713
|
-
* blocks and inline splices render from the store,
|
|
1714
|
-
* cited back to
|
|
1727
|
+
* blocks and inline splices render from the store, with matched rows
|
|
1728
|
+
* cited back to their claims. Ordinary prose is not automatically checked
|
|
1729
|
+
* or cited. Problems mark the text, land on stderr with
|
|
1715
1730
|
* template line numbers, and fail the exit code — the render never
|
|
1716
1731
|
* silently drops a fact.
|
|
1717
1732
|
*/
|
|
@@ -1730,16 +1745,22 @@ export const reportCommand = (argv) => {
|
|
|
1730
1745
|
},
|
|
1731
1746
|
allowPositionals: true
|
|
1732
1747
|
});
|
|
1733
|
-
|
|
1748
|
+
if (values.at !== undefined && Time.parseInstant(values.at) === undefined) {
|
|
1749
|
+
return fail(`cave report: --at cannot parse at anchor ${JSON.stringify(values.at)}\n`);
|
|
1750
|
+
}
|
|
1751
|
+
if (values['as-of'] !== undefined && QuerySql.asOfBoundary(values['as-of']) === undefined) {
|
|
1752
|
+
return fail(`cave report: --as-of cannot parse as-of boundary ${JSON.stringify(values['as-of'])}\n`);
|
|
1753
|
+
}
|
|
1734
1754
|
const maximum = Sensitivity.parse(values['max-sensitivity'] ?? Sensitivity.defaultMaximum);
|
|
1735
1755
|
if (maximum === undefined) {
|
|
1736
1756
|
return fail(`cave report: --max-sensitivity expects ${Sensitivity.levels.join(', ')}, got ${JSON.stringify(values['max-sensitivity'])}\n`);
|
|
1737
1757
|
}
|
|
1738
|
-
if (values.out !== undefined &&
|
|
1758
|
+
if (values.out !== undefined && sameStoreFile(values.db ?? defaultDbPath(), values.out)) {
|
|
1739
1759
|
return fail(`cave report: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1740
1760
|
}
|
|
1761
|
+
const template = readInput(positionals);
|
|
1741
1762
|
const store = openDb(values, 'read');
|
|
1742
|
-
|
|
1763
|
+
return withCommandStore(store, () => {
|
|
1743
1764
|
const rendered = caveReport(store, template, {
|
|
1744
1765
|
aliases: values.aliases === true,
|
|
1745
1766
|
resolve: values.resolve === true,
|
|
@@ -1754,19 +1775,13 @@ export const reportCommand = (argv) => {
|
|
|
1754
1775
|
if (values.out === undefined) {
|
|
1755
1776
|
return { code, out: rendered.markdown, err: err === '' ? '' : `${err}\n` };
|
|
1756
1777
|
}
|
|
1757
|
-
|
|
1778
|
+
writeOutput(values.out, rendered.markdown);
|
|
1758
1779
|
return {
|
|
1759
1780
|
code,
|
|
1760
1781
|
out: `rendered ${rendered.citations} citation(s) to ${values.out}\n`,
|
|
1761
1782
|
err: err === '' ? '' : `${err}\n`
|
|
1762
1783
|
};
|
|
1763
|
-
}
|
|
1764
|
-
catch (error) {
|
|
1765
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1766
|
-
}
|
|
1767
|
-
finally {
|
|
1768
|
-
store.close();
|
|
1769
|
-
}
|
|
1784
|
+
});
|
|
1770
1785
|
};
|
|
1771
1786
|
/**
|
|
1772
1787
|
* True when both paths name the same file: equal once resolved, or — when
|
|
@@ -1786,6 +1801,21 @@ const sameFile = (a, b) => {
|
|
|
1786
1801
|
return false;
|
|
1787
1802
|
}
|
|
1788
1803
|
};
|
|
1804
|
+
/** Protect every physical file SQLite uses, including through a database symlink. */
|
|
1805
|
+
const sameStoreFile = (db, output) => {
|
|
1806
|
+
if (sameFile(db, output))
|
|
1807
|
+
return true;
|
|
1808
|
+
try {
|
|
1809
|
+
if (kindOf(db) !== 'sqlite')
|
|
1810
|
+
return false;
|
|
1811
|
+
const canonicalOutput = join(realpathSync(dirname(resolve(output))), basename(output));
|
|
1812
|
+
return [...new Set([db, realpathSync(db)])].some(base => ['-wal', '-shm', '-journal'].some(suffix => sameFile(`${base}${suffix}`, output) || sameFile(`${base}${suffix}`, canonicalOutput)));
|
|
1813
|
+
}
|
|
1814
|
+
catch {
|
|
1815
|
+
// The normal store-open path reports missing or unreadable source files.
|
|
1816
|
+
return false;
|
|
1817
|
+
}
|
|
1818
|
+
};
|
|
1789
1819
|
export const exportCommand = (argv) => {
|
|
1790
1820
|
const { values } = parseArgs({
|
|
1791
1821
|
args: [...argv],
|
|
@@ -1804,28 +1834,22 @@ export const exportCommand = (argv) => {
|
|
|
1804
1834
|
if (maximum === undefined) {
|
|
1805
1835
|
return fail(`cave export: --max-sensitivity expects ${Sensitivity.levels.join(', ')}, got ${JSON.stringify(values['max-sensitivity'])}\n`);
|
|
1806
1836
|
}
|
|
1807
|
-
if (values.out !== undefined &&
|
|
1837
|
+
if (values.out !== undefined && sameStoreFile(db, values.out)) {
|
|
1808
1838
|
return fail(`cave export: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1809
1839
|
}
|
|
1810
1840
|
const store = openDb(values, 'read');
|
|
1811
|
-
|
|
1841
|
+
return withCommandStore(store, () => {
|
|
1812
1842
|
const text = store.exportText({ current: values.current === true, tx: values.tx === true, maxSensitivity: maximum });
|
|
1813
1843
|
if (values.out === undefined) {
|
|
1814
1844
|
return ok(text);
|
|
1815
1845
|
}
|
|
1816
|
-
|
|
1846
|
+
writeOutput(values.out, text);
|
|
1817
1847
|
// Root claims only: shorthand prefixes and §28.4 annotations are not
|
|
1818
1848
|
// claims, while qualifier/grouping leaves have a materialized parent.
|
|
1819
1849
|
const claims = parseDocument(text).lines
|
|
1820
1850
|
.filter(line => line.kind === 'claim' && line.parent === undefined).length;
|
|
1821
1851
|
return ok(`exported ${claims} claim(s) to ${values.out}\n`);
|
|
1822
|
-
}
|
|
1823
|
-
catch (error) {
|
|
1824
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1825
|
-
}
|
|
1826
|
-
finally {
|
|
1827
|
-
store.close();
|
|
1828
|
-
}
|
|
1852
|
+
});
|
|
1829
1853
|
};
|
|
1830
1854
|
/** `cave generate` — spec §20.4's versioned TypeScript client artifact. */
|
|
1831
1855
|
export const generateCommand = (argv) => {
|
|
@@ -1844,11 +1868,11 @@ export const generateCommand = (argv) => {
|
|
|
1844
1868
|
return fail(`cave generate: --version expects a positive integer, got ${JSON.stringify(values.version)}\n`);
|
|
1845
1869
|
}
|
|
1846
1870
|
const db = values.db ?? defaultDbPath();
|
|
1847
|
-
if (values.out !== undefined &&
|
|
1871
|
+
if (values.out !== undefined && sameStoreFile(db, values.out)) {
|
|
1848
1872
|
return fail(`cave generate: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1849
1873
|
}
|
|
1850
1874
|
const store = openDb(values, 'read');
|
|
1851
|
-
|
|
1875
|
+
return withCommandStore(store, () => {
|
|
1852
1876
|
const generated = generateClient(store, version === undefined ? {} : { version });
|
|
1853
1877
|
if (!generated.ok) {
|
|
1854
1878
|
return fail(`cave generate: schema cannot be generated:\n${generated.problems.map(problem => ` ${problem}`).join('\n')}\n`);
|
|
@@ -1856,16 +1880,10 @@ export const generateCommand = (argv) => {
|
|
|
1856
1880
|
if (values.out === undefined) {
|
|
1857
1881
|
return ok(generated.code);
|
|
1858
1882
|
}
|
|
1859
|
-
|
|
1883
|
+
writeOutput(values.out, generated.code);
|
|
1860
1884
|
return ok(`generated typed client v${generated.version} (${generated.fields.length} field(s), ` +
|
|
1861
1885
|
`sha256:${generated.digest}) to ${values.out}\n`);
|
|
1862
|
-
}
|
|
1863
|
-
catch (error) {
|
|
1864
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1865
|
-
}
|
|
1866
|
-
finally {
|
|
1867
|
-
store.close();
|
|
1868
|
-
}
|
|
1886
|
+
});
|
|
1869
1887
|
};
|
|
1870
1888
|
/**
|
|
1871
1889
|
* `cave reconstruct` — the §18 loop over the store: heuristic policy by
|
|
@@ -1911,7 +1929,7 @@ export const reconstructCommand = async (argv, runtime = {}) => {
|
|
|
1911
1929
|
return fail(`cave reconstruct: --timeout must be a positive number of seconds, got '${values.timeout}'\n`);
|
|
1912
1930
|
}
|
|
1913
1931
|
const store = openDb(values, 'read');
|
|
1914
|
-
|
|
1932
|
+
return await withAsyncCommandStore(store, async () => {
|
|
1915
1933
|
const graph = sqliteStore(store);
|
|
1916
1934
|
const result = values.agent === undefined ?
|
|
1917
1935
|
reconstruct(graph, heuristicPolicy(budgets), positionals) :
|
|
@@ -1928,13 +1946,10 @@ export const reconstructCommand = async (argv, runtime = {}) => {
|
|
|
1928
1946
|
...result.claims.map(claim => emitClaim(claim))
|
|
1929
1947
|
];
|
|
1930
1948
|
return ok(lines.length === 0 ? '' : `${lines.join('\n')}\n`);
|
|
1931
|
-
}
|
|
1932
|
-
finally {
|
|
1933
|
-
store.close();
|
|
1934
|
-
}
|
|
1949
|
+
});
|
|
1935
1950
|
}
|
|
1936
1951
|
catch (error) {
|
|
1937
|
-
return fail(`${
|
|
1952
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1938
1953
|
}
|
|
1939
1954
|
};
|
|
1940
1955
|
/**
|