@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.
- package/LICENSE +21 -0
- package/README.md +287 -0
- package/dist/commands/connect.d.ts +8 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +33 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +176 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/insights.d.ts +13 -0
- package/dist/commands/insights.d.ts.map +1 -0
- package/dist/commands/insights.js +87 -0
- package/dist/commands/insights.js.map +1 -0
- package/dist/commands/install-hook.d.ts +9 -0
- package/dist/commands/install-hook.d.ts.map +1 -0
- package/dist/commands/install-hook.js +98 -0
- package/dist/commands/install-hook.js.map +1 -0
- package/dist/commands/link.d.ts +8 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/link.js +39 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/reset.d.ts +3 -0
- package/dist/commands/reset.d.ts.map +1 -0
- package/dist/commands/reset.js +95 -0
- package/dist/commands/reset.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +107 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +13 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +205 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/firebase/client.d.ts +35 -0
- package/dist/firebase/client.d.ts.map +1 -0
- package/dist/firebase/client.js +317 -0
- package/dist/firebase/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/insights.d.ts +7 -0
- package/dist/parser/insights.d.ts.map +1 -0
- package/dist/parser/insights.js +271 -0
- package/dist/parser/insights.js.map +1 -0
- package/dist/parser/jsonl.d.ts +6 -0
- package/dist/parser/jsonl.d.ts.map +1 -0
- package/dist/parser/jsonl.js +305 -0
- package/dist/parser/jsonl.js.map +1 -0
- package/dist/parser/titles.d.ts +14 -0
- package/dist/parser/titles.d.ts.map +1 -0
- package/dist/parser/titles.js +258 -0
- package/dist/parser/titles.js.map +1 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config.d.ts +46 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +106 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/device.d.ts +32 -0
- package/dist/utils/device.d.ts.map +1 -0
- package/dist/utils/device.js +132 -0
- package/dist/utils/device.js.map +1 -0
- package/dist/utils/firebase-json.d.ts +87 -0
- package/dist/utils/firebase-json.d.ts.map +1 -0
- package/dist/utils/firebase-json.js +206 -0
- package/dist/utils/firebase-json.js.map +1 -0
- package/dist/utils/pricing.d.ts +29 -0
- package/dist/utils/pricing.d.ts.map +1 -0
- package/dist/utils/pricing.js +66 -0
- package/dist/utils/pricing.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/commands/insights.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install Claude Code hook for auto-sync
|
|
3
|
+
*/
|
|
4
|
+
export declare function installHookCommand(): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Uninstall Claude Code hook
|
|
7
|
+
*/
|
|
8
|
+
export declare function uninstallHookCommand(): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=install-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/commands/install-hook.ts"],"names":[],"mappings":"AA4BA;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CA6DxD;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqC1D"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { isConfigured } from '../utils/config.js';
|
|
6
|
+
const CLAUDE_SETTINGS_DIR = path.join(os.homedir(), '.claude');
|
|
7
|
+
const HOOKS_FILE = path.join(CLAUDE_SETTINGS_DIR, 'settings.json');
|
|
8
|
+
/** Extract command string from both old (string) and new ({type, command}) hook formats */
|
|
9
|
+
function getHookCommand(hook) {
|
|
10
|
+
return typeof hook === 'string' ? hook : hook.command;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Install Claude Code hook for auto-sync
|
|
14
|
+
*/
|
|
15
|
+
export async function installHookCommand() {
|
|
16
|
+
console.log(chalk.cyan('\nš Install Code Insights Hook\n'));
|
|
17
|
+
// Check if configured
|
|
18
|
+
if (!isConfigured()) {
|
|
19
|
+
console.log(chalk.red('Not configured. Run `code-insights init` first.'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
// Get CLI path
|
|
23
|
+
const cliPath = process.argv[1];
|
|
24
|
+
const syncCommand = `node ${cliPath} sync -q`;
|
|
25
|
+
console.log(chalk.gray('This will add a Claude Code hook that syncs sessions automatically.'));
|
|
26
|
+
console.log(chalk.gray(`Hook command: ${syncCommand}\n`));
|
|
27
|
+
// Load existing settings
|
|
28
|
+
let settings = {};
|
|
29
|
+
if (fs.existsSync(HOOKS_FILE)) {
|
|
30
|
+
try {
|
|
31
|
+
const content = fs.readFileSync(HOOKS_FILE, 'utf-8');
|
|
32
|
+
settings = JSON.parse(content);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
console.log(chalk.yellow('Could not parse existing settings.json, creating new one.'));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Initialize hooks structure
|
|
39
|
+
if (!settings.hooks) {
|
|
40
|
+
settings.hooks = {};
|
|
41
|
+
}
|
|
42
|
+
// Add Stop hook (runs when Claude finishes responding)
|
|
43
|
+
const stopHook = {
|
|
44
|
+
hooks: [{ type: 'command', command: syncCommand }],
|
|
45
|
+
};
|
|
46
|
+
// Check if hook already exists
|
|
47
|
+
const existingStopHooks = settings.hooks.Stop || [];
|
|
48
|
+
const hookExists = existingStopHooks.some((h) => h.hooks.some((hook) => getHookCommand(hook).includes('code-insights')));
|
|
49
|
+
if (hookExists) {
|
|
50
|
+
console.log(chalk.yellow('Code Insights hook already installed.'));
|
|
51
|
+
console.log(chalk.gray('To reinstall, first run `code-insights uninstall-hook`'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
settings.hooks.Stop = [...existingStopHooks, stopHook];
|
|
55
|
+
// Write settings
|
|
56
|
+
fs.mkdirSync(CLAUDE_SETTINGS_DIR, { recursive: true });
|
|
57
|
+
fs.writeFileSync(HOOKS_FILE, JSON.stringify(settings, null, 2));
|
|
58
|
+
console.log(chalk.green('ā
Hook installed successfully!'));
|
|
59
|
+
console.log(chalk.gray(`\nConfiguration saved to: ${HOOKS_FILE}`));
|
|
60
|
+
console.log(chalk.cyan('\nHow it works:'));
|
|
61
|
+
console.log(chalk.white(' ⢠When a Claude Code session ends, the hook runs'));
|
|
62
|
+
console.log(chalk.white(' ⢠Sessions are automatically synced to your Firestore'));
|
|
63
|
+
console.log(chalk.white(' ⢠Check your dashboard for new insights'));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Uninstall Claude Code hook
|
|
67
|
+
*/
|
|
68
|
+
export async function uninstallHookCommand() {
|
|
69
|
+
console.log(chalk.cyan('\nš Uninstall Code Insights Hook\n'));
|
|
70
|
+
if (!fs.existsSync(HOOKS_FILE)) {
|
|
71
|
+
console.log(chalk.yellow('No hooks file found. Nothing to uninstall.'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const content = fs.readFileSync(HOOKS_FILE, 'utf-8');
|
|
76
|
+
const settings = JSON.parse(content);
|
|
77
|
+
if (!settings.hooks?.Stop) {
|
|
78
|
+
console.log(chalk.yellow('No Stop hooks found. Nothing to uninstall.'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Filter out Code Insights hooks
|
|
82
|
+
settings.hooks.Stop = settings.hooks.Stop.filter((h) => !h.hooks.some((hook) => getHookCommand(hook).includes('code-insights')));
|
|
83
|
+
// Clean up empty arrays
|
|
84
|
+
if (settings.hooks.Stop.length === 0) {
|
|
85
|
+
delete settings.hooks.Stop;
|
|
86
|
+
}
|
|
87
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
88
|
+
delete settings.hooks;
|
|
89
|
+
}
|
|
90
|
+
fs.writeFileSync(HOOKS_FILE, JSON.stringify(settings, null, 2));
|
|
91
|
+
console.log(chalk.green('ā
Hook uninstalled successfully!'));
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.log(chalk.red('Failed to uninstall hook:'));
|
|
95
|
+
console.error(error instanceof Error ? error.message : 'Unknown error');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=install-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-hook.js","sourceRoot":"","sources":["../../src/commands/install-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCrE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import qrcode from 'qrcode-terminal';
|
|
3
|
+
import { isConfigured, loadWebConfig, hasWebConfig } from '../utils/config.js';
|
|
4
|
+
import { generateDashboardUrl, validateWebConfig } from '../utils/firebase-json.js';
|
|
5
|
+
/**
|
|
6
|
+
* Generate and display dashboard link
|
|
7
|
+
*/
|
|
8
|
+
export async function linkCommand(options) {
|
|
9
|
+
if (!isConfigured()) {
|
|
10
|
+
console.log(chalk.red('\nā Code Insights is not configured.'));
|
|
11
|
+
console.log(chalk.gray('Run "code-insights init" first.\n'));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (!hasWebConfig()) {
|
|
15
|
+
console.log(chalk.yellow('\nā No web config found.'));
|
|
16
|
+
console.log(chalk.gray('\nTo generate a dashboard link, add web config:'));
|
|
17
|
+
console.log(chalk.white(' code-insights init --web-config <path-to-config.json>\n'));
|
|
18
|
+
console.log(chalk.gray('Or visit the dashboard and configure Firebase manually:'));
|
|
19
|
+
console.log(chalk.white(' https://code-insights.app\n'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const webConfigData = loadWebConfig();
|
|
23
|
+
if (!webConfigData || !validateWebConfig(webConfigData)) {
|
|
24
|
+
console.log(chalk.red('\nā Invalid web config stored.'));
|
|
25
|
+
console.log(chalk.gray('Run "code-insights init --web-config <path>" to reconfigure.\n'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const webConfig = webConfigData;
|
|
29
|
+
const url = generateDashboardUrl(webConfig);
|
|
30
|
+
console.log(chalk.cyan('\nš Dashboard Link\n'));
|
|
31
|
+
console.log(chalk.white('Open this URL to connect the dashboard:'));
|
|
32
|
+
console.log(chalk.bold.underline(url));
|
|
33
|
+
if (options.qr !== false) {
|
|
34
|
+
console.log(chalk.gray('\nš± QR Code:\n'));
|
|
35
|
+
qrcode.generate(url, { small: true });
|
|
36
|
+
}
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,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,WAAW,CAAC,OAAoB;IACpD,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,iDAAiD,CAAC,CAAC,CAAC;QAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC,CAAC;QACtF,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,gEAAgE,CAAC,CAAC,CAAC;QAC1F,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,uBAAuB,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvC,IAAI,OAAO,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../src/commands/reset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,YAAY,SA2ErB,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import admin from 'firebase-admin';
|
|
5
|
+
import { existsSync, unlinkSync } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { loadConfig } from '../utils/config.js';
|
|
8
|
+
const SYNC_STATE_FILE = join(process.env.HOME || '~', '.code-insights', 'sync-state.json');
|
|
9
|
+
export const resetCommand = new Command('reset')
|
|
10
|
+
.description('Delete all data from Firestore and reset local sync state')
|
|
11
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
console.log(chalk.red.bold('\nā ļø WARNING: This will permanently delete ALL data from your Firestore database!'));
|
|
14
|
+
console.log(chalk.yellow('Collections to be deleted: projects, sessions, insights, messages\n'));
|
|
15
|
+
if (!options.confirm) {
|
|
16
|
+
// Simple confirmation using stdin
|
|
17
|
+
const readline = await import('readline');
|
|
18
|
+
const rl = readline.createInterface({
|
|
19
|
+
input: process.stdin,
|
|
20
|
+
output: process.stdout,
|
|
21
|
+
});
|
|
22
|
+
const answer = await new Promise((resolve) => {
|
|
23
|
+
rl.question(chalk.cyan('Type "DELETE" to confirm: '), resolve);
|
|
24
|
+
});
|
|
25
|
+
rl.close();
|
|
26
|
+
if (answer !== 'DELETE') {
|
|
27
|
+
console.log(chalk.gray('\nAborted. No data was deleted.'));
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Load config
|
|
32
|
+
const config = loadConfig();
|
|
33
|
+
if (!config) {
|
|
34
|
+
console.error(chalk.red('Error: Not configured. Run `code-insights init` first.'));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
// Initialize Firebase
|
|
38
|
+
if (admin.apps.length === 0) {
|
|
39
|
+
admin.initializeApp({
|
|
40
|
+
credential: admin.credential.cert({
|
|
41
|
+
projectId: config.firebase.projectId,
|
|
42
|
+
clientEmail: config.firebase.clientEmail,
|
|
43
|
+
privateKey: config.firebase.privateKey.replace(/\\n/g, '\n'),
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const db = admin.firestore();
|
|
48
|
+
const collections = ['projects', 'sessions', 'insights', 'messages'];
|
|
49
|
+
console.log('');
|
|
50
|
+
for (const collectionName of collections) {
|
|
51
|
+
const spinner = ora(`Deleting ${collectionName}...`).start();
|
|
52
|
+
try {
|
|
53
|
+
const deleted = await deleteCollection(db, collectionName);
|
|
54
|
+
spinner.succeed(`Deleted ${deleted} documents from ${collectionName}`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
spinner.fail(`Failed to delete ${collectionName}: ${error}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Delete local sync state
|
|
61
|
+
const syncSpinner = ora('Removing local sync state...').start();
|
|
62
|
+
try {
|
|
63
|
+
if (existsSync(SYNC_STATE_FILE)) {
|
|
64
|
+
unlinkSync(SYNC_STATE_FILE);
|
|
65
|
+
syncSpinner.succeed('Removed local sync state');
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
syncSpinner.info('No local sync state file found');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
syncSpinner.fail(`Failed to remove sync state: ${error}`);
|
|
73
|
+
}
|
|
74
|
+
console.log(chalk.green('\nā Reset complete. Run `code-insights sync` to re-sync all sessions.\n'));
|
|
75
|
+
process.exit(0);
|
|
76
|
+
});
|
|
77
|
+
async function deleteCollection(db, collectionName) {
|
|
78
|
+
const collectionRef = db.collection(collectionName);
|
|
79
|
+
const batchSize = 500;
|
|
80
|
+
let totalDeleted = 0;
|
|
81
|
+
while (true) {
|
|
82
|
+
const snapshot = await collectionRef.limit(batchSize).get();
|
|
83
|
+
if (snapshot.empty) {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
const batch = db.batch();
|
|
87
|
+
snapshot.docs.forEach((doc) => {
|
|
88
|
+
batch.delete(doc.ref);
|
|
89
|
+
});
|
|
90
|
+
await batch.commit();
|
|
91
|
+
totalDeleted += snapshot.size;
|
|
92
|
+
}
|
|
93
|
+
return totalDeleted;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=reset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset.js","sourceRoot":"","sources":["../../src/commands/reset.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAkFnD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { loadConfig, loadSyncState, isConfigured, getConfigDir, getClaudeDir, hasWebConfig, loadWebConfig } from '../utils/config.js';
|
|
3
|
+
import { initializeFirebase, getProjects } from '../firebase/client.js';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
/**
|
|
6
|
+
* Show Code Insights status
|
|
7
|
+
*/
|
|
8
|
+
export async function statusCommand() {
|
|
9
|
+
console.log(chalk.cyan('\nš Code Insights Status\n'));
|
|
10
|
+
// Check configuration
|
|
11
|
+
console.log(chalk.white('Configuration:'));
|
|
12
|
+
if (isConfigured()) {
|
|
13
|
+
console.log(chalk.green(` ā Configured at ${getConfigDir()}`));
|
|
14
|
+
const config = loadConfig();
|
|
15
|
+
if (config) {
|
|
16
|
+
console.log(chalk.gray(` Project: ${config.firebase.projectId}`));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.log(chalk.red(' ā Not configured'));
|
|
21
|
+
console.log(chalk.gray(' Run `code-insights init` to set up'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Check Claude directory
|
|
25
|
+
console.log(chalk.white('\nClaude Code:'));
|
|
26
|
+
const claudeDir = getClaudeDir();
|
|
27
|
+
if (fs.existsSync(claudeDir)) {
|
|
28
|
+
const projectDirs = fs.readdirSync(claudeDir).filter((d) => !d.startsWith('.'));
|
|
29
|
+
const sessionCount = countJsonlFiles(claudeDir);
|
|
30
|
+
console.log(chalk.green(` ā Found at ${claudeDir}`));
|
|
31
|
+
console.log(chalk.gray(` ${projectDirs.length} projects, ${sessionCount} sessions`));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(chalk.yellow(` ā Not found at ${claudeDir}`));
|
|
35
|
+
}
|
|
36
|
+
// Check sync state
|
|
37
|
+
console.log(chalk.white('\nSync State:'));
|
|
38
|
+
const syncState = loadSyncState();
|
|
39
|
+
if (syncState.lastSync) {
|
|
40
|
+
const lastSync = new Date(syncState.lastSync);
|
|
41
|
+
const syncedFiles = Object.keys(syncState.files).length;
|
|
42
|
+
console.log(chalk.green(` ā Last sync: ${lastSync.toLocaleString()}`));
|
|
43
|
+
console.log(chalk.gray(` ${syncedFiles} files tracked`));
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log(chalk.yellow(' ā Never synced'));
|
|
47
|
+
console.log(chalk.gray(' Run `code-insights sync` to sync'));
|
|
48
|
+
}
|
|
49
|
+
// Check Firebase connection
|
|
50
|
+
console.log(chalk.white('\nFirebase:'));
|
|
51
|
+
const config = loadConfig();
|
|
52
|
+
if (config) {
|
|
53
|
+
try {
|
|
54
|
+
initializeFirebase(config);
|
|
55
|
+
const projects = await getProjects();
|
|
56
|
+
console.log(chalk.green(' ā Connected'));
|
|
57
|
+
console.log(chalk.gray(` ${projects.length} projects in Firestore`));
|
|
58
|
+
if (projects.length > 0) {
|
|
59
|
+
console.log(chalk.white('\nSynced Projects:'));
|
|
60
|
+
for (const project of projects.slice(0, 5)) {
|
|
61
|
+
console.log(chalk.gray(` ${project.name} (${project.sessionCount} sessions)`));
|
|
62
|
+
}
|
|
63
|
+
if (projects.length > 5) {
|
|
64
|
+
console.log(chalk.gray(` ... and ${projects.length - 5} more`));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.log(chalk.red(' ā Connection failed'));
|
|
70
|
+
console.log(chalk.gray(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Check web dashboard config
|
|
74
|
+
console.log(chalk.white('\nWeb Dashboard:'));
|
|
75
|
+
if (hasWebConfig()) {
|
|
76
|
+
const webConfig = loadWebConfig();
|
|
77
|
+
console.log(chalk.green(' ā Configured'));
|
|
78
|
+
if (webConfig && typeof webConfig.projectId === 'string') {
|
|
79
|
+
console.log(chalk.gray(` Project: ${webConfig.projectId}`));
|
|
80
|
+
}
|
|
81
|
+
console.log(chalk.gray(' Run "code-insights connect" to get dashboard URL'));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.log(chalk.yellow(' ā Not configured'));
|
|
85
|
+
console.log(chalk.gray(' Run "code-insights init" to configure'));
|
|
86
|
+
}
|
|
87
|
+
console.log('');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Count JSONL files in Claude directory
|
|
91
|
+
*/
|
|
92
|
+
function countJsonlFiles(baseDir) {
|
|
93
|
+
let count = 0;
|
|
94
|
+
const dirs = fs.readdirSync(baseDir);
|
|
95
|
+
for (const dir of dirs) {
|
|
96
|
+
if (dir.startsWith('.'))
|
|
97
|
+
continue;
|
|
98
|
+
const projectPath = `${baseDir}/${dir}`;
|
|
99
|
+
const stat = fs.statSync(projectPath);
|
|
100
|
+
if (!stat.isDirectory())
|
|
101
|
+
continue;
|
|
102
|
+
const files = fs.readdirSync(projectPath);
|
|
103
|
+
count += files.filter((f) => f.endsWith('.jsonl')).length;
|
|
104
|
+
}
|
|
105
|
+
return count;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface SyncOptions {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
project?: string;
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
quiet?: boolean;
|
|
6
|
+
regenerateTitles?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Sync Claude Code sessions to Firestore
|
|
10
|
+
*/
|
|
11
|
+
export declare function syncCommand(options?: SyncOptions): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAUA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmJ1E"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { loadConfig, loadSyncState, saveSyncState, getClaudeDir } from '../utils/config.js';
|
|
6
|
+
import { parseJsonlFile } from '../parser/jsonl.js';
|
|
7
|
+
import { initializeFirebase, uploadSession, uploadMessages, sessionExists, recalculateUsageStats } from '../firebase/client.js';
|
|
8
|
+
/**
|
|
9
|
+
* Sync Claude Code sessions to Firestore
|
|
10
|
+
*/
|
|
11
|
+
export async function syncCommand(options = {}) {
|
|
12
|
+
const log = options.quiet ? () => { } : console.log.bind(console);
|
|
13
|
+
const noopSpinner = {
|
|
14
|
+
start: function () { return this; },
|
|
15
|
+
succeed: function () { return this; },
|
|
16
|
+
fail: function () { return this; },
|
|
17
|
+
warn: function () { return this; },
|
|
18
|
+
info: function () { return this; },
|
|
19
|
+
};
|
|
20
|
+
const createSpinner = options.quiet
|
|
21
|
+
? () => noopSpinner
|
|
22
|
+
: ora;
|
|
23
|
+
log(chalk.cyan('\nš¤ Code Insights Sync\n'));
|
|
24
|
+
// Load config
|
|
25
|
+
const config = loadConfig();
|
|
26
|
+
if (!config) {
|
|
27
|
+
log(chalk.red('Not configured. Run `code-insights init` first.'));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Initialize Firebase
|
|
31
|
+
const spinner = createSpinner('Connecting to Firebase...').start();
|
|
32
|
+
try {
|
|
33
|
+
initializeFirebase(config);
|
|
34
|
+
spinner.succeed('Connected to Firebase');
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
spinner.fail('Failed to connect to Firebase');
|
|
38
|
+
if (!options.quiet) {
|
|
39
|
+
console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
|
|
40
|
+
}
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
// Find JSONL files
|
|
44
|
+
const claudeDir = getClaudeDir();
|
|
45
|
+
if (!fs.existsSync(claudeDir)) {
|
|
46
|
+
log(chalk.yellow(`Claude directory not found: ${claudeDir}`));
|
|
47
|
+
log(chalk.gray('Make sure you have Claude Code installed and have run at least one session.'));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
spinner.start('Discovering sessions...');
|
|
51
|
+
const jsonlFiles = discoverJsonlFiles(claudeDir, options.project);
|
|
52
|
+
spinner.succeed(`Found ${jsonlFiles.length} session files`);
|
|
53
|
+
if (jsonlFiles.length === 0) {
|
|
54
|
+
log(chalk.yellow('No sessions to sync.'));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Load sync state
|
|
58
|
+
const syncState = options.force ? { lastSync: '', files: {} } : loadSyncState();
|
|
59
|
+
// Filter to only new/modified files
|
|
60
|
+
const filesToSync = filterFilesToSync(jsonlFiles, syncState, options.force);
|
|
61
|
+
log(chalk.gray(` ${filesToSync.length} files need syncing (${jsonlFiles.length - filesToSync.length} already synced)`));
|
|
62
|
+
if (filesToSync.length === 0) {
|
|
63
|
+
log(chalk.green('\nā
Already up to date!'));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (options.dryRun) {
|
|
67
|
+
log(chalk.yellow('\nš Dry run - no changes will be made'));
|
|
68
|
+
for (const file of filesToSync) {
|
|
69
|
+
log(chalk.gray(` Would sync: ${path.basename(file)}`));
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Process files
|
|
74
|
+
let syncedCount = 0;
|
|
75
|
+
let messageCount = 0;
|
|
76
|
+
let errorCount = 0;
|
|
77
|
+
for (const filePath of filesToSync) {
|
|
78
|
+
const fileName = path.basename(filePath);
|
|
79
|
+
spinner.start(`Processing ${fileName}...`);
|
|
80
|
+
try {
|
|
81
|
+
// Parse session
|
|
82
|
+
const session = await parseJsonlFile(filePath);
|
|
83
|
+
if (!session) {
|
|
84
|
+
spinner.warn(`Skipped ${fileName} (no valid data)`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Check if already exists (unless force)
|
|
88
|
+
if (!options.force) {
|
|
89
|
+
const exists = await sessionExists(session.id);
|
|
90
|
+
if (exists) {
|
|
91
|
+
spinner.info(`Skipped ${fileName} (already synced)`);
|
|
92
|
+
updateSyncState(syncState, filePath, session.id);
|
|
93
|
+
saveSyncState(syncState);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Upload session and messages to Firestore
|
|
98
|
+
await uploadSession(session, !!options.force);
|
|
99
|
+
await uploadMessages(session);
|
|
100
|
+
// Update and persist sync state after each file
|
|
101
|
+
// so progress survives crashes (e.g., Firebase quota exceeded)
|
|
102
|
+
updateSyncState(syncState, filePath, session.id);
|
|
103
|
+
saveSyncState(syncState);
|
|
104
|
+
syncedCount++;
|
|
105
|
+
messageCount += session.messages.length;
|
|
106
|
+
spinner.succeed(`Synced ${fileName} (${session.messages.length} messages)`);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
errorCount++;
|
|
110
|
+
spinner.fail(`Failed to sync ${fileName}`);
|
|
111
|
+
if (!options.quiet) {
|
|
112
|
+
console.error(chalk.red(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Reconcile usage stats after force sync
|
|
117
|
+
if (options.force) {
|
|
118
|
+
spinner.start('Recalculating usage stats...');
|
|
119
|
+
try {
|
|
120
|
+
const result = await recalculateUsageStats();
|
|
121
|
+
spinner.succeed(`Usage stats reconciled (${result.sessionsWithUsage} sessions with usage data)`);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
spinner.warn('Could not reconcile usage stats');
|
|
125
|
+
if (!options.quiet) {
|
|
126
|
+
console.error(chalk.red(` ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Save sync state
|
|
131
|
+
syncState.lastSync = new Date().toISOString();
|
|
132
|
+
saveSyncState(syncState);
|
|
133
|
+
// Summary
|
|
134
|
+
log(chalk.cyan('\nš Sync Summary'));
|
|
135
|
+
log(chalk.white(` Sessions synced: ${syncedCount}`));
|
|
136
|
+
log(chalk.white(` Messages uploaded: ${messageCount}`));
|
|
137
|
+
if (errorCount > 0) {
|
|
138
|
+
log(chalk.red(` Errors: ${errorCount}`));
|
|
139
|
+
}
|
|
140
|
+
log(chalk.green('\nā
Sync complete!'));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Discover all JSONL files in Claude directory
|
|
144
|
+
*/
|
|
145
|
+
function discoverJsonlFiles(baseDir, projectFilter) {
|
|
146
|
+
const files = [];
|
|
147
|
+
const projectDirs = fs.readdirSync(baseDir);
|
|
148
|
+
for (const projectDir of projectDirs) {
|
|
149
|
+
// Skip hidden files and non-directories
|
|
150
|
+
if (projectDir.startsWith('.'))
|
|
151
|
+
continue;
|
|
152
|
+
const projectPath = path.join(baseDir, projectDir);
|
|
153
|
+
const stat = fs.statSync(projectPath);
|
|
154
|
+
if (!stat.isDirectory())
|
|
155
|
+
continue;
|
|
156
|
+
// Apply project filter if specified
|
|
157
|
+
if (projectFilter && !projectDir.toLowerCase().includes(projectFilter.toLowerCase())) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// Find JSONL files in project directory
|
|
161
|
+
const projectFiles = fs.readdirSync(projectPath);
|
|
162
|
+
for (const file of projectFiles) {
|
|
163
|
+
if (file.endsWith('.jsonl')) {
|
|
164
|
+
files.push(path.join(projectPath, file));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Also check subagents directory
|
|
168
|
+
const subagentsDir = path.join(projectPath, 'subagents');
|
|
169
|
+
if (fs.existsSync(subagentsDir)) {
|
|
170
|
+
const subagentFiles = fs.readdirSync(subagentsDir);
|
|
171
|
+
for (const file of subagentFiles) {
|
|
172
|
+
if (file.endsWith('.jsonl')) {
|
|
173
|
+
files.push(path.join(subagentsDir, file));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return files;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Filter files to only those that need syncing
|
|
182
|
+
*/
|
|
183
|
+
function filterFilesToSync(files, syncState, force) {
|
|
184
|
+
if (force)
|
|
185
|
+
return files;
|
|
186
|
+
return files.filter((filePath) => {
|
|
187
|
+
const stat = fs.statSync(filePath);
|
|
188
|
+
const lastModified = stat.mtime.toISOString();
|
|
189
|
+
const fileState = syncState.files[filePath];
|
|
190
|
+
// Sync if never synced or modified since last sync
|
|
191
|
+
return !fileState || fileState.lastModified !== lastModified;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Update sync state for a file
|
|
196
|
+
*/
|
|
197
|
+
function updateSyncState(state, filePath, sessionId) {
|
|
198
|
+
const stat = fs.statSync(filePath);
|
|
199
|
+
state.files[filePath] = {
|
|
200
|
+
lastModified: stat.mtime.toISOString(),
|
|
201
|
+
lastSyncedLine: 0, // Not tracking lines for now
|
|
202
|
+
sessionId,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=sync.js.map
|