@cruxy/cli 1.0.3 → 1.0.5

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 (238) hide show
  1. package/package.json +2 -2
  2. package/dist/agent/budget.d.ts +0 -52
  3. package/dist/agent/index.d.ts +0 -3
  4. package/dist/agent/loop.d.ts +0 -159
  5. package/dist/agent/prompts.d.ts +0 -69
  6. package/dist/agent/session.d.ts +0 -212
  7. package/dist/approval/classify.d.ts +0 -18
  8. package/dist/approval/index.d.ts +0 -6
  9. package/dist/approval/mutex.d.ts +0 -45
  10. package/dist/approval/policy.d.ts +0 -43
  11. package/dist/approval/prompt.d.ts +0 -48
  12. package/dist/approval/service.d.ts +0 -36
  13. package/dist/approval/types.d.ts +0 -82
  14. package/dist/brand/index.d.ts +0 -1
  15. package/dist/brand/voice.d.ts +0 -94
  16. package/dist/checkpoint/capture.d.ts +0 -17
  17. package/dist/checkpoint/gate-hook.d.ts +0 -28
  18. package/dist/checkpoint/gate.d.ts +0 -71
  19. package/dist/checkpoint/git-store.d.ts +0 -61
  20. package/dist/checkpoint/index.d.ts +0 -10
  21. package/dist/checkpoint/restore.d.ts +0 -23
  22. package/dist/checkpoint/service.d.ts +0 -89
  23. package/dist/checkpoint/set-rollback.d.ts +0 -51
  24. package/dist/checkpoint/set.d.ts +0 -44
  25. package/dist/checkpoint/shadow-store.d.ts +0 -23
  26. package/dist/checkpoint/types.d.ts +0 -164
  27. package/dist/cli/commands/checkpoint.d.ts +0 -7
  28. package/dist/cli/commands/config.d.ts +0 -2
  29. package/dist/cli/commands/hooks.d.ts +0 -8
  30. package/dist/cli/commands/index.d.ts +0 -7
  31. package/dist/cli/commands/init.d.ts +0 -7
  32. package/dist/cli/commands/login.d.ts +0 -8
  33. package/dist/cli/commands/mcp.d.ts +0 -9
  34. package/dist/cli/commands/memory.d.ts +0 -8
  35. package/dist/cli/commands/pr.d.ts +0 -8
  36. package/dist/cli/commands/rollback.d.ts +0 -18
  37. package/dist/cli/commands/run.d.ts +0 -2
  38. package/dist/cli/commands/skills.d.ts +0 -8
  39. package/dist/cli/commands/test.d.ts +0 -9
  40. package/dist/cli/commands/usage.d.ts +0 -9
  41. package/dist/cli/onboard.d.ts +0 -25
  42. package/dist/cli/program.d.ts +0 -2
  43. package/dist/cli/repl.d.ts +0 -27
  44. package/dist/cli/session-factory.d.ts +0 -42
  45. package/dist/cli/stream-print.d.ts +0 -14
  46. package/dist/components/autocomplete.d.ts +0 -32
  47. package/dist/components/frame.d.ts +0 -28
  48. package/dist/components/fuzzy.d.ts +0 -61
  49. package/dist/components/index.d.ts +0 -6
  50. package/dist/components/input.d.ts +0 -78
  51. package/dist/components/keys.d.ts +0 -48
  52. package/dist/components/select.d.ts +0 -28
  53. package/dist/config/credentials.d.ts +0 -18
  54. package/dist/config/index.d.ts +0 -5
  55. package/dist/config/manager.d.ts +0 -39
  56. package/dist/config/owner-only.d.ts +0 -19
  57. package/dist/config/paths.d.ts +0 -9
  58. package/dist/config/project.d.ts +0 -10
  59. package/dist/config/schema.d.ts +0 -2143
  60. package/dist/constants.d.ts +0 -65
  61. package/dist/errors/boundary.d.ts +0 -43
  62. package/dist/errors/constructors.d.ts +0 -411
  63. package/dist/errors/format.d.ts +0 -31
  64. package/dist/errors/index.d.ts +0 -4
  65. package/dist/errors/types.d.ts +0 -270
  66. package/dist/hooks/config.d.ts +0 -21
  67. package/dist/hooks/index.d.ts +0 -7
  68. package/dist/hooks/router.d.ts +0 -58
  69. package/dist/hooks/runner.d.ts +0 -88
  70. package/dist/hooks/service.d.ts +0 -38
  71. package/dist/hooks/slash.d.ts +0 -48
  72. package/dist/hooks/trust.d.ts +0 -46
  73. package/dist/hooks/types.d.ts +0 -147
  74. package/dist/index.d.ts +0 -2
  75. package/dist/indexing/chunker.d.ts +0 -28
  76. package/dist/indexing/embedder.d.ts +0 -98
  77. package/dist/indexing/index.d.ts +0 -9
  78. package/dist/indexing/indexer.d.ts +0 -45
  79. package/dist/indexing/retriever.d.ts +0 -61
  80. package/dist/indexing/service.d.ts +0 -49
  81. package/dist/indexing/store.d.ts +0 -103
  82. package/dist/indexing/types.d.ts +0 -78
  83. package/dist/indexing/util.d.ts +0 -34
  84. package/dist/indexing/walker.d.ts +0 -53
  85. package/dist/jobs/approval-queue.d.ts +0 -85
  86. package/dist/jobs/dispatch-tool.d.ts +0 -34
  87. package/dist/jobs/index.d.ts +0 -6
  88. package/dist/jobs/log-buffer.d.ts +0 -31
  89. package/dist/jobs/log-renderer.d.ts +0 -32
  90. package/dist/jobs/manager.d.ts +0 -139
  91. package/dist/jobs/types.d.ts +0 -81
  92. package/dist/lsp/client.d.ts +0 -25
  93. package/dist/lsp/index.d.ts +0 -8
  94. package/dist/lsp/pool.d.ts +0 -48
  95. package/dist/lsp/registry.d.ts +0 -38
  96. package/dist/lsp/server.d.ts +0 -48
  97. package/dist/lsp/service.d.ts +0 -44
  98. package/dist/lsp/tools/common.d.ts +0 -50
  99. package/dist/lsp/tools/find-definition.d.ts +0 -23
  100. package/dist/lsp/tools/find-references.d.ts +0 -23
  101. package/dist/lsp/tools/get-diagnostics.d.ts +0 -17
  102. package/dist/lsp/tools/hover.d.ts +0 -23
  103. package/dist/lsp/tools/index.d.ts +0 -4
  104. package/dist/lsp/transport.d.ts +0 -39
  105. package/dist/lsp/types.d.ts +0 -107
  106. package/dist/mcp/adapter.d.ts +0 -44
  107. package/dist/mcp/bounds.d.ts +0 -35
  108. package/dist/mcp/client.d.ts +0 -19
  109. package/dist/mcp/demarcate.d.ts +0 -12
  110. package/dist/mcp/http-transport.d.ts +0 -89
  111. package/dist/mcp/index.d.ts +0 -12
  112. package/dist/mcp/service.d.ts +0 -71
  113. package/dist/mcp/sibling-banner.d.ts +0 -25
  114. package/dist/mcp/transport.d.ts +0 -30
  115. package/dist/mcp/trust-gate.d.ts +0 -59
  116. package/dist/mcp/trust.d.ts +0 -62
  117. package/dist/mcp/types.d.ts +0 -62
  118. package/dist/mcp/url-guard.d.ts +0 -48
  119. package/dist/memory/index.d.ts +0 -7
  120. package/dist/memory/recall.d.ts +0 -56
  121. package/dist/memory/remember-tool.d.ts +0 -28
  122. package/dist/memory/secrets.d.ts +0 -29
  123. package/dist/memory/service.d.ts +0 -92
  124. package/dist/memory/store.d.ts +0 -32
  125. package/dist/memory/trust.d.ts +0 -52
  126. package/dist/memory/types.d.ts +0 -101
  127. package/dist/net/ip-guard.d.ts +0 -55
  128. package/dist/onboarding/detect.d.ts +0 -26
  129. package/dist/onboarding/flow.d.ts +0 -28
  130. package/dist/onboarding/index.d.ts +0 -5
  131. package/dist/onboarding/io.d.ts +0 -9
  132. package/dist/onboarding/steps.d.ts +0 -17
  133. package/dist/onboarding/types.d.ts +0 -81
  134. package/dist/plan/approve.d.ts +0 -16
  135. package/dist/plan/execute.d.ts +0 -28
  136. package/dist/plan/index.d.ts +0 -7
  137. package/dist/plan/policy.d.ts +0 -26
  138. package/dist/plan/render.d.ts +0 -5
  139. package/dist/plan/service.d.ts +0 -58
  140. package/dist/plan/submit-plan.d.ts +0 -33
  141. package/dist/plan/types.d.ts +0 -60
  142. package/dist/render/capabilities.d.ts +0 -31
  143. package/dist/render/diff.d.ts +0 -18
  144. package/dist/render/highlight.d.ts +0 -47
  145. package/dist/render/index.d.ts +0 -22
  146. package/dist/render/layout.d.ts +0 -59
  147. package/dist/render/motion.d.ts +0 -76
  148. package/dist/render/plain-renderer.d.ts +0 -39
  149. package/dist/render/resize.d.ts +0 -36
  150. package/dist/render/screen-reader-renderer.d.ts +0 -45
  151. package/dist/render/state.d.ts +0 -49
  152. package/dist/render/tty-renderer.d.ts +0 -106
  153. package/dist/render/types.d.ts +0 -201
  154. package/dist/routing/index.d.ts +0 -2
  155. package/dist/routing/resolve.d.ts +0 -17
  156. package/dist/routing/router.d.ts +0 -47
  157. package/dist/routing/types.d.ts +0 -42
  158. package/dist/sandbox/detect.d.ts +0 -22
  159. package/dist/sandbox/docker-runtime.d.ts +0 -32
  160. package/dist/sandbox/index.d.ts +0 -7
  161. package/dist/sandbox/policy.d.ts +0 -26
  162. package/dist/sandbox/service.d.ts +0 -64
  163. package/dist/sandbox/types.d.ts +0 -123
  164. package/dist/skills/index.d.ts +0 -4
  165. package/dist/skills/loader.d.ts +0 -43
  166. package/dist/skills/parser.d.ts +0 -31
  167. package/dist/skills/service.d.ts +0 -41
  168. package/dist/skills/types.d.ts +0 -94
  169. package/dist/subagent/index.d.ts +0 -5
  170. package/dist/subagent/orchestrator.d.ts +0 -169
  171. package/dist/subagent/registry-scope.d.ts +0 -41
  172. package/dist/subagent/semaphore.d.ts +0 -56
  173. package/dist/subagent/spawn-tool.d.ts +0 -86
  174. package/dist/subagent/types.d.ts +0 -65
  175. package/dist/testing/detect.d.ts +0 -3
  176. package/dist/testing/index.d.ts +0 -5
  177. package/dist/testing/parse.d.ts +0 -33
  178. package/dist/testing/run-tests-tool.d.ts +0 -64
  179. package/dist/testing/runner.d.ts +0 -26
  180. package/dist/testing/sandbox-runner.d.ts +0 -16
  181. package/dist/testing/types.d.ts +0 -66
  182. package/dist/theme/index.d.ts +0 -2
  183. package/dist/theme/resolve.d.ts +0 -43
  184. package/dist/theme/tokens.d.ts +0 -125
  185. package/dist/tools/create-pull-request.d.ts +0 -27
  186. package/dist/tools/file/apply-patch.d.ts +0 -94
  187. package/dist/tools/file/edit-file.d.ts +0 -12
  188. package/dist/tools/file/glob.d.ts +0 -17
  189. package/dist/tools/file/grep-files.d.ts +0 -43
  190. package/dist/tools/file/index.d.ts +0 -7
  191. package/dist/tools/file/match.d.ts +0 -43
  192. package/dist/tools/file/paths.d.ts +0 -160
  193. package/dist/tools/file/read-file.d.ts +0 -8
  194. package/dist/tools/file/write-file.d.ts +0 -10
  195. package/dist/tools/git-status.d.ts +0 -15
  196. package/dist/tools/index.d.ts +0 -9
  197. package/dist/tools/list-files.d.ts +0 -13
  198. package/dist/tools/list-skills.d.ts +0 -9
  199. package/dist/tools/load-skill.d.ts +0 -21
  200. package/dist/tools/registry.d.ts +0 -23
  201. package/dist/tools/search-codebase.d.ts +0 -35
  202. package/dist/tools/shell/exec.d.ts +0 -53
  203. package/dist/tools/shell/index.d.ts +0 -1
  204. package/dist/tools/shell/resolve-shell.d.ts +0 -81
  205. package/dist/tools/shell/run-command.d.ts +0 -14
  206. package/dist/tools/types.d.ts +0 -257
  207. package/dist/usage/collect.d.ts +0 -53
  208. package/dist/usage/cost.d.ts +0 -19
  209. package/dist/usage/index.d.ts +0 -15
  210. package/dist/usage/store.d.ts +0 -37
  211. package/dist/usage/summary.d.ts +0 -32
  212. package/dist/usage/types.d.ts +0 -283
  213. package/dist/utils/child-tree.d.ts +0 -33
  214. package/dist/utils/git.d.ts +0 -17
  215. package/dist/utils/logger.d.ts +0 -18
  216. package/dist/utils/process-tree.d.ts +0 -16
  217. package/dist/vcs/auth.d.ts +0 -22
  218. package/dist/vcs/generate.d.ts +0 -74
  219. package/dist/vcs/git.d.ts +0 -60
  220. package/dist/vcs/github.d.ts +0 -50
  221. package/dist/vcs/guidance.d.ts +0 -20
  222. package/dist/vcs/index.d.ts +0 -7
  223. package/dist/vcs/service.d.ts +0 -61
  224. package/dist/vcs/types.d.ts +0 -73
  225. package/dist/web/demarcate.d.ts +0 -13
  226. package/dist/web/fetch.d.ts +0 -11
  227. package/dist/web/index.d.ts +0 -7
  228. package/dist/web/provider.d.ts +0 -29
  229. package/dist/web/search.d.ts +0 -17
  230. package/dist/web/ssrf.d.ts +0 -41
  231. package/dist/web/tools.d.ts +0 -20
  232. package/dist/web/types.d.ts +0 -64
  233. package/dist/workspace/add-root.d.ts +0 -27
  234. package/dist/workspace/index.d.ts +0 -6
  235. package/dist/workspace/resolve.d.ts +0 -54
  236. package/dist/workspace/select.d.ts +0 -41
  237. package/dist/workspace/types.d.ts +0 -30
  238. package/dist/workspace/workspace.d.ts +0 -61
@@ -1,270 +0,0 @@
1
- /**
2
- * The one error type for every user-facing failure (U.5). A {@link CruxyError}
3
- * carries structured fields — title, optional human cause, next steps, a stable
4
- * greppable {@link ErrorCode}, and a process exit code — while *formatting* lives
5
- * separately (see `format.ts`). The raw underlying error is preserved but shown
6
- * only under `--verbose`; no Node stack trace ever reaches the user by default.
7
- */
8
- /**
9
- * Stable, greppable error identifiers. The string value *is* the id that appears
10
- * in output (e.g. `CRUXY_E_GATEWAY_UNREACHABLE`) — grep for it in logs/issues.
11
- * Grouped by category; each category maps to a distinct process exit code
12
- * (see {@link exitCodeFor}).
13
- */
14
- export declare const ErrorCode: {
15
- readonly Internal: "CRUXY_E_INTERNAL";
16
- readonly Usage: "CRUXY_E_USAGE";
17
- readonly InteractiveRequired: "CRUXY_E_INTERACTIVE_REQUIRED";
18
- readonly ConfigKeyUnknown: "CRUXY_E_CONFIG_KEY_UNKNOWN";
19
- readonly ProviderUnsupported: "CRUXY_E_PROVIDER_UNSUPPORTED";
20
- readonly GitProtectedBranch: "CRUXY_E_GIT_PROTECTED_BRANCH";
21
- readonly PlanInvalid: "CRUXY_E_PLAN_INVALID";
22
- readonly PlanRevisionLimit: "CRUXY_E_PLAN_REVISION_LIMIT";
23
- readonly CheckpointNotFound: "CRUXY_E_CHECKPOINT_NOT_FOUND";
24
- /** Routing (C.30): a task class is mapped to a tier the gateway does not
25
- * offer — fix the config, NEVER a silent substitution to another tier. */
26
- readonly RoutingTierUnavailable: "CRUXY_E_ROUTING_TIER_UNAVAILABLE";
27
- readonly ConfigParse: "CRUXY_E_CONFIG_PARSE";
28
- readonly ConfigInvalid: "CRUXY_E_CONFIG_INVALID";
29
- readonly AuthMissingKey: "CRUXY_E_AUTH_MISSING_KEY";
30
- readonly AuthInvalid: "CRUXY_E_AUTH_INVALID";
31
- readonly ForgeAuth: "CRUXY_E_FORGE_AUTH";
32
- /** A credential could not be persisted with owner-only permissions (C.27c) —
33
- * e.g. on Windows the store's ACL could not be restricted to the current user
34
- * (non-NTFS filesystem, `icacls`/SID unavailable). Refused loudly rather than
35
- * written world-inheritable: a secret is never persisted at permissions we
36
- * could not verify as owner-only. */
37
- readonly CredentialsUnprotected: "CRUXY_E_CREDENTIALS_UNPROTECTED";
38
- readonly GatewayUnreachable: "CRUXY_E_GATEWAY_UNREACHABLE";
39
- readonly GitPushFailed: "CRUXY_E_GIT_PUSH_FAILED";
40
- readonly Api: "CRUXY_E_API";
41
- readonly ApiRateLimit: "CRUXY_E_API_RATE_LIMIT";
42
- readonly ApiOverloaded: "CRUXY_E_API_OVERLOADED";
43
- readonly BudgetExhausted: "CRUXY_E_BUDGET_EXHAUSTED";
44
- readonly ForgeApi: "CRUXY_E_FORGE_API";
45
- readonly FileNotFound: "CRUXY_E_FILE_NOT_FOUND";
46
- readonly PermissionDenied: "CRUXY_E_PERMISSION_DENIED";
47
- readonly PathEscape: "CRUXY_E_PATH_ESCAPE";
48
- readonly CheckpointFailed: "CRUXY_E_CHECKPOINT_FAILED";
49
- /** The fastembed native module could not be LOADED (missing/broken install,
50
- * un-built onnxruntime-node addon). Fail-loud by design — the embedder never
51
- * silently degrades to the lexical hashing backend (that would be a silent
52
- * quality loss). See the store-vs-embedder asymmetry note in `schema.ts`. */
53
- readonly IndexEmbedderUnavailable: "CRUXY_E_INDEX_EMBEDDER_UNAVAILABLE";
54
- /** The fastembed module loaded, but the model could not be brought up at
55
- * RUNTIME — the first-run download/decompress, or the ONNX-runtime init,
56
- * failed (offline, the model bucket is unreachable, a proxy blocks it). Kept
57
- * DISTINCT from `IndexEmbedderUnavailable` (a load failure) and from the
58
- * generic `IndexFailed` ("re-run --verbose") so the actual, common first-run
59
- * failure carries an actionable cause instead of a shrug. */
60
- readonly IndexEmbedderDownloadFailed: "CRUXY_E_INDEX_EMBEDDER_DOWNLOAD_FAILED";
61
- readonly IndexStoreUnavailable: "CRUXY_E_INDEX_STORE_UNAVAILABLE";
62
- readonly IndexFailed: "CRUXY_E_INDEX_FAILED";
63
- readonly SkillInvalid: "CRUXY_E_SKILL_INVALID";
64
- readonly SkillNotFound: "CRUXY_E_SKILL_NOT_FOUND";
65
- readonly ApprovalRequired: "CRUXY_E_APPROVAL_REQUIRED";
66
- readonly PlanApprovalRequired: "CRUXY_E_PLAN_APPROVAL_REQUIRED";
67
- readonly RollbackApprovalRequired: "CRUXY_E_ROLLBACK_APPROVAL_REQUIRED";
68
- readonly SubagentDepthExceeded: "CRUXY_E_SUBAGENT_DEPTH_EXCEEDED";
69
- /** Carried inside a SubagentResult (informational) — never fatal by itself. */
70
- readonly SubagentBudget: "CRUXY_E_SUBAGENT_BUDGET";
71
- readonly SubagentFailed: "CRUXY_E_SUBAGENT_FAILED";
72
- /** Two children of one parallel fan-out (C.33) declare overlapping write scope
73
- * (same root). Refused pre-dispatch so concurrent siblings can never race on a
74
- * root — the model corrects it (distinct roots, or read-only). */
75
- readonly SubagentScopeOverlap: "CRUXY_E_SUBAGENT_SCOPE_OVERLAP";
76
- /** Carried inside a SubagentResult (informational): the run was cancelled — a
77
- * fatal sibling failure or Ctrl-C aborted the whole fan-out (C.33). Never a
78
- * fabricated success; the parent sees exactly which children did not finish. */
79
- readonly SubagentCancelled: "CRUXY_E_SUBAGENT_CANCELLED";
80
- readonly TestCommandNotFound: "CRUXY_E_TEST_COMMAND_NOT_FOUND";
81
- /** Carried inside a run_tests result (informational) — never fatal by itself. */
82
- readonly TestIterationLimit: "CRUXY_E_TEST_ITERATION_LIMIT";
83
- /** Sandbox was enabled but no container runtime is available — fail loud,
84
- * NEVER fall back to un-sandboxed host execution. */
85
- readonly SandboxUnavailable: "CRUXY_E_SANDBOX_UNAVAILABLE";
86
- readonly SandboxImage: "CRUXY_E_SANDBOX_IMAGE";
87
- readonly SandboxExec: "CRUXY_E_SANDBOX_EXEC";
88
- /** A blocking hook failed (non-zero exit / declined / errored) → the action
89
- * is aborted fail-closed. Advisory hooks never raise this. */
90
- readonly HookFailed: "CRUXY_E_HOOK_FAILED";
91
- /** A project defines hooks that have not been trusted for this repo — they are
92
- * never run silently (supply-chain safety). */
93
- readonly HookUntrusted: "CRUXY_E_HOOK_UNTRUSTED";
94
- /** A malformed hook definition — excluded from the catalog and surfaced,
95
- * never eval'd. */
96
- readonly HookInvalid: "CRUXY_E_HOOK_INVALID";
97
- /** A malformed custom slash-command definition — excluded and surfaced. */
98
- readonly SlashInvalid: "CRUXY_E_SLASH_INVALID";
99
- /** A malformed memory entry — excluded from recall/writes and surfaced,
100
- * never eval'd. */
101
- readonly MemoryInvalid: "CRUXY_E_MEMORY_INVALID";
102
- /** A repo's project memory has not been trusted — it is never recalled into
103
- * context silently (supply-chain safety). */
104
- readonly MemoryUntrusted: "CRUXY_E_MEMORY_UNTRUSTED";
105
- /** A memory write was refused because the content matched a secret shape —
106
- * secrets are never persisted (defense in depth over C.17). */
107
- readonly MemorySecret: "CRUXY_E_MEMORY_SECRET";
108
- /** The local usage store is corrupt/unreadable — the read is SKIPPED and this
109
- * is surfaced; never fatal to a run (usage display is best-effort). */
110
- readonly UsageRead: "CRUXY_E_USAGE_READ";
111
- /** A language server binary is not installed / not on PATH (or no server is
112
- * configured for the file's language). Actionable, NEVER a silent empty
113
- * result — "no server" must not read as "no references found". */
114
- readonly LspServerNotFound: "CRUXY_E_LSP_SERVER_NOT_FOUND";
115
- /** A server's `initialize` handshake or a single request exceeded its timeout
116
- * — the process was killed / the request errored, never left to hang. */
117
- readonly LspTimeout: "CRUXY_E_LSP_TIMEOUT";
118
- /** A language server crashed (and, where applicable, a single restart also
119
- * failed). Distinct from "server returned no results". */
120
- readonly LspCrashed: "CRUXY_E_LSP_CRASHED";
121
- /** A project configures MCP servers that have not been trusted for this repo.
122
- * Trusting a server runs its code UNSANDBOXED with your privileges, so an
123
- * untrusted config is never connected silently — and in non-interactive mode
124
- * it fails closed BEFORE any server is spawned (supply-chain safety). */
125
- readonly McpUntrusted: "CRUXY_E_MCP_UNTRUSTED";
126
- /** A trusted MCP server failed to spawn, complete the `initialize` handshake,
127
- * or list its tools. Surfaced (that server contributes no tools) rather than
128
- * silently swallowed; never fatal to the run. */
129
- readonly McpConnect: "CRUXY_E_MCP_CONNECT";
130
- /** A network (`url`) MCP server was REFUSED before/at connect for a SECURITY
131
- * reason, distinct from an ordinary connect failure: a non-https(non-loopback)
132
- * scheme, a host that resolves into a private/loopback/link-local range (SSRF),
133
- * or an endpoint that tried to redirect. A refusal, not a transient error. */
134
- readonly McpBlocked: "CRUXY_E_MCP_BLOCKED";
135
- /** A network (`url`) MCP server's CREDENTIAL failed (C.27c): the endpoint
136
- * rejected it (401/403) or the named `credentialRef` has no token in the
137
- * `~/.cruxy` store. Distinct from a transport connect failure — the server was
138
- * reached (or the credential was simply absent), not merely unreachable. */
139
- readonly McpAuth: "CRUXY_E_MCP_AUTH";
140
- /** A project-scope config was REFUSED for a credential-safety reason (C.27c):
141
- * it tried to set raw `headers` on an MCP server. A live header value is a
142
- * secret; project scope (a possibly-cloned repo) may only NAME a credential via
143
- * `credentialRef`, never carry the value. Rejected loudly, never silently. */
144
- readonly McpConfig: "CRUXY_E_MCP_CONFIG";
145
- /** `web.enabled` is on but no usable search provider is configured — the API
146
- * key env var is unset or the provider is unknown. Actionable, NEVER a silent
147
- * empty result: "no provider" must not read as "no search results". */
148
- readonly WebUnavailable: "CRUXY_E_WEB_UNAVAILABLE";
149
- /** A web search failed (provider HTTP error, network failure, or timeout). The
150
- * search did NOT run to completion — distinct from a search that ran and found
151
- * nothing (that is an ordinary `ok:true` empty result). */
152
- readonly WebSearch: "CRUXY_E_WEB_SEARCH";
153
- /** A `web_fetch` failed: network error, timeout, oversize/non-text body, or too
154
- * many redirects. Distinct from a page fetched successfully that had no readable
155
- * text (an ordinary `ok:true` empty result). */
156
- readonly WebFetch: "CRUXY_E_WEB_FETCH";
157
- /** A `web_fetch` was REFUSED before any request was dispatched: a non-http(s)
158
- * scheme, or a host that resolves into a private/loopback/link-local range
159
- * (SSRF guard — e.g. 127.0.0.1, 169.254.169.254, 10.x, internal DNS). A
160
- * security stop, kept distinct from an ordinary fetch failure for grep-ability. */
161
- readonly WebBlockedHost: "CRUXY_E_WEB_BLOCKED_HOST";
162
- /** A path/selector names a workspace root that is not in the declared set (or an
163
- * absolute path that lands in no declared root). Fail-loud and NEVER fuzzy- or
164
- * prefix-matched to a nearby root — a silent near-match is a cross-root misfire.
165
- * Refused before any FS access; never falls through to the host filesystem. */
166
- readonly RootUnknown: "CRUXY_E_ROOT_UNKNOWN";
167
- /** A path is ambiguous across the declared root set: an absolute path that falls
168
- * inside ≥2 declared roots, or a mutating tool given no root when there's no
169
- * unambiguous choice. Writes fail closed rather than guess a root. */
170
- readonly RootAmbiguous: "CRUXY_E_ROOT_AMBIGUOUS";
171
- /** Declaration-time: a declared root nests inside / overlaps another. Refused at
172
- * session start — overlap makes "which root owns this path" ambiguous and lets
173
- * two checkpoints/grants fight over the same bytes. Declare the monorepo root OR
174
- * its packages, never both. */
175
- readonly RootOverlap: "CRUXY_E_ROOT_OVERLAP";
176
- /** An interactive add-root was refused: no TTY to confirm, or the user declined
177
- * the confirm/trust prompt. The root set only ever grows by an explicit human
178
- * act — never by the model or a repo-local config. */
179
- readonly RootAddRefused: "CRUXY_E_ROOT_ADD_REFUSED";
180
- /** A write targeted a NON-PRIMARY root while per-root checkpoints are not yet
181
- * wired (C.26 Step 2b). Refused so "every write cruxy makes is checkpointed and
182
- * rollback-able" stays true — an un-checkpointed write to a sibling root would be
183
- * silently un-restorable when rollback reverts the primary. Lifted in Step 3 when
184
- * per-root checkpoints ship. Reads to any root are unaffected. */
185
- readonly MultirootWriteDeferred: "CRUXY_E_MULTIROOT_WRITE_DEFERRED";
186
- /** A multi-root rollback set references a member checkpoint that is missing or
187
- * corrupt, or a touched root has no member. Loud — a partial rollback must never
188
- * masquerade as success. */
189
- readonly CheckpointSetIncomplete: "CRUXY_E_CHECKPOINT_SET_INCOMPLETE";
190
- /** A multi-root rollback failed mid-apply (R3): carries which roots were restored
191
- * and which were not. The set is left recoverable by an idempotent re-run and is
192
- * NEVER reported as success. */
193
- readonly CheckpointSetPartial: "CRUXY_E_CHECKPOINT_SET_PARTIAL";
194
- /** VCS target-integrity guard (C.26 Step 4): the `origin` remote of the acting
195
- * root resolved to a DIFFERENT `owner/repo` between the U.3 preview (what the
196
- * human approved) and the moment the pull-request API call is made (a concurrent
197
- * `git remote set-url` on a mutable `.git/config`). The PR is NOT opened —
198
- * refused, never warn-and-proceed — and both the approved and current targets are
199
- * named. Reachable single-root too; introduced with the multi-root VCS hardening. */
200
- readonly VcsRemoteChanged: "CRUXY_E_VCS_REMOTE_CHANGED";
201
- /** A pull request was requested for one declared root while a SIBLING declared
202
- * root shares the same git working tree (two non-overlapping roots inside one
203
- * repo, e.g. `packages/a` + `packages/b` under one `.git`). A commit there would
204
- * `git add -A` the sibling's changes too, so the PR would span both roots — a PR
205
- * is a single-repo artifact, so it is refused (naming both) rather than silently
206
- * PR one half. */
207
- readonly VcsCrossRoot: "CRUXY_E_VCS_CROSS_ROOT";
208
- /** A `run_in_background` dispatch was refused because the live job count
209
- * (queued + running + paused) already sits at `jobs.maxJobs`. The MODEL corrects
210
- * it — wait for a job to finish (or cancel one) and retry — so it is a usage-tier
211
- * coded error, never a silently-dropped dispatch. */
212
- readonly JobLimit: "CRUXY_E_JOB_LIMIT";
213
- /** `cruxy cancel/logs/rollback <id>` named a job id that does not exist in this
214
- * session. Jobs are session-scoped (NOT a daemon), so an id from a prior session
215
- * is legitimately unknown — fail loud with the id rather than a silent no-op. */
216
- readonly JobNotFound: "CRUXY_E_JOB_NOT_FOUND";
217
- /** A background-jobs command (`cruxy jobs/logs/cancel`) was used while
218
- * `jobs.enabled` is false. The feature is opt-in; surfaced with how to enable it
219
- * rather than pretending there are simply no jobs. */
220
- readonly JobsDisabled: "CRUXY_E_JOBS_DISABLED";
221
- /** No usable host shell was found to run commands through. On Windows this
222
- * means neither Git Bash nor PowerShell could be located and no
223
- * `shell.executable` override was set. Fail loud at session start — NEVER
224
- * silently fall back to cmd.exe running bash-shaped commands (which
225
- * mis-parses `;`/`&&`/quoting and can report a false success). */
226
- readonly NoShell: "CRUXY_E_NO_SHELL";
227
- /** A one-shot `cruxy run` ended WITHOUT completing the task: the agent loop hit
228
- * a hard stop (the iteration cap or a token budget) or was cancelled, rather
229
- * than finishing on its own. Fail loud with a non-zero exit so CI never reads a
230
- * gave-up run as success — the partial work already streamed to stdout stands. */
231
- readonly AgentIncomplete: "CRUXY_E_AGENT_INCOMPLETE";
232
- };
233
- export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
234
- /** The process exit code for an error code (defaults to 1 for safety). */
235
- export declare function exitCodeFor(code: ErrorCode): number;
236
- export interface CruxyErrorInit {
237
- /** Stable error id (drives the exit code and appears in output). */
238
- code: ErrorCode;
239
- /** One plain line: what failed. */
240
- title: string;
241
- /** The specific reason, when known. Always shown (part 2 of the standard). */
242
- cause?: string;
243
- /** Concrete actions the user can take. */
244
- nextSteps?: string[];
245
- /** Structured context (not rendered; for future JSON output / telemetry). */
246
- meta?: Record<string, unknown>;
247
- /** The original thrown error, preserved and shown only under `--verbose`. */
248
- underlying?: unknown;
249
- /** Override the exit code; defaults to {@link exitCodeFor}(code). */
250
- exitCode?: number;
251
- }
252
- /**
253
- * Every user-facing failure is (or becomes) one of these. Extends `Error` so it
254
- * flows through normal throw/catch; `.message` mirrors `title` so logs and
255
- * `instanceof Error` consumers stay useful.
256
- */
257
- export declare class CruxyError extends Error {
258
- readonly code: ErrorCode;
259
- readonly title: string;
260
- /** Human-readable reason (part 2). Narrows the inherited `Error.cause`. */
261
- readonly cause?: string;
262
- readonly nextSteps: string[];
263
- readonly exitCode: number;
264
- readonly meta?: Record<string, unknown>;
265
- /** The wrapped lower-level error — rendered only under `--verbose`. */
266
- readonly underlying?: unknown;
267
- constructor(init: CruxyErrorInit);
268
- /** Type guard — true for any CruxyError (across realms, via the brand). */
269
- static is(err: unknown): err is CruxyError;
270
- }
@@ -1,21 +0,0 @@
1
- import { type HookCatalog } from "./types.js";
2
- /**
3
- * Discovery for hooks + custom slash commands (C.19), mirroring the C.18 skills
4
- * loader: scan layered sources (project > user), validate every definition
5
- * fail-loud, exclude the malformed (collected as {@link HookConfigError}, never
6
- * thrown past the loader, never eval'd), and resolve precedence. Hook
7
- * definitions carry their {@link HookSource} — the trust model depends on
8
- * telling a repo's hooks (project) apart from your own (user).
9
- */
10
- /** The two source directories (each a `.cruxy` dir holding `hooks.json` and
11
- * `commands/`). */
12
- export interface HookSources {
13
- /** `<cwd>/.cruxy` */
14
- project: string;
15
- /** `~/.cruxy` */
16
- user: string;
17
- }
18
- /** The real sources for a project root. */
19
- export declare function defaultHookSources(cwd: string): HookSources;
20
- /** Load and resolve the full hook + command catalog. */
21
- export declare function loadHookCatalog(sources: HookSources): Promise<HookCatalog>;
@@ -1,7 +0,0 @@
1
- export { HOOK_EVENTS, HOOK_SOURCE_PRECEDENCE, HookSpecSchema, HooksFileSchema, SlashFrontmatterSchema, defaultBlocking, type HookCatalog, type HookConfigError, type HookDefinition, type HookEvent, type HookSource, type HookSpec, type HookTrust, type SlashCommandSpec, type SlashKind, } from "./types.js";
2
- export { defaultHookSources, loadHookCatalog, type HookSources, } from "./config.js";
3
- export { fileTrustStore, fingerprintHooks, isTrusted, memoryTrustStore, trustPath, type TrustStore, } from "./trust.js";
4
- export { HookRunner, type HookRunnerDeps, type TrustPromptInfo, } from "./runner.js";
5
- export { BUILTIN_SLASH_COMMANDS, expandTemplate, isBuiltinSlash, resolveSlash, type SlashResolution, } from "./slash.js";
6
- export { buildHooksService, type BuildHooksServiceOptions, type HooksService, } from "./service.js";
7
- export { buildHooksRouter, type BuildHooksRouterOptions, type HooksRouterResult, type UntrustedHookRoot, } from "./router.js";
@@ -1,58 +0,0 @@
1
- import type { CruxyConfig } from "../config/index.js";
2
- import type { LifecycleHookRunner } from "../agent/loop.js";
3
- import type { logger as Logger } from "../utils/logger.js";
4
- import type { DeclaredRoot, Workspace } from "../workspace/index.js";
5
- import { type TrustStore } from "./trust.js";
6
- import type { HookCatalog, SlashCommandSpec } from "./types.js";
7
- /**
8
- * Per-root hook dispatch for a multi-root session (C.26 step 5).
9
- *
10
- * The isolation here is a PROPERTY OF CONSTRUCTION, not a guard: each root gets
11
- * its OWN {@link HookRunner} (own project-hook catalog, own trust key), so there
12
- * is no code path from root A's runner to a root-B action. The router only
13
- * decides WHICH runner to invoke:
14
- *
15
- * - Tool-scoped events (`before-tool` / `after-tool` / `on-file-change`) fire
16
- * exactly the ONE acting root's runner — the same root the tool resolved via
17
- * {@link selectRoot}. A's project hooks structurally cannot fire for a
18
- * B-scoped call (⚖︎10, pinned by test).
19
- * - Session lifecycle events (`before-run` / `after-run`) have NO acting root,
20
- * so they fan EVERY trusted root sequentially, in declaration order,
21
- * root-labeled; a blocking failure in any root aborts the run naming that
22
- * root (JC-1). Untrusted roots are skipped and named in the startup banner —
23
- * never silent (a user's pre-run guard in an untrusted root must not vanish
24
- * without a word).
25
- *
26
- * User-scope hooks (`~/.cruxy`) are session-global — authored by you, shared by
27
- * every root — so they fire EXACTLY ONCE per event through a single shared
28
- * runner, never once per root.
29
- */
30
- /** A root whose project hooks exist but are not trusted → named in the banner. */
31
- export interface UntrustedHookRoot {
32
- name: string;
33
- absPath: string;
34
- count: number;
35
- }
36
- export interface HooksRouterResult {
37
- /** The lifecycle firing seam (a {@link LifecycleHookRunner}). */
38
- runner: LifecycleHookRunner;
39
- /** Custom slash commands (primary root only this release). */
40
- commands: SlashCommandSpec[];
41
- /** Roots with untrusted project hooks — named in the banner, never silent. */
42
- untrustedHookRoots: UntrustedHookRoot[];
43
- }
44
- export interface BuildHooksRouterOptions {
45
- workspace: Workspace;
46
- config: CruxyConfig;
47
- logger: typeof Logger;
48
- trust?: TrustStore;
49
- /** Per-root catalog loader; defaults to the layered on-disk loader. */
50
- loadCatalog?: (root: DeclaredRoot) => Promise<HookCatalog>;
51
- now?: () => string;
52
- }
53
- /**
54
- * Build the multi-root hook router. One project-hook runner per declared root
55
- * (trust-gated against that root's key) plus one shared user-hook runner. Load
56
- * errors are surfaced through the logger exactly as the single-root path does.
57
- */
58
- export declare function buildHooksRouter(opts: BuildHooksRouterOptions): Promise<HooksRouterResult>;
@@ -1,88 +0,0 @@
1
- import type { ToolContext } from "../tools/types.js";
2
- import { type TrustStore } from "./trust.js";
3
- import type { HookDefinition, HookEvent } from "./types.js";
4
- /**
5
- * The hook runner (C.19) — the security core. When a lifecycle event fires, it
6
- * runs the matching user-authored hooks, but a hook is **never** an approval
7
- * bypass:
8
- *
9
- * 1. **Project trust gate** (supply-chain safety). Before ANY project hook runs,
10
- * the repo must be trusted for its current hook fingerprint. Untrusted →
11
- * prompt (interactive) or `CRUXY_E_HOOK_UNTRUSTED` (non-interactive / declined
12
- * / `trustPrompt` off). A cloned repo's hooks never execute silently. User
13
- * hooks skip this prompt (you authored them) but NOT the gate below.
14
- * 2. **Per-command gate + sandbox** — every hook command goes through the SAME
15
- * {@link runGatedShell} as `run_command`: the U.3 approval gate then the C.16
16
- * sandbox (or host). There is no privileged route.
17
- * 3. **Blocking vs advisory** — a blocking hook that fails aborts the action
18
- * fail-closed (`CRUXY_E_HOOK_FAILED`); an advisory hook reports and continues.
19
- */
20
- /** What the interactive trust prompt is shown. */
21
- export interface TrustPromptInfo {
22
- root: string;
23
- hooks: HookDefinition[];
24
- }
25
- export interface HookRunnerDeps {
26
- /** Resolved hooks (with sources) for this project. */
27
- hooks: HookDefinition[];
28
- /** Persisted per-repo trust (see `trust.ts`). */
29
- trust: TrustStore;
30
- /** `config.hooks.enabled` — when false, nothing ever fires. */
31
- enabled: boolean;
32
- /** `config.hooks.trustPrompt` — when false, untrusted project hooks fail loud
33
- * rather than prompting (never auto-trust). */
34
- trustPrompt: boolean;
35
- /** Whether cruxy can actually prompt (stdin is a TTY). */
36
- interactive: boolean;
37
- /** Project root — the trust key and fingerprint scope. */
38
- cwd: string;
39
- /** Root label for multi-root fan-out (C.26 step 5). When set, a blocking
40
- * failure names its root (`<label> ▸ <hook>`) so an aborted run says which
41
- * root refused. Undefined in the single-root path → messages unchanged. */
42
- label?: string;
43
- /** Interactive trust prompt (returns true to trust). Required only when a
44
- * project defines hooks and `trustPrompt` + `interactive` are both on. */
45
- promptTrust?: (info: TrustPromptInfo) => Promise<boolean>;
46
- /** "running hook: <name>" surface (visible on every fire). */
47
- announce?: (message: string) => void;
48
- /** Advisory-failure surface (blocking failures throw instead). */
49
- reportFailure?: (message: string) => void;
50
- /** Injectable clock for the recorded trust timestamp (tests). */
51
- now?: () => string;
52
- }
53
- export declare class HookRunner {
54
- private readonly deps;
55
- constructor(deps: HookRunnerDeps);
56
- /** The project hooks — the trust-gated subset. */
57
- private get projectHooks();
58
- /** Prefix a hook name with the root label (multi-root), else leave it. */
59
- private qualify;
60
- /** Whether this root's project hooks are trusted for their current
61
- * fingerprint. Read-only (never prompts/records) — the router uses it to skip
62
- * untrusted roots and to name them in the banner. */
63
- get projectTrusted(): boolean;
64
- /** Count of project (trust-gated) hooks — for the untrusted-root banner. */
65
- get projectHookCount(): number;
66
- /**
67
- * Fire every hook registered for `event`, in catalog order. Resolves normally
68
- * when all hooks pass (or advisory ones fail); THROWS `CRUXY_E_HOOK_FAILED`
69
- * when a blocking hook fails, or `CRUXY_E_HOOK_UNTRUSTED` when a project's
70
- * hooks are not trusted. A no-op when hooks are disabled or none match.
71
- */
72
- fire(event: HookEvent, ctx: ToolContext): Promise<void>;
73
- /**
74
- * Ensure this repo's project hooks are trusted for their current fingerprint.
75
- * Records trust on an interactive accept; throws `CRUXY_E_HOOK_UNTRUSTED` on
76
- * decline, when `trustPrompt` is off, or when non-interactive — NEVER
77
- * auto-trusts. The fingerprint covers ALL project hooks, so a change to any of
78
- * them invalidates a prior decision (stale → re-prompt).
79
- */
80
- private ensureProjectTrust;
81
- /**
82
- * Run one hook command through the shared gate + sandbox path and reduce it to
83
- * a pass/fail verdict. A throw from {@link runGatedShell} (non-interactive
84
- * approval, sandbox start failure) is a failure whose policy the caller
85
- * applies — so an advisory hook can never abort the run on an infra error.
86
- */
87
- private runOne;
88
- }
@@ -1,38 +0,0 @@
1
- import type { CruxyConfig } from "../config/index.js";
2
- import type { logger as Logger } from "../utils/logger.js";
3
- import { type HookSources } from "./config.js";
4
- import { HookRunner, type TrustPromptInfo } from "./runner.js";
5
- import { type TrustStore } from "./trust.js";
6
- import type { HookCatalog, SlashCommandSpec } from "./types.js";
7
- /**
8
- * Construction/wiring for the hooks subsystem (C.19). Loads the layered catalog,
9
- * builds the {@link HookRunner} with the real trust store + an interactive trust
10
- * prompt, and exposes the resolved custom slash commands. Everything the runner
11
- * needs is injectable so the security behavior is unit-testable without touching
12
- * disk or a TTY.
13
- */
14
- export interface HooksService {
15
- /** The lifecycle firing seam (threaded into the loop / session). */
16
- runner: HookRunner;
17
- /** Resolved custom slash commands (project > user). */
18
- commands: SlashCommandSpec[];
19
- /** The full catalog (for `cruxy hooks list` + surfacing load errors). */
20
- catalog: HookCatalog;
21
- }
22
- export interface BuildHooksServiceOptions {
23
- cwd: string;
24
- config: CruxyConfig;
25
- /** Whether cruxy can prompt (stdin is a TTY). */
26
- interactive: boolean;
27
- logger: typeof Logger;
28
- sources?: HookSources;
29
- trust?: TrustStore;
30
- promptTrust?: (info: TrustPromptInfo) => Promise<boolean>;
31
- now?: () => string;
32
- }
33
- /**
34
- * Load the catalog and assemble the {@link HooksService}. Malformed definitions
35
- * are surfaced (never eval'd, never silently dropped) through the logger; the
36
- * valid ones proceed.
37
- */
38
- export declare function buildHooksService(opts: BuildHooksServiceOptions): Promise<HooksService>;
@@ -1,48 +0,0 @@
1
- import type { SlashCommandSpec } from "./types.js";
2
- /**
3
- * Custom slash-command resolution (C.19). Builtins are reserved and always win —
4
- * a custom command can never shadow `/help`, `/exit`, etc. A resolved custom
5
- * command is either a `prompt` (expanded to safe text fed to the agent) or a
6
- * `shell` binding (executed through the SAME gate + sandbox as everything else,
7
- * by the caller). Nothing here executes anything; it only resolves + expands.
8
- */
9
- /** The builtin slash commands (C.13) — reserved, not overridable. */
10
- export declare const BUILTIN_SLASH_COMMANDS: readonly ["help", "clear", "compact", "reload", "plan", "exit", "quit"];
11
- /** Is `name` (no leading slash) a reserved builtin? */
12
- export declare function isBuiltinSlash(name: string): boolean;
13
- /** The outcome of resolving a `/…` line against the custom catalog. */
14
- export type SlashResolution =
15
- /** A builtin — the REPL's own dispatch handles it (custom never shadows it). */
16
- {
17
- kind: "builtin";
18
- name: string;
19
- }
20
- /** A prompt-template command, already expanded to the text to send the agent. */
21
- | {
22
- kind: "prompt";
23
- spec: SlashCommandSpec;
24
- prompt: string;
25
- }
26
- /** A shell-bound command — the caller runs `spec.command` through the gate. */
27
- | {
28
- kind: "shell";
29
- spec: SlashCommandSpec;
30
- args: string;
31
- }
32
- /** Not a slash line, or an unknown command. */
33
- | {
34
- kind: "none";
35
- };
36
- /**
37
- * Resolve one input line. Non-slash input and unknown names → `none`. Builtins
38
- * short-circuit to `builtin` BEFORE the custom catalog is consulted, so a custom
39
- * command named after a builtin is inert (surfaced separately at load time).
40
- */
41
- export declare function resolveSlash(line: string, commands: readonly SlashCommandSpec[]): SlashResolution;
42
- /**
43
- * Expand a prompt template — substitute every `{{args}}` with the caller's args.
44
- * Pure text in, pure text out: the result is fed to the agent as a user prompt,
45
- * so a prompt command can never execute anything (that is the whole safety of
46
- * the default `prompt` kind).
47
- */
48
- export declare function expandTemplate(template: string, args: string): string;
@@ -1,46 +0,0 @@
1
- import type { HookDefinition, HookTrust } from "./types.js";
2
- /**
3
- * The project-hook trust model (C.19). Trust is recorded in the GLOBAL dir
4
- * (`~/.cruxy/trust.json`) — in the user's home, NEVER inside a repo — so cloning
5
- * a repo carries zero trust and an attacker cannot ship a pre-trusted marker.
6
- *
7
- * Trust is bound to a {@link fingerprintHooks fingerprint} of the exact project
8
- * hook commands seen at trust time. It is re-checked on every run: if the
9
- * project's hooks change (a command / event / blocking edit), the fingerprint no
10
- * longer matches and trust is stale → the user is re-prompted. This is what
11
- * defeats trust-then-swap.
12
- */
13
- /** ~/.cruxy/trust.json */
14
- export declare function trustPath(): string;
15
- /**
16
- * A stable content fingerprint of a repo's PROJECT hook definitions. Canonical
17
- * by construction so a benign reformat of `hooks.json` (reindent, reordered
18
- * keys, extra whitespace inside a command) does NOT change it, while any real
19
- * change to a command, event, or blocking flag DOES:
20
- * - only the meaning-bearing fields are hashed (name, event, command, blocking);
21
- * - the command string is whitespace-normalized (trim + collapse runs);
22
- * - specs are sorted by name and serialized with a fixed key order.
23
- */
24
- export declare function fingerprintHooks(hooks: readonly HookDefinition[]): string;
25
- /** The persisted trust seam — a file-backed store in production, injectable for
26
- * tests. `get`/`record` are synchronous (the record is tiny). */
27
- export interface TrustStore {
28
- /** The recorded decision for a repo root, or undefined if never trusted. */
29
- get(root: string): HookTrust | undefined;
30
- /** Persist a trust decision (overwrites any prior one for the same root). */
31
- record(trust: HookTrust): void;
32
- }
33
- /**
34
- * Is this repo's current project-hook set trusted? True only when a decision
35
- * exists AND its fingerprint matches the current one — a changed hook set is
36
- * treated as untrusted (stale), forcing a fresh decision.
37
- */
38
- export declare function isTrusted(store: TrustStore, root: string, currentFingerprint: string): boolean;
39
- /**
40
- * The real store, persisting to `~/.cruxy/trust.json` as `{ [root]: HookTrust }`.
41
- * Reads are lazy + cached; a corrupt file is treated as "no trust recorded"
42
- * (fail-closed — a broken trust file must never grant trust).
43
- */
44
- export declare function fileTrustStore(file?: string): TrustStore;
45
- /** An in-memory store for tests (and any ephemeral run). */
46
- export declare function memoryTrustStore(seed?: HookTrust[]): TrustStore;