opencode-sync-plugin 0.2.7 → 0.2.8
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/README.md +3 -1
- package/dist/chunk-6K7TIEXR.js +81 -0
- package/dist/cli.js +87 -20
- package/dist/config.d.ts +4 -1
- package/dist/config.js +7 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-JPPDGYOB.js +0 -43
package/README.md
CHANGED
|
@@ -117,7 +117,9 @@ Data is stored in your Convex deployment. You can view, search, and share sessio
|
|
|
117
117
|
| `opencode-sync login` | Configure with Convex URL and API Key |
|
|
118
118
|
| `opencode-sync verify` | Verify credentials and OpenCode config |
|
|
119
119
|
| `opencode-sync sync` | Test connectivity and create a test session |
|
|
120
|
-
| `opencode-sync sync --
|
|
120
|
+
| `opencode-sync sync --new` | Sync only new sessions (uses local tracking) |
|
|
121
|
+
| `opencode-sync sync --all` | Sync all sessions (queries backend, skips existing) |
|
|
122
|
+
| `opencode-sync sync --force` | Clear tracking and resync all sessions |
|
|
121
123
|
| `opencode-sync logout` | Clear stored credentials |
|
|
122
124
|
| `opencode-sync status` | Show authentication status |
|
|
123
125
|
| `opencode-sync config` | Show current configuration |
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
var CONFIG_DIR = join(homedir(), ".opensync");
|
|
6
|
+
var CONFIG_FILE = join(CONFIG_DIR, "credentials.json");
|
|
7
|
+
var SYNCED_SESSIONS_FILE = join(CONFIG_DIR, "synced-sessions.json");
|
|
8
|
+
function getConfig() {
|
|
9
|
+
try {
|
|
10
|
+
if (!existsSync(CONFIG_FILE)) return null;
|
|
11
|
+
const content = readFileSync(CONFIG_FILE, "utf8");
|
|
12
|
+
const config = JSON.parse(content);
|
|
13
|
+
if (!config || !config.convexUrl) return null;
|
|
14
|
+
return config;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.error("Error reading config:", e);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function setConfig(cfg) {
|
|
21
|
+
try {
|
|
22
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
23
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), "utf8");
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.error("Error saving config:", e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function clearConfig() {
|
|
31
|
+
try {
|
|
32
|
+
if (existsSync(CONFIG_FILE)) {
|
|
33
|
+
writeFileSync(CONFIG_FILE, "{}", "utf8");
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.error("Error clearing config:", e);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getSyncedSessions() {
|
|
40
|
+
try {
|
|
41
|
+
if (!existsSync(SYNCED_SESSIONS_FILE)) return /* @__PURE__ */ new Set();
|
|
42
|
+
const content = readFileSync(SYNCED_SESSIONS_FILE, "utf8");
|
|
43
|
+
const data = JSON.parse(content);
|
|
44
|
+
return new Set(Array.isArray(data.sessionIds) ? data.sessionIds : []);
|
|
45
|
+
} catch {
|
|
46
|
+
return /* @__PURE__ */ new Set();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function addSyncedSessions(sessionIds) {
|
|
50
|
+
try {
|
|
51
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
52
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
const existing = getSyncedSessions();
|
|
55
|
+
for (const id of sessionIds) {
|
|
56
|
+
existing.add(id);
|
|
57
|
+
}
|
|
58
|
+
const data = { sessionIds: Array.from(existing), lastUpdated: Date.now() };
|
|
59
|
+
writeFileSync(SYNCED_SESSIONS_FILE, JSON.stringify(data, null, 2), "utf8");
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error("Error saving synced sessions:", e);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function clearSyncedSessions() {
|
|
65
|
+
try {
|
|
66
|
+
if (existsSync(SYNCED_SESSIONS_FILE)) {
|
|
67
|
+
writeFileSync(SYNCED_SESSIONS_FILE, JSON.stringify({ sessionIds: [], lastUpdated: Date.now() }), "utf8");
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
console.error("Error clearing synced sessions:", e);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
getConfig,
|
|
76
|
+
setConfig,
|
|
77
|
+
clearConfig,
|
|
78
|
+
getSyncedSessions,
|
|
79
|
+
addSyncedSessions,
|
|
80
|
+
clearSyncedSessions
|
|
81
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
addSyncedSessions,
|
|
3
4
|
clearConfig,
|
|
5
|
+
clearSyncedSessions,
|
|
4
6
|
getConfig,
|
|
7
|
+
getSyncedSessions,
|
|
5
8
|
setConfig
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6K7TIEXR.js";
|
|
7
10
|
|
|
8
11
|
// src/cli.ts
|
|
9
12
|
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
@@ -204,6 +207,8 @@ function showConfig() {
|
|
|
204
207
|
}
|
|
205
208
|
async function sync() {
|
|
206
209
|
const syncAll = args.includes("--all");
|
|
210
|
+
const syncNew = args.includes("--new");
|
|
211
|
+
const syncForce = args.includes("--force");
|
|
207
212
|
const config = getConfig();
|
|
208
213
|
if (!config || !config.apiKey || !config.convexUrl) {
|
|
209
214
|
console.log("\n Status: Not configured\n");
|
|
@@ -211,8 +216,13 @@ async function sync() {
|
|
|
211
216
|
return;
|
|
212
217
|
}
|
|
213
218
|
const siteUrl = config.convexUrl.replace(".convex.cloud", ".convex.site");
|
|
214
|
-
if (
|
|
215
|
-
|
|
219
|
+
if (syncForce) {
|
|
220
|
+
clearSyncedSessions();
|
|
221
|
+
await syncAllSessions(siteUrl, config.apiKey, "force");
|
|
222
|
+
} else if (syncAll) {
|
|
223
|
+
await syncAllSessions(siteUrl, config.apiKey, "all");
|
|
224
|
+
} else if (syncNew) {
|
|
225
|
+
await syncAllSessions(siteUrl, config.apiKey, "new");
|
|
216
226
|
} else {
|
|
217
227
|
await syncConnectivityTest(siteUrl, config.apiKey);
|
|
218
228
|
}
|
|
@@ -277,8 +287,27 @@ async function syncConnectivityTest(siteUrl, apiKey) {
|
|
|
277
287
|
console.log();
|
|
278
288
|
}
|
|
279
289
|
}
|
|
280
|
-
async function
|
|
281
|
-
|
|
290
|
+
async function fetchBackendSessionIds(siteUrl, apiKey) {
|
|
291
|
+
try {
|
|
292
|
+
const res = await fetch(`${siteUrl}/sync/sessions/list`, {
|
|
293
|
+
method: "GET",
|
|
294
|
+
headers: {
|
|
295
|
+
Authorization: `Bearer ${apiKey}`
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
if (res.ok) {
|
|
299
|
+
const data = await res.json();
|
|
300
|
+
return new Set(Array.isArray(data.sessionIds) ? data.sessionIds : []);
|
|
301
|
+
}
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
return /* @__PURE__ */ new Set();
|
|
305
|
+
}
|
|
306
|
+
async function syncAllSessions(siteUrl, apiKey, mode) {
|
|
307
|
+
const modeLabel = mode === "force" ? "Force Syncing" : mode === "new" ? "Syncing New" : "Syncing All";
|
|
308
|
+
console.log(`
|
|
309
|
+
OpenSync: ${modeLabel} Local Sessions
|
|
310
|
+
`);
|
|
282
311
|
const opencodePath = join(homedir(), ".local", "share", "opencode", "storage");
|
|
283
312
|
const sessionPath = join(opencodePath, "session");
|
|
284
313
|
const messagePath = join(opencodePath, "message");
|
|
@@ -309,15 +338,39 @@ async function syncAllSessions(siteUrl, apiKey) {
|
|
|
309
338
|
console.log(" Error reading sessions:", e instanceof Error ? e.message : String(e));
|
|
310
339
|
return;
|
|
311
340
|
}
|
|
312
|
-
console.log(` Found ${sessions.length} sessions
|
|
313
|
-
`);
|
|
341
|
+
console.log(` Found ${sessions.length} local sessions`);
|
|
314
342
|
if (sessions.length === 0) {
|
|
315
343
|
return;
|
|
316
344
|
}
|
|
317
|
-
let
|
|
345
|
+
let alreadySynced = /* @__PURE__ */ new Set();
|
|
346
|
+
if (mode === "all") {
|
|
347
|
+
console.log(" Checking backend for existing sessions...");
|
|
348
|
+
alreadySynced = await fetchBackendSessionIds(siteUrl, apiKey);
|
|
349
|
+
if (alreadySynced.size > 0) {
|
|
350
|
+
console.log(` Found ${alreadySynced.size} already synced on backend`);
|
|
351
|
+
}
|
|
352
|
+
} else if (mode === "new") {
|
|
353
|
+
alreadySynced = getSyncedSessions();
|
|
354
|
+
if (alreadySynced.size > 0) {
|
|
355
|
+
console.log(` Found ${alreadySynced.size} in local tracking file`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const sessionsToSync = sessions.filter((s) => !alreadySynced.has(s.data.id));
|
|
359
|
+
const skippedCount = sessions.length - sessionsToSync.length;
|
|
360
|
+
if (skippedCount > 0) {
|
|
361
|
+
console.log(` Skipping ${skippedCount} already synced sessions`);
|
|
362
|
+
}
|
|
363
|
+
console.log(` Will sync ${sessionsToSync.length} sessions
|
|
364
|
+
`);
|
|
365
|
+
if (sessionsToSync.length === 0) {
|
|
366
|
+
console.log(" All sessions already synced. Use --force to resync.\n");
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
let syncedSessionCount = 0;
|
|
318
370
|
let syncedMessages = 0;
|
|
319
371
|
let failedSessions = 0;
|
|
320
|
-
|
|
372
|
+
const newlySyncedIds = [];
|
|
373
|
+
for (const session of sessionsToSync) {
|
|
321
374
|
const { data } = session;
|
|
322
375
|
process.stdout.write(` Syncing: ${data.title || data.slug || data.id}... `);
|
|
323
376
|
let totalPromptTokens = 0;
|
|
@@ -380,7 +433,8 @@ async function syncAllSessions(siteUrl, apiKey) {
|
|
|
380
433
|
failedSessions++;
|
|
381
434
|
continue;
|
|
382
435
|
}
|
|
383
|
-
|
|
436
|
+
syncedSessionCount++;
|
|
437
|
+
newlySyncedIds.push(data.id);
|
|
384
438
|
let msgCount = 0;
|
|
385
439
|
for (const msg of messages) {
|
|
386
440
|
try {
|
|
@@ -415,10 +469,16 @@ async function syncAllSessions(siteUrl, apiKey) {
|
|
|
415
469
|
failedSessions++;
|
|
416
470
|
}
|
|
417
471
|
}
|
|
472
|
+
if (newlySyncedIds.length > 0) {
|
|
473
|
+
addSyncedSessions(newlySyncedIds);
|
|
474
|
+
}
|
|
418
475
|
console.log();
|
|
419
476
|
console.log(` Summary:`);
|
|
420
|
-
console.log(` Sessions synced: ${
|
|
477
|
+
console.log(` Sessions synced: ${syncedSessionCount}`);
|
|
421
478
|
console.log(` Messages synced: ${syncedMessages}`);
|
|
479
|
+
if (skippedCount > 0) {
|
|
480
|
+
console.log(` Skipped: ${skippedCount}`);
|
|
481
|
+
}
|
|
422
482
|
if (failedSessions > 0) {
|
|
423
483
|
console.log(` Failed: ${failedSessions}`);
|
|
424
484
|
}
|
|
@@ -433,14 +493,16 @@ function help() {
|
|
|
433
493
|
Usage: opencode-sync <command> [options]
|
|
434
494
|
|
|
435
495
|
Commands:
|
|
436
|
-
login
|
|
437
|
-
verify
|
|
438
|
-
sync
|
|
439
|
-
sync --
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
496
|
+
login Configure with Convex URL and API Key
|
|
497
|
+
verify Verify credentials and OpenCode config
|
|
498
|
+
sync Test connectivity and create a test session
|
|
499
|
+
sync --new Sync only sessions not in local tracking file
|
|
500
|
+
sync --all Sync all sessions (checks backend, skips existing)
|
|
501
|
+
sync --force Clear tracking and resync all sessions
|
|
502
|
+
logout Clear stored credentials
|
|
503
|
+
status Show current authentication status
|
|
504
|
+
config Show current configuration
|
|
505
|
+
version Show version number
|
|
444
506
|
help Show this help message
|
|
445
507
|
|
|
446
508
|
Setup:
|
|
@@ -451,7 +513,12 @@ function help() {
|
|
|
451
513
|
5. Add plugin to opencode.json (see instructions after login)
|
|
452
514
|
6. Run: opencode-sync verify
|
|
453
515
|
7. Run: opencode-sync sync (to test connectivity)
|
|
454
|
-
8. Run: opencode-sync sync --
|
|
516
|
+
8. Run: opencode-sync sync --new (to sync new sessions only)
|
|
517
|
+
|
|
518
|
+
Sync Modes:
|
|
519
|
+
--new Fast: uses local tracking, skips previously synced
|
|
520
|
+
--all Accurate: queries backend, skips existing on server
|
|
521
|
+
--force Full: clears tracking and resyncs everything
|
|
455
522
|
`);
|
|
456
523
|
}
|
|
457
524
|
function prompt(question) {
|
package/dist/config.d.ts
CHANGED
|
@@ -5,5 +5,8 @@ interface Config {
|
|
|
5
5
|
declare function getConfig(): Config | null;
|
|
6
6
|
declare function setConfig(cfg: Config): void;
|
|
7
7
|
declare function clearConfig(): void;
|
|
8
|
+
declare function getSyncedSessions(): Set<string>;
|
|
9
|
+
declare function addSyncedSessions(sessionIds: string[]): void;
|
|
10
|
+
declare function clearSyncedSessions(): void;
|
|
8
11
|
|
|
9
|
-
export { clearConfig, getConfig, setConfig };
|
|
12
|
+
export { addSyncedSessions, clearConfig, clearSyncedSessions, getConfig, getSyncedSessions, setConfig };
|
package/dist/config.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
addSyncedSessions,
|
|
2
3
|
clearConfig,
|
|
4
|
+
clearSyncedSessions,
|
|
3
5
|
getConfig,
|
|
6
|
+
getSyncedSessions,
|
|
4
7
|
setConfig
|
|
5
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6K7TIEXR.js";
|
|
6
9
|
export {
|
|
10
|
+
addSyncedSessions,
|
|
7
11
|
clearConfig,
|
|
12
|
+
clearSyncedSessions,
|
|
8
13
|
getConfig,
|
|
14
|
+
getSyncedSessions,
|
|
9
15
|
setConfig
|
|
10
16
|
};
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
package/dist/chunk-JPPDGYOB.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// src/config.ts
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
3
|
-
import { homedir } from "os";
|
|
4
|
-
import { join } from "path";
|
|
5
|
-
var CONFIG_DIR = join(homedir(), ".opensync");
|
|
6
|
-
var CONFIG_FILE = join(CONFIG_DIR, "credentials.json");
|
|
7
|
-
function getConfig() {
|
|
8
|
-
try {
|
|
9
|
-
if (!existsSync(CONFIG_FILE)) return null;
|
|
10
|
-
const content = readFileSync(CONFIG_FILE, "utf8");
|
|
11
|
-
const config = JSON.parse(content);
|
|
12
|
-
if (!config || !config.convexUrl) return null;
|
|
13
|
-
return config;
|
|
14
|
-
} catch (e) {
|
|
15
|
-
console.error("Error reading config:", e);
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function setConfig(cfg) {
|
|
20
|
-
try {
|
|
21
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
22
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
23
|
-
}
|
|
24
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), "utf8");
|
|
25
|
-
} catch (e) {
|
|
26
|
-
console.error("Error saving config:", e);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function clearConfig() {
|
|
30
|
-
try {
|
|
31
|
-
if (existsSync(CONFIG_FILE)) {
|
|
32
|
-
writeFileSync(CONFIG_FILE, "{}", "utf8");
|
|
33
|
-
}
|
|
34
|
-
} catch (e) {
|
|
35
|
-
console.error("Error clearing config:", e);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
getConfig,
|
|
41
|
-
setConfig,
|
|
42
|
-
clearConfig
|
|
43
|
-
};
|