opencode-synced 0.5.1 → 0.6.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.
@@ -106,34 +106,14 @@ export function stripOverrides(localConfig, overrides, baseConfig) {
106
106
  return result;
107
107
  }
108
108
  export function parseJsonc(content) {
109
- const stripped = stripJsonComments(content);
110
- return JSON.parse(stripped);
111
- }
112
- export async function writeJsonFile(filePath, data, options = { jsonc: false }) {
113
- const json = JSON.stringify(data, null, 2);
114
- const content = options.jsonc ? `// Generated by opencode-synced\n${json}\n` : `${json}\n`;
115
- await fs.writeFile(filePath, content, 'utf8');
116
- if (options.mode !== undefined) {
117
- await fs.chmod(filePath, options.mode);
118
- }
119
- }
120
- export function isPlainObject(value) {
121
- if (!value || typeof value !== 'object')
122
- return false;
123
- return Object.getPrototypeOf(value) === Object.prototype;
124
- }
125
- export function hasOwn(target, key) {
126
- return Object.hasOwn(target, key);
127
- }
128
- function stripJsonComments(input) {
129
109
  let output = '';
130
110
  let inString = false;
131
111
  let inSingleLine = false;
132
112
  let inMultiLine = false;
133
113
  let escapeNext = false;
134
- for (let i = 0; i < input.length; i += 1) {
135
- const current = input[i];
136
- const next = input[i + 1];
114
+ for (let i = 0; i < content.length; i += 1) {
115
+ const current = content[i];
116
+ const next = content[i + 1];
137
117
  if (inSingleLine) {
138
118
  if (current === '\n') {
139
119
  inSingleLine = false;
@@ -163,7 +143,7 @@ function stripJsonComments(input) {
163
143
  }
164
144
  continue;
165
145
  }
166
- if (current === '"' && !inString) {
146
+ if (current === '"') {
167
147
  inString = true;
168
148
  output += current;
169
149
  continue;
@@ -178,7 +158,33 @@ function stripJsonComments(input) {
178
158
  i += 1;
179
159
  continue;
180
160
  }
161
+ if (current === ',') {
162
+ let nextIndex = i + 1;
163
+ while (nextIndex < content.length && /\s/.test(content[nextIndex])) {
164
+ nextIndex += 1;
165
+ }
166
+ const nextChar = content[nextIndex];
167
+ if (nextChar === '}' || nextChar === ']') {
168
+ continue;
169
+ }
170
+ }
181
171
  output += current;
182
172
  }
183
- return output;
173
+ return JSON.parse(output);
174
+ }
175
+ export async function writeJsonFile(filePath, data, options = { jsonc: false }) {
176
+ const json = JSON.stringify(data, null, 2);
177
+ const content = options.jsonc ? `// Generated by opencode-synced\n${json}\n` : `${json}\n`;
178
+ await fs.writeFile(filePath, content, 'utf8');
179
+ if (options.mode !== undefined) {
180
+ await fs.chmod(filePath, options.mode);
181
+ }
182
+ }
183
+ export function isPlainObject(value) {
184
+ if (!value || typeof value !== 'object')
185
+ return false;
186
+ return Object.getPrototypeOf(value) === Object.prototype;
187
+ }
188
+ export function hasOwn(target, key) {
189
+ return Object.hasOwn(target, key);
184
190
  }
@@ -10,7 +10,16 @@ export function createSyncService(ctx) {
10
10
  const log = createLogger(ctx.client);
11
11
  return {
12
12
  startupSync: async () => {
13
- const config = await loadSyncConfig(locations);
13
+ let config = null;
14
+ try {
15
+ config = await loadSyncConfig(locations);
16
+ }
17
+ catch (error) {
18
+ const message = `Failed to load opencode-synced config: ${formatError(error)}`;
19
+ log.error(message, { path: locations.syncConfigPath });
20
+ await showToast(ctx.client, `Failed to load opencode-synced config. Check ${locations.syncConfigPath} for JSON errors.`, 'error');
21
+ return;
22
+ }
14
23
  if (!config) {
15
24
  await showToast(ctx.client, 'Configure opencode-synced with /sync-init or link to an existing repo with /sync-link', 'info');
16
25
  return;
@@ -23,9 +23,14 @@ function log(client, level, message, extra) {
23
23
  });
24
24
  }
25
25
  export async function showToast(client, message, variant) {
26
- await client.tui.showToast({
27
- body: { title: 'opencode-synced plugin', message, variant },
28
- });
26
+ try {
27
+ await client.tui.showToast({
28
+ body: { title: 'opencode-synced plugin', message, variant },
29
+ });
30
+ }
31
+ catch {
32
+ // Ignore toast failures (e.g. headless mode or early startup).
33
+ }
29
34
  }
30
35
  export function unwrapData(response) {
31
36
  if (!response || typeof response !== 'object')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-synced",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Sync global OpenCode config across machines via GitHub.",
5
5
  "author": {
6
6
  "name": "Ian Hildebrand"