@code-insights/cli 1.0.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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +287 -0
  3. package/dist/commands/connect.d.ts +8 -0
  4. package/dist/commands/connect.d.ts.map +1 -0
  5. package/dist/commands/connect.js +33 -0
  6. package/dist/commands/connect.js.map +1 -0
  7. package/dist/commands/init.d.ts +9 -0
  8. package/dist/commands/init.d.ts.map +1 -0
  9. package/dist/commands/init.js +176 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/insights.d.ts +13 -0
  12. package/dist/commands/insights.d.ts.map +1 -0
  13. package/dist/commands/insights.js +87 -0
  14. package/dist/commands/insights.js.map +1 -0
  15. package/dist/commands/install-hook.d.ts +9 -0
  16. package/dist/commands/install-hook.d.ts.map +1 -0
  17. package/dist/commands/install-hook.js +98 -0
  18. package/dist/commands/install-hook.js.map +1 -0
  19. package/dist/commands/link.d.ts +8 -0
  20. package/dist/commands/link.d.ts.map +1 -0
  21. package/dist/commands/link.js +39 -0
  22. package/dist/commands/link.js.map +1 -0
  23. package/dist/commands/reset.d.ts +3 -0
  24. package/dist/commands/reset.d.ts.map +1 -0
  25. package/dist/commands/reset.js +95 -0
  26. package/dist/commands/reset.js.map +1 -0
  27. package/dist/commands/status.d.ts +5 -0
  28. package/dist/commands/status.d.ts.map +1 -0
  29. package/dist/commands/status.js +107 -0
  30. package/dist/commands/status.js.map +1 -0
  31. package/dist/commands/sync.d.ts +13 -0
  32. package/dist/commands/sync.d.ts.map +1 -0
  33. package/dist/commands/sync.js +205 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/firebase/client.d.ts +35 -0
  36. package/dist/firebase/client.d.ts.map +1 -0
  37. package/dist/firebase/client.js +317 -0
  38. package/dist/firebase/client.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +48 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/parser/insights.d.ts +7 -0
  44. package/dist/parser/insights.d.ts.map +1 -0
  45. package/dist/parser/insights.js +271 -0
  46. package/dist/parser/insights.js.map +1 -0
  47. package/dist/parser/jsonl.d.ts +6 -0
  48. package/dist/parser/jsonl.d.ts.map +1 -0
  49. package/dist/parser/jsonl.js +305 -0
  50. package/dist/parser/jsonl.js.map +1 -0
  51. package/dist/parser/titles.d.ts +14 -0
  52. package/dist/parser/titles.d.ts.map +1 -0
  53. package/dist/parser/titles.js +258 -0
  54. package/dist/parser/titles.js.map +1 -0
  55. package/dist/types.d.ts +216 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +3 -0
  58. package/dist/types.js.map +1 -0
  59. package/dist/utils/config.d.ts +46 -0
  60. package/dist/utils/config.d.ts.map +1 -0
  61. package/dist/utils/config.js +106 -0
  62. package/dist/utils/config.js.map +1 -0
  63. package/dist/utils/device.d.ts +32 -0
  64. package/dist/utils/device.d.ts.map +1 -0
  65. package/dist/utils/device.js +132 -0
  66. package/dist/utils/device.js.map +1 -0
  67. package/dist/utils/firebase-json.d.ts +87 -0
  68. package/dist/utils/firebase-json.d.ts.map +1 -0
  69. package/dist/utils/firebase-json.js +206 -0
  70. package/dist/utils/firebase-json.js.map +1 -0
  71. package/dist/utils/pricing.d.ts +29 -0
  72. package/dist/utils/pricing.d.ts.map +1 -0
  73. package/dist/utils/pricing.js +66 -0
  74. package/dist/utils/pricing.js.map +1 -0
  75. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Srikanth Rao M
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,287 @@
1
+ # Code Insights CLI
2
+
3
+ Command-line tool that parses Claude Code session history and syncs it to your own Firebase Firestore.
4
+
5
+ Full documentation: [docs.code-insights.app](https://docs.code-insights.app)
6
+
7
+ ## Prerequisites
8
+
9
+ - **Node.js** 18 or later
10
+ - **pnpm** >= 9 (`npm install -g pnpm` if needed)
11
+ - A **Firebase project** with Firestore enabled (see [Quick Start](../README.md#quick-start))
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # From the repo root
17
+ cd cli
18
+ pnpm install
19
+ pnpm build
20
+ npm link # Makes `code-insights` available globally
21
+ ```
22
+
23
+ After linking, verify it works:
24
+
25
+ ```bash
26
+ code-insights --version
27
+ ```
28
+
29
+ ## Commands
30
+
31
+ ### `code-insights init`
32
+
33
+ Configure Code Insights with your Firebase credentials.
34
+
35
+ ```bash
36
+ # Quick setup — import directly from JSON files (recommended)
37
+ code-insights init \
38
+ --from-json ~/Downloads/serviceAccountKey.json \
39
+ --web-config ~/Downloads/firebase-web-config.json
40
+
41
+ # Interactive setup — prompts for each value
42
+ code-insights init
43
+ ```
44
+
45
+ **Flags:**
46
+ - `--from-json <path>` — Path to the Firebase service account JSON (downloaded from Firebase Console > Project Settings > Service Accounts)
47
+ - `--web-config <path>` — Path to the Firebase web SDK config JSON (saved from Firebase Console > Project Settings > General > Your Apps)
48
+
49
+ You can use one flag, both, or neither. Any values not provided via flags will be collected interactively.
50
+
51
+ Configuration is stored in `~/.code-insights/config.json`. Web config is stored separately in `~/.code-insights/web-config.json`.
52
+
53
+ ### `code-insights connect`
54
+
55
+ Generate a URL to connect the web dashboard to your Firebase.
56
+
57
+ ```bash
58
+ code-insights connect
59
+ ```
60
+
61
+ **Flags:**
62
+ - `--no-qr` — Skip QR code output (prints URL only)
63
+
64
+ The URL includes your Firebase web config base64-encoded as a query parameter. Open it in a browser to connect the dashboard to your Firestore — no manual configuration needed.
65
+
66
+ ### `code-insights sync`
67
+
68
+ Sync Claude Code sessions to Firestore.
69
+
70
+ ```bash
71
+ # Sync new/modified sessions
72
+ code-insights sync
73
+
74
+ # Force re-sync all sessions
75
+ code-insights sync --force
76
+
77
+ # Preview what would be synced
78
+ code-insights sync --dry-run
79
+
80
+ # Sync specific project only
81
+ code-insights sync --project "my-project"
82
+
83
+ # Quiet mode (for hooks)
84
+ code-insights sync --quiet
85
+
86
+ # Regenerate titles for all sessions
87
+ code-insights sync --regenerate-titles
88
+ ```
89
+
90
+ ### `code-insights status`
91
+
92
+ Show sync status and statistics.
93
+
94
+ ```bash
95
+ code-insights status
96
+ ```
97
+
98
+ Displays:
99
+ - Configuration status
100
+ - Total sessions synced
101
+ - Projects tracked
102
+ - Last sync time
103
+
104
+ ### `code-insights reset`
105
+
106
+ Delete all data from Firestore and reset local sync state.
107
+
108
+ ```bash
109
+ # Interactive (asks for confirmation)
110
+ code-insights reset
111
+
112
+ # Skip confirmation
113
+ code-insights reset --confirm
114
+ ```
115
+
116
+ ### `code-insights install-hook`
117
+
118
+ Install a Claude Code hook for automatic sync after each session.
119
+
120
+ ```bash
121
+ code-insights install-hook
122
+ ```
123
+
124
+ ### `code-insights uninstall-hook`
125
+
126
+ Remove the automatic sync hook.
127
+
128
+ ```bash
129
+ code-insights uninstall-hook
130
+ ```
131
+
132
+ ## How It Works
133
+
134
+ ### Session Parsing
135
+
136
+ The CLI reads JSONL files from `~/.claude/projects/` which contain:
137
+ - User and assistant messages
138
+ - Tool calls (Edit, Write, Bash, etc.)
139
+ - Timestamps and metadata
140
+
141
+ Each session is parsed to extract:
142
+ - Project name and path
143
+ - Start/end times and duration
144
+ - Message counts
145
+ - Tool call statistics
146
+ - Git branch (if available)
147
+ - Claude version
148
+ - Token usage, estimated costs, and model information (when available)
149
+
150
+ ### Incremental Sync
151
+
152
+ Sync state is tracked in `~/.code-insights/sync-state.json`:
153
+ - File modification times are recorded
154
+ - Only new or modified files are processed
155
+ - Use `--force` to bypass and re-sync everything
156
+
157
+ ### Multi-Device Support
158
+
159
+ Project IDs are generated from git remote URLs when available:
160
+ - Same repo on different machines → same project ID
161
+ - Non-git projects fall back to path-based hash
162
+ - Each session records device metadata (hostname, platform)
163
+
164
+ ### Title Generation
165
+
166
+ Sessions are automatically titled based on:
167
+ 1. Claude's own title (if present in session)
168
+ 2. First user message (cleaned up)
169
+ 3. Session character detection (deep focus, bug hunt, etc.)
170
+ 4. Fallback to timestamp
171
+
172
+ ## Project Structure
173
+
174
+ ```
175
+ cli/
176
+ ā”œā”€ā”€ src/
177
+ │ ā”œā”€ā”€ commands/
178
+ │ │ ā”œā”€ā”€ init.ts # Interactive Firebase configuration
179
+ │ │ ā”œā”€ā”€ sync.ts # Main sync logic
180
+ │ │ ā”œā”€ā”€ connect.ts # Generate dashboard connection URL
181
+ │ │ ā”œā”€ā”€ status.ts # Status display
182
+ │ │ ā”œā”€ā”€ reset.ts # Clear all data
183
+ │ │ └── install-hook.ts # Hook management
184
+ │ ā”œā”€ā”€ firebase/
185
+ │ │ └── client.ts # Firestore operations
186
+ │ ā”œā”€ā”€ parser/
187
+ │ │ ā”œā”€ā”€ jsonl.ts # JSONL file parsing
188
+ │ │ └── titles.ts # Title generation
189
+ │ ā”œā”€ā”€ utils/
190
+ │ │ ā”œā”€ā”€ config.ts # Config management
191
+ │ │ ā”œā”€ā”€ device.ts # Device identification
192
+ │ │ └── firebase-json.ts # Firebase JSON validation & URL generation
193
+ │ ā”œā”€ā”€ types.ts # TypeScript types
194
+ │ └── index.ts # CLI entry point
195
+ ā”œā”€ā”€ dist/ # Compiled output
196
+ ā”œā”€ā”€ package.json
197
+ └── tsconfig.json
198
+ ```
199
+
200
+ ## Development
201
+
202
+ ```bash
203
+ pnpm dev # Watch mode — recompiles on save
204
+ pnpm build # One-time compile
205
+ pnpm lint # Run ESLint
206
+ ```
207
+
208
+ The CLI is written in TypeScript with ES Modules and compiled to `dist/`. After `npm link`, changes rebuild automatically in watch mode.
209
+
210
+ See [CONTRIBUTING.md](../CONTRIBUTING.md) for the full development workflow, code style, and PR guidelines.
211
+
212
+ ## Firestore Collections
213
+
214
+ The CLI writes to these collections:
215
+
216
+ ### `projects`
217
+ ```typescript
218
+ {
219
+ id: string; // Hash of git remote URL or path
220
+ name: string; // Project directory name
221
+ path: string; // Full path on syncing device
222
+ gitRemoteUrl: string | null;
223
+ projectIdSource: 'git-remote' | 'path-hash';
224
+ sessionCount: number;
225
+ lastActivity: Timestamp;
226
+ }
227
+ ```
228
+
229
+ ### `sessions`
230
+ ```typescript
231
+ {
232
+ id: string; // From JSONL filename
233
+ projectId: string;
234
+ projectName: string;
235
+ projectPath: string;
236
+ gitRemoteUrl: string | null;
237
+ summary: string | null;
238
+ generatedTitle: string | null;
239
+ titleSource: 'claude' | 'user_message' | 'insight' | 'character' | 'fallback' | null;
240
+ sessionCharacter: 'deep_focus' | 'bug_hunt' | 'feature_build' | 'exploration' | 'refactor' | 'learning' | 'quick_task' | null;
241
+ startedAt: Timestamp;
242
+ endedAt: Timestamp;
243
+ messageCount: number;
244
+ userMessageCount: number;
245
+ assistantMessageCount: number;
246
+ toolCallCount: number;
247
+ gitBranch: string | null;
248
+ claudeVersion: string | null;
249
+ deviceId: string;
250
+ deviceHostname: string;
251
+ devicePlatform: string;
252
+ syncedAt: Timestamp; // Server timestamp
253
+ // Usage stats (present when token data is available)
254
+ totalInputTokens?: number;
255
+ totalOutputTokens?: number;
256
+ cacheCreationTokens?: number;
257
+ cacheReadTokens?: number;
258
+ estimatedCostUsd?: number;
259
+ modelsUsed?: string[];
260
+ primaryModel?: string;
261
+ usageSource?: 'jsonl';
262
+ }
263
+ ```
264
+
265
+ ### `messages`
266
+ ```typescript
267
+ {
268
+ id: string;
269
+ sessionId: string;
270
+ type: 'user' | 'assistant' | 'system';
271
+ content: string; // Max 10,000 chars (truncated)
272
+ thinking: string | null; // Extracted thinking content (max 5,000 chars)
273
+ toolCalls: Array<{ id: string; name: string; input: string }>; // Input max 1,000 chars
274
+ toolResults: Array<{ toolUseId: string; output: string }>; // Output max 2,000 chars
275
+ timestamp: Timestamp;
276
+ parentId: string | null;
277
+ // Per-message usage (assistant messages only)
278
+ usage?: {
279
+ inputTokens: number;
280
+ outputTokens: number;
281
+ cacheCreationTokens: number;
282
+ cacheReadTokens: number;
283
+ model: string;
284
+ estimatedCostUsd: number;
285
+ };
286
+ }
287
+ ```
@@ -0,0 +1,8 @@
1
+ export interface ConnectOptions {
2
+ qr?: boolean;
3
+ }
4
+ /**
5
+ * Generate and display the dashboard connection URL
6
+ */
7
+ export declare function connectCommand(options: ConnectOptions): Promise<void>;
8
+ //# sourceMappingURL=connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B3E"}
@@ -0,0 +1,33 @@
1
+ import chalk from 'chalk';
2
+ import { isConfigured, loadWebConfig, hasWebConfig } from '../utils/config.js';
3
+ import { generateDashboardUrl, validateWebConfig } from '../utils/firebase-json.js';
4
+ /**
5
+ * Generate and display the dashboard connection URL
6
+ */
7
+ export async function connectCommand(options) {
8
+ if (!isConfigured()) {
9
+ console.log(chalk.red('\nāŒ Code Insights is not configured.'));
10
+ console.log(chalk.gray('Run "code-insights init" first.\n'));
11
+ return;
12
+ }
13
+ if (!hasWebConfig()) {
14
+ console.log(chalk.yellow('\n⚠ No web config found.'));
15
+ console.log(chalk.gray('\nRe-run "code-insights init" to add your web config.'));
16
+ console.log(chalk.gray('Or visit the dashboard and configure Firebase manually:'));
17
+ console.log(chalk.white(' https://code-insights.app\n'));
18
+ return;
19
+ }
20
+ const webConfigData = loadWebConfig();
21
+ if (!webConfigData || !validateWebConfig(webConfigData)) {
22
+ console.log(chalk.red('\nāŒ Invalid web config stored.'));
23
+ console.log(chalk.gray('Run "code-insights init" to reconfigure.\n'));
24
+ return;
25
+ }
26
+ const webConfig = webConfigData;
27
+ const url = generateDashboardUrl(webConfig);
28
+ console.log(chalk.cyan('\nšŸ”— Dashboard Connection URL\n'));
29
+ console.log(chalk.white('Open this URL to connect the dashboard to your Firebase:'));
30
+ console.log(chalk.bold.underline(url));
31
+ console.log('');
32
+ }
33
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAOpF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC1D,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC7D,OAAO;IACT,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC,CAAC;QACnF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,aAAa,EAAE,CAAC;IACtC,IAAI,CAAC,aAAa,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,aAAkC,CAAC;IACrD,MAAM,GAAG,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface InitOptions {
2
+ fromJson?: string;
3
+ webConfig?: string;
4
+ }
5
+ /**
6
+ * Initialize Code Insights configuration
7
+ */
8
+ export declare function initCommand(options: InitOptions): Promise<void>;
9
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA4LrE"}
@@ -0,0 +1,176 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import { saveConfig, saveWebConfig, getConfigDir, isConfigured } from '../utils/config.js';
4
+ import { readJsonFileWithError, readFirebaseConfigFile, validateServiceAccountJson, validateWebConfig, extractServiceAccountConfig, looksLikeWebConfig, looksLikeServiceAccount, } from '../utils/firebase-json.js';
5
+ const DEFAULT_DASHBOARD_URL = 'https://code-insights.app';
6
+ /**
7
+ * Initialize Code Insights configuration
8
+ */
9
+ export async function initCommand(options) {
10
+ console.log(chalk.cyan('\nšŸ”§ Code Insights Setup\n'));
11
+ if (isConfigured()) {
12
+ const { overwrite } = await inquirer.prompt([
13
+ {
14
+ type: 'confirm',
15
+ name: 'overwrite',
16
+ message: 'Configuration already exists. Overwrite?',
17
+ default: false,
18
+ },
19
+ ]);
20
+ if (!overwrite) {
21
+ console.log(chalk.yellow('Setup cancelled.'));
22
+ return;
23
+ }
24
+ }
25
+ // --- Step 1: Service Account ---
26
+ let firebaseConfig;
27
+ if (options.fromJson) {
28
+ // Read from JSON file
29
+ const result = readJsonFileWithError(options.fromJson);
30
+ if (!result.success) {
31
+ console.log(chalk.red(`\nāŒ ${result.message}`));
32
+ process.exit(1);
33
+ }
34
+ // Cross-type detection: did they pass a web config by mistake?
35
+ if (looksLikeWebConfig(result.data) && !looksLikeServiceAccount(result.data)) {
36
+ console.log(chalk.red('\nāŒ This looks like a web config file, not a service account.'));
37
+ console.log(chalk.gray('Use --web-config for the web SDK config file.'));
38
+ console.log(chalk.gray('Use --from-json for the service account key (downloaded from Firebase).\n'));
39
+ process.exit(1);
40
+ }
41
+ if (!validateServiceAccountJson(result.data)) {
42
+ console.log(chalk.red('\nāŒ Invalid service account JSON.'));
43
+ console.log(chalk.gray('Expected a file with: type, project_id, private_key, client_email'));
44
+ console.log(chalk.gray('Download it from: Firebase Console > Project Settings > Service Accounts\n'));
45
+ process.exit(1);
46
+ }
47
+ firebaseConfig = extractServiceAccountConfig(result.data);
48
+ console.log(chalk.green(`āœ“ Service account loaded from ${options.fromJson}`));
49
+ console.log(chalk.gray(` Project: ${firebaseConfig.projectId}`));
50
+ }
51
+ else {
52
+ // Interactive prompts
53
+ console.log(chalk.bold('šŸ“‹ Step 1: Service Account\n'));
54
+ console.log(chalk.gray('You\'ll need your Firebase service account key JSON file.'));
55
+ console.log(chalk.gray('Download from: Firebase Console > Project Settings > Service Accounts\n'));
56
+ console.log(chalk.gray(chalk.bold('Tip:') + ' Use --from-json <path> to skip these prompts:\n'));
57
+ console.log(chalk.gray(' code-insights init --from-json ~/Downloads/serviceAccountKey.json\n'));
58
+ const answers = await inquirer.prompt([
59
+ {
60
+ type: 'input',
61
+ name: 'projectId',
62
+ message: 'Firebase Project ID:',
63
+ validate: (input) => input.length > 0 || 'Project ID is required',
64
+ },
65
+ {
66
+ type: 'input',
67
+ name: 'clientEmail',
68
+ message: 'Service Account Email (client_email from JSON):',
69
+ validate: (input) => input.includes('@') || 'Please enter a valid service account email',
70
+ },
71
+ {
72
+ type: 'password',
73
+ name: 'privateKey',
74
+ message: 'Private Key (private_key from JSON, including BEGIN/END):',
75
+ validate: (input) => input.includes('PRIVATE KEY') || 'Please paste the complete private key',
76
+ },
77
+ ]);
78
+ firebaseConfig = {
79
+ projectId: answers.projectId,
80
+ clientEmail: answers.clientEmail,
81
+ privateKey: answers.privateKey,
82
+ };
83
+ }
84
+ // --- Step 2: Web Config ---
85
+ let webConfig;
86
+ if (options.webConfig) {
87
+ // Read from file — supports both JSON and Firebase JS snippet format
88
+ const result = readFirebaseConfigFile(options.webConfig);
89
+ if (!result.success) {
90
+ console.log(chalk.red(`\nāŒ ${result.message}`));
91
+ process.exit(1);
92
+ }
93
+ // Cross-type detection: did they pass a service account by mistake?
94
+ if (looksLikeServiceAccount(result.data) && !looksLikeWebConfig(result.data)) {
95
+ console.log(chalk.red('\nāŒ This looks like a service account file, not a web config.'));
96
+ console.log(chalk.gray('Use --from-json for the service account key.'));
97
+ console.log(chalk.gray('Use --web-config for the web SDK config.\n'));
98
+ process.exit(1);
99
+ }
100
+ if (!validateWebConfig(result.data)) {
101
+ console.log(chalk.red('\nāŒ Invalid web config.'));
102
+ console.log(chalk.gray('Expected: apiKey, authDomain, projectId, storageBucket, messagingSenderId, appId'));
103
+ console.log(chalk.gray('Get it from: Firebase Console > Project Settings > General > Your Apps'));
104
+ console.log(chalk.gray('You can paste the JavaScript snippet directly into a file — no need to convert to JSON.\n'));
105
+ process.exit(1);
106
+ }
107
+ webConfig = result.data;
108
+ console.log(chalk.green(`āœ“ Web config loaded from ${options.webConfig}`));
109
+ }
110
+ else {
111
+ // Interactive prompts
112
+ console.log(chalk.bold('\n🌐 Step 2: Web Dashboard Config\n'));
113
+ console.log(chalk.gray('Get these from: Firebase Console > Project Settings > General > Your Apps\n'));
114
+ console.log(chalk.gray(chalk.bold('Tip:') + ' Save the config as a JSON file and use --web-config <path> to skip these prompts.\n'));
115
+ const answers = await inquirer.prompt([
116
+ {
117
+ type: 'input',
118
+ name: 'apiKey',
119
+ message: 'API Key (apiKey):',
120
+ validate: (input) => input.length > 0 || 'API Key is required',
121
+ },
122
+ {
123
+ type: 'input',
124
+ name: 'authDomain',
125
+ message: 'Auth Domain (authDomain):',
126
+ default: `${firebaseConfig.projectId}.firebaseapp.com`,
127
+ },
128
+ {
129
+ type: 'input',
130
+ name: 'storageBucket',
131
+ message: 'Storage Bucket (storageBucket):',
132
+ default: `${firebaseConfig.projectId}.appspot.com`,
133
+ },
134
+ {
135
+ type: 'input',
136
+ name: 'messagingSenderId',
137
+ message: 'Messaging Sender ID (messagingSenderId):',
138
+ validate: (input) => input.length > 0 || 'Messaging Sender ID is required',
139
+ },
140
+ {
141
+ type: 'input',
142
+ name: 'appId',
143
+ message: 'App ID (appId):',
144
+ validate: (input) => input.length > 0 || 'App ID is required',
145
+ },
146
+ ]);
147
+ webConfig = {
148
+ apiKey: answers.apiKey,
149
+ authDomain: answers.authDomain,
150
+ projectId: firebaseConfig.projectId,
151
+ storageBucket: answers.storageBucket,
152
+ messagingSenderId: answers.messagingSenderId,
153
+ appId: answers.appId,
154
+ };
155
+ }
156
+ // --- Save config ---
157
+ const config = {
158
+ firebase: firebaseConfig,
159
+ webConfig,
160
+ sync: {
161
+ claudeDir: '~/.claude/projects',
162
+ excludeProjects: [],
163
+ },
164
+ dashboardUrl: DEFAULT_DASHBOARD_URL,
165
+ };
166
+ saveConfig(config);
167
+ saveWebConfig(webConfig);
168
+ console.log(chalk.green('\nāœ… Configuration saved!'));
169
+ console.log(chalk.gray(`Config location: ${getConfigDir()}/config.json`));
170
+ console.log(chalk.cyan('\nšŸŽ‰ Setup complete! Next steps:\n'));
171
+ console.log(chalk.white(' 1. Sync your sessions:'));
172
+ console.log(chalk.gray(' code-insights sync\n'));
173
+ console.log(chalk.white(' 2. Connect the dashboard:'));
174
+ console.log(chalk.gray(' code-insights connect\n'));
175
+ }
176
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { InsightType } from '../types.js';
2
+ interface InsightsOptions {
3
+ type?: InsightType;
4
+ project?: string;
5
+ today?: boolean;
6
+ limit?: number;
7
+ }
8
+ /**
9
+ * Display recent insights from Firestore
10
+ */
11
+ export declare function insightsCommand(options?: InsightsOptions): Promise<void>;
12
+ export {};
13
+ //# sourceMappingURL=insights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insights.d.ts","sourceRoot":"","sources":["../../src/commands/insights.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,UAAU,eAAe;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ElF"}
@@ -0,0 +1,87 @@
1
+ import chalk from 'chalk';
2
+ import { format } from 'date-fns';
3
+ import { loadConfig, isConfigured } from '../utils/config.js';
4
+ import { initializeFirebase, getRecentInsights } from '../firebase/client.js';
5
+ /**
6
+ * Display recent insights from Firestore
7
+ */
8
+ export async function insightsCommand(options = {}) {
9
+ // Check if configured
10
+ if (!isConfigured()) {
11
+ console.log(chalk.red('Not configured. Run `claudeinsight init` first.'));
12
+ process.exit(1);
13
+ }
14
+ // Load config and initialize Firebase
15
+ const config = loadConfig();
16
+ if (!config) {
17
+ console.log(chalk.red('Configuration error.'));
18
+ process.exit(1);
19
+ }
20
+ try {
21
+ initializeFirebase(config);
22
+ }
23
+ catch (error) {
24
+ console.log(chalk.red('Failed to connect to Firebase.'));
25
+ console.error(error instanceof Error ? error.message : 'Unknown error');
26
+ process.exit(1);
27
+ }
28
+ const limit = options.limit || 20;
29
+ // Fetch insights
30
+ const insights = await getRecentInsights(limit, {
31
+ type: options.type,
32
+ project: options.project,
33
+ todayOnly: options.today,
34
+ });
35
+ if (insights.length === 0) {
36
+ console.log(chalk.yellow('\nNo insights found.'));
37
+ if (options.today) {
38
+ console.log(chalk.gray('Try running without --today to see older insights.'));
39
+ }
40
+ return;
41
+ }
42
+ console.log(chalk.cyan(`\nšŸ“Š Recent Insights (${insights.length})\n`));
43
+ // Group by type
44
+ const summaries = insights.filter((i) => i.type === 'summary');
45
+ const decisions = insights.filter((i) => i.type === 'decision');
46
+ const learnings = insights.filter((i) => i.type === 'learning');
47
+ const techniques = insights.filter((i) => i.type === 'technique');
48
+ if (summaries.length > 0) {
49
+ console.log(chalk.bold.magenta('šŸ“ Summaries'));
50
+ for (const insight of summaries) {
51
+ printInsight(insight);
52
+ }
53
+ console.log();
54
+ }
55
+ if (decisions.length > 0) {
56
+ console.log(chalk.bold.blue('šŸŽÆ Decisions'));
57
+ for (const insight of decisions) {
58
+ printInsight(insight);
59
+ }
60
+ console.log();
61
+ }
62
+ if (learnings.length > 0) {
63
+ console.log(chalk.bold.green('šŸ’” Learnings'));
64
+ for (const insight of learnings) {
65
+ printInsight(insight);
66
+ }
67
+ console.log();
68
+ }
69
+ if (techniques.length > 0) {
70
+ console.log(chalk.bold.yellow('šŸ”§ Techniques'));
71
+ for (const insight of techniques) {
72
+ printInsight(insight);
73
+ }
74
+ console.log();
75
+ }
76
+ }
77
+ function printInsight(insight) {
78
+ const date = insight.timestamp
79
+ ? format(new Date(insight.timestamp), 'MMM d')
80
+ : 'Unknown';
81
+ console.log(chalk.white(` • ${insight.title}`));
82
+ console.log(chalk.gray(` ${insight.projectName} | ${date}`));
83
+ if (insight.content && insight.content.length < 100) {
84
+ console.log(chalk.gray(` ${insight.content}`));
85
+ }
86
+ }
87
+ //# sourceMappingURL=insights.js.map