@getrift/rift 0.1.0-beta.0 → 0.1.0-beta.10

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 (202) hide show
  1. package/README.md +72 -48
  2. package/dist/src/auth/keychain.d.ts +9 -0
  3. package/dist/src/auth/keychain.d.ts.map +1 -1
  4. package/dist/src/auth/keychain.js +37 -0
  5. package/dist/src/auth/keychain.js.map +1 -1
  6. package/dist/src/capture/recover-quarantine.d.ts +221 -0
  7. package/dist/src/capture/recover-quarantine.d.ts.map +1 -0
  8. package/dist/src/capture/recover-quarantine.js +453 -0
  9. package/dist/src/capture/recover-quarantine.js.map +1 -0
  10. package/dist/src/cli/commands/backfill.d.ts.map +1 -1
  11. package/dist/src/cli/commands/backfill.js +5 -2
  12. package/dist/src/cli/commands/backfill.js.map +1 -1
  13. package/dist/src/cli/commands/capture-recover.d.ts +12 -0
  14. package/dist/src/cli/commands/capture-recover.d.ts.map +1 -0
  15. package/dist/src/cli/commands/capture-recover.js +120 -0
  16. package/dist/src/cli/commands/capture-recover.js.map +1 -0
  17. package/dist/src/cli/commands/capture.d.ts.map +1 -1
  18. package/dist/src/cli/commands/capture.js +10 -4
  19. package/dist/src/cli/commands/capture.js.map +1 -1
  20. package/dist/src/cli/commands/feedback.d.ts.map +1 -1
  21. package/dist/src/cli/commands/feedback.js +6 -2
  22. package/dist/src/cli/commands/feedback.js.map +1 -1
  23. package/dist/src/cli/commands/hooks-install.d.ts +19 -0
  24. package/dist/src/cli/commands/hooks-install.d.ts.map +1 -0
  25. package/dist/src/cli/commands/hooks-install.js +103 -0
  26. package/dist/src/cli/commands/hooks-install.js.map +1 -0
  27. package/dist/src/cli/commands/mcp-install.js +5 -2
  28. package/dist/src/cli/commands/mcp-install.js.map +1 -1
  29. package/dist/src/cli/commands/onboard.d.ts +24 -0
  30. package/dist/src/cli/commands/onboard.d.ts.map +1 -1
  31. package/dist/src/cli/commands/onboard.js +200 -21
  32. package/dist/src/cli/commands/onboard.js.map +1 -1
  33. package/dist/src/cli/commands/rebuild.d.ts.map +1 -1
  34. package/dist/src/cli/commands/rebuild.js +6 -3
  35. package/dist/src/cli/commands/rebuild.js.map +1 -1
  36. package/dist/src/cli/commands/review.d.ts.map +1 -1
  37. package/dist/src/cli/commands/review.js +22 -7
  38. package/dist/src/cli/commands/review.js.map +1 -1
  39. package/dist/src/cli/commands/status.d.ts.map +1 -1
  40. package/dist/src/cli/commands/status.js +48 -2
  41. package/dist/src/cli/commands/status.js.map +1 -1
  42. package/dist/src/cli/commands/token-issue.d.ts.map +1 -1
  43. package/dist/src/cli/commands/token-issue.js +9 -1
  44. package/dist/src/cli/commands/token-issue.js.map +1 -1
  45. package/dist/src/cli/commands/triage.d.ts.map +1 -1
  46. package/dist/src/cli/commands/triage.js +7 -5
  47. package/dist/src/cli/commands/triage.js.map +1 -1
  48. package/dist/src/cli/commands/update.d.ts +26 -0
  49. package/dist/src/cli/commands/update.d.ts.map +1 -0
  50. package/dist/src/cli/commands/update.js +130 -0
  51. package/dist/src/cli/commands/update.js.map +1 -0
  52. package/dist/src/cli/default-config-path.d.ts +15 -0
  53. package/dist/src/cli/default-config-path.d.ts.map +1 -0
  54. package/dist/src/cli/default-config-path.js +27 -0
  55. package/dist/src/cli/default-config-path.js.map +1 -0
  56. package/dist/src/cli/hooks-writers/claude-code-policy-script.d.ts +25 -0
  57. package/dist/src/cli/hooks-writers/claude-code-policy-script.d.ts.map +1 -0
  58. package/dist/src/cli/hooks-writers/claude-code-policy-script.js +85 -0
  59. package/dist/src/cli/hooks-writers/claude-code-policy-script.js.map +1 -0
  60. package/dist/src/cli/hooks-writers/claude-code.d.ts +12 -0
  61. package/dist/src/cli/hooks-writers/claude-code.d.ts.map +1 -0
  62. package/dist/src/cli/hooks-writers/claude-code.js +228 -0
  63. package/dist/src/cli/hooks-writers/claude-code.js.map +1 -0
  64. package/dist/src/cli/hooks-writers/errors.d.ts +16 -0
  65. package/dist/src/cli/hooks-writers/errors.d.ts.map +1 -0
  66. package/dist/src/cli/hooks-writers/errors.js +24 -0
  67. package/dist/src/cli/hooks-writers/errors.js.map +1 -0
  68. package/dist/src/cli/hooks-writers/index.d.ts +13 -0
  69. package/dist/src/cli/hooks-writers/index.d.ts.map +1 -0
  70. package/dist/src/cli/hooks-writers/index.js +26 -0
  71. package/dist/src/cli/hooks-writers/index.js.map +1 -0
  72. package/dist/src/cli/hooks-writers/types.d.ts +27 -0
  73. package/dist/src/cli/hooks-writers/types.d.ts.map +1 -0
  74. package/dist/src/cli/hooks-writers/types.js +9 -0
  75. package/dist/src/cli/hooks-writers/types.js.map +1 -0
  76. package/dist/src/cli/http-client.d.ts +56 -1
  77. package/dist/src/cli/http-client.d.ts.map +1 -1
  78. package/dist/src/cli/http-client.js +140 -4
  79. package/dist/src/cli/http-client.js.map +1 -1
  80. package/dist/src/cli/index.d.ts.map +1 -1
  81. package/dist/src/cli/index.js +27 -6
  82. package/dist/src/cli/index.js.map +1 -1
  83. package/dist/src/cli/status/friend-header.d.ts.map +1 -1
  84. package/dist/src/cli/status/friend-header.js +117 -7
  85. package/dist/src/cli/status/friend-header.js.map +1 -1
  86. package/dist/src/ingestion/inbox-core/conversation-key.d.ts +2 -0
  87. package/dist/src/ingestion/inbox-core/conversation-key.d.ts.map +1 -0
  88. package/dist/src/ingestion/inbox-core/conversation-key.js +31 -0
  89. package/dist/src/ingestion/inbox-core/conversation-key.js.map +1 -0
  90. package/dist/src/ingestion/inbox-core/extensions.d.ts +3 -0
  91. package/dist/src/ingestion/inbox-core/extensions.d.ts.map +1 -0
  92. package/dist/src/ingestion/inbox-core/extensions.js +16 -0
  93. package/dist/src/ingestion/inbox-core/extensions.js.map +1 -0
  94. package/dist/src/ingestion/inbox-core/idempotency.d.ts +2 -0
  95. package/dist/src/ingestion/inbox-core/idempotency.d.ts.map +1 -0
  96. package/dist/src/ingestion/inbox-core/idempotency.js +22 -0
  97. package/dist/src/ingestion/inbox-core/idempotency.js.map +1 -0
  98. package/dist/src/ingestion/inbox-core/index.d.ts +19 -0
  99. package/dist/src/ingestion/inbox-core/index.d.ts.map +1 -0
  100. package/dist/src/ingestion/inbox-core/index.js +19 -0
  101. package/dist/src/ingestion/inbox-core/index.js.map +1 -0
  102. package/dist/src/ingestion/inbox-core/source-detection.d.ts +2 -0
  103. package/dist/src/ingestion/inbox-core/source-detection.d.ts.map +1 -0
  104. package/dist/src/ingestion/inbox-core/source-detection.js +23 -0
  105. package/dist/src/ingestion/inbox-core/source-detection.js.map +1 -0
  106. package/dist/src/ingestion/inbox-core/source-sniffer.d.ts +11 -0
  107. package/dist/src/ingestion/inbox-core/source-sniffer.d.ts.map +1 -0
  108. package/dist/src/ingestion/inbox-core/source-sniffer.js +69 -0
  109. package/dist/src/ingestion/inbox-core/source-sniffer.js.map +1 -0
  110. package/dist/src/ingestion/inbox-core/zip-sniffer.d.ts +70 -0
  111. package/dist/src/ingestion/inbox-core/zip-sniffer.d.ts.map +1 -0
  112. package/dist/src/ingestion/inbox-core/zip-sniffer.js +161 -0
  113. package/dist/src/ingestion/inbox-core/zip-sniffer.js.map +1 -0
  114. package/dist/src/ingestion/inbox-watcher.d.ts.map +1 -1
  115. package/dist/src/ingestion/inbox-watcher.js +34 -50
  116. package/dist/src/ingestion/inbox-watcher.js.map +1 -1
  117. package/dist/src/ingestion/indexer.d.ts +7 -0
  118. package/dist/src/ingestion/indexer.d.ts.map +1 -1
  119. package/dist/src/ingestion/indexer.js +36 -2
  120. package/dist/src/ingestion/indexer.js.map +1 -1
  121. package/dist/src/ingestion/metadata-extraction.d.ts +8 -5
  122. package/dist/src/ingestion/metadata-extraction.d.ts.map +1 -1
  123. package/dist/src/ingestion/metadata-extraction.js +24 -5
  124. package/dist/src/ingestion/metadata-extraction.js.map +1 -1
  125. package/dist/src/ingestion/skip-quarantine.d.ts +10 -0
  126. package/dist/src/ingestion/skip-quarantine.d.ts.map +1 -0
  127. package/dist/src/ingestion/skip-quarantine.js +35 -0
  128. package/dist/src/ingestion/skip-quarantine.js.map +1 -0
  129. package/dist/src/jobs/handlers/compact.d.ts.map +1 -1
  130. package/dist/src/jobs/handlers/compact.js +25 -4
  131. package/dist/src/jobs/handlers/compact.js.map +1 -1
  132. package/dist/src/jobs/handlers/ingest.d.ts.map +1 -1
  133. package/dist/src/jobs/handlers/ingest.js +49 -24
  134. package/dist/src/jobs/handlers/ingest.js.map +1 -1
  135. package/dist/src/jobs/handlers/reconcile.d.ts.map +1 -1
  136. package/dist/src/jobs/handlers/reconcile.js +30 -8
  137. package/dist/src/jobs/handlers/reconcile.js.map +1 -1
  138. package/dist/src/jobs/handlers/reindex.d.ts.map +1 -1
  139. package/dist/src/jobs/handlers/reindex.js +12 -2
  140. package/dist/src/jobs/handlers/reindex.js.map +1 -1
  141. package/dist/src/jobs/handlers/save.d.ts.map +1 -1
  142. package/dist/src/jobs/handlers/save.js +9 -2
  143. package/dist/src/jobs/handlers/save.js.map +1 -1
  144. package/dist/src/jobs/queue.d.ts +11 -0
  145. package/dist/src/jobs/queue.d.ts.map +1 -1
  146. package/dist/src/jobs/queue.js +18 -0
  147. package/dist/src/jobs/queue.js.map +1 -1
  148. package/dist/src/jobs/worker-entry.d.ts.map +1 -1
  149. package/dist/src/jobs/worker-entry.js +2 -0
  150. package/dist/src/jobs/worker-entry.js.map +1 -1
  151. package/dist/src/main.js +36 -4
  152. package/dist/src/main.js.map +1 -1
  153. package/dist/src/observability/embedding-events.d.ts +52 -0
  154. package/dist/src/observability/embedding-events.d.ts.map +1 -0
  155. package/dist/src/observability/embedding-events.js +149 -0
  156. package/dist/src/observability/embedding-events.js.map +1 -0
  157. package/dist/src/observability/index-events.d.ts +70 -0
  158. package/dist/src/observability/index-events.d.ts.map +1 -0
  159. package/dist/src/observability/index-events.js +148 -0
  160. package/dist/src/observability/index-events.js.map +1 -0
  161. package/dist/src/observability/tool-usage-stats.d.ts +7 -0
  162. package/dist/src/observability/tool-usage-stats.d.ts.map +1 -1
  163. package/dist/src/observability/tool-usage-stats.js +41 -5
  164. package/dist/src/observability/tool-usage-stats.js.map +1 -1
  165. package/dist/src/observability/tool-usage.d.ts +7 -7
  166. package/dist/src/observability/tool-usage.d.ts.map +1 -1
  167. package/dist/src/observability/tool-usage.js +78 -39
  168. package/dist/src/observability/tool-usage.js.map +1 -1
  169. package/dist/src/observability/version-check.d.ts +70 -0
  170. package/dist/src/observability/version-check.d.ts.map +1 -0
  171. package/dist/src/observability/version-check.js +197 -0
  172. package/dist/src/observability/version-check.js.map +1 -0
  173. package/dist/src/providers/ollama-embed.d.ts +2 -1
  174. package/dist/src/providers/ollama-embed.d.ts.map +1 -1
  175. package/dist/src/providers/ollama-embed.js +1 -0
  176. package/dist/src/providers/ollama-embed.js.map +1 -1
  177. package/dist/src/providers/openai-metadata-extraction.d.ts +3 -3
  178. package/dist/src/providers/openai-metadata-extraction.d.ts.map +1 -1
  179. package/dist/src/providers/openai-metadata-extraction.js +18 -3
  180. package/dist/src/providers/openai-metadata-extraction.js.map +1 -1
  181. package/dist/src/providers/stub.d.ts +2 -0
  182. package/dist/src/providers/stub.d.ts.map +1 -1
  183. package/dist/src/providers/stub.js +2 -0
  184. package/dist/src/providers/stub.js.map +1 -1
  185. package/dist/src/providers/types.d.ts +11 -0
  186. package/dist/src/providers/types.d.ts.map +1 -1
  187. package/dist/src/providers/voyage.d.ts +2 -1
  188. package/dist/src/providers/voyage.d.ts.map +1 -1
  189. package/dist/src/providers/voyage.js +1 -0
  190. package/dist/src/providers/voyage.js.map +1 -1
  191. package/dist/src/server/app.d.ts.map +1 -1
  192. package/dist/src/server/app.js +67 -1
  193. package/dist/src/server/app.js.map +1 -1
  194. package/dist/src/server/routes/friend-status.d.ts +202 -3
  195. package/dist/src/server/routes/friend-status.d.ts.map +1 -1
  196. package/dist/src/server/routes/friend-status.js +290 -7
  197. package/dist/src/server/routes/friend-status.js.map +1 -1
  198. package/dist/src/storage/rebuild.d.ts +14 -1
  199. package/dist/src/storage/rebuild.d.ts.map +1 -1
  200. package/dist/src/storage/rebuild.js +160 -34
  201. package/dist/src/storage/rebuild.js.map +1 -1
  202. package/package.json +1 -1
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Source of truth for the Rift policy hook that ships into
3
+ * `~/.claude/hooks/rift-policy.mjs`.
4
+ *
5
+ * The script is a plain Node ESM module — no `jq`, no `@anthropic-ai`
6
+ * deps, just `node:fs` / `node:os` / `node:path`. Claude Code runs it
7
+ * via the matcher in `settings.json` and pipes the PreToolUse payload
8
+ * on stdin. We branch on `tool_name`:
9
+ *
10
+ * - `mcp__rift__rift_context_pack` → touch session marker, exit 0
11
+ * - `mcp__rift__rift_search` → require marker, else exit 2
12
+ * - `mcp__rift__rift_conversations_search` → same
13
+ * - anything else → exit 0 (defensive; matcher
14
+ * should already exclude these)
15
+ *
16
+ * Disable knobs:
17
+ * - `RIFT_POLICY_DISABLED=1` in env → script no-ops with exit 0
18
+ * - Remove the matcher entry from `~/.claude/settings.json`
19
+ *
20
+ * The body is exported as a string so the writer can install it
21
+ * verbatim — keeping the bytes-on-disk identical to the bytes the
22
+ * tests assert against.
23
+ */
24
+ export declare const CLAUDE_CODE_POLICY_SCRIPT = "#!/usr/bin/env node\n// Rift policy hook for Claude Code \u2014 managed by `rift hooks install --client claude-code`.\n// Enforces: rift_context_pack must be the first Rift retrieval call per session.\n// Disable: set RIFT_POLICY_DISABLED=1 in env, or remove the matcher entry\n// from ~/.claude/settings.json.\n//\n// DO NOT EDIT BY HAND \u2014 re-running `rift hooks install --client claude-code`\n// will overwrite local edits.\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst POLICY_MESSAGE =\n \"Rift policy: call mcp__rift__rift_context_pack first (compact, pre-budgeted). \" +\n \"Only fall back to rift_search/rift_conversations_search if the pack returns \" +\n \"nothing useful, and start with top_k 3-5.\";\n\nif (process.env.RIFT_POLICY_DISABLED === \"1\") process.exit(0);\n\nconst chunks = [];\nfor await (const chunk of process.stdin) chunks.push(chunk);\nconst raw = Buffer.concat(chunks).toString(\"utf8\");\n\nlet payload;\ntry {\n payload = raw.trim() === \"\" ? {} : JSON.parse(raw);\n} catch {\n // Fail-open on malformed input so a future hook-payload schema change\n // can never silently block legitimate tool calls.\n process.exit(0);\n}\n\nconst tool = typeof payload.tool_name === \"string\" ? payload.tool_name : \"\";\nconst session =\n typeof payload.session_id === \"string\" && payload.session_id !== \"\"\n ? payload.session_id\n : \"nosession\";\nconst marker = path.join(os.tmpdir(), `rift-pack-called-${session}`);\n\nif (tool === \"mcp__rift__rift_context_pack\") {\n try {\n fs.closeSync(fs.openSync(marker, \"a\"));\n } catch {\n // best-effort; missing marker only blocks the next search call.\n }\n process.exit(0);\n}\n\nif (\n tool === \"mcp__rift__rift_search\" ||\n tool === \"mcp__rift__rift_conversations_search\"\n) {\n if (!fs.existsSync(marker)) {\n process.stderr.write(POLICY_MESSAGE + \"\\n\");\n process.exit(2);\n }\n}\n\nprocess.exit(0);\n";
25
+ //# sourceMappingURL=claude-code-policy-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code-policy-script.d.ts","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/claude-code-policy-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,eAAO,MAAM,yBAAyB,m8DA4DrC,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Source of truth for the Rift policy hook that ships into
3
+ * `~/.claude/hooks/rift-policy.mjs`.
4
+ *
5
+ * The script is a plain Node ESM module — no `jq`, no `@anthropic-ai`
6
+ * deps, just `node:fs` / `node:os` / `node:path`. Claude Code runs it
7
+ * via the matcher in `settings.json` and pipes the PreToolUse payload
8
+ * on stdin. We branch on `tool_name`:
9
+ *
10
+ * - `mcp__rift__rift_context_pack` → touch session marker, exit 0
11
+ * - `mcp__rift__rift_search` → require marker, else exit 2
12
+ * - `mcp__rift__rift_conversations_search` → same
13
+ * - anything else → exit 0 (defensive; matcher
14
+ * should already exclude these)
15
+ *
16
+ * Disable knobs:
17
+ * - `RIFT_POLICY_DISABLED=1` in env → script no-ops with exit 0
18
+ * - Remove the matcher entry from `~/.claude/settings.json`
19
+ *
20
+ * The body is exported as a string so the writer can install it
21
+ * verbatim — keeping the bytes-on-disk identical to the bytes the
22
+ * tests assert against.
23
+ */
24
+ export const CLAUDE_CODE_POLICY_SCRIPT = `#!/usr/bin/env node
25
+ // Rift policy hook for Claude Code — managed by \`rift hooks install --client claude-code\`.
26
+ // Enforces: rift_context_pack must be the first Rift retrieval call per session.
27
+ // Disable: set RIFT_POLICY_DISABLED=1 in env, or remove the matcher entry
28
+ // from ~/.claude/settings.json.
29
+ //
30
+ // DO NOT EDIT BY HAND — re-running \`rift hooks install --client claude-code\`
31
+ // will overwrite local edits.
32
+
33
+ import fs from "node:fs";
34
+ import os from "node:os";
35
+ import path from "node:path";
36
+
37
+ const POLICY_MESSAGE =
38
+ "Rift policy: call mcp__rift__rift_context_pack first (compact, pre-budgeted). " +
39
+ "Only fall back to rift_search/rift_conversations_search if the pack returns " +
40
+ "nothing useful, and start with top_k 3-5.";
41
+
42
+ if (process.env.RIFT_POLICY_DISABLED === "1") process.exit(0);
43
+
44
+ const chunks = [];
45
+ for await (const chunk of process.stdin) chunks.push(chunk);
46
+ const raw = Buffer.concat(chunks).toString("utf8");
47
+
48
+ let payload;
49
+ try {
50
+ payload = raw.trim() === "" ? {} : JSON.parse(raw);
51
+ } catch {
52
+ // Fail-open on malformed input so a future hook-payload schema change
53
+ // can never silently block legitimate tool calls.
54
+ process.exit(0);
55
+ }
56
+
57
+ const tool = typeof payload.tool_name === "string" ? payload.tool_name : "";
58
+ const session =
59
+ typeof payload.session_id === "string" && payload.session_id !== ""
60
+ ? payload.session_id
61
+ : "nosession";
62
+ const marker = path.join(os.tmpdir(), \`rift-pack-called-\${session}\`);
63
+
64
+ if (tool === "mcp__rift__rift_context_pack") {
65
+ try {
66
+ fs.closeSync(fs.openSync(marker, "a"));
67
+ } catch {
68
+ // best-effort; missing marker only blocks the next search call.
69
+ }
70
+ process.exit(0);
71
+ }
72
+
73
+ if (
74
+ tool === "mcp__rift__rift_search" ||
75
+ tool === "mcp__rift__rift_conversations_search"
76
+ ) {
77
+ if (!fs.existsSync(marker)) {
78
+ process.stderr.write(POLICY_MESSAGE + "\\n");
79
+ process.exit(2);
80
+ }
81
+ }
82
+
83
+ process.exit(0);
84
+ `;
85
+ //# sourceMappingURL=claude-code-policy-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code-policy-script.js","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/claude-code-policy-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DxC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { HookWriteOutcome } from "./types.js";
2
+ export interface ClaudeCodeHookWriteOpts {
3
+ /** Absolute path of the user's $HOME (test override). */
4
+ homeDir: string;
5
+ /** Print outcome only; do not touch disk. */
6
+ dryRun: boolean;
7
+ /** Test injection: stable timestamp for backup IDs. */
8
+ now?: () => Date;
9
+ }
10
+ export declare function writeClaudeCodeHook(opts: ClaudeCodeHookWriteOpts): HookWriteOutcome;
11
+ export { HooksParseFailedError } from "./errors.js";
12
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/claude-code.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAQnD,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,MAAM,EAAE,OAAO,CAAC;IAChB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,uBAAuB,GAC5B,gBAAgB,CAmIlB;AA2GD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Writer for `rift hooks install --client claude-code`.
3
+ *
4
+ * Idempotent install of the Rift policy hook into Claude Code's
5
+ * `~/.claude/settings.json`. Mirrors the `mcp-config-writers/json-config`
6
+ * contract:
7
+ *
8
+ * - Atomic settings.json write (tmp + rename).
9
+ * - Backup the prior settings file to `<file>.bak.<id>` if it existed
10
+ * and we're about to change anything; surface only an opaque ID.
11
+ * - Refuse to overwrite when the file is not parseable JSON OR when
12
+ * `hooks` is present but not an object — emit a redacted error
13
+ * referring to the backup ID only.
14
+ * - Detect an existing Rift policy entry by command substring
15
+ * ("rift-policy.mjs"); rewrite it in place rather than appending a
16
+ * duplicate.
17
+ * - Preserve every other top-level key, every other hook event, every
18
+ * other PreToolUse entry.
19
+ *
20
+ * Hook script lifecycle:
21
+ * - Always installed at `<homeDir>/.claude/hooks/rift-policy.mjs`.
22
+ * - Atomic write (tmp + rename), 0755 permissions.
23
+ * - Re-running with the same package version is a no-op for the script.
24
+ */
25
+ import fs from "node:fs";
26
+ import path from "node:path";
27
+ import { CLAUDE_CODE_POLICY_SCRIPT } from "./claude-code-policy-script.js";
28
+ import { HooksParseFailedError } from "./errors.js";
29
+ const RIFT_HOOK_MATCHER = "mcp__rift__rift_context_pack|mcp__rift__rift_search|mcp__rift__rift_conversations_search";
30
+ const POLICY_SCRIPT_REL = path.join(".claude", "hooks", "rift-policy.mjs");
31
+ const SETTINGS_REL = path.join(".claude", "settings.json");
32
+ export function writeClaudeCodeHook(opts) {
33
+ const scriptPath = path.join(opts.homeDir, POLICY_SCRIPT_REL);
34
+ const settingsPath = path.join(opts.homeDir, SETTINGS_REL);
35
+ const now = opts.now ?? defaultNow;
36
+ // 1. Read settings (or treat missing/empty as `{}`).
37
+ const preexistingSettings = fs.existsSync(settingsPath);
38
+ let raw = "";
39
+ let parsed = {};
40
+ if (preexistingSettings) {
41
+ raw = fs.readFileSync(settingsPath, "utf8");
42
+ if (raw.trim() !== "") {
43
+ try {
44
+ const candidate = JSON.parse(raw);
45
+ if (typeof candidate !== "object" ||
46
+ candidate === null ||
47
+ Array.isArray(candidate)) {
48
+ throw new SyntaxError("settings.json root must be a JSON object");
49
+ }
50
+ parsed = candidate;
51
+ }
52
+ catch (err) {
53
+ throw failParse(settingsPath, raw, now, err, opts.dryRun);
54
+ }
55
+ }
56
+ }
57
+ // 1b. Reject malformed `hooks` shape early — same backup contract as
58
+ // the JSON parse failure path.
59
+ const hooksField = parsed["hooks"];
60
+ if (hooksField !== undefined &&
61
+ (typeof hooksField !== "object" ||
62
+ hooksField === null ||
63
+ Array.isArray(hooksField))) {
64
+ throw failParse(settingsPath, raw, now, new TypeError("settings.json `hooks` is present but not an object"), opts.dryRun);
65
+ }
66
+ // 2. Compare desired script content against on-disk content.
67
+ const desiredScript = CLAUDE_CODE_POLICY_SCRIPT;
68
+ const existingScript = fs.existsSync(scriptPath)
69
+ ? fs.readFileSync(scriptPath, "utf8")
70
+ : null;
71
+ const scriptUpdated = existingScript !== desiredScript;
72
+ // 3. Merge the policy entry into PreToolUse.
73
+ const merged = mergeRiftHookEntry(parsed, scriptPath);
74
+ const settingsChanged = merged.hookEntryAdded || merged.hookEntryReplaced;
75
+ const willTouchDisk = scriptUpdated || settingsChanged;
76
+ const backupId = preexistingSettings && settingsChanged ? formatBackupId(now) : null;
77
+ if (opts.dryRun || !willTouchDisk) {
78
+ return {
79
+ scriptPath,
80
+ settingsPath,
81
+ preexistingSettings,
82
+ backupId: null,
83
+ scriptUpdated,
84
+ hookEntryAdded: merged.hookEntryAdded,
85
+ hookEntryReplaced: merged.hookEntryReplaced,
86
+ dryRun: !!opts.dryRun,
87
+ };
88
+ }
89
+ // 4. Write the script atomically.
90
+ if (scriptUpdated) {
91
+ fs.mkdirSync(path.dirname(scriptPath), { recursive: true });
92
+ const tmpScript = `${scriptPath}.tmp.${process.pid}`;
93
+ fs.writeFileSync(tmpScript, desiredScript, {
94
+ encoding: "utf8",
95
+ mode: 0o755,
96
+ });
97
+ fs.renameSync(tmpScript, scriptPath);
98
+ fs.chmodSync(scriptPath, 0o755);
99
+ }
100
+ // 5. Backup + atomically write settings if it changed.
101
+ if (settingsChanged) {
102
+ if (preexistingSettings && backupId) {
103
+ fs.writeFileSync(`${settingsPath}.bak.${backupId}`, raw, {
104
+ encoding: "utf8",
105
+ mode: 0o600,
106
+ });
107
+ }
108
+ else {
109
+ fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
110
+ }
111
+ const tmpSettings = `${settingsPath}.tmp.${process.pid}`;
112
+ try {
113
+ fs.writeFileSync(tmpSettings, JSON.stringify(merged.parsed, null, 2) + "\n", { encoding: "utf8", mode: 0o644 });
114
+ fs.renameSync(tmpSettings, settingsPath);
115
+ }
116
+ catch (err) {
117
+ try {
118
+ if (fs.existsSync(tmpSettings))
119
+ fs.unlinkSync(tmpSettings);
120
+ }
121
+ catch {
122
+ // ignore
123
+ }
124
+ if (preexistingSettings && backupId) {
125
+ try {
126
+ fs.copyFileSync(`${settingsPath}.bak.${backupId}`, settingsPath);
127
+ }
128
+ catch {
129
+ // best-effort — the backup file is the recovery surface.
130
+ }
131
+ }
132
+ throw err;
133
+ }
134
+ }
135
+ return {
136
+ scriptPath,
137
+ settingsPath,
138
+ preexistingSettings,
139
+ backupId,
140
+ scriptUpdated,
141
+ hookEntryAdded: merged.hookEntryAdded,
142
+ hookEntryReplaced: merged.hookEntryReplaced,
143
+ dryRun: false,
144
+ };
145
+ }
146
+ function mergeRiftHookEntry(parsed, scriptPath) {
147
+ const next = { ...parsed };
148
+ const hooks = typeof next["hooks"] === "object" &&
149
+ next["hooks"] !== null &&
150
+ !Array.isArray(next["hooks"])
151
+ ? { ...next["hooks"] }
152
+ : {};
153
+ const preToolUse = Array.isArray(hooks["PreToolUse"])
154
+ ? [...hooks["PreToolUse"]]
155
+ : [];
156
+ // Quote the script path in case the user's $HOME contains spaces.
157
+ const desiredCommand = `node "${scriptPath}"`;
158
+ const desiredEntry = {
159
+ matcher: RIFT_HOOK_MATCHER,
160
+ hooks: [
161
+ {
162
+ type: "command",
163
+ command: desiredCommand,
164
+ timeout: 5,
165
+ },
166
+ ],
167
+ };
168
+ let hookEntryAdded = false;
169
+ let hookEntryReplaced = false;
170
+ let foundExisting = false;
171
+ const updated = preToolUse.map((entry) => {
172
+ if (!isRiftPolicyEntry(entry))
173
+ return entry;
174
+ foundExisting = true;
175
+ const before = JSON.stringify(entry);
176
+ const after = JSON.stringify(desiredEntry);
177
+ if (before !== after)
178
+ hookEntryReplaced = true;
179
+ return desiredEntry;
180
+ });
181
+ if (!foundExisting) {
182
+ updated.push(desiredEntry);
183
+ hookEntryAdded = true;
184
+ }
185
+ hooks["PreToolUse"] = updated;
186
+ next["hooks"] = hooks;
187
+ return { parsed: next, hookEntryAdded, hookEntryReplaced };
188
+ }
189
+ function isRiftPolicyEntry(entry) {
190
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
191
+ return false;
192
+ }
193
+ const e = entry;
194
+ const innerHooks = Array.isArray(e["hooks"]) ? e["hooks"] : [];
195
+ return innerHooks.some((h) => {
196
+ if (typeof h !== "object" || h === null)
197
+ return false;
198
+ const cmd = h["command"];
199
+ return typeof cmd === "string" && cmd.includes("rift-policy.mjs");
200
+ });
201
+ }
202
+ function formatBackupId(now) {
203
+ return `rift-hooks-claude-code-${now()
204
+ .toISOString()
205
+ .replace(/\.\d{3}Z$/, "Z")
206
+ .replace(/:/g, "-")}`;
207
+ }
208
+ function defaultNow() {
209
+ return new Date();
210
+ }
211
+ function failParse(settingsPath, raw, now, cause, dryRun) {
212
+ const id = formatBackupId(now);
213
+ if (!dryRun) {
214
+ try {
215
+ fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
216
+ fs.writeFileSync(`${settingsPath}.bak.${id}`, raw, {
217
+ encoding: "utf8",
218
+ mode: 0o600,
219
+ });
220
+ }
221
+ catch {
222
+ // best-effort; the operator-side recovery flow handles missing backups.
223
+ }
224
+ }
225
+ return new HooksParseFailedError("claude-code", id, cause);
226
+ }
227
+ export { HooksParseFailedError } from "./errors.js";
228
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { HookClientId } from "./types.js";
2
+ /**
3
+ * Thrown when a client settings file is malformed and we refuse to
4
+ * overwrite. Carries a backup ID the user can reference for recovery —
5
+ * the file's prior contents are saved to `<settings>.bak.<id>`.
6
+ *
7
+ * Message is path-free + content-free by construction so it can be
8
+ * emitted directly without leaking user data.
9
+ */
10
+ export declare class HooksParseFailedError extends Error {
11
+ readonly client: HookClientId;
12
+ readonly backupId: string;
13
+ readonly cause?: unknown;
14
+ constructor(client: HookClientId, backupId: string, cause?: unknown);
15
+ }
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEtB,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAWpE"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Thrown when a client settings file is malformed and we refuse to
3
+ * overwrite. Carries a backup ID the user can reference for recovery —
4
+ * the file's prior contents are saved to `<settings>.bak.<id>`.
5
+ *
6
+ * Message is path-free + content-free by construction so it can be
7
+ * emitted directly without leaking user data.
8
+ */
9
+ export class HooksParseFailedError extends Error {
10
+ client;
11
+ backupId;
12
+ cause;
13
+ constructor(client, backupId, cause) {
14
+ super(`rift hooks install (${client}): existing settings file is not parseable. ` +
15
+ `Refusing to overwrite. A backup of the prior contents was saved (id: ${backupId}). ` +
16
+ `Repair the file by hand and re-run, or delete it and re-run for a fresh write.`);
17
+ this.name = "HooksParseFailedError";
18
+ this.client = client;
19
+ this.backupId = backupId;
20
+ if (cause !== undefined)
21
+ this.cause = cause;
22
+ }
23
+ }
24
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/errors.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,MAAM,CAAe;IACrB,QAAQ,CAAS;IACR,KAAK,CAAW;IAElC,YAAY,MAAoB,EAAE,QAAgB,EAAE,KAAe;QACjE,KAAK,CACH,uBAAuB,MAAM,8CAA8C;YACzE,wEAAwE,QAAQ,KAAK;YACrF,gFAAgF,CACnF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC9C,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { HookClientId, HookWriteOutcome } from "./types.js";
2
+ export declare const ALL_HOOK_CLIENTS: readonly HookClientId[];
3
+ export interface HookDispatchOpts {
4
+ client: HookClientId;
5
+ homeDir: string;
6
+ dryRun: boolean;
7
+ now?: () => Date;
8
+ }
9
+ export declare function writeHookConfig(opts: HookDispatchOpts): HookWriteOutcome;
10
+ export declare function isHookClientId(s: string): s is HookClientId;
11
+ export { HooksParseFailedError } from "./errors.js";
12
+ export type { HookClientId, HookWriteOutcome } from "./types.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjE,eAAO,MAAM,gBAAgB,EAAE,SAAS,YAAY,EAE1C,CAAC;AAEX,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CASxE;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,YAAY,CAE3D;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Hooks-writer dispatch.
3
+ *
4
+ * Currently routes only `claude-code` — kept as a dispatch surface so
5
+ * adding `cursor`, `codex-cli`, or future agents doesn't require
6
+ * reshaping the command layer.
7
+ */
8
+ import { writeClaudeCodeHook } from "./claude-code.js";
9
+ export const ALL_HOOK_CLIENTS = [
10
+ "claude-code",
11
+ ];
12
+ export function writeHookConfig(opts) {
13
+ switch (opts.client) {
14
+ case "claude-code":
15
+ return writeClaudeCodeHook({
16
+ homeDir: opts.homeDir,
17
+ dryRun: opts.dryRun,
18
+ ...(opts.now ? { now: opts.now } : {}),
19
+ });
20
+ }
21
+ }
22
+ export function isHookClientId(s) {
23
+ return ALL_HOOK_CLIENTS.includes(s);
24
+ }
25
+ export { HooksParseFailedError } from "./errors.js";
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD,MAAM,CAAC,MAAM,gBAAgB,GAA4B;IACvD,aAAa;CACL,CAAC;AASX,MAAM,UAAU,eAAe,CAAC,IAAsB;IACpD,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,aAAa;YAChB,OAAO,mBAAmB,CAAC;gBACzB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvC,CAAC,CAAC;IACP,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAQ,gBAAsC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Types for `rift hooks install` writers.
3
+ *
4
+ * Currently only `claude-code` is supported. The shape mirrors
5
+ * `mcp-config-writers/types.ts` so we can extend to other agents later
6
+ * without reshuffling the dispatch surface.
7
+ */
8
+ export type HookClientId = "claude-code";
9
+ export interface HookWriteOutcome {
10
+ /** Absolute path of the policy script we manage. */
11
+ scriptPath: string;
12
+ /** Absolute path of the client settings file we touched. */
13
+ settingsPath: string;
14
+ /** Whether settingsPath existed before this run. */
15
+ preexistingSettings: boolean;
16
+ /** Opaque ID surfaced to the user when a backup was written. */
17
+ backupId: string | null;
18
+ /** Hook script was written or replaced this run. */
19
+ scriptUpdated: boolean;
20
+ /** Settings entry was newly added. */
21
+ hookEntryAdded: boolean;
22
+ /** Settings entry existed but its matcher/command shape changed. */
23
+ hookEntryReplaced: boolean;
24
+ /** True when no write touched disk. */
25
+ dryRun: boolean;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC;AAEzC,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;IACvB,sCAAsC;IACtC,cAAc,EAAE,OAAO,CAAC;IACxB,oEAAoE;IACpE,iBAAiB,EAAE,OAAO,CAAC;IAC3B,uCAAuC;IACvC,MAAM,EAAE,OAAO,CAAC;CACjB"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Types for `rift hooks install` writers.
3
+ *
4
+ * Currently only `claude-code` is supported. The shape mirrors
5
+ * `mcp-config-writers/types.ts` so we can extend to other agents later
6
+ * without reshuffling the dispatch surface.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/cli/hooks-writers/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -1,5 +1,5 @@
1
1
  import { type KeychainOps } from "../auth/keychain.js";
2
- export type CliErrorCode = "connection_refused" | "unauthorized" | "not_found" | "conflict" | "rate_limited" | "validation" | "server_error" | "unknown";
2
+ export type CliErrorCode = "connection_refused" | "unauthorized" | "not_found" | "invalid" | "conflict" | "rate_limited" | "validation" | "server_error" | "unknown";
3
3
  export declare class CliError extends Error {
4
4
  readonly code: CliErrorCode;
5
5
  readonly statusCode?: number | undefined;
@@ -31,6 +31,61 @@ export interface HttpClient {
31
31
  }>;
32
32
  }
33
33
  export declare function createHttpClient(opts: HttpClientOpts): HttpClient;
34
+ /**
35
+ * Single source of truth for "where is the config file?" — pure path
36
+ * resolution, no I/O. Per A-2.1 / A-2.2:
37
+ * --config wins over RIFT_CONFIG wins over default
38
+ * Empty / whitespace-only RIFT_CONFIG falls through to the default
39
+ * Relative paths are resolved with path.resolve at call time
40
+ *
41
+ * Callers that need the file to actually exist should use
42
+ * `requireExistingConfigPath` instead, which also classifies missing
43
+ * vs invalid distinctly.
44
+ */
45
+ export declare function resolveConfigPath(globalOpts: {
46
+ config?: string;
47
+ }): string;
48
+ /**
49
+ * For commands that need an existing, valid config (search, save,
50
+ * import, ingest, mcp install, feedback, capture, etc.). Throws a
51
+ * `CliError` with code "not_found" or "invalid", whose messages are
52
+ * distinct per A-2.3a / A-2.3c. Caller should let the exception
53
+ * propagate so the top-level CLI handler renders it.
54
+ */
55
+ export declare function requireExistingConfigPath(globalOpts: {
56
+ config?: string;
57
+ }): string;
58
+ /**
59
+ * No-config, no-auth direct probe of the daemon's /health endpoint.
60
+ * Used by `rift status` only — every other command needs config and
61
+ * auth. Per A-2.3a/A-2.3b: `rift status` MUST NOT hard-fail when the
62
+ * config is absent; it renders "config missing" instead, with the
63
+ * daemon's actual up/down state taken from this probe.
64
+ */
65
+ export declare function probeDefaultDaemonHealth(): Promise<{
66
+ up: boolean;
67
+ uptimeSeconds?: number;
68
+ voyageKeyPresent?: boolean;
69
+ }>;
70
+ /**
71
+ * resolveBaseUrl stays strict — only commands that actually need the
72
+ * daemon URL call it, and they all need a real config. Per A-2.3a:
73
+ * status's no-config branch MUST NOT route through here; it uses
74
+ * `probeDefaultDaemonHealth()` instead.
75
+ */
34
76
  export declare function resolveBaseUrl(configPath: string): string;
77
+ /**
78
+ * Read the current auth token. Checks `~/.rift/token` first, then the
79
+ * macOS Keychain. Returns `null` only when no token has been issued —
80
+ * a real "not yet onboarded" state. A locked Keychain (typical over
81
+ * SSH or in CI without a GUI session) is a recoverable *failure*, not
82
+ * a missing token, so it surfaces as a typed `CliError` with the exact
83
+ * `security unlock-keychain` recovery command.
84
+ *
85
+ * Without this conversion, CLI commands that call `readToken()` would
86
+ * leak the raw `security find-generic-password` failure to the user.
87
+ * Confirmed live on `0.1.0-beta.6` against an SSH'd test user, post-
88
+ * publish, before this fix landed.
89
+ */
35
90
  export declare function readToken(keychain?: KeychainOps): Promise<string | null>;
36
91
  //# sourceMappingURL=http-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../../src/cli/http-client.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEpE,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,cAAc,GACd,WAAW,GACX,UAAU,GACV,cAAc,GACd,YAAY,GACZ,cAAc,GACd,SAAS,CAAC;AAEd,qBAAa,QAAS,SAAQ,KAAK;aAGf,IAAI,EAAE,YAAY;aAClB,UAAU,CAAC,EAAE,MAAM;aACnB,IAAI,CAAC,EAAE,OAAO;gBAH9B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,IAAI,CAAC,EAAE,OAAO,YAAA;CAKjC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9C,aAAa,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC/D;AAkDD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAqGjE;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAsB,SAAS,CAC7B,QAAQ,GAAE,WAAyB,GAClC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxB"}
1
+ {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../../src/cli/http-client.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,cAAc,GACd,WAAW,GACX,SAAS,GACT,UAAU,GACV,cAAc,GACd,YAAY,GACZ,cAAc,GACd,SAAS,CAAC;AAEd,qBAAa,QAAS,SAAQ,KAAK;aAGf,IAAI,EAAE,YAAY;aAClB,UAAU,CAAC,EAAE,MAAM;aACnB,IAAI,CAAC,EAAE,OAAO;gBAH9B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,IAAI,CAAC,EAAE,OAAO,YAAA;CAKjC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9C,aAAa,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EACd,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC/D;AAkDD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAqGjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAezE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAqBT;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC;IACxD,EAAE,EAAE,OAAO,CAAC;IACZ,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC,CAuBD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAqBzD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,GAAE,WAAyB,GAClC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBxB"}