the-campfire 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/bin/cli.ts +182 -0
  2. package/dist/apple-touch-icon.png +0 -0
  3. package/dist/assets/MermaidDiagram-By1J3Whj.js +2 -0
  4. package/dist/assets/_basePickBy-Dq6gnD-p.js +1 -0
  5. package/dist/assets/_baseUniq-SpgN6cGc.js +1 -0
  6. package/dist/assets/arc-D9SEA8dX.js +1 -0
  7. package/dist/assets/architectureDiagram-VXUJARFQ-CoTcwLeR.js +36 -0
  8. package/dist/assets/blockDiagram-VD42YOAC-Dvc63voV.js +122 -0
  9. package/dist/assets/c4Diagram-YG6GDRKO-tuDcG4_4.js +10 -0
  10. package/dist/assets/channel-CxhcHn7S.js +1 -0
  11. package/dist/assets/chunk-4BX2VUAB-x1hChYu9.js +1 -0
  12. package/dist/assets/chunk-55IACEB6-BX6HWnWP.js +1 -0
  13. package/dist/assets/chunk-B4BG7PRW-B4IlF03G.js +165 -0
  14. package/dist/assets/chunk-DI55MBZ5-TpYb5rLg.js +220 -0
  15. package/dist/assets/chunk-FMBD7UC4-DZX4LUPx.js +15 -0
  16. package/dist/assets/chunk-QN33PNHL-CuQs0NDY.js +1 -0
  17. package/dist/assets/chunk-QZHKN3VN-CygWwVx8.js +1 -0
  18. package/dist/assets/chunk-TZMSLE5B-CtI-IdKV.js +1 -0
  19. package/dist/assets/classDiagram-2ON5EDUG-BM0LptJF.js +1 -0
  20. package/dist/assets/classDiagram-v2-WZHVMYZB-BM0LptJF.js +1 -0
  21. package/dist/assets/clone-C6kt1rE7.js +1 -0
  22. package/dist/assets/cose-bilkent-S5V4N54A-PdySs991.js +1 -0
  23. package/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  24. package/dist/assets/dagre-6UL2VRFP-J0SxEiEu.js +4 -0
  25. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  26. package/dist/assets/diagram-PSM6KHXK-CW0HLXaH.js +24 -0
  27. package/dist/assets/diagram-QEK2KX5R-DADHF-k4.js +43 -0
  28. package/dist/assets/diagram-S2PKOQOG-9S0-PC3S.js +24 -0
  29. package/dist/assets/erDiagram-Q2GNP2WA-BEHAiY_q.js +60 -0
  30. package/dist/assets/flowDiagram-NV44I4VS-Cu6n9Xnd.js +162 -0
  31. package/dist/assets/ganttDiagram-JELNMOA3-Cr_BHryu.js +267 -0
  32. package/dist/assets/gitGraphDiagram-V2S2FVAM-D5pT35v5.js +65 -0
  33. package/dist/assets/graph-DKRbrxcs.js +1 -0
  34. package/dist/assets/index-Byjg9zgI.css +32 -0
  35. package/dist/assets/index-Cwj3m0hT.js +284 -0
  36. package/dist/assets/infoDiagram-HS3SLOUP-BaJlrgKV.js +2 -0
  37. package/dist/assets/init-Gi6I4Gst.js +1 -0
  38. package/dist/assets/journeyDiagram-XKPGCS4Q-CXC4-DJv.js +139 -0
  39. package/dist/assets/kanban-definition-3W4ZIXB7-BtHBu9cx.js +89 -0
  40. package/dist/assets/katex-BlHpptmG.js +261 -0
  41. package/dist/assets/layout-DnxSwLDJ.js +1 -0
  42. package/dist/assets/linear-CWbbIT8l.js +1 -0
  43. package/dist/assets/mermaid.core-DXn1cFAK.js +256 -0
  44. package/dist/assets/mindmap-definition-VGOIOE7T-BR8br1hs.js +68 -0
  45. package/dist/assets/ordinal-BENe2yWM.js +1 -0
  46. package/dist/assets/pieDiagram-ADFJNKIX-B7RmXV7I.js +30 -0
  47. package/dist/assets/quadrantDiagram-AYHSOK5B-DK0FhyV_.js +7 -0
  48. package/dist/assets/requirementDiagram-UZGBJVZJ-3zAGxSpL.js +64 -0
  49. package/dist/assets/sankeyDiagram-TZEHDZUN-DZppKtjc.js +10 -0
  50. package/dist/assets/sequenceDiagram-WL72ISMW-D1x3r3wV.js +145 -0
  51. package/dist/assets/stateDiagram-FKZM4ZOC-2ByD08Vq.js +1 -0
  52. package/dist/assets/stateDiagram-v2-4FDKWEC3-Vm1cYjgV.js +1 -0
  53. package/dist/assets/timeline-definition-IT6M3QCI-l5S35biR.js +61 -0
  54. package/dist/assets/treemap-GDKQZRPO-DIPadPiF.js +162 -0
  55. package/dist/assets/xychartDiagram-PRI3JC2R-9GUvwS2b.js +7 -0
  56. package/dist/favicon.svg +3 -0
  57. package/dist/fonts/Geist-Variable.woff2 +0 -0
  58. package/dist/fonts/GeistMono-Variable.woff2 +0 -0
  59. package/dist/icon-192.png +0 -0
  60. package/dist/icon-512.png +0 -0
  61. package/dist/index.html +33 -0
  62. package/dist/logo-codex.svg +14 -0
  63. package/dist/logo.svg +3 -0
  64. package/dist/manifest.json +26 -0
  65. package/dist/og-image.png +0 -0
  66. package/dist/sw.js +130 -0
  67. package/package.json +92 -0
  68. package/server/ADAPTERS.md +121 -0
  69. package/server/adapter-registry-types.ts +28 -0
  70. package/server/adapter-registry.ts +293 -0
  71. package/server/adapter-types.ts +51 -0
  72. package/server/agent-executor.ts +249 -0
  73. package/server/agent-mcp-bridge.ts +148 -0
  74. package/server/agent-mcp-stdio.ts +171 -0
  75. package/server/agent-mcp-tools.ts +76 -0
  76. package/server/agent-store.ts +183 -0
  77. package/server/agent-types.ts +79 -0
  78. package/server/aider-adapter.ts +525 -0
  79. package/server/auth.ts +153 -0
  80. package/server/auto-namer.ts +132 -0
  81. package/server/capability-discovery.ts +431 -0
  82. package/server/claude-container-auth.ts +40 -0
  83. package/server/claude-stdio-adapter.ts +452 -0
  84. package/server/clawhub-export.ts +218 -0
  85. package/server/cli-launcher.ts +1613 -0
  86. package/server/codex-adapter.ts +1987 -0
  87. package/server/codex-container-auth.ts +40 -0
  88. package/server/codex-home.ts +26 -0
  89. package/server/collective-intelligence.ts +401 -0
  90. package/server/commands-discovery.ts +160 -0
  91. package/server/constants.ts +5 -0
  92. package/server/container-manager.ts +328 -0
  93. package/server/cron-scheduler.ts +243 -0
  94. package/server/cron-store.ts +149 -0
  95. package/server/cron-types.ts +63 -0
  96. package/server/deliberation-engine.ts +323 -0
  97. package/server/embedding.ts +89 -0
  98. package/server/env-manager.ts +146 -0
  99. package/server/environment-detector.ts +106 -0
  100. package/server/environment-rules.ts +106 -0
  101. package/server/gallery-store.ts +216 -0
  102. package/server/gallery-types.ts +52 -0
  103. package/server/gallery-votes.ts +101 -0
  104. package/server/git-utils.ts +384 -0
  105. package/server/github-pr.ts +379 -0
  106. package/server/goose-adapter.ts +929 -0
  107. package/server/image-pull-manager.ts +144 -0
  108. package/server/index.ts +363 -0
  109. package/server/linear-project-manager.ts +78 -0
  110. package/server/moltbook-client.ts +160 -0
  111. package/server/openclaw-adapter.ts +916 -0
  112. package/server/openclaw-channel/channel.ts +188 -0
  113. package/server/openclaw-channel/index.ts +68 -0
  114. package/server/openclaw-channel/package.json +19 -0
  115. package/server/openclaw-channel/types.ts +93 -0
  116. package/server/opencode-adapter.ts +951 -0
  117. package/server/openhands-adapter.ts +775 -0
  118. package/server/orchestrator-executor.ts +184 -0
  119. package/server/orchestrator-store.ts +106 -0
  120. package/server/orchestrator-types.ts +86 -0
  121. package/server/path-resolver.ts +168 -0
  122. package/server/pr-poller.ts +162 -0
  123. package/server/proactive-keepalive.ts +121 -0
  124. package/server/prompt-manager.ts +103 -0
  125. package/server/protocol-monitor.ts +197 -0
  126. package/server/race-controller.ts +295 -0
  127. package/server/race-store.ts +82 -0
  128. package/server/recorder.ts +359 -0
  129. package/server/recording-hub/compat-validator.ts +122 -0
  130. package/server/recording-hub/diagnostics.ts +289 -0
  131. package/server/recording-hub/hub-routes.ts +146 -0
  132. package/server/recording-hub/hub-store.ts +224 -0
  133. package/server/replay.ts +78 -0
  134. package/server/routes/adapter-routes.ts +31 -0
  135. package/server/routes/agent-mcp-routes.ts +35 -0
  136. package/server/routes/agent-routes.ts +185 -0
  137. package/server/routes/auth-routes.ts +101 -0
  138. package/server/routes/ci-routes.ts +165 -0
  139. package/server/routes/commands-routes.ts +94 -0
  140. package/server/routes/cron-routes.ts +100 -0
  141. package/server/routes/env-routes.ts +50 -0
  142. package/server/routes/folder-routes.ts +56 -0
  143. package/server/routes/fs-routes.ts +403 -0
  144. package/server/routes/gallery-routes.ts +410 -0
  145. package/server/routes/git-routes.ts +108 -0
  146. package/server/routes/index.ts +62 -0
  147. package/server/routes/linear-routes.ts +254 -0
  148. package/server/routes/monitor-routes.ts +11 -0
  149. package/server/routes/orchestrator-routes.ts +210 -0
  150. package/server/routes/prompt-routes.ts +47 -0
  151. package/server/routes/race-routes.ts +103 -0
  152. package/server/routes/recording-routes.ts +101 -0
  153. package/server/routes/route-deps.ts +32 -0
  154. package/server/routes/session-routes.ts +560 -0
  155. package/server/routes/settings-routes.ts +108 -0
  156. package/server/routes/skills-routes.ts +52 -0
  157. package/server/routes/system-routes.ts +243 -0
  158. package/server/routes/webhook-routes.ts +135 -0
  159. package/server/routes.ts +44 -0
  160. package/server/security-middleware.ts +100 -0
  161. package/server/semantic-memory.ts +389 -0
  162. package/server/service.ts +733 -0
  163. package/server/session-folders.ts +107 -0
  164. package/server/session-git-info.ts +89 -0
  165. package/server/session-linear-issues.ts +94 -0
  166. package/server/session-names.ts +67 -0
  167. package/server/session-store.ts +169 -0
  168. package/server/session-types.ts +415 -0
  169. package/server/settings-manager.ts +120 -0
  170. package/server/shared-context.ts +401 -0
  171. package/server/skills-manager.ts +250 -0
  172. package/server/sub-session-manager.ts +263 -0
  173. package/server/terminal-manager.ts +185 -0
  174. package/server/update-checker.ts +114 -0
  175. package/server/usage-limits.ts +192 -0
  176. package/server/webhook-manager.ts +228 -0
  177. package/server/webhook-store.ts +168 -0
  178. package/server/webhook-types.ts +66 -0
  179. package/server/worktree-tracker.ts +84 -0
  180. package/server/ws-bridge.ts +2322 -0
@@ -0,0 +1,415 @@
1
+ // Types for the WebSocket bridge between Claude Code CLI and the browser
2
+
3
+ // ─── CLI Message Types (NDJSON from Claude Code CLI) ──────────────────────────
4
+
5
+ export interface CLISystemInitMessage {
6
+ type: "system";
7
+ subtype: "init";
8
+ cwd: string;
9
+ session_id: string;
10
+ tools: string[];
11
+ mcp_servers: { name: string; status: string }[];
12
+ model: string;
13
+ permissionMode: string;
14
+ apiKeySource: string;
15
+ claude_code_version: string;
16
+ slash_commands: string[];
17
+ agents?: string[];
18
+ skills?: string[];
19
+ output_style: string;
20
+ uuid: string;
21
+ }
22
+
23
+ export interface CLISystemStatusMessage {
24
+ type: "system";
25
+ subtype: "status";
26
+ status: "compacting" | null;
27
+ permissionMode?: string;
28
+ uuid: string;
29
+ session_id: string;
30
+ }
31
+
32
+ export interface CLIAssistantMessage {
33
+ type: "assistant";
34
+ message: {
35
+ id: string;
36
+ type: "message";
37
+ role: "assistant";
38
+ model: string;
39
+ content: ContentBlock[];
40
+ stop_reason: string | null;
41
+ usage: {
42
+ input_tokens: number;
43
+ output_tokens: number;
44
+ cache_creation_input_tokens: number;
45
+ cache_read_input_tokens: number;
46
+ };
47
+ };
48
+ parent_tool_use_id: string | null;
49
+ error?: string;
50
+ uuid: string;
51
+ session_id: string;
52
+ }
53
+
54
+ export interface CLIResultMessage {
55
+ type: "result";
56
+ subtype: "success" | "error_during_execution" | "error_max_turns" | "error_max_budget_usd" | "error_max_structured_output_retries";
57
+ is_error: boolean;
58
+ result?: string;
59
+ errors?: string[];
60
+ duration_ms: number;
61
+ duration_api_ms: number;
62
+ num_turns: number;
63
+ total_cost_usd: number;
64
+ stop_reason: string | null;
65
+ usage: {
66
+ input_tokens: number;
67
+ output_tokens: number;
68
+ cache_creation_input_tokens: number;
69
+ cache_read_input_tokens: number;
70
+ };
71
+ modelUsage?: Record<string, {
72
+ inputTokens: number;
73
+ outputTokens: number;
74
+ cacheReadInputTokens: number;
75
+ cacheCreationInputTokens: number;
76
+ contextWindow: number;
77
+ maxOutputTokens: number;
78
+ costUSD: number;
79
+ }>;
80
+ total_lines_added?: number;
81
+ total_lines_removed?: number;
82
+ uuid: string;
83
+ session_id: string;
84
+ }
85
+
86
+ export interface CLIStreamEventMessage {
87
+ type: "stream_event";
88
+ event: unknown;
89
+ parent_tool_use_id: string | null;
90
+ uuid: string;
91
+ session_id: string;
92
+ }
93
+
94
+ export interface CLIToolProgressMessage {
95
+ type: "tool_progress";
96
+ tool_use_id: string;
97
+ tool_name: string;
98
+ parent_tool_use_id: string | null;
99
+ elapsed_time_seconds: number;
100
+ uuid: string;
101
+ session_id: string;
102
+ }
103
+
104
+ export interface CLIToolUseSummaryMessage {
105
+ type: "tool_use_summary";
106
+ summary: string;
107
+ preceding_tool_use_ids: string[];
108
+ uuid: string;
109
+ session_id: string;
110
+ }
111
+
112
+ export interface CLIControlRequestMessage {
113
+ type: "control_request";
114
+ request_id: string;
115
+ request: {
116
+ subtype: "can_use_tool";
117
+ tool_name: string;
118
+ input: Record<string, unknown>;
119
+ permission_suggestions?: PermissionUpdate[];
120
+ description?: string;
121
+ tool_use_id: string;
122
+ agent_id?: string;
123
+ };
124
+ }
125
+
126
+ export interface CLIKeepAliveMessage {
127
+ type: "keep_alive";
128
+ }
129
+
130
+ export interface CLIAuthStatusMessage {
131
+ type: "auth_status";
132
+ isAuthenticating: boolean;
133
+ output: string[];
134
+ error?: string;
135
+ uuid: string;
136
+ session_id: string;
137
+ }
138
+
139
+ export interface CLIControlResponseMessage {
140
+ type: "control_response";
141
+ response: {
142
+ subtype: "success" | "error";
143
+ request_id: string;
144
+ response?: Record<string, unknown>;
145
+ error?: string;
146
+ };
147
+ }
148
+
149
+ export type CLIMessage =
150
+ | CLISystemInitMessage
151
+ | CLISystemStatusMessage
152
+ | CLIAssistantMessage
153
+ | CLIResultMessage
154
+ | CLIStreamEventMessage
155
+ | CLIToolProgressMessage
156
+ | CLIToolUseSummaryMessage
157
+ | CLIControlRequestMessage
158
+ | CLIControlResponseMessage
159
+ | CLIKeepAliveMessage
160
+ | CLIAuthStatusMessage;
161
+
162
+ // ─── Content Block Types ──────────────────────────────────────────────────────
163
+
164
+ export type ContentBlock =
165
+ | { type: "text"; text: string }
166
+ | { type: "tool_use"; id: string; name: string; input: Record<string, unknown> }
167
+ | { type: "tool_result"; tool_use_id: string; content: string | ContentBlock[]; is_error?: boolean }
168
+ | { type: "thinking"; thinking: string; budget_tokens?: number };
169
+
170
+ // ─── Browser Message Types (browser <-> bridge) ──────────────────────────────
171
+
172
+ /** Messages the browser sends to the bridge */
173
+ export type BrowserOutgoingMessage =
174
+ | { type: "user_message"; content: string; session_id?: string; images?: { media_type: string; data: string }[]; client_msg_id?: string }
175
+ | { type: "permission_response"; request_id: string; behavior: "allow" | "deny"; updated_input?: Record<string, unknown>; updated_permissions?: PermissionUpdate[]; message?: string; client_msg_id?: string }
176
+ | { type: "session_subscribe"; last_seq: number }
177
+ | { type: "session_ack"; last_seq: number }
178
+ | { type: "interrupt"; client_msg_id?: string }
179
+ | { type: "set_model"; model: string; client_msg_id?: string }
180
+ | { type: "set_permission_mode"; mode: string; client_msg_id?: string }
181
+ | { type: "mcp_get_status"; client_msg_id?: string }
182
+ | { type: "mcp_toggle"; serverName: string; enabled: boolean; client_msg_id?: string }
183
+ | { type: "mcp_reconnect"; serverName: string; client_msg_id?: string }
184
+ | { type: "mcp_set_servers"; servers: Record<string, McpServerConfig>; client_msg_id?: string }
185
+ // ── Collective Intelligence: Browser → Server ───────────────────────────────
186
+ | { type: "memory_query"; query: string; limit?: number }
187
+ | { type: "memory_store"; content: string; memoryType: string; tags: string[]; gitContext?: Record<string, unknown> }
188
+ | { type: "deliberation_respond"; proposalId: string; stance: string; reasoning: string; suggestedAlternative?: string; concerns?: string[] }
189
+ | { type: "deliberation_resolve"; proposalId: string }
190
+ | { type: "capability_probe_response"; probeId: string; confidence: number; reasoning: string }
191
+ | { type: "route_task"; taskDescription: string; availableSessions?: string[] }
192
+ | { type: "inject_thought"; content: string; thoughtType: string; parentId?: string };
193
+
194
+ /** Messages the bridge sends to the browser */
195
+ export type BrowserIncomingMessageBase =
196
+ | { type: "session_init"; session: SessionState }
197
+ | { type: "session_update"; session: Partial<SessionState> }
198
+ | { type: "assistant"; message: CLIAssistantMessage["message"]; parent_tool_use_id: string | null; timestamp?: number }
199
+ | { type: "stream_event"; event: unknown; parent_tool_use_id: string | null }
200
+ | { type: "result"; data: CLIResultMessage }
201
+ | { type: "permission_request"; request: PermissionRequest }
202
+ | { type: "permission_cancelled"; request_id: string }
203
+ | { type: "tool_progress"; tool_use_id: string; tool_name: string; elapsed_time_seconds: number }
204
+ | { type: "tool_use_summary"; summary: string; tool_use_ids: string[] }
205
+ | { type: "status_change"; status: "compacting" | "idle" | "running" | null }
206
+ | { type: "auth_status"; isAuthenticating: boolean; output: string[]; error?: string }
207
+ | { type: "error"; message: string }
208
+ | { type: "cli_disconnected" }
209
+ | { type: "cli_connected" }
210
+ | { type: "cli_launching" }
211
+ | { type: "user_message"; content: string; timestamp: number; id?: string }
212
+ | { type: "message_history"; messages: BrowserIncomingMessage[] }
213
+ | { type: "event_replay"; events: BufferedBrowserEvent[] }
214
+ | { type: "session_name_update"; name: string }
215
+ | { type: "pr_status_update"; pr: import("./github-pr.js").GitHubPRInfo | null; available: boolean }
216
+ | { type: "mcp_status"; servers: McpServerDetail[] }
217
+ | { type: "presence_update"; viewers: PresenceViewer[] }
218
+ | { type: "role_assigned"; role: SessionRole; viewerId: string }
219
+ | { type: "vote_update"; request_id: string; votes: PermissionVote[]; voters_total: number; deadline: number }
220
+ | { type: "vote_resolved"; request_id: string; result: "allow" | "deny"; policy: VotingPolicy }
221
+ // ── Collective Intelligence: Server → Browser ───────────────────────────────
222
+ // Layer 1: Semantic Memory
223
+ | { type: "memory_stored"; fragment: import("./semantic-memory.js").MemoryFragment }
224
+ | { type: "memory_query_result"; query: string; results: import("./semantic-memory.js").MemoryFragment[] }
225
+ | { type: "memory_consolidated"; tag: string; knowledge: import("./semantic-memory.js").ConsolidatedKnowledge }
226
+ // Layer 2: Deliberation
227
+ | { type: "deliberation_proposal"; proposal: import("./deliberation-engine.js").DeliberationProposal }
228
+ | { type: "deliberation_response"; response: import("./deliberation-engine.js").DeliberationResponse }
229
+ | { type: "deliberation_resolved"; resolution: import("./deliberation-engine.js").DeliberationResolution }
230
+ // Layer 3: Capabilities & Routing
231
+ | { type: "capability_probe"; probeId: string; taskDescription: string; instruction: string }
232
+ | { type: "route_result"; result: import("./capability-discovery.js").RouteTaskResult }
233
+ | { type: "agent_capabilities"; capabilities: import("./capability-discovery.js").AgentCapabilities }
234
+ | { type: "sub_agent_update"; agent: SubAgentUpdate }
235
+ // Layer 4: Shared Context
236
+ | { type: "shared_thought"; fragment: import("./shared-context.js").ContextFragment }
237
+ | { type: "semantic_link_added"; sourceId: string; targetId: string; relation: string }
238
+ | { type: "consensus_update"; state: import("./shared-context.js").ConsensusState };
239
+
240
+ export type BrowserIncomingMessage = BrowserIncomingMessageBase & { seq?: number };
241
+
242
+ export type ReplayableBrowserIncomingMessage = Exclude<BrowserIncomingMessageBase, { type: "event_replay" }>;
243
+
244
+ export interface BufferedBrowserEvent {
245
+ seq: number;
246
+ message: ReplayableBrowserIncomingMessage;
247
+ }
248
+
249
+ // ─── Session State ────────────────────────────────────────────────────────────
250
+
251
+ export type BackendType = "claude" | "codex" | "goose" | "aider" | "openhands" | "openclaw" | "opencode";
252
+
253
+ export interface SessionState {
254
+ session_id: string;
255
+ backend_type?: BackendType;
256
+ parent_session_id?: string;
257
+ orchestration_role?: "lead" | "subagent" | "race_entry";
258
+ model: string;
259
+ cwd: string;
260
+ tools: string[];
261
+ permissionMode: string;
262
+ claude_code_version: string;
263
+ mcp_servers: { name: string; status: string }[];
264
+ agents: string[];
265
+ slash_commands: string[];
266
+ skills: string[];
267
+ total_cost_usd: number;
268
+ num_turns: number;
269
+ context_used_percent: number;
270
+ is_compacting: boolean;
271
+ git_branch: string;
272
+ is_worktree: boolean;
273
+ repo_root: string;
274
+ /** HEAD commit SHA when the session was created — used as diff base. */
275
+ git_start_commit?: string;
276
+ git_ahead: number;
277
+ git_behind: number;
278
+ total_lines_added: number;
279
+ total_lines_removed: number;
280
+ /** Cumulative API duration across all turns (from result.duration_api_ms). */
281
+ total_duration_api_ms: number;
282
+ /** Cost accumulated by child sessions spawned from this session. */
283
+ sub_agent_cost_usd?: number;
284
+ /** Environment detections and MCP recommendations computed for this session cwd. */
285
+ detected_environment?: DetectedEnvironment;
286
+ // Codex-specific token details (forwarded from thread/tokenUsage/updated)
287
+ codex_token_details?: {
288
+ inputTokens: number;
289
+ outputTokens: number;
290
+ cachedInputTokens: number;
291
+ reasoningOutputTokens: number;
292
+ modelContextWindow: number;
293
+ };
294
+ // Claude-specific token details (extracted from result.modelUsage at turn end)
295
+ claude_token_details?: {
296
+ inputTokens: number;
297
+ outputTokens: number;
298
+ cacheReadInputTokens: number;
299
+ cacheCreationInputTokens: number;
300
+ contextWindow: number;
301
+ costUsd: number;
302
+ };
303
+ // Codex-specific rate limits (forwarded from account/rateLimits/updated)
304
+ codex_rate_limits?: {
305
+ primary: { usedPercent: number; windowDurationMins: number; resetsAt: number } | null;
306
+ secondary: { usedPercent: number; windowDurationMins: number; resetsAt: number } | null;
307
+ };
308
+ /** If this session was spawned by a cron job */
309
+ cronJobId?: string;
310
+ /** Human-readable name of the cron job that spawned this session */
311
+ cronJobName?: string;
312
+ }
313
+
314
+ export interface DetectedEnvironmentRule {
315
+ id: string;
316
+ name: string;
317
+ description: string;
318
+ envRequired?: string[];
319
+ envPresent?: string[];
320
+ envMissing?: string[];
321
+ }
322
+
323
+ export interface DetectedEnvironment {
324
+ cwd: string;
325
+ scannedAt: number;
326
+ rules: DetectedEnvironmentRule[];
327
+ mcpServers: Record<string, McpServerConfig>;
328
+ }
329
+
330
+ export interface SubAgentUpdate {
331
+ parentSessionId: string;
332
+ toolUseId: string;
333
+ sessionId?: string;
334
+ backendType: BackendType;
335
+ name: string;
336
+ description: string;
337
+ status: "running" | "completed" | "failed" | "timeout";
338
+ startedAt: number;
339
+ completedAt?: number;
340
+ costUsd?: number;
341
+ durationMs?: number;
342
+ filesChanged?: string[];
343
+ summary?: string;
344
+ error?: string;
345
+ }
346
+
347
+ // ─── MCP Types ───────────────────────────────────────────────────────────────
348
+
349
+ export interface McpServerConfig {
350
+ type: "stdio" | "sse" | "http" | "sdk";
351
+ command?: string;
352
+ args?: string[];
353
+ env?: Record<string, string>;
354
+ url?: string;
355
+ }
356
+
357
+ export interface McpServerDetail {
358
+ name: string;
359
+ status: "connected" | "failed" | "disabled" | "connecting";
360
+ serverInfo?: unknown;
361
+ error?: string;
362
+ config: { type: string; url?: string; command?: string; args?: string[] };
363
+ scope: string;
364
+ tools?: { name: string; annotations?: { readOnly?: boolean; destructive?: boolean; openWorld?: boolean } }[];
365
+ }
366
+
367
+ // ─── Session Roles (RBAC) ────────────────────────────────────────────────
368
+
369
+ /** Roles for shared session access control */
370
+ export type SessionRole = "owner" | "collaborator" | "spectator";
371
+
372
+ /** Viewer info for presence tracking */
373
+ export interface PresenceViewer {
374
+ id: string;
375
+ name: string;
376
+ role: SessionRole;
377
+ }
378
+
379
+ // ─── Voting Types ────────────────────────────────────────────────────────
380
+
381
+ /** Policy for how votes from collaborators are aggregated */
382
+ export type VotingPolicy = "majority-rules" | "any-deny-blocks" | "owner-decides";
383
+
384
+ /** Individual vote cast by a collaborator */
385
+ export interface PermissionVote {
386
+ viewerId: string;
387
+ viewerName: string;
388
+ vote: "allow" | "deny";
389
+ timestamp: number;
390
+ }
391
+
392
+ // ─── Permission Request ──────────────────────────────────────────────────────
393
+
394
+ // ─── Permission Rule Types ───────────────────────────────────────────────────
395
+
396
+ export type PermissionDestination = "userSettings" | "projectSettings" | "localSettings" | "session" | "cliArg";
397
+
398
+ export type PermissionUpdate =
399
+ | { type: "addRules"; rules: { toolName: string; ruleContent?: string }[]; behavior: "allow" | "deny" | "ask"; destination: PermissionDestination }
400
+ | { type: "replaceRules"; rules: { toolName: string; ruleContent?: string }[]; behavior: "allow" | "deny" | "ask"; destination: PermissionDestination }
401
+ | { type: "removeRules"; rules: { toolName: string; ruleContent?: string }[]; behavior: "allow" | "deny" | "ask"; destination: PermissionDestination }
402
+ | { type: "setMode"; mode: string; destination: PermissionDestination }
403
+ | { type: "addDirectories"; directories: string[]; destination: PermissionDestination }
404
+ | { type: "removeDirectories"; directories: string[]; destination: PermissionDestination };
405
+
406
+ export interface PermissionRequest {
407
+ request_id: string;
408
+ tool_name: string;
409
+ input: Record<string, unknown>;
410
+ permission_suggestions?: PermissionUpdate[];
411
+ description?: string;
412
+ tool_use_id: string;
413
+ agent_id?: string;
414
+ timestamp: number;
415
+ }
@@ -0,0 +1,120 @@
1
+ import {
2
+ mkdirSync,
3
+ readFileSync,
4
+ writeFileSync,
5
+ existsSync,
6
+ } from "node:fs";
7
+ import { join, dirname } from "node:path";
8
+ import { homedir } from "node:os";
9
+
10
+ export const DEFAULT_OPENROUTER_MODEL = "openrouter/free";
11
+
12
+ export type EmbeddingProvider = "openai" | "ollama" | "none";
13
+
14
+ export interface CampfireSettings {
15
+ openrouterApiKey: string;
16
+ openrouterModel: string;
17
+ moltbookApiKey: string;
18
+ linearApiKey: string;
19
+ // Provider tokens — auto-injected into sessions for matching backends
20
+ /** Claude Code OAuth token (injected as CLAUDE_CODE_OAUTH_TOKEN for Claude sessions) */
21
+ claudeOAuthToken: string;
22
+ /** OpenAI API key (injected as OPENAI_API_KEY for Codex sessions) */
23
+ openaiApiKey: string;
24
+ /** Anthropic API key (injected as ANTHROPIC_API_KEY — used by Claude, Goose, Aider, etc.) */
25
+ anthropicApiKey: string;
26
+ // Collective Intelligence: embedding provider for semantic memory
27
+ embeddingProvider: EmbeddingProvider;
28
+ embeddingApiKey: string; // OpenAI API key (if provider = "openai")
29
+ embeddingModel: string; // e.g. "text-embedding-3-small" or "nomic-embed-text"
30
+ embeddingBaseUrl: string; // Ollama base URL (if provider = "ollama"), default http://localhost:11434
31
+ /** Whether the onboarding wizard has been completed or skipped */
32
+ onboardingCompleted: boolean;
33
+ updatedAt: number;
34
+ }
35
+
36
+ const DEFAULT_PATH = join(homedir(), ".campfire", "settings.json");
37
+
38
+ let loaded = false;
39
+ let filePath = DEFAULT_PATH;
40
+ let settings: CampfireSettings = {
41
+ openrouterApiKey: "",
42
+ openrouterModel: DEFAULT_OPENROUTER_MODEL,
43
+ moltbookApiKey: "",
44
+ linearApiKey: "",
45
+ claudeOAuthToken: "",
46
+ openaiApiKey: "",
47
+ anthropicApiKey: "",
48
+ embeddingProvider: "none",
49
+ embeddingApiKey: "",
50
+ embeddingModel: "",
51
+ embeddingBaseUrl: "http://localhost:11434",
52
+ onboardingCompleted: false,
53
+ updatedAt: 0,
54
+ };
55
+
56
+ function normalize(raw: Partial<CampfireSettings> | null | undefined): CampfireSettings {
57
+ return {
58
+ openrouterApiKey: typeof raw?.openrouterApiKey === "string" ? raw.openrouterApiKey : "",
59
+ openrouterModel:
60
+ typeof raw?.openrouterModel === "string" && raw.openrouterModel.trim()
61
+ ? raw.openrouterModel
62
+ : DEFAULT_OPENROUTER_MODEL,
63
+ moltbookApiKey: typeof raw?.moltbookApiKey === "string" ? raw.moltbookApiKey : "",
64
+ linearApiKey: typeof raw?.linearApiKey === "string" ? raw.linearApiKey : "",
65
+ claudeOAuthToken: typeof raw?.claudeOAuthToken === "string" ? raw.claudeOAuthToken : "",
66
+ openaiApiKey: typeof raw?.openaiApiKey === "string" ? raw.openaiApiKey : "",
67
+ anthropicApiKey: typeof raw?.anthropicApiKey === "string" ? raw.anthropicApiKey : "",
68
+ embeddingProvider: (raw?.embeddingProvider === "openai" || raw?.embeddingProvider === "ollama") ? raw.embeddingProvider : "none",
69
+ embeddingApiKey: typeof raw?.embeddingApiKey === "string" ? raw.embeddingApiKey : "",
70
+ embeddingModel: typeof raw?.embeddingModel === "string" ? raw.embeddingModel : "",
71
+ embeddingBaseUrl: typeof raw?.embeddingBaseUrl === "string" && raw.embeddingBaseUrl.trim()
72
+ ? raw.embeddingBaseUrl
73
+ : "http://localhost:11434",
74
+ onboardingCompleted: raw?.onboardingCompleted === true,
75
+ updatedAt: typeof raw?.updatedAt === "number" ? raw.updatedAt : 0,
76
+ };
77
+ }
78
+
79
+ function ensureLoaded(): void {
80
+ if (loaded) return;
81
+ try {
82
+ if (existsSync(filePath)) {
83
+ const raw = readFileSync(filePath, "utf-8");
84
+ settings = normalize(JSON.parse(raw) as Partial<CampfireSettings>);
85
+ }
86
+ } catch {
87
+ settings = normalize(null);
88
+ }
89
+ loaded = true;
90
+ }
91
+
92
+ function persist(): void {
93
+ mkdirSync(dirname(filePath), { recursive: true });
94
+ writeFileSync(filePath, JSON.stringify(settings, null, 2), "utf-8");
95
+ }
96
+
97
+ export function getSettings(): CampfireSettings {
98
+ ensureLoaded();
99
+ return { ...settings };
100
+ }
101
+
102
+ export function updateSettings(
103
+ patch: Partial<Pick<CampfireSettings, "openrouterApiKey" | "openrouterModel" | "moltbookApiKey" | "linearApiKey" | "claudeOAuthToken" | "openaiApiKey" | "anthropicApiKey" | "embeddingProvider" | "embeddingApiKey" | "embeddingModel" | "embeddingBaseUrl" | "onboardingCompleted">>,
104
+ ): CampfireSettings {
105
+ ensureLoaded();
106
+ settings = {
107
+ ...settings,
108
+ ...patch,
109
+ openrouterModel: patch.openrouterModel?.trim() || settings.openrouterModel || DEFAULT_OPENROUTER_MODEL,
110
+ updatedAt: Date.now(),
111
+ };
112
+ persist();
113
+ return { ...settings };
114
+ }
115
+
116
+ export function _resetForTest(customPath?: string): void {
117
+ loaded = false;
118
+ filePath = customPath || DEFAULT_PATH;
119
+ settings = normalize(null);
120
+ }