@cavelang/cli 0.33.0 → 0.34.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 +13 -1
- package/dist/internal/automate/main.d.ts.map +1 -1
- package/dist/internal/automate/main.js +7 -2
- package/dist/internal/automate/main.js.map +1 -1
- package/dist/internal/connect/main.d.ts.map +1 -1
- package/dist/internal/connect/main.js +8 -4
- package/dist/internal/connect/main.js.map +1 -1
- package/dist/internal/ingest/main.d.ts.map +1 -1
- package/dist/internal/ingest/main.js +18 -2
- package/dist/internal/ingest/main.js.map +1 -1
- package/dist/internal/mcp/main.d.ts +1 -1
- package/dist/internal/mcp/main.d.ts.map +1 -1
- package/dist/internal/mcp/main.js +13 -3
- package/dist/internal/mcp/main.js.map +1 -1
- package/dist/internal/sync/sync.d.ts +2 -3
- package/dist/internal/sync/sync.d.ts.map +1 -1
- package/dist/internal/sync/sync.js +3 -15
- package/dist/internal/sync/sync.js.map +1 -1
- package/dist/internal/view/main.js +3 -3
- package/dist/internal/view/main.js.map +1 -1
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +68 -18
- package/dist/src/cli.js.map +1 -1
- package/dist/src/doctor.js +1 -1
- package/dist/src/doctor.js.map +1 -1
- package/package.json +19 -19
- package/src/cli.ts +73 -19
- package/src/doctor.ts +1 -1
package/src/cli.ts
CHANGED
|
@@ -41,8 +41,8 @@ import { parseArgs } from 'node:util'
|
|
|
41
41
|
import { Version } from '@cavelang/core'
|
|
42
42
|
import { parseDocument, Token } from '@cavelang/parser'
|
|
43
43
|
import { Registry, standardRegistry } from '@cavelang/canonical'
|
|
44
|
-
import { Sensitivity, backup as backupStore, defaultDbPath,
|
|
45
|
-
import type { Store } from '@cavelang/store'
|
|
44
|
+
import { LocateError, Sensitivity, backup as backupStore, defaultDbPath, openAt, restoreBackup, verifyBackup } from '@cavelang/store'
|
|
45
|
+
import type { OpenIntent, Store } from '@cavelang/store'
|
|
46
46
|
import { defaultLimit as defaultQueryLimit, maxLimit as maxQueryLimit, page as caveQueryPage } from '@cavelang/query'
|
|
47
47
|
import {
|
|
48
48
|
check as caveCheck, defaultMinScore, defaultStaleDays, gatedIngest, judgePrompt, parseJudgeReply,
|
|
@@ -142,10 +142,12 @@ Usage:
|
|
|
142
142
|
cave help [command] this text, or one command's options and examples
|
|
143
143
|
|
|
144
144
|
Every command answers --help. --db defaults to $CAVE_DB, or cave.db in
|
|
145
|
-
the current directory
|
|
145
|
+
the current directory, and names a SQLite store or a CAVE text file: text
|
|
146
|
+
replays into an in-memory store for commands that only read (writes refuse
|
|
147
|
+
it), and a read never creates a missing database. The spec lives in the .claude/skills/ directory at
|
|
146
148
|
the repository root (section index in README.md).`
|
|
147
149
|
|
|
148
|
-
const dbHelp = `--db <path>
|
|
150
|
+
const dbHelp = `--db <path> store: a SQLite file, or CAVE text read into memory (default: $CAVE_DB, or cave.db)`
|
|
149
151
|
|
|
150
152
|
/** Per-command help, printed for \`cave <command> --help\` and \`cave help <command>\`. */
|
|
151
153
|
export const commandHelp: Record<string, string> = {
|
|
@@ -286,6 +288,7 @@ with the answer; fully bound patterns print the raw line, comment included.
|
|
|
286
288
|
|
|
287
289
|
Examples:
|
|
288
290
|
cave query '?x USES jwt'
|
|
291
|
+
cave query --db notes.cave '?x USES jwt'
|
|
289
292
|
cave query --db k.db '?x HAS bug: ?bug #security'
|
|
290
293
|
cave query --db k.db '?cause CAUSE app/crash' 'WHERE conf >= 0.5'
|
|
291
294
|
cave query --db k.db 'terrier EXTENDS+ animal'
|
|
@@ -782,6 +785,21 @@ const readStdin = (): string => {
|
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
787
|
|
|
788
|
+
/**
|
|
789
|
+
* Opens the store `--db` names (spec §13.7): a SQLite file, or a CAVE text
|
|
790
|
+
* file replayed into memory. `read` never creates, migrates, or changes a
|
|
791
|
+
* file — a missing path is an error, not an empty database; `scratch` is a
|
|
792
|
+
* dry run that appends inside a rolled-back transaction, so it may write
|
|
793
|
+
* but creates and migrates nothing; `write` creates a missing SQLite store,
|
|
794
|
+
* migrates an older one, and refuses text files with the materialization
|
|
795
|
+
* hint.
|
|
796
|
+
*/
|
|
797
|
+
const openDb = (values: { db?: string, 'no-prelude'?: boolean }, intent: OpenIntent): Store =>
|
|
798
|
+
openAt(values.db ?? defaultDbPath(), {
|
|
799
|
+
intent,
|
|
800
|
+
...values['no-prelude'] === true ? { registry: Registry.empty } : {}
|
|
801
|
+
})
|
|
802
|
+
|
|
785
803
|
const readInput = (files: readonly string[]): string =>
|
|
786
804
|
files.length === 0 || (files.length === 1 && files[0] === '-') ?
|
|
787
805
|
readStdin() :
|
|
@@ -865,7 +883,7 @@ const ingestCommand = (name: 'add' | 'import') => (argv: readonly string[]): Out
|
|
|
865
883
|
allowPositionals: true
|
|
866
884
|
})
|
|
867
885
|
const input = readInput(positionals)
|
|
868
|
-
const store =
|
|
886
|
+
const store = openDb(values, 'write')
|
|
869
887
|
try {
|
|
870
888
|
const options = {
|
|
871
889
|
strict: values.strict === true,
|
|
@@ -932,7 +950,7 @@ export const queryCommand = (argv: readonly string[]): Output => {
|
|
|
932
950
|
return fail('cave query: a pattern is required (spec §12.1)\n')
|
|
933
951
|
}
|
|
934
952
|
const pattern = positionals.join('\n')
|
|
935
|
-
const store =
|
|
953
|
+
const store = openDb(values, 'read')
|
|
936
954
|
try {
|
|
937
955
|
const limit = values.limit === undefined ? defaultQueryLimit : Number(values.limit)
|
|
938
956
|
const result = caveQueryPage(store, pattern, {
|
|
@@ -1007,7 +1025,7 @@ export const searchCommand = (argv: readonly string[]): Output => {
|
|
|
1007
1025
|
if (!Number.isInteger(limit) || limit < 1 || limit > maxQueryLimit) {
|
|
1008
1026
|
return fail(`cave search: --limit must be an integer from 1 to ${maxQueryLimit}\n`)
|
|
1009
1027
|
}
|
|
1010
|
-
const store =
|
|
1028
|
+
const store = openDb(values, 'read')
|
|
1011
1029
|
try {
|
|
1012
1030
|
const raw = values.raw === true
|
|
1013
1031
|
const found = store.search(query, { raw, limit: limit + 1 })
|
|
@@ -1057,7 +1075,7 @@ export const resolveCommand = (argv: readonly string[]): Output => {
|
|
|
1057
1075
|
allowPositionals: false
|
|
1058
1076
|
})
|
|
1059
1077
|
const percent = (value: number): string => `${Math.round(value * 1000) / 10}%`
|
|
1060
|
-
const store =
|
|
1078
|
+
const store = openDb(values, 'read')
|
|
1061
1079
|
try {
|
|
1062
1080
|
if (values.policy === true) {
|
|
1063
1081
|
const policy = store.resolutionPolicy()
|
|
@@ -1120,7 +1138,12 @@ export const deriveCommand = (argv: readonly string[]): Output => {
|
|
|
1120
1138
|
if (maxPasses !== undefined && (!Number.isInteger(maxPasses) || maxPasses < 1)) {
|
|
1121
1139
|
return fail(`cave derive: --max-passes expects a positive integer, got ${JSON.stringify(values['max-passes'])}\n`)
|
|
1122
1140
|
}
|
|
1123
|
-
|
|
1141
|
+
// The intent follows the branch order below: listing reads, retracting
|
|
1142
|
+
// writes, a dry run appends inside a rolled-back transaction.
|
|
1143
|
+
const store = openDb(values,
|
|
1144
|
+
values.list === true ? 'read' :
|
|
1145
|
+
values.retract !== undefined ? 'write' :
|
|
1146
|
+
values['dry-run'] === true ? 'scratch' : 'write')
|
|
1124
1147
|
try {
|
|
1125
1148
|
if (values.list === true) {
|
|
1126
1149
|
const rules = listRules(store)
|
|
@@ -1274,7 +1297,14 @@ export const actCommand = (argv: readonly string[]): Output => {
|
|
|
1274
1297
|
},
|
|
1275
1298
|
allowPositionals: true
|
|
1276
1299
|
})
|
|
1277
|
-
|
|
1300
|
+
// The intent follows the branch order below: declaring and retracting
|
|
1301
|
+
// write, listing reads, a dry-run execution appends inside a rolled-back
|
|
1302
|
+
// transaction.
|
|
1303
|
+
const store = openDb(values,
|
|
1304
|
+
values.declare === true ? 'write' :
|
|
1305
|
+
values.list === true ? 'read' :
|
|
1306
|
+
values.retract !== undefined ? 'write' :
|
|
1307
|
+
values['dry-run'] === true ? 'scratch' : 'write')
|
|
1278
1308
|
try {
|
|
1279
1309
|
if (values.declare === true) {
|
|
1280
1310
|
const declaration = declareActions(store, readInput(positionals))
|
|
@@ -1395,7 +1425,7 @@ export const checkCommand = (argv: readonly string[]): Output => {
|
|
|
1395
1425
|
if (!Number.isFinite(staleDays) || staleDays < 0) {
|
|
1396
1426
|
return fail(`cave check: --stale expects a non-negative number of days, got ${JSON.stringify(values.stale)}\n`)
|
|
1397
1427
|
}
|
|
1398
|
-
const store =
|
|
1428
|
+
const store = openDb(values, 'read')
|
|
1399
1429
|
try {
|
|
1400
1430
|
const report = caveCheck(store, { staleDays })
|
|
1401
1431
|
const out = values.json === true ?
|
|
@@ -1444,7 +1474,15 @@ export const backupCommand = (argv: readonly string[]): Output => {
|
|
|
1444
1474
|
if (values.out === undefined) {
|
|
1445
1475
|
return fail('cave backup: --out <file> is required\n')
|
|
1446
1476
|
}
|
|
1447
|
-
const
|
|
1477
|
+
const dbPath = values.db ?? defaultDbPath()
|
|
1478
|
+
// A text store is replayed into memory, so the backup API cannot see that
|
|
1479
|
+
// the destination aliases the source: refuse before the file could be
|
|
1480
|
+
// replaced by a SQLite snapshot of itself (a SQLite source is covered by
|
|
1481
|
+
// the API's own check).
|
|
1482
|
+
if (sameFile(dbPath, values.out)) {
|
|
1483
|
+
return fail(`cave backup: --out '${values.out}' is the source database — refusing to overwrite it\n`)
|
|
1484
|
+
}
|
|
1485
|
+
const store = openAt(dbPath, { intent: 'read' })
|
|
1448
1486
|
try {
|
|
1449
1487
|
return ok(snapshotLine('created', backupStore(store, values.out, { force: values.force === true })))
|
|
1450
1488
|
} finally {
|
|
@@ -1527,7 +1565,7 @@ export const suggestAliasCommand = async (
|
|
|
1527
1565
|
if (timeoutSeconds !== undefined && (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0)) {
|
|
1528
1566
|
return fail(`cave suggest-alias: --timeout must be a positive number of seconds, got '${values.timeout}'\n`)
|
|
1529
1567
|
}
|
|
1530
|
-
const store =
|
|
1568
|
+
const store = openDb(values, values.write === true ? 'write' : 'read')
|
|
1531
1569
|
try {
|
|
1532
1570
|
let suggestions = suggestAliases(store, { minScore, ...limit === undefined ? {} : { limit } })
|
|
1533
1571
|
if (values.agent !== undefined && suggestions.length > 0) {
|
|
@@ -1584,7 +1622,7 @@ export const syncCommand = (argv: readonly string[]): Output => {
|
|
|
1584
1622
|
return fail('cave sync: exactly one source is required — a CAVE store file, ;@-annotated text, or - for stdin (spec §28.5)\n')
|
|
1585
1623
|
}
|
|
1586
1624
|
const dbPath = values.db ?? defaultDbPath()
|
|
1587
|
-
const store =
|
|
1625
|
+
const store = openDb(values, values['dry-run'] === true ? 'scratch' : 'write')
|
|
1588
1626
|
try {
|
|
1589
1627
|
const options = {
|
|
1590
1628
|
into: values.into === undefined ? labelOf(dbPath) : sanitizeLabel(values.into),
|
|
@@ -1645,7 +1683,10 @@ export const reportCommand = (argv: readonly string[]): Output => {
|
|
|
1645
1683
|
if (maximum === undefined) {
|
|
1646
1684
|
return fail(`cave report: --max-sensitivity expects ${Sensitivity.levels.join(', ')}, got ${JSON.stringify(values['max-sensitivity'])}\n`)
|
|
1647
1685
|
}
|
|
1648
|
-
|
|
1686
|
+
if (values.out !== undefined && sameFile(values.db ?? defaultDbPath(), values.out)) {
|
|
1687
|
+
return fail(`cave report: --out '${values.out}' is the source database — refusing to overwrite it\n`)
|
|
1688
|
+
}
|
|
1689
|
+
const store = openDb(values, 'read')
|
|
1649
1690
|
try {
|
|
1650
1691
|
const rendered = caveReport(store, template, {
|
|
1651
1692
|
aliases: values.aliases === true,
|
|
@@ -1713,7 +1754,7 @@ export const exportCommand = (argv: readonly string[]): Output => {
|
|
|
1713
1754
|
if (values.out !== undefined && sameFile(db, values.out)) {
|
|
1714
1755
|
return fail(`cave export: --out '${values.out}' is the source database — refusing to overwrite it\n`)
|
|
1715
1756
|
}
|
|
1716
|
-
const store =
|
|
1757
|
+
const store = openDb(values, 'read')
|
|
1717
1758
|
try {
|
|
1718
1759
|
const text = store.exportText({ current: values.current === true, tx: values.tx === true, maxSensitivity: maximum })
|
|
1719
1760
|
if (values.out === undefined) {
|
|
@@ -1752,7 +1793,7 @@ export const generateCommand = (argv: readonly string[]): Output => {
|
|
|
1752
1793
|
if (values.out !== undefined && sameFile(db, values.out)) {
|
|
1753
1794
|
return fail(`cave generate: --out '${values.out}' is the source database — refusing to overwrite it\n`)
|
|
1754
1795
|
}
|
|
1755
|
-
const store =
|
|
1796
|
+
const store = openDb(values, 'read')
|
|
1756
1797
|
try {
|
|
1757
1798
|
const generated = generateClient(store, version === undefined ? {} : { version })
|
|
1758
1799
|
if (!generated.ok) {
|
|
@@ -1817,7 +1858,7 @@ export const reconstructCommand = async (
|
|
|
1817
1858
|
if (timeoutSeconds !== undefined && (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0)) {
|
|
1818
1859
|
return fail(`cave reconstruct: --timeout must be a positive number of seconds, got '${values.timeout}'\n`)
|
|
1819
1860
|
}
|
|
1820
|
-
const store =
|
|
1861
|
+
const store = openDb(values, 'read')
|
|
1821
1862
|
try {
|
|
1822
1863
|
const graph = sqliteStore(store)
|
|
1823
1864
|
const result = values.agent === undefined ?
|
|
@@ -1902,6 +1943,19 @@ export const cave = (argv: readonly string[]): Output => {
|
|
|
1902
1943
|
(rest.includes('--help') || rest.includes('-h'))) {
|
|
1903
1944
|
return ok(`${commandHelp[canonical]}\n`)
|
|
1904
1945
|
}
|
|
1946
|
+
try {
|
|
1947
|
+
return run(canonical, rest)
|
|
1948
|
+
} catch (error) {
|
|
1949
|
+
// A --db path that is not what the command needs (spec §13.7) is a
|
|
1950
|
+
// usage failure, reported the way dispatch reports thrown errors.
|
|
1951
|
+
if (error instanceof LocateError) {
|
|
1952
|
+
return fail(`cave ${canonical}: ${error.message}\n`)
|
|
1953
|
+
}
|
|
1954
|
+
throw error
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
const run = (canonical: undefined | string, rest: readonly string[]): Output => {
|
|
1905
1959
|
switch (canonical) {
|
|
1906
1960
|
case 'parse':
|
|
1907
1961
|
return parseCommand(rest)
|
|
@@ -1948,6 +2002,6 @@ export const cave = (argv: readonly string[]): Output => {
|
|
|
1948
2002
|
case '-h':
|
|
1949
2003
|
return ok(`${usage}\n`)
|
|
1950
2004
|
default:
|
|
1951
|
-
return fail(`cave: unknown command ${JSON.stringify(
|
|
2005
|
+
return fail(`cave: unknown command ${JSON.stringify(canonical)}\n\n${usage}\n`, 2)
|
|
1952
2006
|
}
|
|
1953
2007
|
}
|
package/src/doctor.ts
CHANGED
|
@@ -249,7 +249,7 @@ const inspectDatabase = (path: string, source: DatabaseConfiguration['source']):
|
|
|
249
249
|
configuration,
|
|
250
250
|
checks: [check('store.database', 'warn',
|
|
251
251
|
`Database schema ${version} needs migration to schema ${Schema.currentVersion}`,
|
|
252
|
-
'
|
|
252
|
+
'Close every user and copy the database file as a rollback point, then open it with a writing command such as cave add to migrate it; reads never migrate.')]
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|