@openchamber/web 1.11.0 → 1.11.2

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.
Files changed (43) hide show
  1. package/dist/assets/{JsonTreeView-CUIfrcFf.js → JsonTreeView-9F0tH9yA.js} +1 -1
  2. package/dist/assets/{MarkdownRendererImpl-Bma9y3dD.js → MarkdownRendererImpl-C3QofAGm.js} +2 -2
  3. package/dist/assets/{MultiRunWindow-Cwc0x7fs.js → MultiRunWindow-wnUGv0Dl.js} +1 -1
  4. package/dist/assets/{OnboardingScreen-BhozUlcE.js → OnboardingScreen-17dAs0NH.js} +2 -2
  5. package/dist/assets/{SettingsWindow-B4B2bn0C.js → SettingsWindow-BgyVY5gz.js} +1 -1
  6. package/dist/assets/{TerminalView-BpoHWJj6.js → TerminalView-D11XIZuz.js} +1 -1
  7. package/dist/assets/{ToolOutputDialog-7U42lN20.js → ToolOutputDialog-DFG7ANVw.js} +6 -6
  8. package/dist/assets/es-Chl2Hu6K.js +15 -0
  9. package/dist/assets/index-0bVkxg-Z.css +1 -0
  10. package/dist/assets/{index-B2ztI3pp.js → index-BV2XTsJJ.js} +1 -1
  11. package/dist/assets/ko-BSrH3F9n.js +15 -0
  12. package/dist/assets/{main-rHOaDqOy.js → main-BHkNwOz1.js} +2 -2
  13. package/dist/assets/main-Bqf4fXgq.js +225 -0
  14. package/dist/assets/miniChat-BmB-E5xo.js +2 -0
  15. package/dist/assets/{modelPrefsAutoSave-D5z_F_WP.js → modelPrefsAutoSave-2uwW8uD9.js} +104 -96
  16. package/dist/assets/pl-YlGvPmFg.js +15 -0
  17. package/dist/assets/pt-BR-BonIMDN_.js +15 -0
  18. package/dist/assets/renderElectronMiniChatApp-B_qrXCU2.js +2 -0
  19. package/dist/assets/uk-lPqA3MHn.js +15 -0
  20. package/dist/assets/{vendor-.bun-BFTPeDgG.js → vendor-.bun-Boz6Tqcq.js} +20 -20
  21. package/dist/assets/zh-CN-C5nQQsUL.js +15 -0
  22. package/dist/index.html +4 -4
  23. package/dist/mini-chat.html +4 -4
  24. package/package.json +1 -1
  25. package/server/lib/git/DOCUMENTATION.md +1 -0
  26. package/server/lib/git/routes.js +26 -0
  27. package/server/lib/git/service.js +96 -10
  28. package/server/lib/git/service.test.js +39 -0
  29. package/server/lib/opencode/settings-helpers.js +10 -1
  30. package/server/lib/opencode/settings-helpers.test.js +35 -0
  31. package/server/lib/opencode/skill-routes.js +43 -49
  32. package/server/lib/opencode/skills.js +78 -10
  33. package/server/lib/preview/proxy-runtime.js +43 -3
  34. package/dist/assets/es-DLzL0vVb.js +0 -15
  35. package/dist/assets/index-D5TVqnib.css +0 -1
  36. package/dist/assets/ko-apnbnEuD.js +0 -15
  37. package/dist/assets/main-ClS4RVxe.js +0 -217
  38. package/dist/assets/miniChat-Cx8YK32Y.js +0 -2
  39. package/dist/assets/pl-DUKUujvh.js +0 -15
  40. package/dist/assets/pt-BR-D0UPeIZC.js +0 -15
  41. package/dist/assets/renderElectronMiniChatApp-zbukf-1g.js +0 -2
  42. package/dist/assets/uk-CaTe2At9.js +0 -15
  43. package/dist/assets/zh-CN-D-oQmPdK.js +0 -15
@@ -69,6 +69,14 @@ function getClaudeSkillPath(workingDirectory, skillName) {
69
69
  return path.join(getClaudeSkillDir(workingDirectory, skillName), 'SKILL.md');
70
70
  }
71
71
 
72
+ function getUserClaudeSkillDir(skillName) {
73
+ return path.join(os.homedir(), '.claude', 'skills', skillName);
74
+ }
75
+
76
+ function getUserClaudeSkillPath(skillName) {
77
+ return path.join(getUserClaudeSkillDir(skillName), 'SKILL.md');
78
+ }
79
+
72
80
  function getUserAgentsSkillDir(skillName) {
73
81
  return path.join(os.homedir(), '.agents', 'skills', skillName);
74
82
  }
@@ -107,6 +115,16 @@ function getSkillScope(skillName, workingDirectory) {
107
115
  if (fs.existsSync(userPath)) {
108
116
  return { scope: SKILL_SCOPE.USER, path: userPath, source: 'opencode' };
109
117
  }
118
+
119
+ const userClaudePath = getUserClaudeSkillPath(skillName);
120
+ if (fs.existsSync(userClaudePath)) {
121
+ return { scope: SKILL_SCOPE.USER, path: userClaudePath, source: 'claude' };
122
+ }
123
+
124
+ const userAgentsPath = getUserAgentsSkillPath(skillName);
125
+ if (fs.existsSync(userAgentsPath)) {
126
+ return { scope: SKILL_SCOPE.USER, path: userAgentsPath, source: 'agents' };
127
+ }
110
128
 
111
129
  return { scope: null, path: null, source: null };
112
130
  }
@@ -226,11 +244,18 @@ function getSkillSources(skillName, workingDirectory, discoveredSkill = null) {
226
244
  const claudePath = workingDirectory ? getClaudeSkillPath(workingDirectory, skillName) : null;
227
245
  const claudeExists = claudePath && fs.existsSync(claudePath);
228
246
  const claudeDir = claudeExists ? path.dirname(claudePath) : null;
247
+ const userClaudePath = getUserClaudeSkillPath(skillName);
248
+ const userClaudeExists = fs.existsSync(userClaudePath);
249
+ const userClaudeDir = userClaudeExists ? path.dirname(userClaudePath) : null;
229
250
 
230
251
  const userPath = getUserSkillPath(skillName);
231
252
  const userExists = fs.existsSync(userPath);
232
253
  const userDir = userExists ? path.dirname(userPath) : null;
233
254
 
255
+ const userAgentsPath = getUserAgentsSkillPath(skillName);
256
+ const userAgentsExists = fs.existsSync(userAgentsPath);
257
+ const userAgentsDir = userAgentsExists ? path.dirname(userAgentsPath) : null;
258
+
234
259
  const matchedDiscovered = discoveredSkill && discoveredSkill.name === skillName
235
260
  ? discoveredSkill
236
261
  : discoverSkills(workingDirectory).find((skill) => skill.name === skillName);
@@ -240,7 +265,12 @@ function getSkillSources(skillName, workingDirectory, discoveredSkill = null) {
240
265
  let mdSource = null;
241
266
  let mdDir = null;
242
267
 
243
- if (projectExists) {
268
+ if (matchedDiscovered?.path) {
269
+ mdPath = matchedDiscovered.path;
270
+ mdScope = matchedDiscovered.scope || null;
271
+ mdSource = matchedDiscovered.source || null;
272
+ mdDir = path.dirname(matchedDiscovered.path);
273
+ } else if (projectExists) {
244
274
  mdPath = projectPath;
245
275
  mdScope = SKILL_SCOPE.PROJECT;
246
276
  mdSource = 'opencode';
@@ -255,14 +285,23 @@ function getSkillSources(skillName, workingDirectory, discoveredSkill = null) {
255
285
  mdScope = SKILL_SCOPE.USER;
256
286
  mdSource = 'opencode';
257
287
  mdDir = userDir;
258
- } else if (matchedDiscovered?.path) {
259
- mdPath = matchedDiscovered.path;
260
- mdScope = matchedDiscovered.scope || null;
261
- mdSource = matchedDiscovered.source || null;
262
- mdDir = path.dirname(matchedDiscovered.path);
288
+ } else if (userClaudeExists) {
289
+ mdPath = userClaudePath;
290
+ mdScope = SKILL_SCOPE.USER;
291
+ mdSource = 'claude';
292
+ mdDir = userClaudeDir;
293
+ } else if (userAgentsExists) {
294
+ mdPath = userAgentsPath;
295
+ mdScope = SKILL_SCOPE.USER;
296
+ mdSource = 'agents';
297
+ mdDir = userAgentsDir;
263
298
  }
264
299
 
265
- const mdExists = !!mdPath;
300
+ const mdExists = !!mdPath && fs.existsSync(mdPath);
301
+ if (!mdExists) {
302
+ mdPath = null;
303
+ mdDir = null;
304
+ }
266
305
 
267
306
  const sources = {
268
307
  md: {
@@ -288,6 +327,16 @@ function getSkillSources(skillName, workingDirectory, discoveredSkill = null) {
288
327
  exists: userExists,
289
328
  path: userPath,
290
329
  dir: userDir
330
+ },
331
+ userClaudeMd: {
332
+ exists: userClaudeExists,
333
+ path: userClaudePath,
334
+ dir: userClaudeDir
335
+ },
336
+ userAgentsMd: {
337
+ exists: userAgentsExists,
338
+ path: userAgentsPath,
339
+ dir: userAgentsDir
291
340
  }
292
341
  };
293
342
 
@@ -374,22 +423,34 @@ function createSkill(skillName, config, workingDirectory, scope) {
374
423
  console.log(`Created new skill: ${skillName} (scope: ${targetScope}, path: ${targetPath})`);
375
424
  }
376
425
 
377
- function updateSkill(skillName, updates, workingDirectory) {
426
+ function updateSkill(skillName, updates, workingDirectory, targetPath = null) {
378
427
  ensureDirs();
379
428
 
380
- const existing = getSkillScope(skillName, workingDirectory);
429
+ const requestedPath = typeof targetPath === 'string' && targetPath.trim()
430
+ ? path.resolve(targetPath.trim())
431
+ : null;
432
+ const existing = requestedPath && fs.existsSync(requestedPath)
433
+ ? { scope: null, path: requestedPath, source: null }
434
+ : getSkillScope(skillName, workingDirectory);
381
435
  if (!existing.path) {
382
436
  throw new Error(`Skill "${skillName}" not found`);
383
437
  }
438
+ if (path.basename(existing.path) !== 'SKILL.md') {
439
+ throw new Error(`Skill "${skillName}" target must be a SKILL.md file`);
440
+ }
384
441
 
385
442
  const mdPath = existing.path;
386
443
  const mdDir = path.dirname(mdPath);
387
444
  const mdData = parseMdFile(mdPath);
445
+ const frontmatterName = typeof mdData.frontmatter?.name === 'string' ? mdData.frontmatter.name : skillName;
446
+ if (frontmatterName !== skillName) {
447
+ throw new Error(`Skill "${skillName}" does not match ${mdPath}`);
448
+ }
388
449
 
389
450
  let mdModified = false;
390
451
 
391
452
  for (const [field, value] of Object.entries(updates)) {
392
- if (field === 'scope') {
453
+ if (field === 'scope' || field === 'source' || field === 'targetPath') {
393
454
  continue;
394
455
  }
395
456
 
@@ -464,6 +525,13 @@ function deleteSkill(skillName, workingDirectory) {
464
525
  deleted = true;
465
526
  }
466
527
 
528
+ const userClaudeDir = getUserClaudeSkillDir(skillName);
529
+ if (fs.existsSync(userClaudeDir)) {
530
+ fs.rmSync(userClaudeDir, { recursive: true, force: true });
531
+ console.log(`Deleted user-level claude skill directory: ${userClaudeDir}`);
532
+ deleted = true;
533
+ }
534
+
467
535
  if (!deleted) {
468
536
  throw new Error(`Skill "${skillName}" not found`);
469
537
  }
@@ -484,9 +484,35 @@ const PREVIEW_BRIDGE_SCRIPT = String.raw`(() => {
484
484
  };
485
485
 
486
486
  const proxiedUrl = (value) => {
487
- if (typeof value !== 'string' || !value.startsWith('/')) return value;
488
- if (!shouldProxyPath(value)) return value;
489
- return proxyBase + value;
487
+ if (typeof value !== 'string') return value;
488
+ if (value.startsWith('/')) {
489
+ if (!shouldProxyPath(value)) return value;
490
+ return proxyBase + value;
491
+ }
492
+
493
+ try {
494
+ const parsed = new URL(value, window.location.href);
495
+ if (parsed.origin === window.location.origin && shouldProxyPath(parsed.pathname)) {
496
+ return proxyBase + parsed.pathname + parsed.search + parsed.hash;
497
+ }
498
+ } catch {}
499
+
500
+ return value;
501
+ };
502
+
503
+ const proxiedWebSocketUrl = (value) => {
504
+ if (typeof value !== 'string') return value;
505
+ try {
506
+ const parsed = new URL(value, window.location.href);
507
+ const current = new URL(window.location.href);
508
+ const sameHost = parsed.host === current.host;
509
+ const isWebSocketProtocol = parsed.protocol === 'ws:' || parsed.protocol === 'wss:';
510
+ if (sameHost && isWebSocketProtocol && shouldProxyPath(parsed.pathname)) {
511
+ parsed.pathname = proxyBase + parsed.pathname;
512
+ return parsed.toString();
513
+ }
514
+ } catch {}
515
+ return value;
490
516
  };
491
517
 
492
518
  if (typeof window.fetch === 'function') {
@@ -529,6 +555,20 @@ const PREVIEW_BRIDGE_SCRIPT = String.raw`(() => {
529
555
  Object.defineProperty(OpenChamberPreviewEventSource, 'name', { value: 'EventSource' });
530
556
  window.EventSource = OpenChamberPreviewEventSource;
531
557
  }
558
+
559
+ if (typeof window.WebSocket === 'function') {
560
+ const NativeWebSocket = window.WebSocket;
561
+ function OpenChamberPreviewAppWebSocket(url, protocols) {
562
+ const nextUrl = proxiedWebSocketUrl(String(url));
563
+ return arguments.length === 1
564
+ ? new NativeWebSocket(nextUrl)
565
+ : new NativeWebSocket(nextUrl, protocols);
566
+ }
567
+ OpenChamberPreviewAppWebSocket.prototype = NativeWebSocket.prototype;
568
+ Object.setPrototypeOf(OpenChamberPreviewAppWebSocket, NativeWebSocket);
569
+ Object.defineProperty(OpenChamberPreviewAppWebSocket, 'name', { value: 'WebSocket' });
570
+ window.WebSocket = OpenChamberPreviewAppWebSocket;
571
+ }
532
572
  };
533
573
 
534
574
  const selectorPart = (element) => {