@nocoo/pew 0.2.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/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +5 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +221 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/login.d.ts +34 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +108 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/status.d.ts +19 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +35 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +49 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +267 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/upload.d.ts +53 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +185 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/config/manager.d.ts +14 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +32 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/discovery/sources.d.ts +37 -0
- package/dist/discovery/sources.d.ts.map +1 -0
- package/dist/discovery/sources.js +110 -0
- package/dist/discovery/sources.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/claude.d.ts +34 -0
- package/dist/parsers/claude.d.ts.map +1 -0
- package/dist/parsers/claude.js +101 -0
- package/dist/parsers/claude.js.map +1 -0
- package/dist/parsers/gemini.d.ts +38 -0
- package/dist/parsers/gemini.d.ts.map +1 -0
- package/dist/parsers/gemini.js +142 -0
- package/dist/parsers/gemini.js.map +1 -0
- package/dist/parsers/openclaw.d.ts +23 -0
- package/dist/parsers/openclaw.d.ts.map +1 -0
- package/dist/parsers/openclaw.js +85 -0
- package/dist/parsers/openclaw.js.map +1 -0
- package/dist/parsers/opencode.d.ts +35 -0
- package/dist/parsers/opencode.d.ts.map +1 -0
- package/dist/parsers/opencode.js +118 -0
- package/dist/parsers/opencode.js.map +1 -0
- package/dist/storage/cursor-store.d.ts +14 -0
- package/dist/storage/cursor-store.d.ts.map +1 -0
- package/dist/storage/cursor-store.js +34 -0
- package/dist/storage/cursor-store.js.map +1 -0
- package/dist/storage/local-queue.d.ts +30 -0
- package/dist/storage/local-queue.d.ts.map +1 -0
- package/dist/storage/local-queue.js +70 -0
- package/dist/storage/local-queue.js.map +1 -0
- package/dist/utils/buckets.d.ts +17 -0
- package/dist/utils/buckets.d.ts.map +1 -0
- package/dist/utils/buckets.js +38 -0
- package/dist/utils/buckets.js.map +1 -0
- package/dist/utils/paths.d.ts +17 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +21 -0
- package/dist/utils/paths.js.map +1 -0
- package/package.json +44 -0
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|
package/dist/bin.js
ADDED
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAmPA,eAAO,MAAM,IAAI,qDAWf,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
import { consola } from "consola";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { resolveDefaultPaths } from "./utils/paths.js";
|
|
5
|
+
import { executeSync } from "./commands/sync.js";
|
|
6
|
+
import { executeStatus } from "./commands/status.js";
|
|
7
|
+
import { executeLogin, resolveHost } from "./commands/login.js";
|
|
8
|
+
import { executeUpload } from "./commands/upload.js";
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Dev mode detection (otter pattern)
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
function isDevMode() {
|
|
13
|
+
return process.argv.includes("--dev");
|
|
14
|
+
}
|
|
15
|
+
// Allow self-signed certs (mkcert) in dev mode
|
|
16
|
+
if (isDevMode()) {
|
|
17
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
18
|
+
}
|
|
19
|
+
const syncCommand = defineCommand({
|
|
20
|
+
meta: {
|
|
21
|
+
name: "sync",
|
|
22
|
+
description: "Parse local AI tool usage and upload to dashboard",
|
|
23
|
+
},
|
|
24
|
+
args: {
|
|
25
|
+
upload: {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Upload to dashboard after syncing (default: true if logged in)",
|
|
28
|
+
default: true,
|
|
29
|
+
},
|
|
30
|
+
dev: {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
description: "Use the dev host (pew.dev.hexly.ai)",
|
|
33
|
+
default: false,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
async run({ args }) {
|
|
37
|
+
const paths = resolveDefaultPaths();
|
|
38
|
+
consola.start("Syncing token usage from AI coding tools...\n");
|
|
39
|
+
const result = await executeSync({
|
|
40
|
+
stateDir: paths.stateDir,
|
|
41
|
+
claudeDir: paths.claudeDir,
|
|
42
|
+
geminiDir: paths.geminiDir,
|
|
43
|
+
openCodeMessageDir: paths.openCodeMessageDir,
|
|
44
|
+
openclawDir: paths.openclawDir,
|
|
45
|
+
onProgress(event) {
|
|
46
|
+
if (event.phase === "parse" && event.current && event.total) {
|
|
47
|
+
// Only log at 25% intervals or small counts
|
|
48
|
+
if (event.total <= 10 ||
|
|
49
|
+
event.current === event.total ||
|
|
50
|
+
event.current % Math.ceil(event.total / 4) === 0) {
|
|
51
|
+
consola.info(` ${pc.cyan(event.source)} ${event.current}/${event.total} files`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
// Summary
|
|
57
|
+
consola.log("");
|
|
58
|
+
if (result.totalDeltas === 0) {
|
|
59
|
+
consola.info("No new token usage found.");
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
consola.success(`Synced ${pc.bold(String(result.totalDeltas))} new events → ${pc.bold(String(result.totalRecords))} queue records`);
|
|
63
|
+
const deltaParts = [];
|
|
64
|
+
if (result.sources.claude > 0)
|
|
65
|
+
deltaParts.push(`Claude: ${result.sources.claude}`);
|
|
66
|
+
if (result.sources.gemini > 0)
|
|
67
|
+
deltaParts.push(`Gemini: ${result.sources.gemini}`);
|
|
68
|
+
if (result.sources.opencode > 0)
|
|
69
|
+
deltaParts.push(`OpenCode: ${result.sources.opencode}`);
|
|
70
|
+
if (result.sources.openclaw > 0)
|
|
71
|
+
deltaParts.push(`OpenClaw: ${result.sources.openclaw}`);
|
|
72
|
+
if (deltaParts.length > 0) {
|
|
73
|
+
consola.info(` ${pc.dim(deltaParts.join(" | "))}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Always show files scanned
|
|
77
|
+
const fs = result.filesScanned;
|
|
78
|
+
const scanParts = [];
|
|
79
|
+
if (fs.claude > 0)
|
|
80
|
+
scanParts.push(`Claude: ${fs.claude}`);
|
|
81
|
+
if (fs.gemini > 0)
|
|
82
|
+
scanParts.push(`Gemini: ${fs.gemini}`);
|
|
83
|
+
if (fs.opencode > 0)
|
|
84
|
+
scanParts.push(`OpenCode: ${fs.opencode}`);
|
|
85
|
+
if (fs.openclaw > 0)
|
|
86
|
+
scanParts.push(`OpenClaw: ${fs.openclaw}`);
|
|
87
|
+
if (scanParts.length > 0) {
|
|
88
|
+
consola.info(` Files scanned: ${pc.dim(scanParts.join(" | "))}`);
|
|
89
|
+
}
|
|
90
|
+
// Auto-upload if logged in
|
|
91
|
+
if (args.upload) {
|
|
92
|
+
const dev = isDevMode();
|
|
93
|
+
await runUpload(paths.stateDir, resolveHost(dev), dev);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const statusCommand = defineCommand({
|
|
98
|
+
meta: {
|
|
99
|
+
name: "status",
|
|
100
|
+
description: "Show current sync status and token usage summary",
|
|
101
|
+
},
|
|
102
|
+
async run() {
|
|
103
|
+
const paths = resolveDefaultPaths();
|
|
104
|
+
const result = await executeStatus({ stateDir: paths.stateDir });
|
|
105
|
+
consola.log("");
|
|
106
|
+
consola.log(pc.bold("Pew Status"));
|
|
107
|
+
consola.log(pc.dim("─".repeat(40)));
|
|
108
|
+
consola.log(` Tracked files: ${pc.cyan(String(result.trackedFiles))}`);
|
|
109
|
+
consola.log(` Last sync: ${result.lastSync ? pc.green(result.lastSync) : pc.dim("never")}`);
|
|
110
|
+
consola.log(` Pending upload: ${result.pendingRecords > 0 ? pc.yellow(String(result.pendingRecords)) : pc.dim("0")} records`);
|
|
111
|
+
if (Object.keys(result.sources).length > 0) {
|
|
112
|
+
consola.log("");
|
|
113
|
+
consola.log(pc.bold(" Files by source:"));
|
|
114
|
+
for (const [source, count] of Object.entries(result.sources)) {
|
|
115
|
+
consola.log(` ${pc.cyan(source.padEnd(14))} ${count}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
consola.log("");
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
const loginCommand = defineCommand({
|
|
122
|
+
meta: {
|
|
123
|
+
name: "login",
|
|
124
|
+
description: "Connect your CLI to the Pew dashboard via browser OAuth",
|
|
125
|
+
},
|
|
126
|
+
args: {
|
|
127
|
+
force: {
|
|
128
|
+
type: "boolean",
|
|
129
|
+
description: "Force re-login even if already authenticated",
|
|
130
|
+
default: false,
|
|
131
|
+
},
|
|
132
|
+
dev: {
|
|
133
|
+
type: "boolean",
|
|
134
|
+
description: "Use the dev host (pew.dev.hexly.ai)",
|
|
135
|
+
default: false,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
async run({ args }) {
|
|
139
|
+
const paths = resolveDefaultPaths();
|
|
140
|
+
const dev = isDevMode();
|
|
141
|
+
const host = resolveHost(dev);
|
|
142
|
+
const { exec } = await import("node:child_process");
|
|
143
|
+
consola.start("Opening browser for authentication...\n");
|
|
144
|
+
const result = await executeLogin({
|
|
145
|
+
configDir: paths.stateDir,
|
|
146
|
+
apiUrl: host,
|
|
147
|
+
dev,
|
|
148
|
+
force: args.force,
|
|
149
|
+
openBrowser: async (url) => {
|
|
150
|
+
const cmd = process.platform === "darwin"
|
|
151
|
+
? "open"
|
|
152
|
+
: process.platform === "win32"
|
|
153
|
+
? "start"
|
|
154
|
+
: "xdg-open";
|
|
155
|
+
exec(`${cmd} "${url}"`);
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
if (result.alreadyLoggedIn) {
|
|
159
|
+
consola.info(`Already logged in. Use ${pc.cyan("pew login --force")} to re-authenticate.`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (result.success) {
|
|
163
|
+
consola.success(`Logged in as ${pc.bold(result.email ?? "unknown")}`);
|
|
164
|
+
consola.info(`Token saved to ${pc.dim(paths.stateDir + (dev ? "/config.dev.json" : "/config.json"))}`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
consola.error(`Login failed: ${result.error}`);
|
|
168
|
+
process.exitCode = 1;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// Upload helper (used by `sync --upload`)
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
async function runUpload(stateDir, apiUrl, dev) {
|
|
176
|
+
consola.log("");
|
|
177
|
+
consola.start("Uploading to dashboard...");
|
|
178
|
+
const uploadResult = await executeUpload({
|
|
179
|
+
stateDir,
|
|
180
|
+
apiUrl,
|
|
181
|
+
dev,
|
|
182
|
+
fetch: globalThis.fetch,
|
|
183
|
+
onProgress(event) {
|
|
184
|
+
if (event.phase === "uploading") {
|
|
185
|
+
consola.info(` ${pc.dim(`Batch ${event.batch}/${event.totalBatches}`)} (${event.message})`);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
if (!uploadResult.success && uploadResult.error?.match(/not logged in/i)) {
|
|
190
|
+
consola.info(`Not logged in — skipping upload. Run ${pc.cyan("pew login")} to enable.`);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (uploadResult.success) {
|
|
194
|
+
if (uploadResult.uploaded === 0) {
|
|
195
|
+
consola.info("No pending records to upload.");
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
consola.success(`Uploaded ${pc.bold(String(uploadResult.uploaded))} records in ${uploadResult.batches} batch(es).`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
consola.error(`Upload failed: ${uploadResult.error}`);
|
|
203
|
+
if (uploadResult.uploaded > 0) {
|
|
204
|
+
consola.info(` ${pc.yellow(String(uploadResult.uploaded))} records uploaded before failure.`);
|
|
205
|
+
}
|
|
206
|
+
process.exitCode = 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
export const main = defineCommand({
|
|
210
|
+
meta: {
|
|
211
|
+
name: "pew",
|
|
212
|
+
version: "0.2.0",
|
|
213
|
+
description: "Track token usage from your local AI coding tools",
|
|
214
|
+
},
|
|
215
|
+
subCommands: {
|
|
216
|
+
sync: syncCommand,
|
|
217
|
+
status: statusCommand,
|
|
218
|
+
login: loginCommand,
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,8EAA8E;AAC9E,qCAAqC;AACrC,8EAA8E;AAE9E,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,+CAA+C;AAC/C,IAAI,SAAS,EAAE,EAAE,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,4BAA4B,GAAG,GAAG,CAAC;AACjD,CAAC;AAED,MAAM,WAAW,GAAG,aAAa,CAAC;IAChC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,mDAAmD;KACjE;IACD,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,gEAAgE;YAC7E,OAAO,EAAE,IAAI;SACd;QACD,GAAG,EAAE;YACH,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,qCAAqC;YAClD,OAAO,EAAE,KAAK;SACf;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAE/D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;YAC5C,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,UAAU,CAAC,KAAK;gBACd,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC5D,4CAA4C;oBAC5C,IACE,KAAK,CAAC,KAAK,IAAI,EAAE;wBACjB,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,KAAK;wBAC7B,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,EAChD,CAAC;wBACD,OAAO,CAAC,IAAI,CACV,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,QAAQ,CACnE,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,UAAU;QACV,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,IAAI,MAAM,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,OAAO,CACb,UAAU,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,gBAAgB,CACnH,CAAC;YACF,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YACnF,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YACnF,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACzF,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACzF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,MAAM,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC;QAC/B,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,IAAI,EAAE,CAAC,QAAQ,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChE,IAAI,EAAE,CAAC,QAAQ,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,2BAA2B;QAC3B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;YACxB,MAAM,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,aAAa,CAAC;IAClC,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,kDAAkD;KAChE;IACD,KAAK,CAAC,GAAG;QACP,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEjE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CACT,sBAAsB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CACtF,CAAC;QACF,OAAO,CAAC,GAAG,CACT,sBAAsB,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CACnH,CAAC;QAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC3C,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7D,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,aAAa,CAAC;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,yDAAyD;KACvE;IACD,IAAI,EAAE;QACJ,KAAK,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,8CAA8C;YAC3D,OAAO,EAAE,KAAK;SACf;QACD,GAAG,EAAE;YACH,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,qCAAqC;YAClD,OAAO,EAAE,KAAK;SACf;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAEpD,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAEzD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;YAChC,SAAS,EAAE,KAAK,CAAC,QAAQ;YACzB,MAAM,EAAE,IAAI;YACZ,GAAG;YACH,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACzB,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,QAAQ;oBAC3B,CAAC,CAAC,MAAM;oBACR,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;wBAC5B,CAAC,CAAC,OAAO;wBACT,CAAC,CAAC,UAAU,CAAC;gBACnB,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;YAC1B,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CACV,0BAA0B,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,sBAAsB,CAC7E,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,OAAO,CACb,gBAAgB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,EAAE,CACrD,CAAC;YACF,OAAO,CAAC,IAAI,CACV,kBAAkB,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE,CACzF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,iBAAiB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,8EAA8E;AAC9E,0CAA0C;AAC1C,8EAA8E;AAE9E,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,MAAc,EAAE,GAAY;IACrE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAE3C,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC;QACvC,QAAQ;QACR,MAAM;QACN,GAAG;QACH,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,UAAU,CAAC,KAAK;YACd,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CACV,KAAK,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAC/E,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACzE,OAAO,CAAC,IAAI,CACV,wCAAwC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,CAC1E,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;QACzB,IAAI,YAAY,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,OAAO,CACb,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,eAAe,YAAY,CAAC,OAAO,aAAa,CACnG,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,kBAAkB,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;QACtD,IAAI,YAAY,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CACV,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,mCAAmC,CACjF,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,aAAa,CAAC;IAChC,IAAI,EAAE;QACJ,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,mDAAmD;KACjE;IACD,WAAW,EAAE;QACX,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,aAAa;QACrB,KAAK,EAAE,YAAY;KACpB;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI login command — browser-based OAuth flow.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Start local HTTP server on random port
|
|
6
|
+
* 2. Open browser to SaaS auth endpoint with callback URL
|
|
7
|
+
* 3. SaaS authenticates user (Google OAuth) and redirects back with api_key
|
|
8
|
+
* 4. Save api_key to ~/.config/pew/config.json
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_HOST = "https://pew.md";
|
|
11
|
+
export declare const DEV_HOST = "https://pew.dev.hexly.ai";
|
|
12
|
+
export declare function resolveHost(dev: boolean): string;
|
|
13
|
+
export interface LoginOptions {
|
|
14
|
+
/** Directory for config file */
|
|
15
|
+
configDir: string;
|
|
16
|
+
/** Base URL of the Pew SaaS */
|
|
17
|
+
apiUrl: string;
|
|
18
|
+
/** Whether dev mode is active (uses config.dev.json) */
|
|
19
|
+
dev?: boolean;
|
|
20
|
+
/** Timeout in milliseconds (default: 120000) */
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
/** Force re-login even if already authenticated */
|
|
23
|
+
force?: boolean;
|
|
24
|
+
/** Injected browser opener (for testing) */
|
|
25
|
+
openBrowser: (url: string) => Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export interface LoginResult {
|
|
28
|
+
success: boolean;
|
|
29
|
+
email?: string;
|
|
30
|
+
alreadyLoggedIn?: boolean;
|
|
31
|
+
error?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function executeLogin(options: LoginOptions): Promise<LoginResult>;
|
|
34
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAC7C,eAAO,MAAM,QAAQ,6BAA6B,CAAC;AAEnD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAEhD;AAMD,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4CAA4C;IAC5C,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA6F9E"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI login command — browser-based OAuth flow.
|
|
3
|
+
*
|
|
4
|
+
* Flow:
|
|
5
|
+
* 1. Start local HTTP server on random port
|
|
6
|
+
* 2. Open browser to SaaS auth endpoint with callback URL
|
|
7
|
+
* 3. SaaS authenticates user (Google OAuth) and redirects back with api_key
|
|
8
|
+
* 4. Save api_key to ~/.config/pew/config.json
|
|
9
|
+
*/
|
|
10
|
+
import { createServer } from "node:http";
|
|
11
|
+
import { ConfigManager } from "../config/manager.js";
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Host constants
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export const DEFAULT_HOST = "https://pew.md";
|
|
16
|
+
export const DEV_HOST = "https://pew.dev.hexly.ai";
|
|
17
|
+
export function resolveHost(dev) {
|
|
18
|
+
return dev ? DEV_HOST : DEFAULT_HOST;
|
|
19
|
+
}
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Implementation
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
export async function executeLogin(options) {
|
|
24
|
+
const { configDir, apiUrl, dev = false, timeoutMs = 120_000, force = false, openBrowser, } = options;
|
|
25
|
+
const configManager = new ConfigManager(configDir, dev);
|
|
26
|
+
// 1. Check existing login
|
|
27
|
+
if (!force) {
|
|
28
|
+
const existing = await configManager.load();
|
|
29
|
+
if (existing.token) {
|
|
30
|
+
return { success: true, alreadyLoggedIn: true };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// 2. Start local callback server using Node http
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
let settled = false;
|
|
36
|
+
let timeoutHandle;
|
|
37
|
+
const server = createServer(async (req, res) => {
|
|
38
|
+
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
39
|
+
if (url.pathname === "/callback") {
|
|
40
|
+
const apiKey = url.searchParams.get("api_key");
|
|
41
|
+
const email = url.searchParams.get("email") ?? undefined;
|
|
42
|
+
if (!apiKey) {
|
|
43
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
44
|
+
res.end(htmlPage("Login Failed", "No API key was received. Please try again."));
|
|
45
|
+
settle({
|
|
46
|
+
success: false,
|
|
47
|
+
error: "No api_key received in callback",
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Save to config
|
|
52
|
+
await configManager.save({ token: apiKey });
|
|
53
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
54
|
+
res.end(htmlPage("Login Successful!", `Logged in as ${email ?? "unknown"}. You can close this tab.`));
|
|
55
|
+
settle({ success: true, email });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
res.writeHead(404);
|
|
59
|
+
res.end("Not Found");
|
|
60
|
+
});
|
|
61
|
+
function settle(result) {
|
|
62
|
+
if (settled)
|
|
63
|
+
return;
|
|
64
|
+
settled = true;
|
|
65
|
+
clearTimeout(timeoutHandle);
|
|
66
|
+
server.close();
|
|
67
|
+
resolve(result);
|
|
68
|
+
}
|
|
69
|
+
// Listen on port 0 for random available port
|
|
70
|
+
server.listen(0, () => {
|
|
71
|
+
const addr = server.address();
|
|
72
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
73
|
+
const callbackUrl = `http://localhost:${port}/callback`;
|
|
74
|
+
const loginUrl = `${apiUrl}/api/auth/cli?callback=${encodeURIComponent(callbackUrl)}`;
|
|
75
|
+
// 3. Set timeout
|
|
76
|
+
timeoutHandle = setTimeout(() => {
|
|
77
|
+
settle({
|
|
78
|
+
success: false,
|
|
79
|
+
error: `Login timeout after ${timeoutMs / 1000}s — no callback received`,
|
|
80
|
+
});
|
|
81
|
+
}, timeoutMs);
|
|
82
|
+
// 4. Open browser
|
|
83
|
+
openBrowser(loginUrl).catch((err) => {
|
|
84
|
+
settle({
|
|
85
|
+
success: false,
|
|
86
|
+
error: `Failed to open browser: ${String(err)}`,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function htmlPage(title, message) {
|
|
93
|
+
return `<!DOCTYPE html>
|
|
94
|
+
<html>
|
|
95
|
+
<head><title>Pew — ${title}</title>
|
|
96
|
+
<style>
|
|
97
|
+
body { font-family: -apple-system, sans-serif; text-align: center; padding: 60px 20px; background: #0a0a0a; color: #fafafa; }
|
|
98
|
+
h1 { font-size: 2rem; margin-bottom: 1rem; }
|
|
99
|
+
p { color: #888; font-size: 1.1rem; }
|
|
100
|
+
</style>
|
|
101
|
+
</head>
|
|
102
|
+
<body>
|
|
103
|
+
<h1>${title}</h1>
|
|
104
|
+
<p>${message}</p>
|
|
105
|
+
</body>
|
|
106
|
+
</html>`;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Status summary for display */
|
|
2
|
+
export interface StatusResult {
|
|
3
|
+
/** Number of tracked files */
|
|
4
|
+
trackedFiles: number;
|
|
5
|
+
/** Last sync timestamp (ISO) or null */
|
|
6
|
+
lastSync: string | null;
|
|
7
|
+
/** Number of unuploaded records in queue */
|
|
8
|
+
pendingRecords: number;
|
|
9
|
+
/** Breakdown by source */
|
|
10
|
+
sources: Record<string, number>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compute the current sync status.
|
|
14
|
+
* Pure logic — no CLI I/O.
|
|
15
|
+
*/
|
|
16
|
+
export declare function executeStatus(opts: {
|
|
17
|
+
stateDir: string;
|
|
18
|
+
}): Promise<StatusResult>;
|
|
19
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAKA,iCAAiC;AACjC,MAAM,WAAW,YAAY;IAC3B,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4CAA4C;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,YAAY,CAAC,CA4BxB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CursorStore } from "../storage/cursor-store.js";
|
|
2
|
+
import { LocalQueue } from "../storage/local-queue.js";
|
|
3
|
+
/**
|
|
4
|
+
* Compute the current sync status.
|
|
5
|
+
* Pure logic — no CLI I/O.
|
|
6
|
+
*/
|
|
7
|
+
export async function executeStatus(opts) {
|
|
8
|
+
const { stateDir } = opts;
|
|
9
|
+
const cursorStore = new CursorStore(stateDir);
|
|
10
|
+
const queue = new LocalQueue(stateDir);
|
|
11
|
+
const cursors = await cursorStore.load();
|
|
12
|
+
const offset = await queue.loadOffset();
|
|
13
|
+
const { records } = await queue.readFromOffset(offset);
|
|
14
|
+
// Count files by source based on path patterns
|
|
15
|
+
const sources = {};
|
|
16
|
+
for (const filePath of Object.keys(cursors.files)) {
|
|
17
|
+
let source = "unknown";
|
|
18
|
+
if (filePath.includes(".claude"))
|
|
19
|
+
source = "claude-code";
|
|
20
|
+
else if (filePath.includes(".gemini"))
|
|
21
|
+
source = "gemini-cli";
|
|
22
|
+
else if (filePath.includes("opencode"))
|
|
23
|
+
source = "opencode";
|
|
24
|
+
else if (filePath.includes(".openclaw"))
|
|
25
|
+
source = "openclaw";
|
|
26
|
+
sources[source] = (sources[source] || 0) + 1;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
trackedFiles: Object.keys(cursors.files).length,
|
|
30
|
+
lastSync: cursors.updatedAt,
|
|
31
|
+
pendingRecords: records.length,
|
|
32
|
+
sources,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAevD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAEnC;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE1B,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;IACxC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvD,+CAA+C;IAC/C,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,IAAI,MAAM,GAAG,SAAS,CAAC;QACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,MAAM,GAAG,aAAa,CAAC;aACpD,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,MAAM,GAAG,YAAY,CAAC;aACxD,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,MAAM,GAAG,UAAU,CAAC;aACvD,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,MAAM,GAAG,UAAU,CAAC;QAE7D,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO;QACL,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM;QAC/C,QAAQ,EAAE,OAAO,CAAC,SAAS;QAC3B,cAAc,EAAE,OAAO,CAAC,MAAM;QAC9B,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Sync execution options */
|
|
2
|
+
export interface SyncOptions {
|
|
3
|
+
/** Directory for persisting state (cursors, queue) */
|
|
4
|
+
stateDir: string;
|
|
5
|
+
/** Override: Claude data directory (~/.claude) */
|
|
6
|
+
claudeDir?: string;
|
|
7
|
+
/** Override: Gemini data directory (~/.gemini) */
|
|
8
|
+
geminiDir?: string;
|
|
9
|
+
/** Override: OpenCode message directory (~/.local/share/opencode/storage/message) */
|
|
10
|
+
openCodeMessageDir?: string;
|
|
11
|
+
/** Override: OpenClaw data directory (~/.openclaw) */
|
|
12
|
+
openclawDir?: string;
|
|
13
|
+
/** Progress callback */
|
|
14
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Progress event for UI display */
|
|
17
|
+
export interface ProgressEvent {
|
|
18
|
+
source: string;
|
|
19
|
+
phase: "discover" | "parse" | "aggregate" | "done";
|
|
20
|
+
current?: number;
|
|
21
|
+
total?: number;
|
|
22
|
+
message?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Result of a sync execution */
|
|
25
|
+
export interface SyncResult {
|
|
26
|
+
totalDeltas: number;
|
|
27
|
+
totalRecords: number;
|
|
28
|
+
sources: {
|
|
29
|
+
claude: number;
|
|
30
|
+
gemini: number;
|
|
31
|
+
opencode: number;
|
|
32
|
+
openclaw: number;
|
|
33
|
+
};
|
|
34
|
+
/** Total files scanned per source */
|
|
35
|
+
filesScanned: {
|
|
36
|
+
claude: number;
|
|
37
|
+
gemini: number;
|
|
38
|
+
opencode: number;
|
|
39
|
+
openclaw: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Execute the sync operation: discover files, parse incrementally,
|
|
44
|
+
* aggregate into half-hour buckets, and write to local queue.
|
|
45
|
+
*
|
|
46
|
+
* Pure logic — no CLI I/O. Receives all dependencies via options.
|
|
47
|
+
*/
|
|
48
|
+
export declare function executeSync(opts: SyncOptions): Promise<SyncResult>;
|
|
49
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AA0BA,6BAA6B;AAC7B,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC7C;AAED,oCAAoC;AACpC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,iCAAiC;AACjC,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,qCAAqC;IACrC,YAAY,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAUD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA2SxE"}
|