opencode-sync-plugin 0.2.9 → 0.3.1
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 +22 -0
- package/dist/{chunk-FYT43SUA.js → chunk-J64QRI6W.js} +0 -14
- package/dist/cli.js +14 -33
- package/dist/config.d.ts +1 -4
- package/dist/config.js +3 -7
- package/dist/index.js +10 -53
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -4,6 +4,14 @@ Sync your OpenCode sessions to the cloud. Search, share, and access your coding
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/opencode-sync-plugin)
|
|
6
6
|
|
|
7
|
+
## OpenSync Ecosystem
|
|
8
|
+
|
|
9
|
+
| Package | Description | Links |
|
|
10
|
+
|---------|-------------|-------|
|
|
11
|
+
| **OpenSync** | Beautiful dashboards for OpenCode and Claude Code sessions synced to the cloud. Track coding sessions, analyze tool usage, and monitor token consumption across projects. | [Website](https://opensync.dev/) / [GitHub](https://github.com/waynesutton/opensync) |
|
|
12
|
+
| **opencode-sync-plugin** | Sync your OpenCode sessions to the OpenSync dashboard. | [GitHub](https://github.com/waynesutton/opencode-sync-plugin) / [npm](https://www.npmjs.com/package/opencode-sync-plugin) |
|
|
13
|
+
| **claude-code-sync** | Sync your Claude Code sessions to the OpenSync dashboard. | [GitHub](https://github.com/waynesutton/claude-code-sync) / [npm](https://www.npmjs.com/package/claude-code-sync) |
|
|
14
|
+
|
|
7
15
|
## Installation
|
|
8
16
|
|
|
9
17
|
### From npm
|
|
@@ -168,6 +176,8 @@ This plugin exports both a named and default export so OpenCode can load it from
|
|
|
168
176
|
|
|
169
177
|
## Troubleshooting
|
|
170
178
|
|
|
179
|
+
Having issues? [Open an issue on GitHub](https://github.com/waynesutton/opencode-sync-plugin/issues) and we'll help you out.
|
|
180
|
+
|
|
171
181
|
### OpenCode won't start or shows blank screen
|
|
172
182
|
|
|
173
183
|
If OpenCode hangs or shows a blank screen after adding the plugin, remove the plugin config:
|
|
@@ -222,6 +232,10 @@ opencode-sync status
|
|
|
222
232
|
|
|
223
233
|
Plugin logs are available in OpenCode's log output. Look for entries with `service: "opencode-sync"`.
|
|
224
234
|
|
|
235
|
+
### Still having issues?
|
|
236
|
+
|
|
237
|
+
If none of the above solutions work, [open an issue](https://github.com/waynesutton/opencode-sync-plugin/issues) with details about your setup and the error you're seeing.
|
|
238
|
+
|
|
225
239
|
## Development
|
|
226
240
|
|
|
227
241
|
```bash
|
|
@@ -235,6 +249,14 @@ npm run build
|
|
|
235
249
|
npm run dev
|
|
236
250
|
```
|
|
237
251
|
|
|
252
|
+
## Links
|
|
253
|
+
|
|
254
|
+
- [OpenSync Dashboard](https://opensync.dev/)
|
|
255
|
+
- [OpenSync GitHub](https://github.com/waynesutton/opensync)
|
|
256
|
+
- [opencode-sync-plugin npm](https://www.npmjs.com/package/opencode-sync-plugin)
|
|
257
|
+
- [claude-code-sync npm](https://www.npmjs.com/package/claude-code-sync)
|
|
258
|
+
- [Report Issues](https://github.com/waynesutton/opencode-sync-plugin/issues)
|
|
259
|
+
|
|
238
260
|
## License
|
|
239
261
|
|
|
240
262
|
MIT
|
|
@@ -36,18 +36,6 @@ function clearConfig() {
|
|
|
36
36
|
console.error("Error clearing config:", e);
|
|
37
37
|
}
|
|
38
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
39
|
function getSyncedSessions() {
|
|
52
40
|
try {
|
|
53
41
|
if (!existsSync(SYNCED_SESSIONS_FILE)) return /* @__PURE__ */ new Set();
|
|
@@ -91,8 +79,6 @@ export {
|
|
|
91
79
|
getConfig,
|
|
92
80
|
setConfig,
|
|
93
81
|
clearConfig,
|
|
94
|
-
isLoggingEnabled,
|
|
95
|
-
setLogging,
|
|
96
82
|
getSyncedSessions,
|
|
97
83
|
addSyncedSessions,
|
|
98
84
|
clearSyncedSessions
|
package/dist/cli.js
CHANGED
|
@@ -5,9 +5,8 @@ import {
|
|
|
5
5
|
clearSyncedSessions,
|
|
6
6
|
getConfig,
|
|
7
7
|
getSyncedSessions,
|
|
8
|
-
setConfig
|
|
9
|
-
|
|
10
|
-
} from "./chunk-FYT43SUA.js";
|
|
8
|
+
setConfig
|
|
9
|
+
} from "./chunk-J64QRI6W.js";
|
|
11
10
|
|
|
12
11
|
// src/cli.ts
|
|
13
12
|
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
@@ -78,7 +77,7 @@ async function login() {
|
|
|
78
77
|
process.exit(1);
|
|
79
78
|
}
|
|
80
79
|
const apiKey = await prompt(
|
|
81
|
-
"API
|
|
80
|
+
"Get your API key from your OpenSync.dev Settings page, starts with osk_. Enter it here: "
|
|
82
81
|
);
|
|
83
82
|
if (!apiKey) {
|
|
84
83
|
console.error("API Key is required");
|
|
@@ -220,21 +219,6 @@ function status() {
|
|
|
220
219
|
console.log();
|
|
221
220
|
}
|
|
222
221
|
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
222
|
showConfig();
|
|
239
223
|
}
|
|
240
224
|
function showConfig() {
|
|
@@ -250,7 +234,6 @@ function showConfig() {
|
|
|
250
234
|
" API Key:",
|
|
251
235
|
config.apiKey ? config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4) : "Not set"
|
|
252
236
|
);
|
|
253
|
-
console.log(" Logging:", config.logging ? "enabled" : "disabled");
|
|
254
237
|
console.log();
|
|
255
238
|
}
|
|
256
239
|
function getMessageTextContent(partBasePath, messageId) {
|
|
@@ -586,19 +569,17 @@ function help() {
|
|
|
586
569
|
Usage: opencode-sync <command> [options]
|
|
587
570
|
|
|
588
571
|
Commands:
|
|
589
|
-
login
|
|
590
|
-
verify
|
|
591
|
-
sync
|
|
592
|
-
sync --new
|
|
593
|
-
sync --all
|
|
594
|
-
sync --force
|
|
595
|
-
logout
|
|
596
|
-
status
|
|
597
|
-
config
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
version Show version number
|
|
601
|
-
help Show this help message
|
|
572
|
+
login Configure with Convex URL and API Key
|
|
573
|
+
verify Verify credentials and OpenCode config
|
|
574
|
+
sync Test connectivity and create a test session
|
|
575
|
+
sync --new Sync only sessions not in local tracking file
|
|
576
|
+
sync --all Sync all sessions (checks backend, skips existing)
|
|
577
|
+
sync --force Clear tracking and resync all sessions
|
|
578
|
+
logout Clear stored credentials
|
|
579
|
+
status Show current authentication status
|
|
580
|
+
config Show current configuration
|
|
581
|
+
version Show version number
|
|
582
|
+
help Show this help message
|
|
602
583
|
|
|
603
584
|
Setup:
|
|
604
585
|
1. Go to your OpenSync dashboard Settings page
|
package/dist/config.d.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
interface Config {
|
|
2
2
|
convexUrl: string;
|
|
3
3
|
apiKey: string;
|
|
4
|
-
logging?: boolean;
|
|
5
4
|
}
|
|
6
5
|
declare function getConfig(): Config | null;
|
|
7
6
|
declare function setConfig(cfg: Config): void;
|
|
8
7
|
declare function clearConfig(): void;
|
|
9
|
-
declare function isLoggingEnabled(): boolean;
|
|
10
|
-
declare function setLogging(enabled: boolean): void;
|
|
11
8
|
declare function getSyncedSessions(): Set<string>;
|
|
12
9
|
declare function addSyncedSessions(sessionIds: string[]): void;
|
|
13
10
|
declare function clearSyncedSessions(): void;
|
|
14
11
|
|
|
15
|
-
export { addSyncedSessions, clearConfig, clearSyncedSessions, getConfig, getSyncedSessions,
|
|
12
|
+
export { addSyncedSessions, clearConfig, clearSyncedSessions, getConfig, getSyncedSessions, setConfig };
|
package/dist/config.js
CHANGED
|
@@ -4,17 +4,13 @@ import {
|
|
|
4
4
|
clearSyncedSessions,
|
|
5
5
|
getConfig,
|
|
6
6
|
getSyncedSessions,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
setLogging
|
|
10
|
-
} from "./chunk-FYT43SUA.js";
|
|
7
|
+
setConfig
|
|
8
|
+
} from "./chunk-J64QRI6W.js";
|
|
11
9
|
export {
|
|
12
10
|
addSyncedSessions,
|
|
13
11
|
clearConfig,
|
|
14
12
|
clearSyncedSessions,
|
|
15
13
|
getConfig,
|
|
16
14
|
getSyncedSessions,
|
|
17
|
-
|
|
18
|
-
setConfig,
|
|
19
|
-
setLogging
|
|
15
|
+
setConfig
|
|
20
16
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
getConfig
|
|
3
|
-
|
|
4
|
-
} from "./chunk-FYT43SUA.js";
|
|
2
|
+
getConfig
|
|
3
|
+
} from "./chunk-J64QRI6W.js";
|
|
5
4
|
|
|
6
5
|
// src/index.ts
|
|
7
|
-
function log(...args) {
|
|
8
|
-
if (isLoggingEnabled()) {
|
|
9
|
-
console.log(...args);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
6
|
var syncedSessions = /* @__PURE__ */ new Set();
|
|
13
7
|
var syncedMessages = /* @__PURE__ */ new Set();
|
|
14
8
|
var messagePartsText = /* @__PURE__ */ new Map();
|
|
@@ -19,20 +13,14 @@ function inferRole(textContent) {
|
|
|
19
13
|
const assistantPatterns = [
|
|
20
14
|
/^(I'll|Let me|Here's|I can|I've|I'm going to|I will|Sure|Certainly|Of course)/i,
|
|
21
15
|
/```[\s\S]+```/,
|
|
22
|
-
// Code blocks
|
|
23
16
|
/^(Yes|No),?\s+(I|you|we|this|that)/i,
|
|
24
|
-
// Answering patterns
|
|
25
17
|
/\*\*[^*]+\*\*/,
|
|
26
|
-
// Bold markdown (explanations)
|
|
27
18
|
/^\d+\.\s+\*\*/
|
|
28
|
-
// Numbered lists with bold
|
|
29
19
|
];
|
|
30
20
|
const userPatterns = [
|
|
31
21
|
/\?$/,
|
|
32
|
-
// Questions
|
|
33
22
|
/^(create|fix|add|update|show|make|build|implement|write|delete|remove|change|modify|help|can you|please|I want|I need)/i,
|
|
34
23
|
/^@/
|
|
35
|
-
// File references
|
|
36
24
|
];
|
|
37
25
|
for (const pattern of assistantPatterns) {
|
|
38
26
|
if (pattern.test(textContent)) {
|
|
@@ -50,11 +38,9 @@ function doSyncSession(session) {
|
|
|
50
38
|
try {
|
|
51
39
|
const config = getConfig();
|
|
52
40
|
if (!config?.apiKey || !config?.convexUrl) {
|
|
53
|
-
console.error("[opencode-sync] Missing config - cannot sync session");
|
|
54
41
|
return;
|
|
55
42
|
}
|
|
56
43
|
const url = config.convexUrl.replace(".convex.cloud", ".convex.site");
|
|
57
|
-
log("[opencode-sync] Syncing session:", session.id);
|
|
58
44
|
const projectPath = session.path?.cwd || session.cwd || session.directory;
|
|
59
45
|
const modelId = session.modelID || session.model?.modelID || session.model;
|
|
60
46
|
const providerId = session.providerID || session.model?.providerID || session.provider;
|
|
@@ -78,34 +64,22 @@ function doSyncSession(session) {
|
|
|
78
64
|
completionTokens,
|
|
79
65
|
cost
|
|
80
66
|
})
|
|
81
|
-
}).
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
} catch (err) {
|
|
85
|
-
console.error("[opencode-sync] doSyncSession error:", err);
|
|
67
|
+
}).catch(() => {
|
|
68
|
+
});
|
|
69
|
+
} catch {
|
|
86
70
|
}
|
|
87
71
|
}
|
|
88
72
|
function doSyncMessage(sessionId, messageId, role, textContent, metadata) {
|
|
89
73
|
try {
|
|
90
74
|
const config = getConfig();
|
|
91
75
|
if (!config?.apiKey || !config?.convexUrl) {
|
|
92
|
-
console.error("[opencode-sync] Missing config - cannot sync message");
|
|
93
76
|
return;
|
|
94
77
|
}
|
|
95
78
|
if (!textContent || textContent.trim().length === 0) {
|
|
96
|
-
log("[opencode-sync] Skipping empty message:", messageId);
|
|
97
79
|
return;
|
|
98
80
|
}
|
|
99
81
|
const finalRole = role === "unknown" || !role ? inferRole(textContent) : role;
|
|
100
82
|
const url = config.convexUrl.replace(".convex.cloud", ".convex.site");
|
|
101
|
-
log(
|
|
102
|
-
"[opencode-sync] Syncing message:",
|
|
103
|
-
messageId,
|
|
104
|
-
"role:",
|
|
105
|
-
finalRole,
|
|
106
|
-
"text length:",
|
|
107
|
-
textContent.length
|
|
108
|
-
);
|
|
109
83
|
let durationMs;
|
|
110
84
|
if (metadata?.time?.completed && metadata?.time?.created) {
|
|
111
85
|
durationMs = metadata.time.completed - metadata.time.created;
|
|
@@ -126,11 +100,9 @@ function doSyncMessage(sessionId, messageId, role, textContent, metadata) {
|
|
|
126
100
|
completionTokens: metadata?.tokens?.output,
|
|
127
101
|
durationMs
|
|
128
102
|
})
|
|
129
|
-
}).
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
} catch (err) {
|
|
133
|
-
console.error("[opencode-sync] doSyncMessage error:", err);
|
|
103
|
+
}).catch(() => {
|
|
104
|
+
});
|
|
105
|
+
} catch {
|
|
134
106
|
}
|
|
135
107
|
}
|
|
136
108
|
function trySyncMessage(messageId) {
|
|
@@ -160,8 +132,7 @@ function scheduleSyncMessage(messageId) {
|
|
|
160
132
|
}, DEBOUNCE_MS);
|
|
161
133
|
syncTimeouts.set(messageId, timeout);
|
|
162
134
|
}
|
|
163
|
-
var OpenCodeSyncPlugin = async (
|
|
164
|
-
log("[opencode-sync] Plugin initialized for project:", input.project?.id);
|
|
135
|
+
var OpenCodeSyncPlugin = async () => {
|
|
165
136
|
return {
|
|
166
137
|
event: async ({ event }) => {
|
|
167
138
|
try {
|
|
@@ -179,12 +150,6 @@ var OpenCodeSyncPlugin = async (input) => {
|
|
|
179
150
|
if (event.type === "message.updated") {
|
|
180
151
|
const info = props?.info;
|
|
181
152
|
if (info?.id && info?.sessionID && info?.role) {
|
|
182
|
-
log(
|
|
183
|
-
"[opencode-sync] Message metadata received:",
|
|
184
|
-
info.id,
|
|
185
|
-
"role:",
|
|
186
|
-
info.role
|
|
187
|
-
);
|
|
188
153
|
messageMetadata.set(info.id, {
|
|
189
154
|
role: info.role,
|
|
190
155
|
sessionId: info.sessionID,
|
|
@@ -200,17 +165,10 @@ var OpenCodeSyncPlugin = async (input) => {
|
|
|
200
165
|
if (part?.type === "text" && part?.messageID && part?.sessionID) {
|
|
201
166
|
const messageId = part.messageID;
|
|
202
167
|
const text = part.text || "";
|
|
203
|
-
log(
|
|
204
|
-
"[opencode-sync] Text part received for message:",
|
|
205
|
-
messageId,
|
|
206
|
-
"length:",
|
|
207
|
-
text.length
|
|
208
|
-
);
|
|
209
168
|
messagePartsText.set(messageId, [text]);
|
|
210
169
|
if (!messageMetadata.has(messageId)) {
|
|
211
170
|
messageMetadata.set(messageId, {
|
|
212
171
|
role: "unknown",
|
|
213
|
-
// Will be inferred or updated from message.updated
|
|
214
172
|
sessionId: part.sessionID,
|
|
215
173
|
info: {}
|
|
216
174
|
});
|
|
@@ -218,8 +176,7 @@ var OpenCodeSyncPlugin = async (input) => {
|
|
|
218
176
|
scheduleSyncMessage(messageId);
|
|
219
177
|
}
|
|
220
178
|
}
|
|
221
|
-
} catch
|
|
222
|
-
console.error("[opencode-sync] Event handler error:", err);
|
|
179
|
+
} catch {
|
|
223
180
|
}
|
|
224
181
|
}
|
|
225
182
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-sync-plugin",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Sync your OpenCode sessions to the
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Sync your OpenCode sessions to the OpenSync dashboard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -24,16 +24,24 @@
|
|
|
24
24
|
"keywords": [
|
|
25
25
|
"opencode",
|
|
26
26
|
"opencode-plugin",
|
|
27
|
+
"opensync",
|
|
27
28
|
"ai",
|
|
28
29
|
"sync",
|
|
29
30
|
"sessions",
|
|
30
|
-
"convex"
|
|
31
|
+
"convex",
|
|
32
|
+
"claude-code",
|
|
33
|
+
"ai-coding",
|
|
34
|
+
"session-tracking"
|
|
31
35
|
],
|
|
32
36
|
"author": "waynesutton",
|
|
33
37
|
"repository": {
|
|
34
38
|
"type": "git",
|
|
35
39
|
"url": "https://github.com/waynesutton/opencode-sync-plugin"
|
|
36
40
|
},
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/waynesutton/opencode-sync-plugin/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://opensync.dev/",
|
|
37
45
|
"license": "MIT",
|
|
38
46
|
"devDependencies": {
|
|
39
47
|
"@opencode-ai/plugin": "^1.1.25",
|