@cavelang/cli 0.34.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 +225 -13
- 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 +240 -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 +204 -0
- package/dist/internal/connect/declared.d.ts.map +1 -0
- package/dist/internal/connect/declared.js +610 -0
- package/dist/internal/connect/declared.js.map +1 -0
- 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/index.d.ts +4 -2
- package/dist/internal/connect/index.d.ts.map +1 -1
- package/dist/internal/connect/index.js +3 -1
- package/dist/internal/connect/index.js.map +1 -1
- 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 +575 -59
- 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 +48 -19
- package/dist/internal/connect/run.d.ts.map +1 -1
- package/dist/internal/connect/run.js +185 -77
- package/dist/internal/connect/run.js.map +1 -1
- package/dist/internal/connect/source.d.ts +36 -3
- package/dist/internal/connect/source.d.ts.map +1 -1
- package/dist/internal/connect/source.js +378 -39
- package/dist/internal/connect/source.js.map +1 -1
- package/dist/internal/connect/template.d.ts +20 -2
- package/dist/internal/connect/template.d.ts.map +1 -1
- package/dist/internal/connect/template.js +53 -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 +48 -17
- 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 +44 -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/rules/rule.d.ts.map +1 -1
- package/dist/internal/rules/rule.js +1 -22
- package/dist/internal/rules/rule.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 +63 -9
- 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 +17 -2
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +333 -195
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands.d.ts +2 -2
- package/dist/src/commands.js +2 -2
- package/dist/src/commands.js.map +1 -1
- package/dist/src/dispatch.d.ts.map +1 -1
- package/dist/src/dispatch.js +10 -3
- package/dist/src/dispatch.js.map +1 -1
- package/dist/src/doctor.d.ts +1 -1
- package/dist/src/doctor.d.ts.map +1 -1
- package/dist/src/doctor.js +192 -91
- 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/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/package.json +23 -20
- package/src/atomic-output.ts +47 -0
- package/src/cli.ts +345 -171
- package/src/commands.ts +2 -2
- package/src/dispatch.ts +10 -3
- package/src/doctor.ts +207 -100
- package/src/error-message.ts +13 -0
- package/src/hooks-config.ts +22 -0
- package/src/index.ts +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -34,13 +34,17 @@
|
|
|
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 {
|
|
46
|
+
import { backup as backupStore, defaultDbPath, kindOf, LocateError, openAt, QuerySql, restoreBackup, Sensitivity, verifyBackup } from '@cavelang/store';
|
|
47
|
+
import { Declared, assemble as assembleSources } from '@cavelang/cli/connect';
|
|
44
48
|
import { defaultLimit as defaultQueryLimit, maxLimit as maxQueryLimit, page as caveQueryPage } from '@cavelang/query';
|
|
45
49
|
import { check as caveCheck, defaultMinScore, defaultStaleDays, gatedIngest, judgePrompt, parseJudgeReply, generateClient, suggestAliases, writeSuggestions } from '@cavelang/cli/shape';
|
|
46
50
|
import { declareRules, defaultMaxPasses, defaultMinConf, derive, listRules, retractRule } from '@cavelang/cli/rules';
|
|
@@ -218,7 +222,7 @@ Examples:
|
|
|
218
222
|
query: `cave query — run a CAVE-Q pattern against a store
|
|
219
223
|
|
|
220
224
|
Usage:
|
|
221
|
-
cave query [--db <path>] <pattern> [WHERE <filter>] [--limit <n>] [--cursor <token>] [--json] [--all] [--aliases] [--as-of <t>] [--at <t>] [--resolve] [--no-prelude]
|
|
225
|
+
cave query [--db <path>] <pattern> [WHERE <filter>] [--limit <n>] [--cursor <token>] [--json] [--all] [--aliases] [--as-of <t>] [--at <t>] [--resolve] [--sources] [--no-prelude]
|
|
222
226
|
|
|
223
227
|
Options:
|
|
224
228
|
${dbHelp}
|
|
@@ -244,6 +248,12 @@ Options:
|
|
|
244
248
|
collapse to the row the resolution policy picks
|
|
245
249
|
(precedence class, reliability-weighted confidence, tx);
|
|
246
250
|
incompatible with --all
|
|
251
|
+
--sources overlay the store's declared sources (spec §23.4) inside a
|
|
252
|
+
rolled-back transaction — federation-lite: external data is
|
|
253
|
+
consulted at query time, nothing persists. The answer is
|
|
254
|
+
whole (no --cursor, --limit is not a page size); a text
|
|
255
|
+
store followed its local sources on open, so only URL
|
|
256
|
+
sources are loaded here
|
|
247
257
|
--no-prelude open the store without the standard verb registry
|
|
248
258
|
|
|
249
259
|
Patterns are claim triples with ?variables and optional metadata filters
|
|
@@ -263,6 +273,7 @@ Examples:
|
|
|
263
273
|
cave query --db k.db 'revenue IS' --at 2026-07
|
|
264
274
|
cave query --db k.db 'alice WORKS-AT ?org' --at 2021
|
|
265
275
|
cave query --db k.db 'service HAS owner: ?who' --resolve
|
|
276
|
+
cave query --db k.db '?who WORKS-AT acme' --sources
|
|
266
277
|
cave query --db k.db '?x ?verb ?y @production' --json`,
|
|
267
278
|
search: `cave search — full-text search over claims and comments (spec §13.2)
|
|
268
279
|
|
|
@@ -479,7 +490,7 @@ Usage:
|
|
|
479
490
|
|
|
480
491
|
Options:
|
|
481
492
|
${dbHelp}
|
|
482
|
-
--out <file>
|
|
493
|
+
--out <file> atomically replace a file with the generated module
|
|
483
494
|
--version <n> generated-client format version (default and currently
|
|
484
495
|
supported: 1)
|
|
485
496
|
--no-prelude open the store without the standard verb registry
|
|
@@ -502,7 +513,7 @@ Usage:
|
|
|
502
513
|
Options:
|
|
503
514
|
${dbHelp}
|
|
504
515
|
--min <s> minimum evidence score, 0..1 or N% (default 60%)
|
|
505
|
-
--limit <n> at most n suggestions, strongest first
|
|
516
|
+
--limit <n> positive safe integer; at most n suggestions, strongest first
|
|
506
517
|
--agent <template> LLM judge filtering the candidates — the cave
|
|
507
518
|
ingest/eval shell contract: the prompt (each pair
|
|
508
519
|
with both sides' current claims) is piped to stdin
|
|
@@ -533,6 +544,10 @@ claim, so the opt-in §13.6 closure links it until reviewed:
|
|
|
533
544
|
claim identity, §9.2, so a plain @ 0% append would start a new series
|
|
534
545
|
and leave the suggested link standing).
|
|
535
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
|
+
|
|
536
551
|
Examples:
|
|
537
552
|
cave suggest-alias --db k.db
|
|
538
553
|
cave suggest-alias --db k.db --min 80% --limit 10
|
|
@@ -588,7 +603,7 @@ Usage:
|
|
|
588
603
|
|
|
589
604
|
Options:
|
|
590
605
|
${dbHelp}
|
|
591
|
-
--out <file>
|
|
606
|
+
--out <file> atomically replace a file instead of stdout — refused when it
|
|
592
607
|
names the store's own database file
|
|
593
608
|
--current current beliefs only (skip superseded rows); compacting
|
|
594
609
|
view, not sanitization or selective erasure (spec §9.6)
|
|
@@ -604,6 +619,10 @@ Options:
|
|
|
604
619
|
Retention: claim history is permanent. Retraction and --current do not
|
|
605
620
|
guarantee erasure from the store, exports, peers, or backups (spec §9.6).
|
|
606
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
|
+
|
|
607
626
|
Examples:
|
|
608
627
|
cave export --db k.db
|
|
609
628
|
cave export --db k.db --out internal-export.cave
|
|
@@ -622,7 +641,7 @@ Usage:
|
|
|
622
641
|
|
|
623
642
|
Options:
|
|
624
643
|
${dbHelp}
|
|
625
|
-
--out <file>
|
|
644
|
+
--out <file> atomically replace a file with the rendered markdown
|
|
626
645
|
--aliases queries match through the alias closure (spec §13.6)
|
|
627
646
|
--resolve queries match resolved winners only (spec §26) — the fix
|
|
628
647
|
when an inline splice reports an ambiguous fact
|
|
@@ -716,6 +735,15 @@ Examples:
|
|
|
716
735
|
cave help query
|
|
717
736
|
cave help serve`
|
|
718
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
|
+
};
|
|
719
747
|
const readStdin = () => {
|
|
720
748
|
const chunks = [];
|
|
721
749
|
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
@@ -724,7 +752,7 @@ const readStdin = () => {
|
|
|
724
752
|
try {
|
|
725
753
|
const size = readSync(0, buffer, 0, buffer.length, null);
|
|
726
754
|
if (size === 0)
|
|
727
|
-
return Buffer.concat(chunks)
|
|
755
|
+
return decodeInput(Buffer.concat(chunks), 'stdin');
|
|
728
756
|
chunks.push(Buffer.from(buffer.subarray(0, size)));
|
|
729
757
|
}
|
|
730
758
|
catch (error) {
|
|
@@ -747,11 +775,78 @@ const readStdin = () => {
|
|
|
747
775
|
*/
|
|
748
776
|
const openDb = (values, intent) => openAt(values.db ?? defaultDbPath(), {
|
|
749
777
|
intent,
|
|
778
|
+
// A text store follows its declared sources on open (spec §23.4).
|
|
779
|
+
assemble: assembleSources,
|
|
750
780
|
...values['no-prelude'] === true ? { registry: Registry.empty } : {}
|
|
751
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
|
+
};
|
|
814
|
+
const sourcesRollback = Symbol('cave query --sources rollback');
|
|
815
|
+
/**
|
|
816
|
+
* Runs `body` with the store's declared sources overlaid (spec §23.4): the
|
|
817
|
+
* sources, loaded beforehand (URLs included), append inside a transaction
|
|
818
|
+
* that always rolls back, so external data is consulted at query time and
|
|
819
|
+
* nothing persists, digests included.
|
|
820
|
+
*/
|
|
821
|
+
const withSources = (store, discovered, body) => {
|
|
822
|
+
let result;
|
|
823
|
+
try {
|
|
824
|
+
store.transaction(() => {
|
|
825
|
+
// Discovered on a snapshot: if a writer changed the declarations
|
|
826
|
+
// since, the sequence is stale and the caller rediscovers.
|
|
827
|
+
if (!Declared.sameDeclarations(discovered.baseline, Declared.declarationState(store))) {
|
|
828
|
+
throw sourcesRollback;
|
|
829
|
+
}
|
|
830
|
+
for (const source of discovered.sequence) {
|
|
831
|
+
const report = Declared.run(store, source, { force: true });
|
|
832
|
+
if (report.failures.length > 0) {
|
|
833
|
+
throw new LocateError(`source/${source.declared.name}: ${report.failures.map(failure => `${failure.record}: ${failure.problems.join('; ')}`).join('; ')}`);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
result = { value: body() };
|
|
837
|
+
throw sourcesRollback;
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
catch (error) {
|
|
841
|
+
if (error !== sourcesRollback) {
|
|
842
|
+
throw error;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return result;
|
|
846
|
+
};
|
|
752
847
|
const readInput = (files) => files.length === 0 || (files.length === 1 && files[0] === '-') ?
|
|
753
848
|
readStdin() :
|
|
754
|
-
files.map(file => readFileSync(file,
|
|
849
|
+
files.map(file => decodeInput(readFileSync(file), file)).join('\n');
|
|
755
850
|
export const parseCommand = (argv) => {
|
|
756
851
|
const { values, positionals } = parseArgs({
|
|
757
852
|
args: [...argv],
|
|
@@ -826,7 +921,7 @@ const ingestCommand = (name) => (argv) => {
|
|
|
826
921
|
});
|
|
827
922
|
const input = readInput(positionals);
|
|
828
923
|
const store = openDb(values, 'write');
|
|
829
|
-
|
|
924
|
+
return withCommandStore(store, () => {
|
|
830
925
|
const options = {
|
|
831
926
|
strict: values.strict === true,
|
|
832
927
|
...name === 'add' && values['no-src'] !== true ? { source: 'cli' } : {}
|
|
@@ -848,13 +943,7 @@ const ingestCommand = (name) => (argv) => {
|
|
|
848
943
|
out: `added ${outcome.result.ids.length} claim(s), ${outcome.result.edges} edge(s)\n`,
|
|
849
944
|
err: problems === '' ? '' : `${problems}\n`
|
|
850
945
|
};
|
|
851
|
-
}
|
|
852
|
-
catch (error) {
|
|
853
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
854
|
-
}
|
|
855
|
-
finally {
|
|
856
|
-
store.close();
|
|
857
|
-
}
|
|
946
|
+
});
|
|
858
947
|
};
|
|
859
948
|
export const addCommand = ingestCommand('add');
|
|
860
949
|
/**
|
|
@@ -870,39 +959,113 @@ export const addCommand = ingestCommand('add');
|
|
|
870
959
|
* identity.
|
|
871
960
|
*/
|
|
872
961
|
export const importCommand = ingestCommand('import');
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
allowPositionals: true
|
|
889
|
-
});
|
|
962
|
+
const queryOptions = {
|
|
963
|
+
db: { type: 'string' },
|
|
964
|
+
json: { type: 'boolean' },
|
|
965
|
+
all: { type: 'boolean' },
|
|
966
|
+
aliases: { type: 'boolean' },
|
|
967
|
+
'as-of': { type: 'string' },
|
|
968
|
+
at: { type: 'string' },
|
|
969
|
+
resolve: { type: 'boolean' },
|
|
970
|
+
sources: { type: 'boolean' },
|
|
971
|
+
limit: { type: 'string' },
|
|
972
|
+
cursor: { type: 'string' },
|
|
973
|
+
'no-prelude': { type: 'boolean' }
|
|
974
|
+
};
|
|
975
|
+
const parseQuery = (argv) => {
|
|
976
|
+
const { values, positionals } = parseArgs({ args: [...argv], options: queryOptions, allowPositionals: true });
|
|
890
977
|
if (positionals.length === 0) {
|
|
891
|
-
return fail('cave query: a pattern is required (spec §12.1)\n');
|
|
978
|
+
return { failure: fail('cave query: a pattern is required (spec §12.1)\n') };
|
|
979
|
+
}
|
|
980
|
+
if (values.sources === true && values.cursor !== undefined) {
|
|
981
|
+
return { failure: fail('cave query: --cursor does not apply to --sources — the overlay exists for one invocation and is answered whole\n') };
|
|
982
|
+
}
|
|
983
|
+
return { values, pattern: positionals.join('\n') };
|
|
984
|
+
};
|
|
985
|
+
/**
|
|
986
|
+
* `cave query --sources` — the store with its declared sources overlaid
|
|
987
|
+
* (spec §23.4). Asynchronous because the sources load first, URLs
|
|
988
|
+
* included, before the overlay appends inside a transaction that rolls
|
|
989
|
+
* back; the dispatcher routes `--sources` here. A text store followed its
|
|
990
|
+
* local sources on open, so only what assembly could not follow — URL
|
|
991
|
+
* sources and what they declare — is loaded. The overlay exists for this
|
|
992
|
+
* invocation alone, so the answer is whole: pages are followed inside the
|
|
993
|
+
* transaction and no cursor is handed out.
|
|
994
|
+
*/
|
|
995
|
+
export const querySourcesCommand = async (argv, runtime = {}) => {
|
|
996
|
+
const parsed = parseQuery(argv);
|
|
997
|
+
if ('failure' in parsed) {
|
|
998
|
+
return parsed.failure;
|
|
999
|
+
}
|
|
1000
|
+
const { values, pattern } = parsed;
|
|
1001
|
+
if (values.sources !== true) {
|
|
1002
|
+
return queryCommand(argv);
|
|
1003
|
+
}
|
|
1004
|
+
const root = values.db ?? defaultDbPath();
|
|
1005
|
+
// The overlay appends inside a transaction it rolls back: writable, but
|
|
1006
|
+
// never creating or migrating (spec §13.7).
|
|
1007
|
+
const store = openDb(values, 'scratch');
|
|
1008
|
+
return await withAsyncCommandStore(store, async () => {
|
|
1009
|
+
for (let attempt = 0; attempt < Declared.overlayAttempts; attempt += 1) {
|
|
1010
|
+
const discovered = await Declared.discovery(store, root, {
|
|
1011
|
+
// The overlay applies every source it loads (force), so discovery
|
|
1012
|
+
// simulates that; a text store skips what assembly already followed.
|
|
1013
|
+
force: true,
|
|
1014
|
+
...kindOf(root) === 'text' ? { skipFollowed: true } : {},
|
|
1015
|
+
...runtime.fetchImpl === undefined ? {} : { fetchImpl: runtime.fetchImpl }
|
|
1016
|
+
});
|
|
1017
|
+
const page = withSources(store, discovered, () => wholeQuery(store, values, pattern));
|
|
1018
|
+
if (page !== undefined) {
|
|
1019
|
+
return renderQueryPage(store, values, pattern, () => page.value);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
throw Declared.staleOverlay();
|
|
1023
|
+
});
|
|
1024
|
+
};
|
|
1025
|
+
export const queryCommand = (argv) => {
|
|
1026
|
+
const parsed = parseQuery(argv);
|
|
1027
|
+
if ('failure' in parsed) {
|
|
1028
|
+
return parsed.failure;
|
|
1029
|
+
}
|
|
1030
|
+
const { values, pattern } = parsed;
|
|
1031
|
+
if (values.sources === true) {
|
|
1032
|
+
// Loading sources cannot be synchronous: the in-process entry for the
|
|
1033
|
+
// overlay is `querySourcesCommand`, which the dispatcher uses.
|
|
1034
|
+
return fail('cave query: --sources loads the declared sources first and runs asynchronously — use querySourcesCommand\n');
|
|
892
1035
|
}
|
|
893
|
-
const pattern = positionals.join('\n');
|
|
894
1036
|
const store = openDb(values, 'read');
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
});
|
|
1037
|
+
return withCommandStore(store, () => {
|
|
1038
|
+
return renderQueryPage(store, values, pattern, () => queryPage(store, values, pattern));
|
|
1039
|
+
});
|
|
1040
|
+
};
|
|
1041
|
+
/** Every match of the overlay: the pages are followed here, inside the transaction that holds it. */
|
|
1042
|
+
const wholeQuery = (store, values, pattern) => {
|
|
1043
|
+
const matches = [];
|
|
1044
|
+
let first;
|
|
1045
|
+
let cursor;
|
|
1046
|
+
for (;;) {
|
|
1047
|
+
const page = queryPage(store, { ...values, limit: '1000', ...cursor === undefined ? {} : { cursor } }, pattern);
|
|
1048
|
+
first ??= page;
|
|
1049
|
+
matches.push(...page.matches);
|
|
1050
|
+
if (page.next === undefined) {
|
|
1051
|
+
const { next: _next, ...rest } = first;
|
|
1052
|
+
return { ...rest, matches };
|
|
1053
|
+
}
|
|
1054
|
+
cursor = page.next;
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
const queryPage = (store, values, pattern) => caveQueryPage(store, pattern, {
|
|
1058
|
+
all: values.all === true,
|
|
1059
|
+
aliases: values.aliases === true,
|
|
1060
|
+
resolve: values.resolve === true,
|
|
1061
|
+
limit: values.limit === undefined ? defaultQueryLimit : Number(values.limit),
|
|
1062
|
+
...values.cursor === undefined ? {} : { cursor: values.cursor },
|
|
1063
|
+
...values['as-of'] === undefined ? {} : { asOf: values['as-of'] },
|
|
1064
|
+
...values.at === undefined ? {} : { at: values.at }
|
|
1065
|
+
});
|
|
1066
|
+
const renderQueryPage = (store, values, pattern, page) => {
|
|
1067
|
+
{
|
|
1068
|
+
const result = page();
|
|
906
1069
|
if (values.json === true) {
|
|
907
1070
|
return ok(`${JSON.stringify(result, undefined, 2)}\n`);
|
|
908
1071
|
}
|
|
@@ -932,12 +1095,6 @@ export const queryCommand = (argv) => {
|
|
|
932
1095
|
});
|
|
933
1096
|
return ok(`${lines.join('\n')}\n${result.next === undefined ? '' : `next: ${result.next}\n`}`);
|
|
934
1097
|
}
|
|
935
|
-
catch (error) {
|
|
936
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
937
|
-
}
|
|
938
|
-
finally {
|
|
939
|
-
store.close();
|
|
940
|
-
}
|
|
941
1098
|
};
|
|
942
1099
|
export const searchFormat = 'cave.search';
|
|
943
1100
|
export const searchVersion = 1;
|
|
@@ -967,7 +1124,7 @@ export const searchCommand = (argv) => {
|
|
|
967
1124
|
return fail(`cave search: --limit must be an integer from 1 to ${maxQueryLimit}\n`);
|
|
968
1125
|
}
|
|
969
1126
|
const store = openDb(values, 'read');
|
|
970
|
-
|
|
1127
|
+
return withCommandStore(store, () => {
|
|
971
1128
|
const raw = values.raw === true;
|
|
972
1129
|
const found = store.search(query, { raw, limit: limit + 1 });
|
|
973
1130
|
const matches = found.slice(0, limit);
|
|
@@ -991,13 +1148,7 @@ export const searchCommand = (argv) => {
|
|
|
991
1148
|
lines.push(`more matches beyond ${limit}; raise --limit`);
|
|
992
1149
|
}
|
|
993
1150
|
return ok(`${lines.join('\n')}\n`);
|
|
994
|
-
}
|
|
995
|
-
catch (error) {
|
|
996
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
997
|
-
}
|
|
998
|
-
finally {
|
|
999
|
-
store.close();
|
|
1000
|
-
}
|
|
1151
|
+
});
|
|
1001
1152
|
};
|
|
1002
1153
|
/**
|
|
1003
1154
|
* `cave resolve` — the human view of contradiction resolution (spec §26.4):
|
|
@@ -1016,15 +1167,22 @@ export const resolveCommand = (argv) => {
|
|
|
1016
1167
|
},
|
|
1017
1168
|
allowPositionals: false
|
|
1018
1169
|
});
|
|
1019
|
-
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
|
+
};
|
|
1020
1178
|
const store = openDb(values, 'read');
|
|
1021
|
-
|
|
1179
|
+
return withCommandStore(store, () => {
|
|
1022
1180
|
if (values.policy === true) {
|
|
1023
1181
|
const policy = store.resolutionPolicy();
|
|
1024
1182
|
if (values.json === true) {
|
|
1025
1183
|
return ok(`${JSON.stringify(policy, undefined, 2)}\n`);
|
|
1026
1184
|
}
|
|
1027
|
-
const width =
|
|
1185
|
+
const width = policy.reduce((maximum, entry) => Math.max(maximum, entry.prefix.length + 7), 0);
|
|
1028
1186
|
const lines = policy.map(entry => {
|
|
1029
1187
|
const subject = entry.prefix === '' ? 'source' : `source/${entry.prefix}`;
|
|
1030
1188
|
const dimensions = [
|
|
@@ -1044,13 +1202,7 @@ export const resolveCommand = (argv) => {
|
|
|
1044
1202
|
}
|
|
1045
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)}`));
|
|
1046
1204
|
return ok(`${lines.join('\n')}\n`);
|
|
1047
|
-
}
|
|
1048
|
-
catch (error) {
|
|
1049
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1050
|
-
}
|
|
1051
|
-
finally {
|
|
1052
|
-
store.close();
|
|
1053
|
-
}
|
|
1205
|
+
});
|
|
1054
1206
|
};
|
|
1055
1207
|
export const deriveCommand = (argv) => {
|
|
1056
1208
|
const { values, positionals } = parseArgs({
|
|
@@ -1076,15 +1228,15 @@ export const deriveCommand = (argv) => {
|
|
|
1076
1228
|
return fail(`cave derive: --min-conf expects a confidence in 0..1 or N%, got ${JSON.stringify(values['min-conf'])}\n`);
|
|
1077
1229
|
}
|
|
1078
1230
|
const maxPasses = values['max-passes'] === undefined ? undefined : Number(values['max-passes']);
|
|
1079
|
-
if (maxPasses !== undefined && (!Number.
|
|
1080
|
-
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`);
|
|
1081
1233
|
}
|
|
1082
1234
|
// The intent follows the branch order below: listing reads, retracting
|
|
1083
1235
|
// writes, a dry run appends inside a rolled-back transaction.
|
|
1084
1236
|
const store = openDb(values, values.list === true ? 'read' :
|
|
1085
1237
|
values.retract !== undefined ? 'write' :
|
|
1086
1238
|
values['dry-run'] === true ? 'scratch' : 'write');
|
|
1087
|
-
|
|
1239
|
+
return withCommandStore(store, () => {
|
|
1088
1240
|
if (values.list === true) {
|
|
1089
1241
|
const rules = listRules(store);
|
|
1090
1242
|
if (values.json === true) {
|
|
@@ -1144,13 +1296,16 @@ export const deriveCommand = (argv) => {
|
|
|
1144
1296
|
report = derive(store, options);
|
|
1145
1297
|
}
|
|
1146
1298
|
if (declaration !== undefined) {
|
|
1147
|
-
|
|
1299
|
+
for (const problem of declaration.problems)
|
|
1300
|
+
err.push(`rules line ${problem.line}: ${problem.message}`);
|
|
1148
1301
|
out.push(`declared ${declaration.declared} rule(s)` +
|
|
1149
1302
|
(declaration.unchanged > 0 ? `, ${declaration.unchanged} unchanged` : '') +
|
|
1150
1303
|
(declaration.prelude > 0 ? `, +${declaration.prelude} prelude claim(s)` : ''));
|
|
1151
1304
|
}
|
|
1305
|
+
const hasProblems = (declaration?.problems.length ?? 0) > 0 || !report.complete ||
|
|
1306
|
+
report.problems.length > 0 || report.rules.some(rule => rule.problems.length > 0);
|
|
1152
1307
|
if (values.json === true) {
|
|
1153
|
-
return { code:
|
|
1308
|
+
return { code: hasProblems ? 1 : 0, out: `${stableJson(store, report)}\n`, err: err.join('\n') + (err.length > 0 ? '\n' : '') };
|
|
1154
1309
|
}
|
|
1155
1310
|
for (const problem of report.problems) {
|
|
1156
1311
|
err.push(`${problem.subject}: ${problem.problems.join('; ')}`);
|
|
@@ -1160,33 +1315,16 @@ export const deriveCommand = (argv) => {
|
|
|
1160
1315
|
`${rule.solutions} solution(s), +${rule.appended} appended, ${rule.updated} updated, ${rule.retracted} retracted, ${rule.unchanged} unchanged` :
|
|
1161
1316
|
'unchanged premises, skipped';
|
|
1162
1317
|
out.push(`${rule.subject}: ${state}${rule.label === undefined ? '' : ` ; ${rule.label}`}`);
|
|
1163
|
-
|
|
1318
|
+
for (const problem of rule.problems)
|
|
1319
|
+
err.push(`${rule.subject}: ${problem}`);
|
|
1164
1320
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
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)' : ''}: ` +
|
|
1167
1324
|
`+${report.appended} appended, ${report.updated} updated, ${report.retracted} retracted, ` +
|
|
1168
1325
|
`${report.unchanged} unchanged (${report.passes} pass(es))`);
|
|
1169
|
-
const hasProblems = !report.complete || report.problems.length > 0 || report.rules.some(rule => rule.problems.length > 0);
|
|
1170
1326
|
return { code: hasProblems ? 1 : 0, out: `${out.join('\n')}\n`, err: err.length === 0 ? '' : `${err.join('\n')}\n` };
|
|
1171
|
-
}
|
|
1172
|
-
catch (error) {
|
|
1173
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1174
|
-
}
|
|
1175
|
-
finally {
|
|
1176
|
-
store.close();
|
|
1177
|
-
}
|
|
1178
|
-
};
|
|
1179
|
-
/**
|
|
1180
|
-
* Loads a hooks configuration file (spec §25.4): a JSON object mapping
|
|
1181
|
-
* hook names to shell command templates.
|
|
1182
|
-
*/
|
|
1183
|
-
const readHooks = (path) => {
|
|
1184
|
-
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
1185
|
-
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed) ||
|
|
1186
|
-
Object.values(parsed).some(value => typeof value !== 'string')) {
|
|
1187
|
-
throw new Error(`${path}: hooks must be a JSON object of name → shell template strings`);
|
|
1188
|
-
}
|
|
1189
|
-
return parsed;
|
|
1327
|
+
});
|
|
1190
1328
|
};
|
|
1191
1329
|
/** Text rendering of a spec §25.2 execution report. */
|
|
1192
1330
|
const renderActReport = (report) => {
|
|
@@ -1205,17 +1343,16 @@ const renderActReport = (report) => {
|
|
|
1205
1343
|
];
|
|
1206
1344
|
let code = 0;
|
|
1207
1345
|
if (report.hook !== undefined) {
|
|
1208
|
-
if (
|
|
1209
|
-
|
|
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;
|
|
1210
1350
|
}
|
|
1211
|
-
else if (report.hook.
|
|
1212
|
-
lines.push(`hook ${report.hook.name}:
|
|
1351
|
+
else if (!report.hook.fired) {
|
|
1352
|
+
lines.push(`hook ${report.hook.name}: not fired (${report.hook.note})`);
|
|
1213
1353
|
}
|
|
1214
1354
|
else {
|
|
1215
|
-
|
|
1216
|
-
// failure is reported, and the exit code carries it.
|
|
1217
|
-
lines.push(`hook ${report.hook.name}: ${report.hook.error}`);
|
|
1218
|
-
code = 1;
|
|
1355
|
+
lines.push(`hook ${report.hook.name}: ok`);
|
|
1219
1356
|
}
|
|
1220
1357
|
}
|
|
1221
1358
|
return { lines, code };
|
|
@@ -1244,7 +1381,7 @@ export const actCommand = (argv) => {
|
|
|
1244
1381
|
values.list === true ? 'read' :
|
|
1245
1382
|
values.retract !== undefined ? 'write' :
|
|
1246
1383
|
values['dry-run'] === true ? 'scratch' : 'write');
|
|
1247
|
-
|
|
1384
|
+
return withCommandStore(store, () => {
|
|
1248
1385
|
if (values.declare === true) {
|
|
1249
1386
|
const declaration = declareActions(store, readInput(positionals));
|
|
1250
1387
|
const err = declaration.problems.map(problem => `line ${problem.line}: ${problem.message}`);
|
|
@@ -1290,7 +1427,13 @@ export const actCommand = (argv) => {
|
|
|
1290
1427
|
if (at <= 0) {
|
|
1291
1428
|
return fail(`cave act: expected param=value, got ${JSON.stringify(pair)}\n`);
|
|
1292
1429
|
}
|
|
1293
|
-
|
|
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
|
+
});
|
|
1294
1437
|
}
|
|
1295
1438
|
const hooksPath = values.hooks ?? process.env['CAVE_HOOKS'];
|
|
1296
1439
|
const report = act(store, name, args, {
|
|
@@ -1306,13 +1449,7 @@ export const actCommand = (argv) => {
|
|
|
1306
1449
|
return report.ok ?
|
|
1307
1450
|
{ code, out: `${lines.join('\n')}\n`, err: '' } :
|
|
1308
1451
|
{ code, out: '', err: `${lines.join('\n')}\n` };
|
|
1309
|
-
}
|
|
1310
|
-
catch (error) {
|
|
1311
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1312
|
-
}
|
|
1313
|
-
finally {
|
|
1314
|
-
store.close();
|
|
1315
|
-
}
|
|
1452
|
+
});
|
|
1316
1453
|
};
|
|
1317
1454
|
/** Text rendering of the §20.2 report: always shape + coverage, non-empty advisory sections. */
|
|
1318
1455
|
const renderReport = (report, staleDays) => {
|
|
@@ -1321,26 +1458,38 @@ const renderReport = (report, staleDays) => {
|
|
|
1321
1458
|
lines.push(`shape: ${coverage.expectations} expectation(s), ${coverage.instances} instance(s), ${coverage.satisfied}/${coverage.checks} satisfied`);
|
|
1322
1459
|
if (report.violations.length > 0) {
|
|
1323
1460
|
lines.push(`violations (${report.violations.length}):`);
|
|
1324
|
-
|
|
1461
|
+
for (const violation of report.violations)
|
|
1462
|
+
lines.push(` ${formatViolation(violation)}`);
|
|
1325
1463
|
}
|
|
1326
1464
|
if (report.stale.length > 0) {
|
|
1327
1465
|
lines.push(`stale (${report.stale.length}, older than ${staleDays} day(s)):`);
|
|
1328
|
-
|
|
1466
|
+
for (const { row, ageDays } of report.stale)
|
|
1467
|
+
lines.push(` ${row.raw_line} (${ageDays}d)`);
|
|
1329
1468
|
}
|
|
1330
1469
|
if (report.review.length > 0) {
|
|
1331
1470
|
lines.push(`review candidates (${report.review.length}, conf 0.3-0.7):`);
|
|
1332
|
-
|
|
1471
|
+
for (const row of report.review)
|
|
1472
|
+
lines.push(` ${row.raw_line}`);
|
|
1333
1473
|
}
|
|
1334
1474
|
if (report.disagreements.length > 0) {
|
|
1335
1475
|
lines.push(`alias disagreements (${report.disagreements.length}):`);
|
|
1336
1476
|
for (const disagreement of report.disagreements) {
|
|
1337
1477
|
lines.push(` ${disagreement.about} across ${disagreement.entities.join(', ')}:`);
|
|
1338
|
-
|
|
1478
|
+
for (const row of disagreement.rows)
|
|
1479
|
+
lines.push(` ${row.raw_line}`);
|
|
1339
1480
|
}
|
|
1340
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
|
+
};
|
|
1341
1490
|
const confidence = coverage.averageConfidence === null ?
|
|
1342
1491
|
'' :
|
|
1343
|
-
`; avg conf ${
|
|
1492
|
+
`; avg conf ${confidencePercent(coverage.averageConfidence)}, ${coverage.lowConfidence} low (< 0.3)`;
|
|
1344
1493
|
lines.push(`coverage: ${coverage.rows} row(s), ${coverage.facts} fact(s) — ` +
|
|
1345
1494
|
`${coverage.current} current, ${coverage.retracted} retracted, ${coverage.negated} negated` +
|
|
1346
1495
|
`${confidence}; ${coverage.entities} entities, ${coverage.typedEntities} typed`);
|
|
@@ -1362,17 +1511,14 @@ export const checkCommand = (argv) => {
|
|
|
1362
1511
|
return fail(`cave check: --stale expects a non-negative number of days, got ${JSON.stringify(values.stale)}\n`);
|
|
1363
1512
|
}
|
|
1364
1513
|
const store = openDb(values, 'read');
|
|
1365
|
-
|
|
1514
|
+
return withCommandStore(store, () => {
|
|
1366
1515
|
const report = caveCheck(store, { staleDays });
|
|
1367
1516
|
const out = values.json === true ?
|
|
1368
1517
|
`${stableJson(store, report)}\n` :
|
|
1369
1518
|
renderReport(report, staleDays);
|
|
1370
1519
|
// Violations fail the check (spec §20.2); the other sections are advisory.
|
|
1371
1520
|
return { code: report.violations.length > 0 ? 1 : 0, out, err: '' };
|
|
1372
|
-
}
|
|
1373
|
-
finally {
|
|
1374
|
-
store.close();
|
|
1375
|
-
}
|
|
1521
|
+
});
|
|
1376
1522
|
};
|
|
1377
1523
|
const snapshotLine = (action, snapshot) => `${action} exact backup (${snapshot.rows} row(s), schema v${snapshot.schemaVersion}, ` +
|
|
1378
1524
|
`${snapshot.bytes} bytes, sha256:${snapshot.sha256}) at ${snapshot.path}\n`;
|
|
@@ -1410,19 +1556,17 @@ export const backupCommand = (argv) => {
|
|
|
1410
1556
|
// the destination aliases the source: refuse before the file could be
|
|
1411
1557
|
// replaced by a SQLite snapshot of itself (a SQLite source is covered by
|
|
1412
1558
|
// the API's own check).
|
|
1413
|
-
if (
|
|
1559
|
+
if (sameStoreFile(dbPath, values.out)) {
|
|
1414
1560
|
return fail(`cave backup: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1415
1561
|
}
|
|
1416
|
-
const
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
store.close();
|
|
1422
|
-
}
|
|
1562
|
+
const destination = values.out;
|
|
1563
|
+
const store = openAt(dbPath, { intent: 'read', assemble: assembleSources });
|
|
1564
|
+
return withCommandStore(store, () => {
|
|
1565
|
+
return ok(snapshotLine('created', backupStore(store, destination, { force: values.force === true })));
|
|
1566
|
+
});
|
|
1423
1567
|
}
|
|
1424
1568
|
catch (error) {
|
|
1425
|
-
return fail(`${
|
|
1569
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1426
1570
|
}
|
|
1427
1571
|
};
|
|
1428
1572
|
/** `cave restore` — verify and atomically restore an exact snapshot (§13.2.2). */
|
|
@@ -1452,7 +1596,7 @@ export const restoreCommand = (argv) => {
|
|
|
1452
1596
|
})));
|
|
1453
1597
|
}
|
|
1454
1598
|
catch (error) {
|
|
1455
|
-
return fail(`${
|
|
1599
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1456
1600
|
}
|
|
1457
1601
|
};
|
|
1458
1602
|
/**
|
|
@@ -1487,15 +1631,15 @@ export const suggestAliasCommand = async (argv, runtime = {}) => {
|
|
|
1487
1631
|
return fail(`cave suggest-alias: --min expects a score in 0..1 or N%, got ${JSON.stringify(values.min)}\n`);
|
|
1488
1632
|
}
|
|
1489
1633
|
const limit = values.limit === undefined ? undefined : Number(values.limit);
|
|
1490
|
-
if (limit !== undefined && (!Number.
|
|
1491
|
-
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`);
|
|
1492
1636
|
}
|
|
1493
1637
|
const timeoutSeconds = values.timeout === undefined ? undefined : Number(values.timeout);
|
|
1494
1638
|
if (timeoutSeconds !== undefined && (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0)) {
|
|
1495
1639
|
return fail(`cave suggest-alias: --timeout must be a positive number of seconds, got '${values.timeout}'\n`);
|
|
1496
1640
|
}
|
|
1497
1641
|
const store = openDb(values, values.write === true ? 'write' : 'read');
|
|
1498
|
-
|
|
1642
|
+
return await withAsyncCommandStore(store, async () => {
|
|
1499
1643
|
let suggestions = suggestAliases(store, { minScore, ...limit === undefined ? {} : { limit } });
|
|
1500
1644
|
if (values.agent !== undefined && suggestions.length > 0) {
|
|
1501
1645
|
const reply = await shellComplete(values.agent, {
|
|
@@ -1505,7 +1649,9 @@ export const suggestAliasCommand = async (argv, runtime = {}) => {
|
|
|
1505
1649
|
suggestions = parseJudgeReply(reply, suggestions.length).map(index => suggestions[index]);
|
|
1506
1650
|
}
|
|
1507
1651
|
if (values.json === true) {
|
|
1508
|
-
|
|
1652
|
+
const result = values.write === true ?
|
|
1653
|
+
{ suggestions, ...writeSuggestions(store, suggestions) } : suggestions;
|
|
1654
|
+
return ok(`${JSON.stringify(result, undefined, 2)}\n`);
|
|
1509
1655
|
}
|
|
1510
1656
|
if (suggestions.length === 0) {
|
|
1511
1657
|
return ok('no alias suggestions\n');
|
|
@@ -1516,13 +1662,10 @@ export const suggestAliasCommand = async (argv, runtime = {}) => {
|
|
|
1516
1662
|
return ok(`${lines.join('\n')}\nappended ${appended} suggested alias claim(s)\n`);
|
|
1517
1663
|
}
|
|
1518
1664
|
return ok(`${lines.join('\n')}\n`);
|
|
1519
|
-
}
|
|
1520
|
-
finally {
|
|
1521
|
-
store.close();
|
|
1522
|
-
}
|
|
1665
|
+
});
|
|
1523
1666
|
}
|
|
1524
1667
|
catch (error) {
|
|
1525
|
-
return fail(`${
|
|
1668
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1526
1669
|
}
|
|
1527
1670
|
};
|
|
1528
1671
|
/**
|
|
@@ -1551,7 +1694,7 @@ export const syncCommand = (argv) => {
|
|
|
1551
1694
|
}
|
|
1552
1695
|
const dbPath = values.db ?? defaultDbPath();
|
|
1553
1696
|
const store = openDb(values, values['dry-run'] === true ? 'scratch' : 'write');
|
|
1554
|
-
|
|
1697
|
+
return withCommandStore(store, () => {
|
|
1555
1698
|
const options = {
|
|
1556
1699
|
into: values.into === undefined ? labelOf(dbPath) : sanitizeLabel(values.into),
|
|
1557
1700
|
record: values['no-record'] !== true,
|
|
@@ -1565,7 +1708,7 @@ export const syncCommand = (argv) => {
|
|
|
1565
1708
|
return { code: report.problems.length > 0 ? 1 : 0, out: `${JSON.stringify(report, undefined, 2)}\n`, err: '' };
|
|
1566
1709
|
}
|
|
1567
1710
|
if (report.problems.length > 0) {
|
|
1568
|
-
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');
|
|
1569
1712
|
return fail(`cave sync: ${source}: ${report.problems.length} problem(s), nothing merged\n${detail}\n`);
|
|
1570
1713
|
}
|
|
1571
1714
|
const lines = [
|
|
@@ -1577,18 +1720,13 @@ export const syncCommand = (argv) => {
|
|
|
1577
1720
|
lines.push(`record: ${report.record}`);
|
|
1578
1721
|
}
|
|
1579
1722
|
return ok(`${lines.join('\n')}\n`);
|
|
1580
|
-
}
|
|
1581
|
-
catch (error) {
|
|
1582
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1583
|
-
}
|
|
1584
|
-
finally {
|
|
1585
|
-
store.close();
|
|
1586
|
-
}
|
|
1723
|
+
});
|
|
1587
1724
|
};
|
|
1588
1725
|
/**
|
|
1589
1726
|
* `cave report` — the §31 deliverable: a markdown template's cave-q
|
|
1590
|
-
* blocks and inline splices render from the store,
|
|
1591
|
-
* 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
|
|
1592
1730
|
* template line numbers, and fail the exit code — the render never
|
|
1593
1731
|
* silently drops a fact.
|
|
1594
1732
|
*/
|
|
@@ -1607,16 +1745,22 @@ export const reportCommand = (argv) => {
|
|
|
1607
1745
|
},
|
|
1608
1746
|
allowPositionals: true
|
|
1609
1747
|
});
|
|
1610
|
-
|
|
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
|
+
}
|
|
1611
1754
|
const maximum = Sensitivity.parse(values['max-sensitivity'] ?? Sensitivity.defaultMaximum);
|
|
1612
1755
|
if (maximum === undefined) {
|
|
1613
1756
|
return fail(`cave report: --max-sensitivity expects ${Sensitivity.levels.join(', ')}, got ${JSON.stringify(values['max-sensitivity'])}\n`);
|
|
1614
1757
|
}
|
|
1615
|
-
if (values.out !== undefined &&
|
|
1758
|
+
if (values.out !== undefined && sameStoreFile(values.db ?? defaultDbPath(), values.out)) {
|
|
1616
1759
|
return fail(`cave report: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1617
1760
|
}
|
|
1761
|
+
const template = readInput(positionals);
|
|
1618
1762
|
const store = openDb(values, 'read');
|
|
1619
|
-
|
|
1763
|
+
return withCommandStore(store, () => {
|
|
1620
1764
|
const rendered = caveReport(store, template, {
|
|
1621
1765
|
aliases: values.aliases === true,
|
|
1622
1766
|
resolve: values.resolve === true,
|
|
@@ -1631,19 +1775,13 @@ export const reportCommand = (argv) => {
|
|
|
1631
1775
|
if (values.out === undefined) {
|
|
1632
1776
|
return { code, out: rendered.markdown, err: err === '' ? '' : `${err}\n` };
|
|
1633
1777
|
}
|
|
1634
|
-
|
|
1778
|
+
writeOutput(values.out, rendered.markdown);
|
|
1635
1779
|
return {
|
|
1636
1780
|
code,
|
|
1637
1781
|
out: `rendered ${rendered.citations} citation(s) to ${values.out}\n`,
|
|
1638
1782
|
err: err === '' ? '' : `${err}\n`
|
|
1639
1783
|
};
|
|
1640
|
-
}
|
|
1641
|
-
catch (error) {
|
|
1642
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1643
|
-
}
|
|
1644
|
-
finally {
|
|
1645
|
-
store.close();
|
|
1646
|
-
}
|
|
1784
|
+
});
|
|
1647
1785
|
};
|
|
1648
1786
|
/**
|
|
1649
1787
|
* True when both paths name the same file: equal once resolved, or — when
|
|
@@ -1663,6 +1801,21 @@ const sameFile = (a, b) => {
|
|
|
1663
1801
|
return false;
|
|
1664
1802
|
}
|
|
1665
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
|
+
};
|
|
1666
1819
|
export const exportCommand = (argv) => {
|
|
1667
1820
|
const { values } = parseArgs({
|
|
1668
1821
|
args: [...argv],
|
|
@@ -1681,28 +1834,22 @@ export const exportCommand = (argv) => {
|
|
|
1681
1834
|
if (maximum === undefined) {
|
|
1682
1835
|
return fail(`cave export: --max-sensitivity expects ${Sensitivity.levels.join(', ')}, got ${JSON.stringify(values['max-sensitivity'])}\n`);
|
|
1683
1836
|
}
|
|
1684
|
-
if (values.out !== undefined &&
|
|
1837
|
+
if (values.out !== undefined && sameStoreFile(db, values.out)) {
|
|
1685
1838
|
return fail(`cave export: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1686
1839
|
}
|
|
1687
1840
|
const store = openDb(values, 'read');
|
|
1688
|
-
|
|
1841
|
+
return withCommandStore(store, () => {
|
|
1689
1842
|
const text = store.exportText({ current: values.current === true, tx: values.tx === true, maxSensitivity: maximum });
|
|
1690
1843
|
if (values.out === undefined) {
|
|
1691
1844
|
return ok(text);
|
|
1692
1845
|
}
|
|
1693
|
-
|
|
1846
|
+
writeOutput(values.out, text);
|
|
1694
1847
|
// Root claims only: shorthand prefixes and §28.4 annotations are not
|
|
1695
1848
|
// claims, while qualifier/grouping leaves have a materialized parent.
|
|
1696
1849
|
const claims = parseDocument(text).lines
|
|
1697
1850
|
.filter(line => line.kind === 'claim' && line.parent === undefined).length;
|
|
1698
1851
|
return ok(`exported ${claims} claim(s) to ${values.out}\n`);
|
|
1699
|
-
}
|
|
1700
|
-
catch (error) {
|
|
1701
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1702
|
-
}
|
|
1703
|
-
finally {
|
|
1704
|
-
store.close();
|
|
1705
|
-
}
|
|
1852
|
+
});
|
|
1706
1853
|
};
|
|
1707
1854
|
/** `cave generate` — spec §20.4's versioned TypeScript client artifact. */
|
|
1708
1855
|
export const generateCommand = (argv) => {
|
|
@@ -1721,11 +1868,11 @@ export const generateCommand = (argv) => {
|
|
|
1721
1868
|
return fail(`cave generate: --version expects a positive integer, got ${JSON.stringify(values.version)}\n`);
|
|
1722
1869
|
}
|
|
1723
1870
|
const db = values.db ?? defaultDbPath();
|
|
1724
|
-
if (values.out !== undefined &&
|
|
1871
|
+
if (values.out !== undefined && sameStoreFile(db, values.out)) {
|
|
1725
1872
|
return fail(`cave generate: --out '${values.out}' is the source database — refusing to overwrite it\n`);
|
|
1726
1873
|
}
|
|
1727
1874
|
const store = openDb(values, 'read');
|
|
1728
|
-
|
|
1875
|
+
return withCommandStore(store, () => {
|
|
1729
1876
|
const generated = generateClient(store, version === undefined ? {} : { version });
|
|
1730
1877
|
if (!generated.ok) {
|
|
1731
1878
|
return fail(`cave generate: schema cannot be generated:\n${generated.problems.map(problem => ` ${problem}`).join('\n')}\n`);
|
|
@@ -1733,16 +1880,10 @@ export const generateCommand = (argv) => {
|
|
|
1733
1880
|
if (values.out === undefined) {
|
|
1734
1881
|
return ok(generated.code);
|
|
1735
1882
|
}
|
|
1736
|
-
|
|
1883
|
+
writeOutput(values.out, generated.code);
|
|
1737
1884
|
return ok(`generated typed client v${generated.version} (${generated.fields.length} field(s), ` +
|
|
1738
1885
|
`sha256:${generated.digest}) to ${values.out}\n`);
|
|
1739
|
-
}
|
|
1740
|
-
catch (error) {
|
|
1741
|
-
return fail(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1742
|
-
}
|
|
1743
|
-
finally {
|
|
1744
|
-
store.close();
|
|
1745
|
-
}
|
|
1886
|
+
});
|
|
1746
1887
|
};
|
|
1747
1888
|
/**
|
|
1748
1889
|
* `cave reconstruct` — the §18 loop over the store: heuristic policy by
|
|
@@ -1788,7 +1929,7 @@ export const reconstructCommand = async (argv, runtime = {}) => {
|
|
|
1788
1929
|
return fail(`cave reconstruct: --timeout must be a positive number of seconds, got '${values.timeout}'\n`);
|
|
1789
1930
|
}
|
|
1790
1931
|
const store = openDb(values, 'read');
|
|
1791
|
-
|
|
1932
|
+
return await withAsyncCommandStore(store, async () => {
|
|
1792
1933
|
const graph = sqliteStore(store);
|
|
1793
1934
|
const result = values.agent === undefined ?
|
|
1794
1935
|
reconstruct(graph, heuristicPolicy(budgets), positionals) :
|
|
@@ -1805,13 +1946,10 @@ export const reconstructCommand = async (argv, runtime = {}) => {
|
|
|
1805
1946
|
...result.claims.map(claim => emitClaim(claim))
|
|
1806
1947
|
];
|
|
1807
1948
|
return ok(lines.length === 0 ? '' : `${lines.join('\n')}\n`);
|
|
1808
|
-
}
|
|
1809
|
-
finally {
|
|
1810
|
-
store.close();
|
|
1811
|
-
}
|
|
1949
|
+
});
|
|
1812
1950
|
}
|
|
1813
1951
|
catch (error) {
|
|
1814
|
-
return fail(`${
|
|
1952
|
+
return fail(`${errorMessage(error)}\n`);
|
|
1815
1953
|
}
|
|
1816
1954
|
};
|
|
1817
1955
|
/**
|