opencode-sync-plugin 0.2.7 → 0.2.9

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 CHANGED
@@ -117,10 +117,14 @@ 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 --all` | Sync all local OpenCode sessions to the cloud |
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 |
126
+ | `opencode-sync version` | Show installed version |
127
+ | `opencode-sync help` | Show help message |
124
128
 
125
129
  ## Configuration storage
126
130
 
@@ -0,0 +1,99 @@
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 isLoggingEnabled() {
40
+ const config = getConfig();
41
+ return config?.logging === true;
42
+ }
43
+ function setLogging(enabled) {
44
+ const config = getConfig();
45
+ if (config) {
46
+ setConfig({ ...config, logging: enabled });
47
+ } else {
48
+ console.error("No config found. Please run 'opencode-sync login' first.");
49
+ }
50
+ }
51
+ function getSyncedSessions() {
52
+ try {
53
+ if (!existsSync(SYNCED_SESSIONS_FILE)) return /* @__PURE__ */ new Set();
54
+ const content = readFileSync(SYNCED_SESSIONS_FILE, "utf8");
55
+ const data = JSON.parse(content);
56
+ return new Set(Array.isArray(data.sessionIds) ? data.sessionIds : []);
57
+ } catch {
58
+ return /* @__PURE__ */ new Set();
59
+ }
60
+ }
61
+ function addSyncedSessions(sessionIds) {
62
+ try {
63
+ if (!existsSync(CONFIG_DIR)) {
64
+ mkdirSync(CONFIG_DIR, { recursive: true });
65
+ }
66
+ const existing = getSyncedSessions();
67
+ for (const id of sessionIds) {
68
+ existing.add(id);
69
+ }
70
+ const data = { sessionIds: Array.from(existing), lastUpdated: Date.now() };
71
+ writeFileSync(SYNCED_SESSIONS_FILE, JSON.stringify(data, null, 2), "utf8");
72
+ } catch (e) {
73
+ console.error("Error saving synced sessions:", e);
74
+ }
75
+ }
76
+ function clearSyncedSessions() {
77
+ try {
78
+ if (existsSync(SYNCED_SESSIONS_FILE)) {
79
+ writeFileSync(
80
+ SYNCED_SESSIONS_FILE,
81
+ JSON.stringify({ sessionIds: [], lastUpdated: Date.now() }),
82
+ "utf8"
83
+ );
84
+ }
85
+ } catch (e) {
86
+ console.error("Error clearing synced sessions:", e);
87
+ }
88
+ }
89
+
90
+ export {
91
+ getConfig,
92
+ setConfig,
93
+ clearConfig,
94
+ isLoggingEnabled,
95
+ setLogging,
96
+ getSyncedSessions,
97
+ addSyncedSessions,
98
+ clearSyncedSessions
99
+ };
package/dist/cli.js CHANGED
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ addSyncedSessions,
3
4
  clearConfig,
5
+ clearSyncedSessions,
4
6
  getConfig,
5
- setConfig
6
- } from "./chunk-JPPDGYOB.js";
7
+ getSyncedSessions,
8
+ setConfig,
9
+ setLogging
10
+ } from "./chunk-FYT43SUA.js";
7
11
 
8
12
  // src/cli.ts
9
13
  import { readFileSync, existsSync, readdirSync } from "fs";
@@ -39,7 +43,7 @@ async function main() {
39
43
  status();
40
44
  break;
41
45
  case "config":
42
- showConfig();
46
+ handleConfig();
43
47
  break;
44
48
  case "sync":
45
49
  await sync();
@@ -60,16 +64,22 @@ async function main() {
60
64
  }
61
65
  async function login() {
62
66
  console.log("\n OpenSync Login\n");
63
- const convexUrl = await prompt("Convex URL (e.g., https://your-project.convex.cloud): ");
67
+ const convexUrl = await prompt(
68
+ "Convex URL (e.g., https://your-project.convex.cloud): "
69
+ );
64
70
  if (!convexUrl) {
65
71
  console.error("Convex URL is required");
66
72
  process.exit(1);
67
73
  }
68
74
  if (!convexUrl.includes(".convex.cloud") && !convexUrl.includes(".convex.site")) {
69
- console.error("Invalid Convex URL. Should end with .convex.cloud or .convex.site");
75
+ console.error(
76
+ "Invalid Convex URL. Should end with .convex.cloud or .convex.site"
77
+ );
70
78
  process.exit(1);
71
79
  }
72
- const apiKey = await prompt("API Key (from Settings page, starts with osk_): ");
80
+ const apiKey = await prompt(
81
+ "API Key (from Settings page, starts with osk_): "
82
+ );
73
83
  if (!apiKey) {
74
84
  console.error("API Key is required");
75
85
  process.exit(1);
@@ -99,8 +109,12 @@ async function login() {
99
109
  }' > ~/.config/opencode/opencode.json`);
100
110
  console.log("\n Then verify your setup:\n");
101
111
  console.log(" opencode-sync verify\n");
102
- console.log(" Note: If you have existing opencode.json settings, manually add");
103
- console.log(' "plugin": ["opencode-sync-plugin"] to preserve your config.\n');
112
+ console.log(
113
+ " Note: If you have existing opencode.json settings, manually add"
114
+ );
115
+ console.log(
116
+ ' "plugin": ["opencode-sync-plugin"] to preserve your config.\n'
117
+ );
104
118
  } catch (e) {
105
119
  console.error("\nFailed to connect to OpenSync backend.");
106
120
  console.error("Please verify your Convex URL is correct.");
@@ -122,10 +136,18 @@ function verify() {
122
136
  } else {
123
137
  console.log(" Credentials: OK");
124
138
  console.log(" Convex URL:", config.convexUrl);
125
- console.log(" API Key:", config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4));
139
+ console.log(
140
+ " API Key:",
141
+ config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4)
142
+ );
126
143
  console.log();
127
144
  }
128
- const opencodeConfigPath = join(homedir(), ".config", "opencode", "opencode.json");
145
+ const opencodeConfigPath = join(
146
+ homedir(),
147
+ ".config",
148
+ "opencode",
149
+ "opencode.json"
150
+ );
129
151
  const projectConfigPath = join(process.cwd(), "opencode.json");
130
152
  let configFound = false;
131
153
  let configPath = "";
@@ -166,9 +188,13 @@ function verify() {
166
188
  console.log();
167
189
  }
168
190
  if (hasErrors) {
169
- console.log(" Setup incomplete. Fix the issues above and run verify again.\n");
191
+ console.log(
192
+ " Setup incomplete. Fix the issues above and run verify again.\n"
193
+ );
170
194
  } else {
171
- console.log(" Ready! Start OpenCode and the plugin will load automatically.\n");
195
+ console.log(
196
+ " Ready! Start OpenCode and the plugin will load automatically.\n"
197
+ );
172
198
  }
173
199
  }
174
200
  function status() {
@@ -187,9 +213,30 @@ function status() {
187
213
  }
188
214
  console.log(" Status: Configured\n");
189
215
  console.log(" Convex URL:", config.convexUrl);
190
- console.log(" API Key:", config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4));
216
+ console.log(
217
+ " API Key:",
218
+ config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4)
219
+ );
191
220
  console.log();
192
221
  }
222
+ function handleConfig() {
223
+ const loggingArg = args.find((a) => a.startsWith("--logging="));
224
+ if (loggingArg) {
225
+ const value = loggingArg.split("=")[1]?.toLowerCase();
226
+ if (value === "true" || value === "1" || value === "on") {
227
+ setLogging(true);
228
+ console.log("\n Logging enabled.\n");
229
+ } else if (value === "false" || value === "0" || value === "off") {
230
+ setLogging(false);
231
+ console.log("\n Logging disabled.\n");
232
+ } else {
233
+ console.log("\n Invalid value for --logging. Use true or false.\n");
234
+ console.log(" Example: opencode-sync config --logging=true\n");
235
+ }
236
+ return;
237
+ }
238
+ showConfig();
239
+ }
193
240
  function showConfig() {
194
241
  const config = getConfig();
195
242
  console.log("\n OpenSync Config\n");
@@ -199,11 +246,43 @@ function showConfig() {
199
246
  return;
200
247
  }
201
248
  console.log(" Convex URL:", config.convexUrl);
202
- console.log(" API Key:", config.apiKey ? config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4) : "Not set");
249
+ console.log(
250
+ " API Key:",
251
+ config.apiKey ? config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4) : "Not set"
252
+ );
253
+ console.log(" Logging:", config.logging ? "enabled" : "disabled");
203
254
  console.log();
204
255
  }
256
+ function getMessageTextContent(partBasePath, messageId) {
257
+ const messagePartPath = join(partBasePath, messageId);
258
+ if (!existsSync(messagePartPath)) {
259
+ return "";
260
+ }
261
+ try {
262
+ const partFiles = readdirSync(messagePartPath).filter(
263
+ (f) => f.endsWith(".json")
264
+ );
265
+ let textContent = "";
266
+ for (const partFile of partFiles) {
267
+ try {
268
+ const partData = JSON.parse(
269
+ readFileSync(join(messagePartPath, partFile), "utf8")
270
+ );
271
+ if (partData.type === "text" && partData.text) {
272
+ textContent += partData.text;
273
+ }
274
+ } catch {
275
+ }
276
+ }
277
+ return textContent;
278
+ } catch {
279
+ return "";
280
+ }
281
+ }
205
282
  async function sync() {
206
283
  const syncAll = args.includes("--all");
284
+ const syncNew = args.includes("--new");
285
+ const syncForce = args.includes("--force");
207
286
  const config = getConfig();
208
287
  if (!config || !config.apiKey || !config.convexUrl) {
209
288
  console.log("\n Status: Not configured\n");
@@ -211,8 +290,13 @@ async function sync() {
211
290
  return;
212
291
  }
213
292
  const siteUrl = config.convexUrl.replace(".convex.cloud", ".convex.site");
214
- if (syncAll) {
215
- await syncAllSessions(siteUrl, config.apiKey);
293
+ if (syncForce) {
294
+ clearSyncedSessions();
295
+ await syncAllSessions(siteUrl, config.apiKey, "force");
296
+ } else if (syncAll) {
297
+ await syncAllSessions(siteUrl, config.apiKey, "all");
298
+ } else if (syncNew) {
299
+ await syncAllSessions(siteUrl, config.apiKey, "new");
216
300
  } else {
217
301
  await syncConnectivityTest(siteUrl, config.apiKey);
218
302
  }
@@ -277,11 +361,37 @@ async function syncConnectivityTest(siteUrl, apiKey) {
277
361
  console.log();
278
362
  }
279
363
  }
280
- async function syncAllSessions(siteUrl, apiKey) {
281
- console.log("\n OpenSync: Syncing All Local Sessions\n");
282
- const opencodePath = join(homedir(), ".local", "share", "opencode", "storage");
364
+ async function fetchBackendSessionIds(siteUrl, apiKey) {
365
+ try {
366
+ const res = await fetch(`${siteUrl}/sync/sessions/list`, {
367
+ method: "GET",
368
+ headers: {
369
+ Authorization: `Bearer ${apiKey}`
370
+ }
371
+ });
372
+ if (res.ok) {
373
+ const data = await res.json();
374
+ return new Set(Array.isArray(data.sessionIds) ? data.sessionIds : []);
375
+ }
376
+ } catch {
377
+ }
378
+ return /* @__PURE__ */ new Set();
379
+ }
380
+ async function syncAllSessions(siteUrl, apiKey, mode) {
381
+ const modeLabel = mode === "force" ? "Force Syncing" : mode === "new" ? "Syncing New" : "Syncing All";
382
+ console.log(`
383
+ OpenSync: ${modeLabel} Local Sessions
384
+ `);
385
+ const opencodePath = join(
386
+ homedir(),
387
+ ".local",
388
+ "share",
389
+ "opencode",
390
+ "storage"
391
+ );
283
392
  const sessionPath = join(opencodePath, "session");
284
393
  const messagePath = join(opencodePath, "message");
394
+ const partPath = join(opencodePath, "part");
285
395
  if (!existsSync(sessionPath)) {
286
396
  console.log(" No OpenCode sessions found.");
287
397
  console.log(" Expected path:", sessionPath);
@@ -293,7 +403,9 @@ async function syncAllSessions(siteUrl, apiKey) {
293
403
  const projectDirs = readdirSync(sessionPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
294
404
  for (const projectDir of projectDirs) {
295
405
  const projectSessionPath = join(sessionPath, projectDir);
296
- const sessionFiles = readdirSync(projectSessionPath).filter((f) => f.endsWith(".json"));
406
+ const sessionFiles = readdirSync(projectSessionPath).filter(
407
+ (f) => f.endsWith(".json")
408
+ );
297
409
  for (const file of sessionFiles) {
298
410
  try {
299
411
  const content = readFileSync(join(projectSessionPath, file), "utf8");
@@ -306,20 +418,49 @@ async function syncAllSessions(siteUrl, apiKey) {
306
418
  }
307
419
  }
308
420
  } catch (e) {
309
- console.log(" Error reading sessions:", e instanceof Error ? e.message : String(e));
421
+ console.log(
422
+ " Error reading sessions:",
423
+ e instanceof Error ? e.message : String(e)
424
+ );
310
425
  return;
311
426
  }
312
- console.log(` Found ${sessions.length} sessions
313
- `);
427
+ console.log(` Found ${sessions.length} local sessions`);
314
428
  if (sessions.length === 0) {
315
429
  return;
316
430
  }
317
- let syncedSessions = 0;
431
+ let alreadySynced = /* @__PURE__ */ new Set();
432
+ if (mode === "all") {
433
+ console.log(" Checking backend for existing sessions...");
434
+ alreadySynced = await fetchBackendSessionIds(siteUrl, apiKey);
435
+ if (alreadySynced.size > 0) {
436
+ console.log(` Found ${alreadySynced.size} already synced on backend`);
437
+ }
438
+ } else if (mode === "new") {
439
+ alreadySynced = getSyncedSessions();
440
+ if (alreadySynced.size > 0) {
441
+ console.log(` Found ${alreadySynced.size} in local tracking file`);
442
+ }
443
+ }
444
+ const sessionsToSync = sessions.filter((s) => !alreadySynced.has(s.data.id));
445
+ const skippedCount = sessions.length - sessionsToSync.length;
446
+ if (skippedCount > 0) {
447
+ console.log(` Skipping ${skippedCount} already synced sessions`);
448
+ }
449
+ console.log(` Will sync ${sessionsToSync.length} sessions
450
+ `);
451
+ if (sessionsToSync.length === 0) {
452
+ console.log(" All sessions already synced. Use --force to resync.\n");
453
+ return;
454
+ }
455
+ let syncedSessionCount = 0;
318
456
  let syncedMessages = 0;
319
457
  let failedSessions = 0;
320
- for (const session of sessions) {
458
+ const newlySyncedIds = [];
459
+ for (const session of sessionsToSync) {
321
460
  const { data } = session;
322
- process.stdout.write(` Syncing: ${data.title || data.slug || data.id}... `);
461
+ process.stdout.write(
462
+ ` Syncing: ${data.title || data.slug || data.id}... `
463
+ );
323
464
  let totalPromptTokens = 0;
324
465
  let totalCompletionTokens = 0;
325
466
  let totalCost = 0;
@@ -329,10 +470,15 @@ async function syncAllSessions(siteUrl, apiKey) {
329
470
  const messages = [];
330
471
  if (existsSync(sessionMessagePath)) {
331
472
  try {
332
- const messageFiles = readdirSync(sessionMessagePath).filter((f) => f.endsWith(".json"));
473
+ const messageFiles = readdirSync(sessionMessagePath).filter(
474
+ (f) => f.endsWith(".json")
475
+ );
333
476
  for (const msgFile of messageFiles) {
334
477
  try {
335
- const msgContent = readFileSync(join(sessionMessagePath, msgFile), "utf8");
478
+ const msgContent = readFileSync(
479
+ join(sessionMessagePath, msgFile),
480
+ "utf8"
481
+ );
336
482
  const msgData = JSON.parse(msgContent);
337
483
  if (msgData.id && msgData.sessionID === data.id) {
338
484
  messages.push(msgData);
@@ -380,10 +526,12 @@ async function syncAllSessions(siteUrl, apiKey) {
380
526
  failedSessions++;
381
527
  continue;
382
528
  }
383
- syncedSessions++;
529
+ syncedSessionCount++;
530
+ newlySyncedIds.push(data.id);
384
531
  let msgCount = 0;
385
532
  for (const msg of messages) {
386
533
  try {
534
+ const textContent = getMessageTextContent(partPath, msg.id);
387
535
  const msgRes = await fetch(`${siteUrl}/sync/message`, {
388
536
  method: "POST",
389
537
  headers: {
@@ -394,8 +542,7 @@ async function syncAllSessions(siteUrl, apiKey) {
394
542
  sessionExternalId: data.id,
395
543
  externalId: msg.id,
396
544
  role: msg.role,
397
- textContent: "",
398
- // We don't have content in the message metadata files
545
+ textContent,
399
546
  model: msg.modelID,
400
547
  promptTokens: msg.tokens?.input,
401
548
  completionTokens: msg.tokens?.output,
@@ -415,10 +562,16 @@ async function syncAllSessions(siteUrl, apiKey) {
415
562
  failedSessions++;
416
563
  }
417
564
  }
565
+ if (newlySyncedIds.length > 0) {
566
+ addSyncedSessions(newlySyncedIds);
567
+ }
418
568
  console.log();
419
569
  console.log(` Summary:`);
420
- console.log(` Sessions synced: ${syncedSessions}`);
570
+ console.log(` Sessions synced: ${syncedSessionCount}`);
421
571
  console.log(` Messages synced: ${syncedMessages}`);
572
+ if (skippedCount > 0) {
573
+ console.log(` Skipped: ${skippedCount}`);
574
+ }
422
575
  if (failedSessions > 0) {
423
576
  console.log(` Failed: ${failedSessions}`);
424
577
  }
@@ -433,15 +586,19 @@ function help() {
433
586
  Usage: opencode-sync <command> [options]
434
587
 
435
588
  Commands:
436
- login Configure with Convex URL and API Key
437
- verify Verify credentials and OpenCode config
438
- sync Test connectivity and create a test session
439
- sync --all Sync all local OpenCode sessions to the cloud
440
- logout Clear stored credentials
441
- status Show current authentication status
442
- config Show current configuration
443
- version Show version number
444
- help Show this help message
589
+ login Configure with Convex URL and API Key
590
+ verify Verify credentials and OpenCode config
591
+ sync Test connectivity and create a test session
592
+ sync --new Sync only sessions not in local tracking file
593
+ sync --all Sync all sessions (checks backend, skips existing)
594
+ sync --force Clear tracking and resync all sessions
595
+ logout Clear stored credentials
596
+ status Show current authentication status
597
+ config Show current configuration
598
+ config --logging=true Enable debug logging
599
+ config --logging=false Disable debug logging (default)
600
+ version Show version number
601
+ help Show this help message
445
602
 
446
603
  Setup:
447
604
  1. Go to your OpenSync dashboard Settings page
@@ -451,7 +608,12 @@ function help() {
451
608
  5. Add plugin to opencode.json (see instructions after login)
452
609
  6. Run: opencode-sync verify
453
610
  7. Run: opencode-sync sync (to test connectivity)
454
- 8. Run: opencode-sync sync --all (to sync existing sessions)
611
+ 8. Run: opencode-sync sync --new (to sync new sessions only)
612
+
613
+ Sync Modes:
614
+ --new Fast: uses local tracking, skips previously synced
615
+ --all Accurate: queries backend, skips existing on server
616
+ --force Full: clears tracking and resyncs everything
455
617
  `);
456
618
  }
457
619
  function prompt(question) {
package/dist/config.d.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  interface Config {
2
2
  convexUrl: string;
3
3
  apiKey: string;
4
+ logging?: boolean;
4
5
  }
5
6
  declare function getConfig(): Config | null;
6
7
  declare function setConfig(cfg: Config): void;
7
8
  declare function clearConfig(): void;
9
+ declare function isLoggingEnabled(): boolean;
10
+ declare function setLogging(enabled: boolean): void;
11
+ declare function getSyncedSessions(): Set<string>;
12
+ declare function addSyncedSessions(sessionIds: string[]): void;
13
+ declare function clearSyncedSessions(): void;
8
14
 
9
- export { clearConfig, getConfig, setConfig };
15
+ export { addSyncedSessions, clearConfig, clearSyncedSessions, getConfig, getSyncedSessions, isLoggingEnabled, setConfig, setLogging };
package/dist/config.js CHANGED
@@ -1,10 +1,20 @@
1
1
  import {
2
+ addSyncedSessions,
2
3
  clearConfig,
4
+ clearSyncedSessions,
3
5
  getConfig,
4
- setConfig
5
- } from "./chunk-JPPDGYOB.js";
6
+ getSyncedSessions,
7
+ isLoggingEnabled,
8
+ setConfig,
9
+ setLogging
10
+ } from "./chunk-FYT43SUA.js";
6
11
  export {
12
+ addSyncedSessions,
7
13
  clearConfig,
14
+ clearSyncedSessions,
8
15
  getConfig,
9
- setConfig
16
+ getSyncedSessions,
17
+ isLoggingEnabled,
18
+ setConfig,
19
+ setLogging
10
20
  };
package/dist/index.js CHANGED
@@ -1,8 +1,14 @@
1
1
  import {
2
- getConfig
3
- } from "./chunk-JPPDGYOB.js";
2
+ getConfig,
3
+ isLoggingEnabled
4
+ } from "./chunk-FYT43SUA.js";
4
5
 
5
6
  // src/index.ts
7
+ function log(...args) {
8
+ if (isLoggingEnabled()) {
9
+ console.log(...args);
10
+ }
11
+ }
6
12
  var syncedSessions = /* @__PURE__ */ new Set();
7
13
  var syncedMessages = /* @__PURE__ */ new Set();
8
14
  var messagePartsText = /* @__PURE__ */ new Map();
@@ -48,7 +54,7 @@ function doSyncSession(session) {
48
54
  return;
49
55
  }
50
56
  const url = config.convexUrl.replace(".convex.cloud", ".convex.site");
51
- console.log("[opencode-sync] Syncing session:", session.id);
57
+ log("[opencode-sync] Syncing session:", session.id);
52
58
  const projectPath = session.path?.cwd || session.cwd || session.directory;
53
59
  const modelId = session.modelID || session.model?.modelID || session.model;
54
60
  const providerId = session.providerID || session.model?.providerID || session.provider;
@@ -72,7 +78,9 @@ function doSyncSession(session) {
72
78
  completionTokens,
73
79
  cost
74
80
  })
75
- }).then((r) => r.json()).then((data) => console.log("[opencode-sync] Session sync response:", data)).catch((err) => console.error("[opencode-sync] Session sync error:", err));
81
+ }).then((r) => r.json()).then((data) => log("[opencode-sync] Session sync response:", data)).catch(
82
+ (err) => console.error("[opencode-sync] Session sync error:", err)
83
+ );
76
84
  } catch (err) {
77
85
  console.error("[opencode-sync] doSyncSession error:", err);
78
86
  }
@@ -85,12 +93,12 @@ function doSyncMessage(sessionId, messageId, role, textContent, metadata) {
85
93
  return;
86
94
  }
87
95
  if (!textContent || textContent.trim().length === 0) {
88
- console.log("[opencode-sync] Skipping empty message:", messageId);
96
+ log("[opencode-sync] Skipping empty message:", messageId);
89
97
  return;
90
98
  }
91
99
  const finalRole = role === "unknown" || !role ? inferRole(textContent) : role;
92
100
  const url = config.convexUrl.replace(".convex.cloud", ".convex.site");
93
- console.log(
101
+ log(
94
102
  "[opencode-sync] Syncing message:",
95
103
  messageId,
96
104
  "role:",
@@ -118,7 +126,9 @@ function doSyncMessage(sessionId, messageId, role, textContent, metadata) {
118
126
  completionTokens: metadata?.tokens?.output,
119
127
  durationMs
120
128
  })
121
- }).then((r) => r.json()).then((data) => console.log("[opencode-sync] Message sync response:", data)).catch((err) => console.error("[opencode-sync] Message sync error:", err));
129
+ }).then((r) => r.json()).then((data) => log("[opencode-sync] Message sync response:", data)).catch(
130
+ (err) => console.error("[opencode-sync] Message sync error:", err)
131
+ );
122
132
  } catch (err) {
123
133
  console.error("[opencode-sync] doSyncMessage error:", err);
124
134
  }
@@ -131,7 +141,13 @@ function trySyncMessage(messageId) {
131
141
  const textContent = textParts.join("");
132
142
  if (!textContent.trim()) return;
133
143
  syncedMessages.add(messageId);
134
- doSyncMessage(metadata.sessionId, messageId, metadata.role, textContent, metadata.info);
144
+ doSyncMessage(
145
+ metadata.sessionId,
146
+ messageId,
147
+ metadata.role,
148
+ textContent,
149
+ metadata.info
150
+ );
135
151
  messagePartsText.delete(messageId);
136
152
  messageMetadata.delete(messageId);
137
153
  }
@@ -145,7 +161,7 @@ function scheduleSyncMessage(messageId) {
145
161
  syncTimeouts.set(messageId, timeout);
146
162
  }
147
163
  var OpenCodeSyncPlugin = async (input) => {
148
- console.log("[opencode-sync] Plugin initialized for project:", input.project?.id);
164
+ log("[opencode-sync] Plugin initialized for project:", input.project?.id);
149
165
  return {
150
166
  event: async ({ event }) => {
151
167
  try {
@@ -163,7 +179,12 @@ var OpenCodeSyncPlugin = async (input) => {
163
179
  if (event.type === "message.updated") {
164
180
  const info = props?.info;
165
181
  if (info?.id && info?.sessionID && info?.role) {
166
- console.log("[opencode-sync] Message metadata received:", info.id, "role:", info.role);
182
+ log(
183
+ "[opencode-sync] Message metadata received:",
184
+ info.id,
185
+ "role:",
186
+ info.role
187
+ );
167
188
  messageMetadata.set(info.id, {
168
189
  role: info.role,
169
190
  sessionId: info.sessionID,
@@ -179,7 +200,7 @@ var OpenCodeSyncPlugin = async (input) => {
179
200
  if (part?.type === "text" && part?.messageID && part?.sessionID) {
180
201
  const messageId = part.messageID;
181
202
  const text = part.text || "";
182
- console.log(
203
+ log(
183
204
  "[opencode-sync] Text part received for message:",
184
205
  messageId,
185
206
  "length:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-sync-plugin",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Sync your OpenCode sessions to the cloud",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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
- };