@cavelang/cli 0.27.14 → 0.29.1

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.
Files changed (321) hide show
  1. package/Authors.md +5 -0
  2. package/License.md +6 -0
  3. package/README.md +122 -24
  4. package/dist/internal/act/action.d.ts +69 -0
  5. package/dist/internal/act/action.d.ts.map +1 -0
  6. package/dist/internal/act/action.js +201 -0
  7. package/dist/internal/act/action.js.map +1 -0
  8. package/dist/internal/act/declare.d.ts +102 -0
  9. package/dist/internal/act/declare.d.ts.map +1 -0
  10. package/dist/internal/act/declare.js +270 -0
  11. package/dist/internal/act/declare.js.map +1 -0
  12. package/dist/internal/act/engine.d.ts +103 -0
  13. package/dist/internal/act/engine.d.ts.map +1 -0
  14. package/dist/internal/act/engine.js +298 -0
  15. package/dist/internal/act/engine.js.map +1 -0
  16. package/dist/internal/act/index.d.ts +27 -0
  17. package/dist/internal/act/index.d.ts.map +1 -0
  18. package/dist/internal/act/index.js +25 -0
  19. package/dist/internal/act/index.js.map +1 -0
  20. package/dist/internal/automate/automation.d.ts +78 -0
  21. package/dist/internal/automate/automation.d.ts.map +1 -0
  22. package/dist/internal/automate/automation.js +135 -0
  23. package/dist/internal/automate/automation.js.map +1 -0
  24. package/dist/internal/automate/declare.d.ts +84 -0
  25. package/dist/internal/automate/declare.d.ts.map +1 -0
  26. package/dist/internal/automate/declare.js +233 -0
  27. package/dist/internal/automate/declare.js.map +1 -0
  28. package/dist/internal/automate/engine.d.ts +125 -0
  29. package/dist/internal/automate/engine.d.ts.map +1 -0
  30. package/dist/internal/automate/engine.js +388 -0
  31. package/dist/internal/automate/engine.js.map +1 -0
  32. package/dist/internal/automate/index.d.ts +28 -0
  33. package/dist/internal/automate/index.d.ts.map +1 -0
  34. package/dist/internal/automate/index.js +26 -0
  35. package/dist/internal/automate/index.js.map +1 -0
  36. package/dist/internal/automate/main.d.ts +26 -0
  37. package/dist/internal/automate/main.d.ts.map +1 -0
  38. package/dist/internal/automate/main.js +298 -0
  39. package/dist/internal/automate/main.js.map +1 -0
  40. package/dist/internal/connect/index.d.ts +26 -0
  41. package/dist/internal/connect/index.d.ts.map +1 -0
  42. package/dist/internal/connect/index.js +24 -0
  43. package/dist/internal/connect/index.js.map +1 -0
  44. package/dist/internal/connect/main.d.ts +23 -0
  45. package/dist/internal/connect/main.d.ts.map +1 -0
  46. package/dist/internal/connect/main.js +330 -0
  47. package/dist/internal/connect/main.js.map +1 -0
  48. package/dist/internal/connect/run.d.ts +85 -0
  49. package/dist/internal/connect/run.d.ts.map +1 -0
  50. package/dist/internal/connect/run.js +242 -0
  51. package/dist/internal/connect/run.js.map +1 -0
  52. package/dist/internal/connect/source.d.ts +44 -0
  53. package/dist/internal/connect/source.d.ts.map +1 -0
  54. package/dist/internal/connect/source.js +215 -0
  55. package/dist/internal/connect/source.js.map +1 -0
  56. package/dist/internal/connect/template.d.ts +69 -0
  57. package/dist/internal/connect/template.d.ts.map +1 -0
  58. package/dist/internal/connect/template.js +221 -0
  59. package/dist/internal/connect/template.js.map +1 -0
  60. package/dist/internal/eval/index.d.ts +28 -0
  61. package/dist/internal/eval/index.d.ts.map +1 -0
  62. package/dist/internal/eval/index.js +27 -0
  63. package/dist/internal/eval/index.js.map +1 -0
  64. package/dist/internal/eval/judge.d.ts +30 -0
  65. package/dist/internal/eval/judge.d.ts.map +1 -0
  66. package/dist/internal/eval/judge.js +101 -0
  67. package/dist/internal/eval/judge.js.map +1 -0
  68. package/dist/internal/eval/loop.d.ts +64 -0
  69. package/dist/internal/eval/loop.d.ts.map +1 -0
  70. package/dist/internal/eval/loop.js +123 -0
  71. package/dist/internal/eval/loop.js.map +1 -0
  72. package/dist/internal/eval/main.d.ts +17 -0
  73. package/dist/internal/eval/main.d.ts.map +1 -0
  74. package/dist/internal/eval/main.js +236 -0
  75. package/dist/internal/eval/main.js.map +1 -0
  76. package/dist/internal/eval/queries.d.ts +74 -0
  77. package/dist/internal/eval/queries.d.ts.map +1 -0
  78. package/dist/internal/eval/queries.js +161 -0
  79. package/dist/internal/eval/queries.js.map +1 -0
  80. package/dist/internal/eval/run.d.ts +143 -0
  81. package/dist/internal/eval/run.d.ts.map +1 -0
  82. package/dist/internal/eval/run.js +376 -0
  83. package/dist/internal/eval/run.js.map +1 -0
  84. package/dist/internal/eval/score.d.ts +81 -0
  85. package/dist/internal/eval/score.d.ts.map +1 -0
  86. package/dist/internal/eval/score.js +126 -0
  87. package/dist/internal/eval/score.js.map +1 -0
  88. package/dist/internal/eval/suite.d.ts +66 -0
  89. package/dist/internal/eval/suite.d.ts.map +1 -0
  90. package/dist/internal/eval/suite.js +130 -0
  91. package/dist/internal/eval/suite.js.map +1 -0
  92. package/dist/internal/ingest/context.d.ts +20 -0
  93. package/dist/internal/ingest/context.d.ts.map +1 -0
  94. package/dist/internal/ingest/context.js +59 -0
  95. package/dist/internal/ingest/context.js.map +1 -0
  96. package/dist/internal/ingest/files.d.ts +46 -0
  97. package/dist/internal/ingest/files.d.ts.map +1 -0
  98. package/dist/internal/ingest/files.js +115 -0
  99. package/dist/internal/ingest/files.js.map +1 -0
  100. package/dist/internal/ingest/index.d.ts +31 -0
  101. package/dist/internal/ingest/index.d.ts.map +1 -0
  102. package/dist/internal/ingest/index.js +29 -0
  103. package/dist/internal/ingest/index.js.map +1 -0
  104. package/dist/internal/ingest/main.d.ts +12 -0
  105. package/dist/internal/ingest/main.d.ts.map +1 -0
  106. package/dist/internal/ingest/main.js +180 -0
  107. package/dist/internal/ingest/main.js.map +1 -0
  108. package/dist/internal/ingest/prompt.d.ts +32 -0
  109. package/dist/internal/ingest/prompt.d.ts.map +1 -0
  110. package/dist/internal/ingest/prompt.js +75 -0
  111. package/dist/internal/ingest/prompt.js.map +1 -0
  112. package/dist/internal/ingest/run.d.ts +142 -0
  113. package/dist/internal/ingest/run.d.ts.map +1 -0
  114. package/dist/internal/ingest/run.js +350 -0
  115. package/dist/internal/ingest/run.js.map +1 -0
  116. package/dist/internal/ingest/web.d.ts +48 -0
  117. package/dist/internal/ingest/web.d.ts.map +1 -0
  118. package/dist/internal/ingest/web.js +140 -0
  119. package/dist/internal/ingest/web.js.map +1 -0
  120. package/dist/internal/loop/demo.d.ts +22 -0
  121. package/dist/internal/loop/demo.d.ts.map +1 -0
  122. package/dist/internal/loop/demo.js +67 -0
  123. package/dist/internal/loop/demo.js.map +1 -0
  124. package/dist/internal/loop/index.d.ts +20 -0
  125. package/dist/internal/loop/index.d.ts.map +1 -0
  126. package/dist/internal/loop/index.js +17 -0
  127. package/dist/internal/loop/index.js.map +1 -0
  128. package/dist/internal/loop/llm.d.ts +99 -0
  129. package/dist/internal/loop/llm.d.ts.map +1 -0
  130. package/dist/internal/loop/llm.js +231 -0
  131. package/dist/internal/loop/llm.js.map +1 -0
  132. package/dist/internal/loop/reconstruct.d.ts +87 -0
  133. package/dist/internal/loop/reconstruct.d.ts.map +1 -0
  134. package/dist/internal/loop/reconstruct.js +157 -0
  135. package/dist/internal/loop/reconstruct.js.map +1 -0
  136. package/dist/internal/loop/sqlite.d.ts +13 -0
  137. package/dist/internal/loop/sqlite.d.ts.map +1 -0
  138. package/dist/internal/loop/sqlite.js +33 -0
  139. package/dist/internal/loop/sqlite.js.map +1 -0
  140. package/dist/internal/loop/store.d.ts +50 -0
  141. package/dist/internal/loop/store.d.ts.map +1 -0
  142. package/dist/internal/loop/store.js +100 -0
  143. package/dist/internal/loop/store.js.map +1 -0
  144. package/dist/internal/mcp/bin.d.ts +7 -0
  145. package/dist/internal/mcp/bin.d.ts.map +1 -0
  146. package/dist/internal/mcp/bin.js +8 -0
  147. package/dist/internal/mcp/bin.js.map +1 -0
  148. package/dist/internal/mcp/index.d.ts +25 -0
  149. package/dist/internal/mcp/index.d.ts.map +1 -0
  150. package/dist/internal/mcp/index.js +23 -0
  151. package/dist/internal/mcp/index.js.map +1 -0
  152. package/dist/internal/mcp/main.d.ts +23 -0
  153. package/dist/internal/mcp/main.d.ts.map +1 -0
  154. package/dist/internal/mcp/main.js +156 -0
  155. package/dist/internal/mcp/main.js.map +1 -0
  156. package/dist/internal/mcp/server.d.ts +92 -0
  157. package/dist/internal/mcp/server.d.ts.map +1 -0
  158. package/dist/internal/mcp/server.js +251 -0
  159. package/dist/internal/mcp/server.js.map +1 -0
  160. package/dist/internal/mcp/tools.d.ts +91 -0
  161. package/dist/internal/mcp/tools.d.ts.map +1 -0
  162. package/dist/internal/mcp/tools.js +584 -0
  163. package/dist/internal/mcp/tools.js.map +1 -0
  164. package/dist/internal/rules/declare.d.ts +58 -0
  165. package/dist/internal/rules/declare.d.ts.map +1 -0
  166. package/dist/internal/rules/declare.js +152 -0
  167. package/dist/internal/rules/declare.js.map +1 -0
  168. package/dist/internal/rules/engine.d.ts +125 -0
  169. package/dist/internal/rules/engine.d.ts.map +1 -0
  170. package/dist/internal/rules/engine.js +575 -0
  171. package/dist/internal/rules/engine.js.map +1 -0
  172. package/dist/internal/rules/index.d.ts +23 -0
  173. package/dist/internal/rules/index.d.ts.map +1 -0
  174. package/dist/internal/rules/index.js +21 -0
  175. package/dist/internal/rules/index.js.map +1 -0
  176. package/dist/internal/rules/rule.d.ts +88 -0
  177. package/dist/internal/rules/rule.d.ts.map +1 -0
  178. package/dist/internal/rules/rule.js +221 -0
  179. package/dist/internal/rules/rule.js.map +1 -0
  180. package/dist/internal/shape/check.d.ts +118 -0
  181. package/dist/internal/shape/check.d.ts.map +1 -0
  182. package/dist/internal/shape/check.js +331 -0
  183. package/dist/internal/shape/check.js.map +1 -0
  184. package/dist/internal/shape/client.d.ts +31 -0
  185. package/dist/internal/shape/client.d.ts.map +1 -0
  186. package/dist/internal/shape/client.js +170 -0
  187. package/dist/internal/shape/client.js.map +1 -0
  188. package/dist/internal/shape/gate.d.ts +33 -0
  189. package/dist/internal/shape/gate.d.ts.map +1 -0
  190. package/dist/internal/shape/gate.js +0 -0
  191. package/dist/internal/shape/gate.js.map +1 -0
  192. package/dist/internal/shape/index.d.ts +27 -0
  193. package/dist/internal/shape/index.d.ts.map +1 -0
  194. package/dist/internal/shape/index.js +23 -0
  195. package/dist/internal/shape/index.js.map +1 -0
  196. package/dist/internal/shape/suggest.d.ts +82 -0
  197. package/dist/internal/shape/suggest.d.ts.map +1 -0
  198. package/dist/internal/shape/suggest.js +374 -0
  199. package/dist/internal/shape/suggest.js.map +1 -0
  200. package/dist/internal/sync/index.d.ts +22 -0
  201. package/dist/internal/sync/index.d.ts.map +1 -0
  202. package/dist/internal/sync/index.js +21 -0
  203. package/dist/internal/sync/index.js.map +1 -0
  204. package/dist/internal/sync/sync.d.ts +95 -0
  205. package/dist/internal/sync/sync.d.ts.map +1 -0
  206. package/dist/internal/sync/sync.js +342 -0
  207. package/dist/internal/sync/sync.js.map +1 -0
  208. package/dist/internal/view/api.d.ts +196 -0
  209. package/dist/internal/view/api.d.ts.map +1 -0
  210. package/dist/internal/view/api.js +189 -0
  211. package/dist/internal/view/api.js.map +1 -0
  212. package/dist/internal/view/index.d.ts +33 -0
  213. package/dist/internal/view/index.d.ts.map +1 -0
  214. package/dist/internal/view/index.js +30 -0
  215. package/dist/internal/view/index.js.map +1 -0
  216. package/dist/internal/view/main.d.ts +11 -0
  217. package/dist/internal/view/main.d.ts.map +1 -0
  218. package/dist/internal/view/main.js +98 -0
  219. package/dist/internal/view/main.js.map +1 -0
  220. package/dist/internal/view/page.d.ts +14 -0
  221. package/dist/internal/view/page.d.ts.map +1 -0
  222. package/dist/internal/view/page.js +370 -0
  223. package/dist/internal/view/page.js.map +1 -0
  224. package/dist/internal/view/report.d.ts +52 -0
  225. package/dist/internal/view/report.d.ts.map +1 -0
  226. package/dist/internal/view/report.js +367 -0
  227. package/dist/internal/view/report.js.map +1 -0
  228. package/dist/internal/view/scope.d.ts +11 -0
  229. package/dist/internal/view/scope.d.ts.map +1 -0
  230. package/dist/internal/view/scope.js +41 -0
  231. package/dist/internal/view/scope.js.map +1 -0
  232. package/dist/internal/view/server.d.ts +35 -0
  233. package/dist/internal/view/server.d.ts.map +1 -0
  234. package/dist/internal/view/server.js +141 -0
  235. package/dist/internal/view/server.js.map +1 -0
  236. package/dist/src/act.d.ts +3 -0
  237. package/dist/src/act.d.ts.map +1 -0
  238. package/dist/src/act.js +3 -0
  239. package/dist/src/act.js.map +1 -0
  240. package/dist/src/automate.d.ts +3 -0
  241. package/dist/src/automate.d.ts.map +1 -0
  242. package/dist/src/automate.js +3 -0
  243. package/dist/src/automate.js.map +1 -0
  244. package/dist/src/cli.d.ts +24 -17
  245. package/dist/src/cli.d.ts.map +1 -1
  246. package/dist/src/cli.js +408 -107
  247. package/dist/src/cli.js.map +1 -1
  248. package/dist/src/commands.d.ts +104 -0
  249. package/dist/src/commands.d.ts.map +1 -0
  250. package/dist/src/commands.js +33 -0
  251. package/dist/src/commands.js.map +1 -0
  252. package/dist/src/connect.d.ts +3 -0
  253. package/dist/src/connect.d.ts.map +1 -0
  254. package/dist/src/connect.js +3 -0
  255. package/dist/src/connect.js.map +1 -0
  256. package/dist/src/dispatch.d.ts +14 -0
  257. package/dist/src/dispatch.d.ts.map +1 -0
  258. package/dist/src/dispatch.js +116 -0
  259. package/dist/src/dispatch.js.map +1 -0
  260. package/dist/src/doctor.d.ts +45 -0
  261. package/dist/src/doctor.d.ts.map +1 -0
  262. package/dist/src/doctor.js +284 -0
  263. package/dist/src/doctor.js.map +1 -0
  264. package/dist/src/eval.d.ts +3 -0
  265. package/dist/src/eval.d.ts.map +1 -0
  266. package/dist/src/eval.js +3 -0
  267. package/dist/src/eval.js.map +1 -0
  268. package/dist/src/index.d.ts +9 -2
  269. package/dist/src/index.d.ts.map +1 -1
  270. package/dist/src/index.js +6 -2
  271. package/dist/src/index.js.map +1 -1
  272. package/dist/src/ingest.d.ts +3 -0
  273. package/dist/src/ingest.d.ts.map +1 -0
  274. package/dist/src/ingest.js +3 -0
  275. package/dist/src/ingest.js.map +1 -0
  276. package/dist/src/loop.d.ts +3 -0
  277. package/dist/src/loop.d.ts.map +1 -0
  278. package/dist/src/loop.js +3 -0
  279. package/dist/src/loop.js.map +1 -0
  280. package/dist/src/main.d.ts +1 -1
  281. package/dist/src/main.d.ts.map +1 -1
  282. package/dist/src/main.js +3 -75
  283. package/dist/src/main.js.map +1 -1
  284. package/dist/src/mcp.d.ts +3 -0
  285. package/dist/src/mcp.d.ts.map +1 -0
  286. package/dist/src/mcp.js +3 -0
  287. package/dist/src/mcp.js.map +1 -0
  288. package/dist/src/rules.d.ts +3 -0
  289. package/dist/src/rules.d.ts.map +1 -0
  290. package/dist/src/rules.js +3 -0
  291. package/dist/src/rules.js.map +1 -0
  292. package/dist/src/shape.d.ts +3 -0
  293. package/dist/src/shape.d.ts.map +1 -0
  294. package/dist/src/shape.js +3 -0
  295. package/dist/src/shape.js.map +1 -0
  296. package/dist/src/sync.d.ts +3 -0
  297. package/dist/src/sync.d.ts.map +1 -0
  298. package/dist/src/sync.js +3 -0
  299. package/dist/src/sync.js.map +1 -0
  300. package/dist/src/view.d.ts +3 -0
  301. package/dist/src/view.d.ts.map +1 -0
  302. package/dist/src/view.js +3 -0
  303. package/dist/src/view.js.map +1 -0
  304. package/package.json +81 -21
  305. package/src/act.ts +2 -0
  306. package/src/automate.ts +2 -0
  307. package/src/cli.ts +416 -102
  308. package/src/commands.ts +48 -0
  309. package/src/connect.ts +2 -0
  310. package/src/dispatch.ts +141 -0
  311. package/src/doctor.ts +370 -0
  312. package/src/eval.ts +2 -0
  313. package/src/index.ts +9 -2
  314. package/src/ingest.ts +2 -0
  315. package/src/loop.ts +2 -0
  316. package/src/main.ts +3 -66
  317. package/src/mcp.ts +2 -0
  318. package/src/rules.ts +2 -0
  319. package/src/shape.ts +2 -0
  320. package/src/sync.ts +2 -0
  321. package/src/view.ts +2 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Authoritative inventory of the commands shipped by the `cave` binary.
3
+ *
4
+ * `importantOptions` is deliberately smaller than each command's complete
5
+ * `--help`: it is the review contract for the package README's reference
6
+ * table. Add a command or an option here when it becomes part of the public
7
+ * surface; the documentation test then identifies every stale copy.
8
+ */
9
+ export type CommandReference = {
10
+ readonly name: string
11
+ readonly importantOptions: readonly string[]
12
+ /** The command implementation and detailed help live in another package. */
13
+ readonly delegated?: true
14
+ }
15
+
16
+ export const commandRegistry = [
17
+ { name: 'parse', importantOptions: ['--json'] },
18
+ { name: 'highlight', importantOptions: [] },
19
+ { name: 'add', importantOptions: ['--strict', '--check', '--no-prelude', '--no-src'] },
20
+ { name: 'import', importantOptions: ['--strict', '--no-prelude'] },
21
+ { name: 'query', importantOptions: ['--json', '--limit', '--cursor', '--all', '--aliases', '--as-of', '--at', '--resolve', '--no-prelude'] },
22
+ { name: 'resolve', importantOptions: ['--aliases', '--policy', '--json', '--no-prelude'] },
23
+ { name: 'derive', importantOptions: ['--dry-run', '--full', '--aliases', '--min-conf', '--max-passes', '--list', '--retract', '--json', '--no-prelude'] },
24
+ { name: 'act', importantOptions: ['--declare', '--list', '--retract', '--dry-run', '--no-check', '--aliases', '--hooks', '--json', '--no-prelude'] },
25
+ { name: 'automate', importantOptions: ['--once', '--declare', '--list', '--retract', '--hooks', '--agent', '--json', '--no-prelude'], delegated: true },
26
+ { name: 'check', importantOptions: ['--stale', '--json', '--no-prelude'] },
27
+ { name: 'backup', importantOptions: ['--out', '--force', '--verify', '--sha256'] },
28
+ { name: 'restore', importantOptions: ['--db', '--force', '--sha256'] },
29
+ { name: 'generate', importantOptions: ['--out', '--version', '--no-prelude'] },
30
+ { name: 'suggest-alias', importantOptions: ['--min', '--limit', '--agent', '--timeout', '--write', '--json', '--no-prelude'] },
31
+ { name: 'sync', importantOptions: ['--as', '--into', '--dry-run', '--no-record', '--json', '--no-prelude'] },
32
+ { name: 'export', importantOptions: ['--out', '--current', '--tx', '--max-sensitivity', '--no-prelude'] },
33
+ { name: 'report', importantOptions: ['--out', '--aliases', '--resolve', '--as-of', '--at', '--max-sensitivity', '--no-prelude'] },
34
+ { name: 'serve', importantOptions: ['--port', '--host', '--max-sensitivity', '--no-prelude'], delegated: true },
35
+ { name: 'mcp', importantOptions: ['--read-only', '--permissions', '--tools', '--hooks', '--no-prelude', '--src', '--no-src'], delegated: true },
36
+ { name: 'ingest', importantOptions: ['--agent', '--stdout', '--lenient', '--plan', '--dry-run', '--json', '--no-prelude'], delegated: true },
37
+ { name: 'eval', importantOptions: ['--agent', '--judge', '--runs', '--stdout', '--min', '--json', '--no-prelude'], delegated: true },
38
+ { name: 'connect', importantOptions: ['--map', '--key', '--watch', '--prune', '--query', '--dry-run', '--no-prelude'], delegated: true },
39
+ { name: 'reconstruct', importantOptions: ['--query', '--agent', '--steps', '--claims', '--timeout', '--trace', '--no-prelude'] },
40
+ { name: 'doctor', importantOptions: ['--hooks', '--json'] },
41
+ { name: 'demo', importantOptions: [] },
42
+ { name: 'version', importantOptions: [] },
43
+ { name: 'help', importantOptions: [] }
44
+ ] as const satisfies readonly CommandReference[]
45
+
46
+ export const delegatedCommandNames: readonly string[] = commandRegistry
47
+ .filter(command => 'delegated' in command && command.delegated === true)
48
+ .map(command => command.name)
package/src/connect.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Compatibility subpath for deterministic structured ingestion. */
2
+ export * from '@cavelang/connect'
@@ -0,0 +1,141 @@
1
+ /** One promise-based command dispatcher and process lifecycle for every command. */
2
+
3
+ import { cave, highlightCommand, reconstructCommand, suggestAliasCommand } from './cli.ts'
4
+ import { delegatedCommandNames } from './commands.ts'
5
+ import type { Output } from './cli.ts'
6
+
7
+ export type CommandRuntime = {
8
+ readonly stdin: NodeJS.ReadableStream
9
+ readonly stdout: NodeJS.WritableStream
10
+ readonly stderr: NodeJS.WritableStream
11
+ readonly signal?: AbortSignal
12
+ /** Include stack traces for unexpected exceptions. */
13
+ readonly debug?: boolean
14
+ }
15
+
16
+ const processRuntime = (): CommandRuntime => ({
17
+ stdin: process.stdin,
18
+ stdout: process.stdout,
19
+ stderr: process.stderr,
20
+ debug: process.env['CAVE_DEBUG'] === '1'
21
+ })
22
+
23
+ const delegatedHelp = new Set<string>(delegatedCommandNames)
24
+
25
+ const normalizedArgs = (raw: readonly string[]): readonly string[] =>
26
+ raw[0] === 'help' && raw[1] !== undefined && delegatedHelp.has(raw[1]) ? [raw[1], '--help'] : raw
27
+
28
+ const write = (runtime: CommandRuntime, output: Output): number => {
29
+ if (output.out !== '') runtime.stdout.write(output.out)
30
+ if (output.err !== '') runtime.stderr.write(output.err)
31
+ return output.code
32
+ }
33
+
34
+ const runOutput = async (
35
+ runtime: CommandRuntime,
36
+ argv: readonly string[],
37
+ handler: (args: readonly string[]) => Output | Promise<Output>
38
+ ): Promise<number> => {
39
+ runtime.signal?.throwIfAborted()
40
+ const output = await handler(argv.slice(1))
41
+ runtime.signal?.throwIfAborted()
42
+ return write(runtime, output)
43
+ }
44
+
45
+ const execute = async (raw: readonly string[], runtime: CommandRuntime): Promise<number> => {
46
+ const argv = normalizedArgs(raw)
47
+ const [command, ...rest] = argv
48
+ const context = {
49
+ stdin: runtime.stdin,
50
+ stdout: runtime.stdout,
51
+ stderr: runtime.stderr,
52
+ ...runtime.signal === undefined ? {} : { signal: runtime.signal }
53
+ }
54
+ switch (command) {
55
+ case 'mcp': {
56
+ const { runMcp } = await import('@cavelang/mcp')
57
+ return await runMcp(rest, context)
58
+ }
59
+ case 'ingest': {
60
+ const { runIngest } = await import('@cavelang/ingest')
61
+ return await runIngest(rest, context)
62
+ }
63
+ case 'eval': {
64
+ const { runEval } = await import('@cavelang/eval')
65
+ return await runEval(rest, context)
66
+ }
67
+ case 'connect': {
68
+ const { runConnect } = await import('@cavelang/connect')
69
+ return await runConnect(rest, context)
70
+ }
71
+ case 'automate': {
72
+ const { runAutomate } = await import('@cavelang/automate')
73
+ return await runAutomate(rest, context)
74
+ }
75
+ case 'serve': {
76
+ const { runServe } = await import('@cavelang/view')
77
+ return await runServe(rest, context)
78
+ }
79
+ case 'reconstruct':
80
+ return await runOutput(runtime, argv, reconstructCommand)
81
+ case 'suggest-alias':
82
+ return await runOutput(runtime, argv, suggestAliasCommand)
83
+ case 'highlight':
84
+ if (!rest.includes('--help') && !rest.includes('-h')) {
85
+ return await runOutput(runtime, argv, highlightCommand)
86
+ }
87
+ break
88
+ }
89
+
90
+ runtime.signal?.throwIfAborted()
91
+ const output = await Promise.resolve(cave(argv))
92
+ runtime.signal?.throwIfAborted()
93
+ const colorize = output.code === 0 && command === 'export' && !rest.includes('--out') &&
94
+ output.out !== '' && runtime.stdout === process.stdout && process.stdout.isTTY === true &&
95
+ process.env['NO_COLOR'] === undefined
96
+ if (!colorize) return write(runtime, output)
97
+ const { highlighter } = await import('@cavelang/highlight')
98
+ return write(runtime, { ...output, out: (await highlighter()).ansi(output.out) })
99
+ }
100
+
101
+ /** Dispatch one invocation through the shared argument, I/O, error, and exit path. */
102
+ export const dispatch = async (
103
+ argv: readonly string[],
104
+ runtime: CommandRuntime = processRuntime()
105
+ ): Promise<number> => {
106
+ try {
107
+ return await execute(argv, runtime)
108
+ } catch (error) {
109
+ if (runtime.signal?.aborted === true) return 0
110
+ const command = argv[0] === 'q' ? 'query' : argv[0]
111
+ const message = runtime.debug === true && error instanceof Error && error.stack !== undefined ?
112
+ error.stack : error instanceof Error ? error.message : String(error)
113
+ runtime.stderr.write(`cave${command === undefined || command.startsWith('-') ? '' : ` ${command}`}: ${message}\n`)
114
+ return 1
115
+ }
116
+ }
117
+
118
+ const signalExitCode = { SIGINT: 130, SIGTERM: 143 } as const
119
+
120
+ /** Run the process lifecycle, aborting handlers and awaiting their cleanup on signals. */
121
+ export const runCli = async (
122
+ argv: readonly string[],
123
+ runtime: CommandRuntime = processRuntime()
124
+ ): Promise<number> => {
125
+ const controller = new AbortController()
126
+ let received: keyof typeof signalExitCode | undefined
127
+ const handlers = {
128
+ SIGINT: (): void => { received = 'SIGINT'; controller.abort() },
129
+ SIGTERM: (): void => { received = 'SIGTERM'; controller.abort() }
130
+ }
131
+ process.once('SIGINT', handlers.SIGINT)
132
+ process.once('SIGTERM', handlers.SIGTERM)
133
+ const signal = runtime.signal === undefined ? controller.signal : AbortSignal.any([runtime.signal, controller.signal])
134
+ try {
135
+ const code = await dispatch(argv, { ...runtime, signal })
136
+ return received === undefined ? code : signalExitCode[received]
137
+ } finally {
138
+ process.removeListener('SIGINT', handlers.SIGINT)
139
+ process.removeListener('SIGTERM', handlers.SIGTERM)
140
+ }
141
+ }
package/src/doctor.ts ADDED
@@ -0,0 +1,370 @@
1
+ /** Read-only installation, runtime, and store diagnostics for `cave doctor`. */
2
+
3
+ import { existsSync, readFileSync, statSync } from 'node:fs'
4
+ import { createRequire } from 'node:module'
5
+ import { dirname, join, parse } from 'node:path'
6
+ import { spawnSync } from 'node:child_process'
7
+ import { parseArgs } from 'node:util'
8
+ import { Version } from '@cavelang/core'
9
+ import { Schema, defaultDbPath } from '@cavelang/store'
10
+ import { nodeSqliteAdapter } from '@cavelang/store/adapter/node'
11
+ import type { SqliteDatabase } from '@cavelang/store/adapter'
12
+
13
+ export type DoctorStatus = 'pass' | 'warn' | 'fail'
14
+
15
+ export type DoctorCheck = {
16
+ readonly id: string
17
+ readonly status: DoctorStatus
18
+ readonly summary: string
19
+ readonly remediation?: string
20
+ }
21
+
22
+ export type DoctorReport = {
23
+ readonly format: 'cave.doctor'
24
+ readonly version: 1
25
+ readonly ok: boolean
26
+ readonly caveVersion: string
27
+ readonly runtime: {
28
+ readonly node: string
29
+ readonly platform: NodeJS.Platform
30
+ readonly arch: string
31
+ }
32
+ readonly configuration: {
33
+ readonly database: {
34
+ readonly source: 'flag' | 'environment' | 'default'
35
+ readonly kind: 'memory' | 'file'
36
+ readonly exists: boolean
37
+ readonly schemaVersion?: number
38
+ readonly claims?: number
39
+ }
40
+ readonly hooks: {
41
+ readonly source: 'flag' | 'none'
42
+ readonly exists: boolean
43
+ readonly entries?: number
44
+ }
45
+ }
46
+ readonly checks: readonly DoctorCheck[]
47
+ }
48
+
49
+ export type DoctorOutput = {
50
+ readonly code: number
51
+ readonly out: string
52
+ readonly err: string
53
+ }
54
+
55
+ const requiredNode = '22.18.0'
56
+
57
+ const versionParts = (value: string): readonly [number, number, number] | undefined => {
58
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(value)
59
+ return match === null ? undefined : [Number(match[1]), Number(match[2]), Number(match[3])]
60
+ }
61
+
62
+ const numericVersion = (value: string): string | undefined => {
63
+ const parts = versionParts(value)
64
+ return parts === undefined ? undefined : parts.join('.')
65
+ }
66
+
67
+ const atLeast = (actual: string, required: string): boolean => {
68
+ const a = versionParts(actual)
69
+ const b = versionParts(required)
70
+ if (a === undefined || b === undefined) return false
71
+ for (let index = 0; index < 3; index += 1) {
72
+ if (a[index]! !== b[index]!) return a[index]! > b[index]!
73
+ }
74
+ return true
75
+ }
76
+
77
+ const check = (
78
+ id: string,
79
+ status: DoctorStatus,
80
+ summary: string,
81
+ remediation?: string
82
+ ): DoctorCheck => ({ id, status, summary, ...remediation === undefined ? {} : { remediation } })
83
+
84
+ const nodeCheck = (): DoctorCheck =>
85
+ atLeast(process.versions.node, requiredNode) ?
86
+ check('runtime.node', 'pass', `Node ${process.versions.node} satisfies >=${requiredNode}`) :
87
+ check('runtime.node', 'fail', `Node ${process.versions.node} is unsupported`,
88
+ `Install Node ${requiredNode} or newer and rerun cave doctor.`)
89
+
90
+ const sqliteCheck = (): DoctorCheck => {
91
+ let db: SqliteDatabase | undefined
92
+ try {
93
+ db = nodeSqliteAdapter.open(':memory:')
94
+ db.exec('PRAGMA foreign_keys = ON')
95
+ const sqlite = db.prepare('SELECT sqlite_version() AS version').get()?.['version']
96
+ const json = db.prepare(`SELECT json_valid('{}') AS available`).get()?.['available']
97
+ const foreignKeys = db.prepare('PRAGMA foreign_keys').get()?.['foreign_keys']
98
+ db.exec('CREATE VIRTUAL TABLE doctor_fts USING fts5(value)')
99
+ db.exec('DROP TABLE doctor_fts')
100
+ if (typeof sqlite !== 'string' || json !== 1 || foreignKeys !== 1 ||
101
+ nodeSqliteAdapter.capabilities.loadExtension === undefined) {
102
+ throw new Error('capability unavailable')
103
+ }
104
+ return check('runtime.sqlite', 'pass',
105
+ `SQLite ${sqlite} supports FTS5, JSON functions, foreign keys, and extension loading`)
106
+ } catch {
107
+ return check('runtime.sqlite', 'fail', 'The Node SQLite runtime lacks a required capability',
108
+ `Use an official Node ${requiredNode}+ build with SQLite FTS5 and JSON support.`)
109
+ } finally {
110
+ db?.close()
111
+ }
112
+ }
113
+
114
+ const grammarCheck = (): DoctorCheck => {
115
+ try {
116
+ const fromHighlight = createRequire(import.meta.resolve('@cavelang/highlight'))
117
+ const assets = [
118
+ fromHighlight.resolve('@cavelang/tree-sitter-cave/wasm'),
119
+ fromHighlight.resolve('@cavelang/tree-sitter-cave/highlights')
120
+ ]
121
+ if (assets.some(asset => !statSync(asset).isFile() || statSync(asset).size === 0)) {
122
+ throw new Error('asset unavailable')
123
+ }
124
+ return check('package.grammar', 'pass', 'Grammar WASM and highlight query are installed')
125
+ } catch {
126
+ return check('package.grammar', 'fail', 'Grammar assets are missing from the installed package layout',
127
+ 'Reinstall @cavelang/cli without omitting its production dependencies.')
128
+ }
129
+ }
130
+
131
+ type Workspace = { readonly packageManager: string }
132
+
133
+ const workspaceFrom = (start: string): Workspace | undefined => {
134
+ let directory = start
135
+ while (true) {
136
+ if (existsSync(join(directory, 'pnpm-workspace.yaml'))) {
137
+ try {
138
+ const manifest = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8')) as {
139
+ packageManager?: unknown
140
+ }
141
+ if (typeof manifest.packageManager === 'string' && manifest.packageManager.startsWith('pnpm@')) {
142
+ return { packageManager: manifest.packageManager }
143
+ }
144
+ } catch {
145
+ return { packageManager: 'pnpm' }
146
+ }
147
+ return { packageManager: 'pnpm' }
148
+ }
149
+ const parent = dirname(directory)
150
+ if (parent === directory || directory === parse(directory).root) return undefined
151
+ directory = parent
152
+ }
153
+ }
154
+
155
+ const pnpmCheck = (): DoctorCheck => {
156
+ const workspace = workspaceFrom(process.cwd())
157
+ if (workspace === undefined) {
158
+ return check('workspace.pnpm', 'pass', 'pnpm is not required for this installed CLI')
159
+ }
160
+ const result = spawnSync('pnpm', ['--version'], {
161
+ encoding: 'utf8',
162
+ timeout: 3_000,
163
+ stdio: ['ignore', 'pipe', 'ignore']
164
+ })
165
+ const actual = result.status === 0 ? numericVersion(result.stdout.trim()) : undefined
166
+ const pinned = workspace.packageManager.startsWith('pnpm@')
167
+ const required = pinned ? numericVersion(workspace.packageManager.slice('pnpm@'.length)) : undefined
168
+ if (actual === undefined) {
169
+ return check('workspace.pnpm', 'fail', 'This workspace requires pnpm, but pnpm is unavailable',
170
+ 'Enable Corepack or install the pnpm version declared by the workspace.')
171
+ }
172
+ if (required !== undefined && !atLeast(actual, required)) {
173
+ return check('workspace.pnpm', 'fail', `pnpm ${actual} is older than the workspace requirement`,
174
+ `Enable Corepack or install pnpm ${required}.`)
175
+ }
176
+ return check('workspace.pnpm', 'pass', `pnpm ${actual} satisfies the workspace requirement`)
177
+ }
178
+
179
+ type DatabaseConfiguration = DoctorReport['configuration']['database']
180
+
181
+ const inspectDatabase = (path: string, source: DatabaseConfiguration['source']): {
182
+ readonly configuration: DatabaseConfiguration
183
+ readonly checks: readonly DoctorCheck[]
184
+ } => {
185
+ const memory = path === ':memory:'
186
+ const exists = memory || existsSync(path)
187
+ const base: DatabaseConfiguration = { source, kind: memory ? 'memory' : 'file', exists }
188
+ if (!exists) {
189
+ return {
190
+ configuration: base,
191
+ checks: [check('store.database', 'warn', 'The configured database does not exist yet',
192
+ 'Run cave add to create it, or pass --db for an existing store.')]
193
+ }
194
+ }
195
+
196
+ let db: SqliteDatabase | undefined
197
+ let observed = base
198
+ try {
199
+ db = nodeSqliteAdapter.open(path, { readOnly: true })
200
+ const version = db.prepare('PRAGMA user_version').get()?.['user_version']
201
+ if (typeof version !== 'number') throw new Error('invalid version')
202
+ const caveObjects = db.prepare(
203
+ `SELECT count(*) AS count FROM sqlite_schema WHERE name LIKE 'cave_%' OR name LIKE 'idx_cave_%'`
204
+ ).get()?.['count']
205
+ const configuration = { ...base, schemaVersion: version }
206
+ observed = configuration
207
+
208
+ if (version > Schema.currentVersion) {
209
+ return {
210
+ configuration,
211
+ checks: [check('store.database', 'fail',
212
+ `Database schema ${version} is newer than supported schema ${Schema.currentVersion}`,
213
+ 'Upgrade CAVE before opening this database.')]
214
+ }
215
+ }
216
+ if (version === 0 && caveObjects === 0) {
217
+ return {
218
+ configuration,
219
+ checks: [check('store.database', 'warn', 'The database is readable but is not initialized as a CAVE store',
220
+ 'Run cave add to initialize it; cave doctor made no changes.')]
221
+ }
222
+ }
223
+ if (version < Schema.currentVersion) {
224
+ return {
225
+ configuration,
226
+ checks: [check('store.database', 'warn',
227
+ `Database schema ${version} needs migration to schema ${Schema.currentVersion}`,
228
+ 'Back up the database, then open it with a normal cave command to migrate it.')]
229
+ }
230
+ }
231
+
232
+ Schema.validate(db, version)
233
+ const integrity = db.prepare('PRAGMA integrity_check').all()
234
+ if (integrity.length !== 1 || integrity[0]?.['integrity_check'] !== 'ok') {
235
+ return {
236
+ configuration,
237
+ checks: [check('store.integrity', 'fail', 'SQLite integrity checking failed',
238
+ 'Restore a verified backup or recover the database with SQLite tooling.')]
239
+ }
240
+ }
241
+ const foreignKeys = db.prepare('PRAGMA foreign_key_check').all()
242
+ if (foreignKeys.length > 0) {
243
+ return {
244
+ configuration,
245
+ checks: [check('store.integrity', 'fail', 'The store contains broken foreign-key references',
246
+ 'Restore a verified backup or repair the affected database rows.')]
247
+ }
248
+ }
249
+ const claims = db.prepare('SELECT count(*) AS count FROM cave_claim').get()?.['count']
250
+ if (typeof claims !== 'number') throw new Error('invalid count')
251
+ return {
252
+ configuration: { ...configuration, claims },
253
+ checks: [
254
+ check('store.database', 'pass', `CAVE schema ${version} is compatible (${claims} claim(s))`),
255
+ check('store.integrity', 'pass', 'SQLite integrity and foreign-key checks passed')
256
+ ]
257
+ }
258
+ } catch {
259
+ return {
260
+ configuration: observed,
261
+ checks: [check('store.database', 'fail', 'The configured database is unreadable or has an incompatible schema',
262
+ 'Check file permissions, restore a verified backup, or pass --db for another store.')]
263
+ }
264
+ } finally {
265
+ db?.close()
266
+ }
267
+ }
268
+
269
+ type HooksConfiguration = DoctorReport['configuration']['hooks']
270
+
271
+ const inspectHooks = (path: string | undefined): {
272
+ readonly configuration: HooksConfiguration
273
+ readonly check: DoctorCheck
274
+ } => {
275
+ if (path === undefined) {
276
+ return {
277
+ configuration: { source: 'none', exists: false },
278
+ check: check('config.hooks', 'pass', 'No optional hooks file was configured')
279
+ }
280
+ }
281
+ const configuration = { source: 'flag' as const, exists: existsSync(path) }
282
+ if (!configuration.exists) {
283
+ return {
284
+ configuration,
285
+ check: check('config.hooks', 'fail', 'The configured hooks file does not exist',
286
+ 'Create a JSON object of hook names to shell command strings, or omit --hooks.')
287
+ }
288
+ }
289
+ try {
290
+ const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'))
291
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) throw new Error('invalid')
292
+ const entries = Object.entries(parsed)
293
+ if (entries.some(([name, command]) => name.trim() === '' || typeof command !== 'string')) {
294
+ throw new Error('invalid')
295
+ }
296
+ return {
297
+ configuration: { ...configuration, entries: entries.length },
298
+ check: check('config.hooks', 'pass', `Hooks configuration is valid (${entries.length} entr${entries.length === 1 ? 'y' : 'ies'})`)
299
+ }
300
+ } catch {
301
+ return {
302
+ configuration,
303
+ check: check('config.hooks', 'fail', 'The configured hooks file is unreadable or malformed',
304
+ 'Use a JSON object whose values are shell command strings.')
305
+ }
306
+ }
307
+ }
308
+
309
+ export const diagnose = (options: { readonly db?: string, readonly hooks?: string } = {}): DoctorReport => {
310
+ const databasePath = options.db ?? defaultDbPath()
311
+ const databaseSource: DatabaseConfiguration['source'] = options.db !== undefined ? 'flag' :
312
+ process.env['CAVE_DB'] !== undefined ? 'environment' : 'default'
313
+ const database = inspectDatabase(databasePath, databaseSource)
314
+ const hooks = inspectHooks(options.hooks)
315
+ const checks = [
316
+ nodeCheck(),
317
+ sqliteCheck(),
318
+ grammarCheck(),
319
+ pnpmCheck(),
320
+ ...database.checks,
321
+ hooks.check
322
+ ]
323
+ return {
324
+ format: 'cave.doctor',
325
+ version: 1,
326
+ ok: checks.every(entry => entry.status !== 'fail'),
327
+ caveVersion: Version.current(),
328
+ runtime: { node: process.versions.node, platform: process.platform, arch: process.arch },
329
+ configuration: { database: database.configuration, hooks: hooks.configuration },
330
+ checks
331
+ }
332
+ }
333
+
334
+ const render = (report: DoctorReport): string => {
335
+ const lines = [`cave doctor ${report.caveVersion}`]
336
+ for (const entry of report.checks) {
337
+ lines.push(`${entry.status.toUpperCase().padEnd(4)} ${entry.summary}`)
338
+ if (entry.remediation !== undefined) lines.push(` ${entry.remediation}`)
339
+ }
340
+ const failures = report.checks.filter(entry => entry.status === 'fail').length
341
+ const warnings = report.checks.filter(entry => entry.status === 'warn').length
342
+ lines.push(report.ok ?
343
+ `result: ready${warnings === 0 ? '' : ` with ${warnings} warning(s)`}` :
344
+ `result: ${failures} problem(s), ${warnings} warning(s)`)
345
+ return `${lines.join('\n')}\n`
346
+ }
347
+
348
+ export const doctorCommand = (argv: readonly string[]): DoctorOutput => {
349
+ const { values, positionals } = parseArgs({
350
+ args: [...argv],
351
+ options: {
352
+ db: { type: 'string' },
353
+ hooks: { type: 'string' },
354
+ json: { type: 'boolean' }
355
+ },
356
+ allowPositionals: true
357
+ })
358
+ if (positionals.length > 0) {
359
+ return { code: 2, out: '', err: 'cave doctor: unexpected positional arguments\n' }
360
+ }
361
+ const report = diagnose({
362
+ ...values.db === undefined ? {} : { db: values.db },
363
+ ...values.hooks === undefined ? {} : { hooks: values.hooks }
364
+ })
365
+ return {
366
+ code: report.ok ? 0 : 1,
367
+ out: values.json === true ? `${JSON.stringify(report, undefined, 2)}\n` : render(report),
368
+ err: ''
369
+ }
370
+ }
package/src/eval.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Compatibility subpath for the evaluation tooling. */
2
+ export * from '@cavelang/eval'
package/src/index.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  /**
2
2
  * `@cavelang/cli` — the `cave` command (parse / add / query / resolve / derive / act / check / suggest-alias / sync / export / report / reconstruct / demo).
3
- * Programmatic access to the same implementations lives here.
3
+ * Programmatic access to the same implementations lives here; `dispatch`
4
+ * and `runCli` expose the shared awaited command lifecycle.
4
5
  */
5
6
 
6
- export { actCommand, addCommand, cave, checkCommand, commandHelp, demoCommand, deriveCommand, exportCommand, helpCommand, highlightCommand, importCommand, parseCommand, queryCommand, reconstructCommand, reportCommand, resolveCommand, suggestAliasCommand, syncCommand, usage, versionCommand } from './cli.ts'
7
+ export { actCommand, addCommand, backupCommand, cave, checkCommand, commandHelp, demoCommand, deriveCommand, exportCommand, generateCommand, helpCommand, highlightCommand, importCommand, parseCommand, queryCommand, reconstructCommand, reportCommand, resolveCommand, restoreCommand, suggestAliasCommand, syncCommand, usage, versionCommand } from './cli.ts'
8
+ export { dispatch, runCli } from './dispatch.ts'
9
+ export type { CommandRuntime } from './dispatch.ts'
10
+ export { commandRegistry } from './commands.ts'
11
+ export type { CommandReference } from './commands.ts'
7
12
  export type { Output } from './cli.ts'
13
+ export { diagnose, doctorCommand } from './doctor.ts'
14
+ export type { DoctorCheck, DoctorOutput, DoctorReport, DoctorStatus } from './doctor.ts'
package/src/ingest.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Compatibility subpath for the agent ingestion tooling. */
2
+ export * from '@cavelang/ingest'
package/src/loop.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Compatibility subpath for reconstruction policies. */
2
+ export * from '@cavelang/loop'
package/src/main.ts CHANGED
@@ -1,69 +1,6 @@
1
1
  #!/usr/bin/env node
2
- /** `cave` binary entry point — see `cli.ts` for the command implementations. */
2
+ /** `cave` binary entry point — one lifecycle for every command. */
3
3
 
4
- import { cave, highlightCommand, reconstructCommand, suggestAliasCommand } from './cli.ts'
4
+ import { runCli } from './dispatch.ts'
5
5
 
6
- const write = (code: number, out: string, err: string): void => {
7
- if (out !== '') {
8
- process.stdout.write(out)
9
- }
10
- if (err !== '') {
11
- process.stderr.write(err)
12
- }
13
- process.exitCode = code
14
- }
15
-
16
- // mcp, ingest, connect, eval, automate and serve own their help text, so `cave help X` becomes `cave X --help`.
17
- const raw = process.argv.slice(2)
18
- const argv = raw[0] === 'help' && (raw[1] === 'mcp' || raw[1] === 'ingest' || raw[1] === 'connect' || raw[1] === 'eval' || raw[1] === 'automate' || raw[1] === 'serve') ?
19
- [raw[1], '--help'] :
20
- raw
21
- if (argv[0] === 'mcp') {
22
- // Long-running: serves MCP on stdio until the client disconnects.
23
- const { runMcp } = await import('@cavelang/mcp')
24
- process.exitCode = await runMcp(argv.slice(1))
25
- } else if (argv[0] === 'ingest') {
26
- // Long-running: drives an LLM agent over batches of files.
27
- const { runIngest } = await import('@cavelang/ingest')
28
- process.exitCode = await runIngest(argv.slice(1))
29
- } else if (argv[0] === 'eval') {
30
- // Long-running: drives an agent (and optionally a judge) over eval fixtures.
31
- const { runEval } = await import('@cavelang/eval')
32
- process.exitCode = await runEval(argv.slice(1))
33
- } else if (argv[0] === 'connect') {
34
- // Async (URL sources fetch) and potentially long-running (--watch).
35
- const { runConnect } = await import('@cavelang/connect')
36
- process.exitCode = await runConnect(argv.slice(1))
37
- } else if (argv[0] === 'automate') {
38
- // Async (prompt steps run a shell agent) and potentially long-running (the loop).
39
- const { runAutomate } = await import('@cavelang/automate')
40
- process.exitCode = await runAutomate(argv.slice(1))
41
- } else if (argv[0] === 'serve') {
42
- // Long-running: the human read surface serves HTTP until interrupted.
43
- const { runServe } = await import('@cavelang/view')
44
- process.exitCode = await runServe(argv.slice(1))
45
- } else if (argv[0] === 'reconstruct') {
46
- // Async: the LLM policy runs a shell agent once per step.
47
- const { code, out, err } = await reconstructCommand(argv.slice(1))
48
- write(code, out, err)
49
- } else if (argv[0] === 'suggest-alias') {
50
- // Async: the optional judge runs a shell agent.
51
- const { code, out, err } = await suggestAliasCommand(argv.slice(1))
52
- write(code, out, err)
53
- } else if (argv[0] === 'highlight' && !argv.includes('--help') && !argv.includes('-h')) {
54
- // Async (grammar WASM loads on first use); --help stays on the sync path.
55
- const { code, out, err } = await highlightCommand(argv.slice(1))
56
- write(code, out, err)
57
- } else {
58
- const { code, out, err } = cave(argv)
59
- // Canonical CAVE text going to a terminal gets syntax colors from the same
60
- // grammar query `cave highlight` uses; piping or NO_COLOR keeps bytes clean.
61
- const colorize = code === 0 && argv[0] === 'export' && !argv.includes('--out') &&
62
- out !== '' && process.stdout.isTTY === true && process.env['NO_COLOR'] === undefined
63
- if (colorize) {
64
- const { highlighter } = await import('@cavelang/highlight')
65
- write(code, (await highlighter()).ansi(out), err)
66
- } else {
67
- write(code, out, err)
68
- }
69
- }
6
+ process.exitCode = await runCli(process.argv.slice(2))
package/src/mcp.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Compatibility subpath for the MCP server API. */
2
+ export * from '@cavelang/mcp'
package/src/rules.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Compatibility subpath for the internal rules engine. */
2
+ export * from '@cavelang/rules'