@rho-workspace/rho 0.5.4 → 0.5.6

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 (161) hide show
  1. package/dist/agent-connect.d.ts +8 -0
  2. package/dist/agent-connect.js +15 -0
  3. package/dist/browser-access.js +3 -2
  4. package/dist/capabilities.d.ts +2 -2
  5. package/dist/capabilities.js +6 -1
  6. package/dist/cli.js +219 -176
  7. package/dist/contract.generated.d.ts +472 -4
  8. package/dist/contract.generated.js +1 -1
  9. package/dist/contracts/owners.generated.js +455 -6
  10. package/dist/conversations.d.ts +157 -4
  11. package/dist/conversations.js +69 -6
  12. package/dist/discovery.d.ts +1 -0
  13. package/dist/discovery.js +3 -3
  14. package/dist/extension-contract.d.ts +99 -0
  15. package/dist/extension-contract.js +52 -0
  16. package/dist/extension-directory.d.ts +9 -0
  17. package/dist/extension-directory.js +11 -0
  18. package/dist/extension-worker.d.ts +1 -0
  19. package/dist/extension-worker.js +36 -0
  20. package/dist/extensions.d.ts +157 -0
  21. package/dist/extensions.js +349 -0
  22. package/dist/plugin-cli.d.ts +1 -0
  23. package/dist/plugin-cli.js +139 -0
  24. package/dist/plugin-inventory.json +18 -0
  25. package/dist/plugins.d.ts +3 -3
  26. package/dist/project-work.d.ts +3 -1
  27. package/dist/project-work.js +15 -2
  28. package/dist/protocol.d.ts +8 -0
  29. package/dist/protocol.js +16 -7
  30. package/dist/server.d.ts +5 -10
  31. package/dist/server.js +122 -12
  32. package/dist/web/.vite/manifest.json +67 -67
  33. package/dist/web/assets/{canvas-BXhC8RDZ.js → canvas-D8rDdfDz.js} +1 -1
  34. package/dist/web/assets/choices-D-YfnFP6.js +1 -0
  35. package/dist/web/assets/{console-Dbdo-5oO.js → console-Trqc0swD.js} +1 -1
  36. package/dist/web/assets/{dist-B2V0VDO0.js → dist-DZmszrjG.js} +2 -2
  37. package/dist/web/assets/dist-DpIHRk3B.js +1 -0
  38. package/dist/web/assets/{dist-D25Vn17i.js → dist-eMx6b8N1.js} +1 -1
  39. package/dist/web/assets/dist-pF902jHA.js +3 -0
  40. package/dist/web/assets/explore-in-BCHqjJ7B.js +1 -0
  41. package/dist/web/assets/graph-lENgfQNH.js +2 -0
  42. package/dist/web/assets/index-B3_OVy91.css +1 -0
  43. package/dist/web/assets/{index-BHQIaDsx.js → index-BpL_Kl_s.js} +87 -86
  44. package/dist/web/assets/{notes-meaning-DdPbtNzJ.js → notes-meaning-DcVGUBBY.js} +1 -1
  45. package/dist/web/assets/overview-CDnVKlOt.js +6 -0
  46. package/dist/web/assets/preview-BEC1E9MK.js +1 -0
  47. package/dist/web/assets/{review-CmWou4Iv.js → review-DYP0aCXb.js} +1 -1
  48. package/dist/web/assets/{skills-Dy7n3L9d.js → skills-1ec0Z-jx.js} +1 -1
  49. package/dist/web/assets/{skills-work-Cj0W6b-I.js → skills-work-DNexV4OJ.js} +1 -1
  50. package/dist/web/assets/{studio-process-QOY_n2_8.js → studio-process-EYQgikxq.js} +2 -2
  51. package/dist/web/assets/{timeline-events-DmX1BCh3.js → timeline-events-Chj2Gbx7.js} +1 -1
  52. package/dist/web/assets/{work-turns-Co0C71rJ.js → work-turns-CT9RVcWY.js} +1 -1
  53. package/dist/web/assets/workspace-COmCbGV3.js +5 -0
  54. package/dist/web/composition.json +65 -65
  55. package/dist/web/index.html +3 -3
  56. package/dist/web/renderer.json +1 -1
  57. package/dist/web-assets.d.ts +2 -1
  58. package/dist/web-assets.js +3 -2
  59. package/dist/work-contract.js +2 -2
  60. package/docs/FRONTEND.md +26 -18
  61. package/docs/HEADLESS.md +38 -28
  62. package/docs/PLUGIN-AUTHORING.md +4 -0
  63. package/docs/THIRD-PARTY-PLUGINS.md +190 -0
  64. package/node_modules/@rho-workspace/plugin-agent/README.md +68 -0
  65. package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.d.ts +1 -0
  66. package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.js +9 -1
  67. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.d.ts +1 -0
  68. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +10 -0
  69. package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.d.ts +1 -0
  70. package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.js +2 -2
  71. package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.d.ts +6 -0
  72. package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.js +174 -0
  73. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.d.ts +82 -0
  74. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.js +20 -0
  75. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.d.ts +84 -0
  76. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.js +190 -0
  77. package/node_modules/@rho-workspace/plugin-agent/dist/index.d.ts +373 -0
  78. package/node_modules/@rho-workspace/plugin-agent/dist/index.js +1 -0
  79. package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.d.ts +70 -0
  80. package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.js +538 -0
  81. package/node_modules/@rho-workspace/plugin-agent/dist/operations.d.ts +33 -0
  82. package/node_modules/@rho-workspace/plugin-agent/dist/operations.js +3 -0
  83. package/node_modules/@rho-workspace/plugin-agent/dist/presentation.d.ts +14 -0
  84. package/node_modules/@rho-workspace/plugin-agent/dist/presentation.js +2 -0
  85. package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.d.ts +15 -0
  86. package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.js +37 -0
  87. package/node_modules/@rho-workspace/plugin-agent/package.json +6 -1
  88. package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -1
  89. package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -1
  90. package/node_modules/hono/dist/cjs/adapter/bun/serve-static.js +1 -1
  91. package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +1 -1
  92. package/node_modules/hono/dist/cjs/client/fetch-result-please.js +1 -1
  93. package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +2 -1
  94. package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +5 -3
  95. package/node_modules/hono/dist/cjs/jsx/base.js +49 -30
  96. package/node_modules/hono/dist/cjs/jsx/components.js +2 -2
  97. package/node_modules/hono/dist/cjs/jsx/constants.js +2 -0
  98. package/node_modules/hono/dist/cjs/jsx/jsx-runtime.js +13 -17
  99. package/node_modules/hono/dist/cjs/middleware/etag/index.js +3 -1
  100. package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +1 -0
  101. package/node_modules/hono/dist/cjs/middleware/timing/timing.js +4 -3
  102. package/node_modules/hono/dist/cjs/utils/cookie.js +2 -2
  103. package/node_modules/hono/dist/cjs/utils/mime.js +1 -1
  104. package/node_modules/hono/dist/cjs/utils/url.js +1 -1
  105. package/node_modules/hono/dist/client/fetch-result-please.js +1 -1
  106. package/node_modules/hono/dist/helper/accepts/accepts.js +2 -1
  107. package/node_modules/hono/dist/helper/ssg/ssg.js +5 -3
  108. package/node_modules/hono/dist/jsx/base.js +49 -32
  109. package/node_modules/hono/dist/jsx/components.js +2 -2
  110. package/node_modules/hono/dist/jsx/constants.js +2 -1
  111. package/node_modules/hono/dist/jsx/jsx-runtime.js +15 -19
  112. package/node_modules/hono/dist/middleware/etag/index.js +3 -1
  113. package/node_modules/hono/dist/middleware/language/language.js +1 -1
  114. package/node_modules/hono/dist/middleware/pretty-json/index.js +1 -0
  115. package/node_modules/hono/dist/middleware/timing/timing.js +4 -3
  116. package/node_modules/hono/dist/utils/cookie.js +2 -2
  117. package/node_modules/hono/dist/utils/mime.js +1 -1
  118. package/node_modules/hono/dist/utils/url.js +1 -1
  119. package/node_modules/hono/package.json +1 -1
  120. package/package.json +5 -3
  121. package/protocol/index.json +93 -33
  122. package/protocol/operations/agent.sessions.list.json +146 -0
  123. package/protocol/operations/agent.sessions.read.json +315 -0
  124. package/protocol/operations/conversation.configure.json +29 -0
  125. package/protocol/operations/conversation.decide.json +29 -0
  126. package/protocol/operations/conversation.list.json +29 -0
  127. package/protocol/operations/conversation.permission.json +29 -0
  128. package/protocol/operations/conversation.read.json +29 -0
  129. package/protocol/operations/conversation.restore.json +29 -0
  130. package/protocol/operations/conversation.send.json +29 -0
  131. package/protocol/operations/conversation.settings.check.json +92 -0
  132. package/protocol/operations/conversation.settings.read.json +92 -0
  133. package/protocol/operations/conversation.settings.update.json +92 -0
  134. package/protocol/operations/conversation.start.json +46 -1
  135. package/protocol/operations/conversation.stop.json +29 -0
  136. package/protocol/operations/conversation.trash.json +29 -0
  137. package/protocol/operations/extension.call.json +132 -0
  138. package/protocol/operations/extension.content.json +78 -0
  139. package/protocol/operations/extension.describe.json +195 -0
  140. package/protocol/operations/extension.install.json +198 -0
  141. package/protocol/operations/extension.list.json +123 -0
  142. package/protocol/operations/extension.manage.json +55 -0
  143. package/protocol/operations/extension.read.json +112 -0
  144. package/protocol/operations/observation.snapshot.json +29 -0
  145. package/protocol/operations/project.work.read.json +3 -2
  146. package/protocol/operations/session.grant.json +9 -0
  147. package/protocol/operations/session.instructions.json +43 -0
  148. package/scripts/third-party-acceptance.mjs +77 -0
  149. package/vendor/composition.json +83 -83
  150. package/vendor/rho-workspace-plugin-agent-0.4.30.tgz +0 -0
  151. package/web/theme.css +12 -0
  152. package/dist/web/assets/choices-DU9kHlyQ.js +0 -1
  153. package/dist/web/assets/dist-BV3hWfn_.js +0 -3
  154. package/dist/web/assets/dist-CLNF2g-E.js +0 -1
  155. package/dist/web/assets/explore-in-8Q5ftt-E.js +0 -1
  156. package/dist/web/assets/graph-hS2kvHTI.js +0 -2
  157. package/dist/web/assets/index-Cj1_iqyK.css +0 -1
  158. package/dist/web/assets/overview-BV6ZO5TO.js +0 -6
  159. package/dist/web/assets/preview-n5lOOdjN.js +0 -1
  160. package/dist/web/assets/workspace-BKFefRfJ.js +0 -5
  161. package/vendor/rho-workspace-plugin-agent-0.4.28.tgz +0 -0
package/dist/server.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { Extensions } from './extensions.js';
2
+ import { extensionManagement } from './extension-contract.js';
1
3
  import { EvidenceExporter, evidenceExportLimits } from './evidence-export.js';
2
- import { Discovery } from './discovery.js';
4
+ import { Discovery, applicationEffects } from './discovery.js';
3
5
  import * as http from 'node:http';
4
6
  import * as fs from 'node:fs/promises';
5
7
  import path from 'node:path';
@@ -17,10 +19,10 @@ import { Interactions } from './interactions.js';
17
19
  import { TaskMap } from './task-map.js';
18
20
  import { Capabilities } from './capabilities.js';
19
21
  import { BrowserAccess, localBrowserId, localBrowserPrincipal } from './browser-access.js';
20
- import { addToAgent, connectLimits, mcpCommand, mcpName, outsideLabel } from './agent-connect.js';
22
+ import { addToAgent, connectionInstructions, connectLimits, mcpCommand, mcpName, outsideLabel } from './agent-connect.js';
21
23
  import { NativeFolderPicker, nativeFolderLimits } from './native-folders.js';
22
24
  import { homedir } from 'node:os';
23
- import { serveWeb, servePageFrame, pageFramePath, webRoot, installedWebEntries } from './web-assets.js';
25
+ import { serveWeb, servePageFrame, pageFramePath, extensionFramePath, webRoot, installedWebEntries } from './web-assets.js';
24
26
  import { Presentation } from './presentation.js';
25
27
  import { presentationSchemas } from './presentation-contracts.js';
26
28
  import { isNativeTime } from './native-time.js';
@@ -178,6 +180,7 @@ function explainFailure(e) {
178
180
  }
179
181
  export class RhoService {
180
182
  config;
183
+ extensions;
181
184
  plugins;
182
185
  state;
183
186
  bridge;
@@ -377,6 +380,7 @@ export class RhoService {
377
380
  if (typeof value === 'number')
378
381
  requireThat(Number.isSafeInteger(value) && (key === 'port' ? value >= 0 && value <= 65535 : value > 0), 'invalid', 'Invalid service budget.', { field: key });
379
382
  }
383
+ this.extensions = new Extensions(path.join(config.stateDir, 'plugins'), config.extensions);
380
384
  this.plugins = new Plugins(config);
381
385
  this.state = new State(config.root, config.stateDir);
382
386
  this.bridge = new CoreBridge(config.coreBinary, config.rscript);
@@ -448,6 +452,7 @@ export class RhoService {
448
452
  return [await writeClaudePlugin(path.join(this.state.directory, 'claude-plugins'), { name: 'rho', version: selectedPluginVersions.agent, description: 'Skills and hooks of the plugins selected in Rho.', ...declared })];
449
453
  },
450
454
  changed: async (project, conversationId) => { void this.serial(project.id, () => this.emit(project, 'conversation.changed', conversationId, localBrowserId)).catch(() => { }); },
455
+ nativeSession: async (project, producer, sessionId) => (await import('@rho-workspace/plugin-agent/native-sessions')).nativeSession(project.root, producer, sessionId),
451
456
  // The person's own Claude Code when one is named, with no tools and in an empty folder of
452
457
  // Rho's state, so it reads only what it is given and loads no project instructions. What
453
458
  // a call cost comes from Claude Code when it knows the model's price, else from models.dev.
@@ -484,6 +489,7 @@ export class RhoService {
484
489
  await this.plugins.load();
485
490
  this.plugins.installUi(await installedWebEntries(this.config.webRoot), Object.keys(operations));
486
491
  await this.state.init();
492
+ await this.extensions.init();
487
493
  // A person who starts Rho on a fresh state sees one finished study beside their own work.
488
494
  // It is copied into the projects folder once and is otherwise an ordinary project.
489
495
  this.example = await seedExampleProject(this.state, { enabled: this.config.example === true }).catch(() => null);
@@ -558,18 +564,29 @@ export class RhoService {
558
564
  const capabilities = new Capabilities(this.plugins, project);
559
565
  const state = await capabilities.state();
560
566
  // The shared project listing remains available alongside an Agent's native tools.
561
- const available = Object.keys(operations).filter(m => !m.startsWith('agent.activity.') && !m.startsWith('session.') && !m.startsWith('conversation.') && (!m.startsWith('project.') || m === 'project.entries') && !m.startsWith('requirements.prepare') && !m.startsWith('workspace.restore') && !['task.routing.put', 'binding.activity.append', 'feedback.submit', 'view.observe', 'view.observations.read', 'task.map.respond', 'annotation.decide', 'evidence.export', 'evidence.preview', 'console.run', 'console.stop', 'kernel.stop'].includes(m));
567
+ const available = Object.keys(operations).filter(m => !extensionManagement.includes(m) && !m.startsWith('agent.activity.') && !m.startsWith('agent.sessions.') && !m.startsWith('session.') && !m.startsWith('conversation.') && (!m.startsWith('project.') || m === 'project.entries') && !m.startsWith('requirements.prepare') && !m.startsWith('workspace.restore') && !['task.routing.put', 'binding.activity.append', 'feedback.submit', 'view.observe', 'view.observations.read', 'task.map.respond', 'annotation.decide', 'evidence.export', 'evidence.preview', 'console.run', 'console.stop', 'kernel.stop'].includes(m));
562
568
  const profileMethods = profile === 'layered-presentation' ? ['binding.open', 'capability.index', 'capability.resolve', 'workspace.observe', 'workspace.enhance'] : available.filter(m => !['workspace.observe', 'workspace.enhance', ...(profile ? ['skill.list', 'skill.read', 'protocol.describe'] : [])].includes(m));
563
569
  const selected = methods ?? (profile === 'layered-presentation' ? profileMethods : (await Promise.all(profileMethods.map(async (method) => [method, await capabilities.isAvailable(method, state)]))).filter(([, enabled]) => enabled).map(([method]) => method));
564
570
  requireThat(profile !== 'layered-presentation' || selected.every(m => profileMethods.includes(m)), 'scope', 'The selected role cannot receive broader methods.');
565
- requireThat(selected.every(m => !!operations[m] && !m.startsWith('session.') && !m.startsWith('conversation.') && (!m.startsWith('project.') || m === 'project.entries') && !['task.routing.put', 'console.run', 'console.stop', 'kernel.stop'].includes(m)), 'invalid', 'Unknown or operator-only Agent capability.');
571
+ requireThat(selected.every(m => !extensionManagement.includes(m) && !!operations[m] && !m.startsWith('agent.sessions.') && !m.startsWith('session.') && !m.startsWith('conversation.') && (!m.startsWith('project.') || m === 'project.entries') && !['task.routing.put', 'console.run', 'console.stop', 'kernel.stop'].includes(m)), 'invalid', 'Unknown or operator-only Agent capability.');
566
572
  requireThat(await Promise.all(selected.map(method => capabilities.isAvailable(method, state))).then(values => values.every(Boolean)), 'unavailable', 'A requested Agent operation has no selected provider.');
567
573
  requireThat(!profile || new Set(['capability.index', 'capability.resolve', ...selected]).size <= layeredGrantLimits.maxMethods, 'limit', `Layered connection methods exceed the ${layeredGrantLimits.maxMethods}-method profile; choose an explicit narrower grant.`, { limit: 'maxMethods', maximum: layeredGrantLimits.maxMethods });
568
- const token = randomBytes(32).toString('hex');
569
574
  const id = 'agent:' + digest(projectId + ':' + externalSessionId).slice(0, 32);
575
+ const grantedMethods = [...new Set([...(profile ? ['capability.index', 'capability.resolve'] : ['protocol.describe', 'capability.list']), ...selected])];
576
+ const existing = this.state.principals.find(p => p.id === id);
577
+ const kept = await fs.readFile(file, 'utf8').then(text => JSON.parse(text), () => null);
578
+ // Repeating the same setup must not disconnect a client already using its grant.
579
+ // Changed scope, expired access or a stale address still requires a fresh credential.
580
+ if (existing && !(existing.expiresAt && Date.parse(existing.expiresAt) <= Date.now())
581
+ && kept?.url === this.url && kept.projectId === projectId && kept.externalSessionId === externalSessionId
582
+ && typeof kept.token === 'string' && digest(kept.token) === existing.tokenHash
583
+ && canonical([...existing.methods].sort()) === canonical([...grantedMethods].sort())
584
+ && kept.profile === profile && canonical(existing.pluginFilter ?? []) === canonical(pluginFilter ?? []))
585
+ return kept;
586
+ const token = randomBytes(32).toString('hex');
570
587
  this.state.principals = this.state.principals.filter(p => p.id !== id);
571
588
  requireThat(!pluginFilter || pluginFilter.every(id => this.plugins.isKnown(id)), 'invalid', 'Unknown MCP plugin filter.');
572
- await this.state.addPrincipal({ id, tokenHash: digest(token), projectId, label: who.label ?? externalSessionId, ...(who.conversationId ? { conversationId: who.conversationId } : {}), methods: [...new Set([...(profile ? ['capability.index', 'capability.resolve'] : ['protocol.describe', 'capability.list']), ...selected])], ...(profile ? { profile } : {}), ...(pluginFilter ? { pluginFilter } : {}) });
589
+ await this.state.addPrincipal({ id, tokenHash: digest(token), projectId, label: who.label ?? externalSessionId, ...(who.conversationId ? { conversationId: who.conversationId } : {}), methods: grantedMethods, ...(profile ? { profile } : {}), ...(pluginFilter ? { pluginFilter } : {}) });
573
590
  const connection = { url: this.url, token, projectId, externalSessionId, methods: [...new Set([...(profile ? ['capability.index', 'capability.resolve'] : []), ...selected])], ...(profile ? { profile } : {}), ...(pluginFilter ? { pluginFilter } : {}), apiVersion: '2.0' };
574
591
  await atomicJson(file, connection);
575
592
  return connection;
@@ -656,8 +673,8 @@ export class RhoService {
656
673
  }
657
674
  if (!url.pathname.startsWith('/api/')) {
658
675
  requireThat((req.method === 'GET' || req.method === 'HEAD') && !url.search, 'not_found', 'Use the same-origin browser entry without query credentials.');
659
- if (url.pathname === pageFramePath) {
660
- servePageFrame(res, req.method === 'HEAD');
676
+ if (url.pathname === pageFramePath || url.pathname === extensionFramePath) {
677
+ servePageFrame(res, req.method === 'HEAD', url.pathname === extensionFramePath);
661
678
  return;
662
679
  }
663
680
  await serveWeb(url.pathname, res, this.config.webRoot, req.method === 'HEAD');
@@ -688,7 +705,7 @@ export class RhoService {
688
705
  requireThat(read.ok, read.ok ? 'invalid' : read.kind, read.ok ? '' : (read.problems[0]?.fix ? `Request does not match the versioned schema: ${read.problems[0].fix}` : 'Request does not match the versioned schema.'), read.ok ? {} : { problems: read.problems, remedy: 'Fix the named fields and resend the same request identity.' });
689
706
  const request = read.request, contractRef = typeof req.headers['x-rho-contract-ref'] === 'string' ? req.headers['x-rho-contract-ref'] : undefined;
690
707
  let value;
691
- if (body.projectId && method.startsWith('kernel.')) {
708
+ if (body.projectId && (method.startsWith('kernel.') || method === 'extension.call')) {
692
709
  // A cell may run for minutes and a run may wait for it. The live sessions keep their own
693
710
  // order, so waiting holds no other request of the project, an interrupt among them.
694
711
  const projectId = body.projectId;
@@ -780,6 +797,32 @@ export class RhoService {
780
797
  // What the project's Agents did, for the person's screen:
781
798
  // only principals whose grant names this project, only the fields the activity record
782
799
  // keeps. A grant is the scope; an Agent need not have opened a binding.
800
+ // Every Agent session in the project folder, wherever it was started: Harness conversations Rho
801
+ // observes and the sessions Claude Code and Codex keep in their own files. Each names the Agent
802
+ // Rho continues it with and the Rho conversation that already continues it. Reads files only.
803
+ async agentSessions(p) {
804
+ const agent = this.plugins.optional('agent');
805
+ const external = agent ? agent.listExternalSessions(p.root) : { sessions: [], omitted: 0 };
806
+ const native = (await import('@rho-workspace/plugin-agent/native-sessions')).listNativeSessions(p.root);
807
+ const conversations = [...await this.conversations.list(p, {}), ...await this.conversations.list(p, { trashed: true })];
808
+ const bySession = new Map(conversations.filter(c => c.sessionId).map(c => [c.sessionId, c]));
809
+ const sessions = [...external.sessions, ...native.sessions].flatMap(s => {
810
+ const conversation = bySession.get(s.sessionId);
811
+ if (conversation?.trashedAt)
812
+ return [];
813
+ const continueWith = s.producer === 'claude-code' ? 'claude-acp' : s.producer === 'codex' ? 'codex-acp' : s.producer === 'dsh' && this.config.acpCommand ? 'acp' : null;
814
+ // Harness reports a turn in progress, not whether a window holds the session idle; a turn
815
+ // Rho itself is running is Rho's.
816
+ const open = s.producer === 'dsh' && s.state === 'running' && conversation?.state !== 'running' ? { where: 'DeepSeek Harness' } : s.open;
817
+ return [{ ...s, continueWith, ...(open !== undefined ? { open } : {}), ...(conversation ? { conversationId: conversation.conversationId } : {}) }];
818
+ });
819
+ // A session held only by Rho's own connection is not open elsewhere.
820
+ for (const s of sessions)
821
+ if (s.open && s.conversationId && await this.conversations.owns(p, s.conversationId, s.open.pid))
822
+ s.open = null;
823
+ sessions.sort((a, b) => b.lastAt.localeCompare(a.lastAt));
824
+ return { sessions: sessions.slice(0, 128), omitted: external.omitted + native.omitted + Math.max(0, sessions.length - 128) };
825
+ }
783
826
  async projectActivity(p) {
784
827
  const agent = this.plugins.project(p.root, p.id).agent;
785
828
  if (!agent)
@@ -862,6 +905,14 @@ export class RhoService {
862
905
  requireThat(this.state.principals.some(current => current.id === principal.id && current.tokenHash === principal.tokenHash && current.methods.includes(method) && (!current.expiresAt || Date.parse(current.expiresAt) > Date.now())), 'unauthorized', 'Session authorization expired or was revoked before this operation.');
863
906
  if (method === 'protocol.describe')
864
907
  return describeProtocol(protocol, principal.methods, b);
908
+ if (extensionManagement.includes(method)) {
909
+ requireThat(principal.id === 'operator' || principal.id === localBrowserId, 'scope', 'Plugin installation and management belong to the person at this machine.');
910
+ return method === 'extension.install' ? this.extensions.install(b.source, b.replace, b.expectedDigest) : this.extensions.manage(b.pluginId, b.expectedDigest, b.action);
911
+ }
912
+ if (method === 'extension.list' && !b.projectId) {
913
+ requireThat(principal.id === 'operator' || principal.id === localBrowserId, 'scope', 'A project-scoped caller must supply its project.');
914
+ return this.extensions.list();
915
+ }
865
916
  // A dry run of any operation body: the same schema the server enforces, with the
866
917
  // edit each problem needs. Nothing is executed and no project is touched.
867
918
  if (method === 'protocol.validate') {
@@ -936,6 +987,32 @@ export class RhoService {
936
987
  const workspace = new Workspace(p, owners, this.config.workspace, this.config.interactions);
937
988
  const interactions = new Interactions(p, owners, this.config.interactions);
938
989
  const routing = new TaskRouting(p, this.config.capabilityLimits?.maxReceipts, this.config.maxRetainedMetadataBytes);
990
+ if (method.startsWith('extension.')) {
991
+ if (contractRef) {
992
+ const reader = new Discovery(this.plugins, p, principal, await routing.read(), await readJson(path.join(await this.dataDir(p), 'bindings.json'), []));
993
+ await reader.assertContract(method, contractRef);
994
+ }
995
+ if (method === 'extension.list')
996
+ return this.extensions.list();
997
+ if (method === 'extension.describe')
998
+ return this.extensions.describe(b.pluginId);
999
+ if (method === 'extension.content')
1000
+ return this.extensions.content(b.pluginId, b.expectedDigest, b.kind, b.entryId);
1001
+ if (method === 'extension.read')
1002
+ return this.extensions.read(b.invocationId, principal.id, p.id);
1003
+ if (method === 'extension.call')
1004
+ return this.extensions.call(b, principal.id, p.root, async (target, body, effect) => {
1005
+ requireThat(principal.methods.includes(target), 'scope', 'The caller has not been granted this Rho method.');
1006
+ requireThat(!body?.projectId || body.projectId === p.id, 'scope', 'A plugin cannot delegate into another project.');
1007
+ const request = readOperation(target, { ...body, projectId: p.id });
1008
+ requireThat(request.ok, 'invalid', 'Plugin delegated an invalid Rho request.');
1009
+ const capabilities = new Capabilities(this.plugins, p);
1010
+ const status = (await capabilities.operationStatus(principal, await capabilities.state())).find(op => op.method === target);
1011
+ requireThat(effect !== 'read' || (status?.effect ?? applicationEffects[target]) === 'read', 'scope', 'A read operation cannot delegate a mutating Rho method.');
1012
+ const run = () => this.dispatch(request.request, principal);
1013
+ return target.startsWith('kernel.') ? run() : this.serial(p.id, run);
1014
+ });
1015
+ }
939
1016
  // A person's own view of the folder they selected. The tab is confined to this one
940
1017
  // project, so it may list that folder and open a text file from it; registering
941
1018
  // resources and execution stay Agent/operator work.
@@ -1117,10 +1194,15 @@ export class RhoService {
1117
1194
  await this.emit(p, 'composition.changed', b.compositionId);
1118
1195
  return { document, viewId, composition };
1119
1196
  }
1197
+ if (method === 'session.instructions') {
1198
+ requireThat(principal.id === localBrowserId || principal.id === 'operator', 'unauthorized', 'Only the person at this machine can read Agent setup instructions.');
1199
+ return connectionInstructions(p, this.state.directory);
1200
+ }
1120
1201
  if (method === 'session.grant') {
1121
1202
  requireThat(principal.id === 'operator', 'unauthorized', 'Only the local operator may provision a project-scoped session.');
1122
1203
  const file = path.join(this.state.directory, 'agent-' + digest(p.id + ':' + b.externalSessionId) + '.json');
1123
1204
  const connection = await this.agentConnection(p.id, b.externalSessionId, file, b.methods, undefined, b.profile);
1205
+ await this.emit(p, 'activity.changed', method);
1124
1206
  return { profile: connection.profile, connectionFile: file, projectId: p.id, methods: connection.methods, transport: 'stdio-mcp', externalSessionId: b.externalSessionId };
1125
1207
  }
1126
1208
  // The person's own Claude Code or Codex, outside Rho: the same grant the operator gives, kept
@@ -1150,6 +1232,18 @@ export class RhoService {
1150
1232
  }
1151
1233
  // The person at this machine talks to a conversation Rho started; Agents and narrower links
1152
1234
  // cannot start one, and an Agent started this way cannot start another.
1235
+ if (method.startsWith('agent.sessions.')) {
1236
+ requireThat(principal.id === localBrowserId, 'unauthorized', 'Agent session history belongs to the person at this machine.');
1237
+ if (method === 'agent.sessions.list')
1238
+ return this.agentSessions(p);
1239
+ const listed = (await this.agentSessions(p)).sessions.find(s => s.id === b.session);
1240
+ requireThat(listed, 'not_found', 'That Agent session is not in this project.');
1241
+ const read = listed.producer === 'claude-code' || listed.producer === 'codex'
1242
+ ? await (await import('@rho-workspace/plugin-agent/native-sessions')).readNativeSession(p.root, b)
1243
+ : this.plugins.need('agent').readExternalSession(p.root, b);
1244
+ requireThat(read, 'not_found', 'That Agent session is no longer in this project.');
1245
+ return { ...read, session: { ...read.session, ...listed } };
1246
+ }
1153
1247
  if (method === 'project.work.read') {
1154
1248
  requireThat(principal.id === localBrowserId, 'scope', 'Project work is available to the person at this machine.');
1155
1249
  const agent = (await new Capabilities(this.plugins, p).state()).enabled.includes('agent') ? this.plugins.optional('agent') : null;
@@ -1166,7 +1260,7 @@ export class RhoService {
1166
1260
  }
1167
1261
  return projectWork({ project: p, cursor: (await this.events(p)).cursor, conversations: await this.conversations.work(p, b.limit),
1168
1262
  documents: await owners.documentSummaries(), activity: (await this.projectActivity(p)).entries,
1169
- native, external: agent?.readExternalAcp(p.root), inspect: agent?.observeSessionFiles });
1263
+ native, external: agent?.readExternalAcp(p.root), observed: agent?.listExternalSessions(p.root), readObserved: agent?.readExternalSession, inspect: agent?.observeSessionFiles });
1170
1264
  }
1171
1265
  if (method.startsWith('conversation.')) {
1172
1266
  requireThat(principal.id === localBrowserId, 'unauthorized', 'Conversations started in Rho belong to the person at this machine. Open Rho in a browser on this machine.');
@@ -1189,10 +1283,25 @@ export class RhoService {
1189
1283
  if (method === 'conversation.settings.read')
1190
1284
  return this.conversations.settings();
1191
1285
  this.plugins.need('agent');
1286
+ if (method === 'conversation.start' && b.continue) {
1287
+ const listed = (await this.agentSessions(p)).sessions.find(s => s.id === b.continue.session);
1288
+ requireThat(listed, 'not_found', 'That Agent session is not in this project. Nothing was sent.');
1289
+ requireThat(listed.continueWith, 'condition', listed.producer === 'dsh'
1290
+ ? 'Rho continues DeepSeek Harness sessions through Harness\'s ACP command. Start Rho with --agent-backend acp --acp-command \'["dsh","acp"]\', or continue in Harness. Nothing was sent.'
1291
+ : 'Rho cannot continue this Agent\'s sessions. Nothing was sent.');
1292
+ requireThat(!listed.conversationId, 'conflict', 'This session already continues as a conversation here. Open it to send your message.');
1293
+ requireThat(!b.continue.copy || listed.producer !== 'dsh', 'condition', 'DeepSeek Harness cannot copy a session. Continue it in place once it is not answering. Nothing was sent.');
1294
+ requireThat(!listed.open || listed.producer !== 'dsh', 'condition', 'DeepSeek Harness is answering in this session now. Continue it once that turn ends. Nothing was sent.', { heldBy: 'DeepSeek Harness' });
1295
+ return this.conversations.start(p, principal.id, { ...b, continue: { producer: listed.producer, sessionId: listed.sessionId, title: listed.title, where: listed.where ?? (listed.producer === 'dsh' ? 'DeepSeek Harness' : 'another window'), copy: !!b.continue.copy, backend: listed.continueWith } });
1296
+ }
1192
1297
  if (method === 'conversation.start')
1193
1298
  return this.conversations.start(p, principal.id, b);
1194
- if (method === 'conversation.send')
1299
+ if (method === 'conversation.send') {
1300
+ // A Harness session reports its own turns through its adapter; Rho does not write into one it is answering.
1301
+ const listed = (await this.agentSessions(p)).sessions.find(s => s.conversationId === b.conversationId && s.producer === 'dsh');
1302
+ requireThat(!listed?.open, 'condition', 'DeepSeek Harness is answering in this session now. Send once that turn ends. Nothing was sent.', { heldBy: 'DeepSeek Harness' });
1195
1303
  return this.conversations.send(p, principal.id, b);
1304
+ }
1196
1305
  if (method === 'conversation.configure')
1197
1306
  return this.conversations.configure(p, principal.id, b);
1198
1307
  if (method === 'conversation.settings.update')
@@ -1715,6 +1824,7 @@ export class RhoService {
1715
1824
  return this.state.principals.some(p => p.id === id && p.tokenHash === tokenHash && p.methods.includes('observation.snapshot') && (!p.expiresAt || Date.parse(p.expiresAt) > Date.now()));
1716
1825
  }
1717
1826
  async close() {
1827
+ this.extensions.close();
1718
1828
  this.closing = true;
1719
1829
  this.folderPicker.close();
1720
1830
  for (const s of this.subscribers)
@@ -253,7 +253,7 @@
253
253
  ]
254
254
  },
255
255
  "../node_modules/@codemirror/lang-markdown/dist/index.js": {
256
- "file": "assets/dist-B2V0VDO0.js",
256
+ "file": "assets/dist-DZmszrjG.js",
257
257
  "name": "dist",
258
258
  "src": "../node_modules/@codemirror/lang-markdown/dist/index.js",
259
259
  "isDynamicEntry": true,
@@ -261,22 +261,22 @@
261
261
  "index.html",
262
262
  "_dist-DCtcCJPs.js",
263
263
  "../node_modules/@codemirror/language/dist/index.js",
264
- "_dist-CLNF2g-E.js"
264
+ "_dist-DpIHRk3B.js"
265
265
  ]
266
266
  },
267
267
  "../node_modules/@codemirror/lang-python/dist/index.js": {
268
- "file": "assets/dist-D25Vn17i.js",
268
+ "file": "assets/dist-eMx6b8N1.js",
269
269
  "name": "dist",
270
270
  "src": "../node_modules/@codemirror/lang-python/dist/index.js",
271
271
  "isDynamicEntry": true,
272
272
  "imports": [
273
273
  "_dist-DCtcCJPs.js",
274
274
  "../node_modules/@codemirror/language/dist/index.js",
275
- "_dist-CLNF2g-E.js"
275
+ "_dist-DpIHRk3B.js"
276
276
  ]
277
277
  },
278
278
  "../node_modules/@codemirror/language/dist/index.js": {
279
- "file": "assets/dist-BV3hWfn_.js",
279
+ "file": "assets/dist-pF902jHA.js",
280
280
  "name": "dist",
281
281
  "src": "../node_modules/@codemirror/language/dist/index.js",
282
282
  "isDynamicEntry": true,
@@ -295,8 +295,8 @@
295
295
  "file": "assets/answer-board-CBkGbSLD.js",
296
296
  "name": "answer-board"
297
297
  },
298
- "_canvas-BXhC8RDZ.js": {
299
- "file": "assets/canvas-BXhC8RDZ.js",
298
+ "_canvas-D8rDdfDz.js": {
299
+ "file": "assets/canvas-D8rDdfDz.js",
300
300
  "name": "canvas",
301
301
  "imports": [
302
302
  "_rolldown-runtime-XKyaHtl9.js",
@@ -304,64 +304,64 @@
304
304
  "_home-CCbP6kS-.js"
305
305
  ]
306
306
  },
307
- "_choices-DLah50GC.css": {
308
- "file": "assets/choices-DLah50GC.css",
309
- "src": "_choices-DLah50GC.css"
310
- },
311
- "_choices-DU9kHlyQ.js": {
312
- "file": "assets/choices-DU9kHlyQ.js",
307
+ "_choices-D-YfnFP6.js": {
308
+ "file": "assets/choices-D-YfnFP6.js",
313
309
  "name": "choices",
314
310
  "imports": [
315
311
  "_rolldown-runtime-XKyaHtl9.js",
316
312
  "_react-Dss-ouuy.js",
317
313
  "_markdown-0ngRuTpW.js",
318
- "_canvas-BXhC8RDZ.js",
314
+ "_canvas-D8rDdfDz.js",
319
315
  "index.html",
320
- "_notes-meaning-DdPbtNzJ.js"
316
+ "_notes-meaning-DcVGUBBY.js"
321
317
  ],
322
318
  "css": [
323
319
  "assets/choices-DLah50GC.css"
324
320
  ]
325
321
  },
322
+ "_choices-DLah50GC.css": {
323
+ "file": "assets/choices-DLah50GC.css",
324
+ "src": "_choices-DLah50GC.css"
325
+ },
326
326
  "_console-By4Mvn1y.css": {
327
327
  "file": "assets/console-By4Mvn1y.css",
328
328
  "src": "_console-By4Mvn1y.css"
329
329
  },
330
- "_console-Dbdo-5oO.js": {
331
- "file": "assets/console-Dbdo-5oO.js",
330
+ "_console-Trqc0swD.js": {
331
+ "file": "assets/console-Trqc0swD.js",
332
332
  "name": "console",
333
333
  "imports": [
334
334
  "_rolldown-runtime-XKyaHtl9.js",
335
335
  "_react-Dss-ouuy.js",
336
336
  "_home-CCbP6kS-.js",
337
337
  "_markdown-0ngRuTpW.js",
338
- "_canvas-BXhC8RDZ.js",
338
+ "_canvas-D8rDdfDz.js",
339
339
  "index.html",
340
340
  "_facts-BMO6V3-3.js",
341
- "_work-turns-Co0C71rJ.js"
341
+ "_work-turns-CT9RVcWY.js"
342
342
  ],
343
343
  "css": [
344
344
  "assets/console-By4Mvn1y.css"
345
345
  ]
346
346
  },
347
- "_dist-CLNF2g-E.js": {
348
- "file": "assets/dist-CLNF2g-E.js",
347
+ "_dist-DCtcCJPs.js": {
348
+ "file": "assets/dist-DCtcCJPs.js",
349
349
  "name": "dist",
350
350
  "imports": [
351
- "index.html",
352
- "_dist-DCtcCJPs.js",
353
- "../node_modules/@codemirror/language/dist/index.js"
351
+ "_rolldown-runtime-XKyaHtl9.js"
354
352
  ]
355
353
  },
356
- "_dist-DCtcCJPs.js": {
357
- "file": "assets/dist-DCtcCJPs.js",
354
+ "_dist-DpIHRk3B.js": {
355
+ "file": "assets/dist-DpIHRk3B.js",
358
356
  "name": "dist",
359
357
  "imports": [
360
- "_rolldown-runtime-XKyaHtl9.js"
358
+ "index.html",
359
+ "_dist-DCtcCJPs.js",
360
+ "../node_modules/@codemirror/language/dist/index.js"
361
361
  ]
362
362
  },
363
- "_explore-in-8Q5ftt-E.js": {
364
- "file": "assets/explore-in-8Q5ftt-E.js",
363
+ "_explore-in-BCHqjJ7B.js": {
364
+ "file": "assets/explore-in-BCHqjJ7B.js",
365
365
  "name": "explore-in",
366
366
  "imports": [
367
367
  "_react-Dss-ouuy.js",
@@ -402,8 +402,8 @@
402
402
  "_react-Dss-ouuy.js"
403
403
  ]
404
404
  },
405
- "_notes-meaning-DdPbtNzJ.js": {
406
- "file": "assets/notes-meaning-DdPbtNzJ.js",
405
+ "_notes-meaning-DcVGUBBY.js": {
406
+ "file": "assets/notes-meaning-DcVGUBBY.js",
407
407
  "name": "notes-meaning",
408
408
  "imports": [
409
409
  "index.html"
@@ -420,8 +420,8 @@
420
420
  "file": "assets/rolldown-runtime-XKyaHtl9.js",
421
421
  "name": "rolldown-runtime"
422
422
  },
423
- "_skills-work-Cj0W6b-I.js": {
424
- "file": "assets/skills-work-Cj0W6b-I.js",
423
+ "_skills-work-DNexV4OJ.js": {
424
+ "file": "assets/skills-work-DNexV4OJ.js",
425
425
  "name": "skills-work",
426
426
  "imports": [
427
427
  "_rolldown-runtime-XKyaHtl9.js",
@@ -439,8 +439,8 @@
439
439
  "_react-Dss-ouuy.js"
440
440
  ]
441
441
  },
442
- "_timeline-events-DmX1BCh3.js": {
443
- "file": "assets/timeline-events-DmX1BCh3.js",
442
+ "_timeline-events-Chj2Gbx7.js": {
443
+ "file": "assets/timeline-events-Chj2Gbx7.js",
444
444
  "name": "timeline-events",
445
445
  "imports": [
446
446
  "_rolldown-runtime-XKyaHtl9.js",
@@ -448,8 +448,8 @@
448
448
  "index.html"
449
449
  ]
450
450
  },
451
- "_work-turns-Co0C71rJ.js": {
452
- "file": "assets/work-turns-Co0C71rJ.js",
451
+ "_work-turns-CT9RVcWY.js": {
452
+ "file": "assets/work-turns-CT9RVcWY.js",
453
453
  "name": "work-turns",
454
454
  "imports": [
455
455
  "_rolldown-runtime-XKyaHtl9.js",
@@ -458,7 +458,7 @@
458
458
  ]
459
459
  },
460
460
  "graph.tsx": {
461
- "file": "assets/graph-hS2kvHTI.js",
461
+ "file": "assets/graph-lENgfQNH.js",
462
462
  "name": "graph",
463
463
  "src": "graph.tsx",
464
464
  "isDynamicEntry": true,
@@ -466,19 +466,19 @@
466
466
  "_rolldown-runtime-XKyaHtl9.js",
467
467
  "_react-Dss-ouuy.js",
468
468
  "_markdown-0ngRuTpW.js",
469
- "_canvas-BXhC8RDZ.js",
469
+ "_canvas-D8rDdfDz.js",
470
470
  "index.html",
471
- "_work-turns-Co0C71rJ.js",
471
+ "_work-turns-CT9RVcWY.js",
472
472
  "_snapshot-CAxBYPvV.js",
473
- "_timeline-events-DmX1BCh3.js",
474
- "_choices-DU9kHlyQ.js"
473
+ "_timeline-events-Chj2Gbx7.js",
474
+ "_choices-D-YfnFP6.js"
475
475
  ],
476
476
  "css": [
477
477
  "assets/graph-BYKN84J3.css"
478
478
  ]
479
479
  },
480
480
  "index.html": {
481
- "file": "assets/index-BHQIaDsx.js",
481
+ "file": "assets/index-BpL_Kl_s.js",
482
482
  "name": "index",
483
483
  "src": "index.html",
484
484
  "isEntry": true,
@@ -487,7 +487,7 @@
487
487
  "_react-Dss-ouuy.js",
488
488
  "_home-CCbP6kS-.js",
489
489
  "_markdown-0ngRuTpW.js",
490
- "_canvas-BXhC8RDZ.js"
490
+ "_canvas-D8rDdfDz.js"
491
491
  ],
492
492
  "dynamicImports": [
493
493
  "_dist-DCtcCJPs.js",
@@ -501,17 +501,17 @@
501
501
  "overview.tsx",
502
502
  "preview.tsx",
503
503
  "graph.tsx",
504
- "_console-Dbdo-5oO.js",
504
+ "_console-Trqc0swD.js",
505
505
  "index.html",
506
506
  "skills.tsx",
507
507
  "studio-process.tsx"
508
508
  ],
509
509
  "css": [
510
- "assets/index-Cj1_iqyK.css"
510
+ "assets/index-B3_OVy91.css"
511
511
  ]
512
512
  },
513
513
  "overview.tsx": {
514
- "file": "assets/overview-BV6ZO5TO.js",
514
+ "file": "assets/overview-CDnVKlOt.js",
515
515
  "name": "overview",
516
516
  "src": "overview.tsx",
517
517
  "isDynamicEntry": true,
@@ -520,13 +520,13 @@
520
520
  "_react-Dss-ouuy.js",
521
521
  "_home-CCbP6kS-.js",
522
522
  "_markdown-0ngRuTpW.js",
523
- "_canvas-BXhC8RDZ.js",
523
+ "_canvas-D8rDdfDz.js",
524
524
  "index.html",
525
525
  "_facts-BMO6V3-3.js",
526
- "_work-turns-Co0C71rJ.js",
527
- "_choices-DU9kHlyQ.js",
528
- "_skills-work-Cj0W6b-I.js",
529
- "_explore-in-8Q5ftt-E.js",
526
+ "_work-turns-CT9RVcWY.js",
527
+ "_choices-D-YfnFP6.js",
528
+ "_skills-work-DNexV4OJ.js",
529
+ "_explore-in-BCHqjJ7B.js",
530
530
  "_answer-board-CBkGbSLD.js"
531
531
  ],
532
532
  "dynamicImports": [
@@ -537,7 +537,7 @@
537
537
  ]
538
538
  },
539
539
  "preview.tsx": {
540
- "file": "assets/preview-n5lOOdjN.js",
540
+ "file": "assets/preview-BEC1E9MK.js",
541
541
  "name": "preview",
542
542
  "src": "preview.tsx",
543
543
  "isDynamicEntry": true,
@@ -545,13 +545,13 @@
545
545
  "_rolldown-runtime-XKyaHtl9.js",
546
546
  "_react-Dss-ouuy.js",
547
547
  "_markdown-0ngRuTpW.js",
548
- "_canvas-BXhC8RDZ.js",
548
+ "_canvas-D8rDdfDz.js",
549
549
  "index.html",
550
- "_explore-in-8Q5ftt-E.js"
550
+ "_explore-in-BCHqjJ7B.js"
551
551
  ]
552
552
  },
553
553
  "review.tsx": {
554
- "file": "assets/review-CmWou4Iv.js",
554
+ "file": "assets/review-DYP0aCXb.js",
555
555
  "name": "review",
556
556
  "src": "review.tsx",
557
557
  "isDynamicEntry": true,
@@ -564,7 +564,7 @@
564
564
  ]
565
565
  },
566
566
  "shell/workspace.tsx": {
567
- "file": "assets/workspace-BKFefRfJ.js",
567
+ "file": "assets/workspace-COmCbGV3.js",
568
568
  "name": "workspace",
569
569
  "src": "shell/workspace.tsx",
570
570
  "isDynamicEntry": true,
@@ -572,16 +572,16 @@
572
572
  "_rolldown-runtime-XKyaHtl9.js",
573
573
  "_react-Dss-ouuy.js",
574
574
  "_markdown-0ngRuTpW.js",
575
- "_canvas-BXhC8RDZ.js",
575
+ "_canvas-D8rDdfDz.js",
576
576
  "index.html",
577
- "_console-Dbdo-5oO.js",
577
+ "_console-Trqc0swD.js",
578
578
  "_facts-BMO6V3-3.js",
579
579
  "_snapshot-CAxBYPvV.js",
580
- "_explore-in-8Q5ftt-E.js"
580
+ "_explore-in-BCHqjJ7B.js"
581
581
  ]
582
582
  },
583
583
  "skills.tsx": {
584
- "file": "assets/skills-Dy7n3L9d.js",
584
+ "file": "assets/skills-1ec0Z-jx.js",
585
585
  "name": "skills",
586
586
  "src": "skills.tsx",
587
587
  "isDynamicEntry": true,
@@ -591,14 +591,14 @@
591
591
  "_home-CCbP6kS-.js",
592
592
  "_markdown-0ngRuTpW.js",
593
593
  "index.html",
594
- "_skills-work-Cj0W6b-I.js"
594
+ "_skills-work-DNexV4OJ.js"
595
595
  ],
596
596
  "css": [
597
597
  "assets/skills-WkE0KCzn.css"
598
598
  ]
599
599
  },
600
600
  "studio-process.tsx": {
601
- "file": "assets/studio-process-QOY_n2_8.js",
601
+ "file": "assets/studio-process-EYQgikxq.js",
602
602
  "name": "studio-process",
603
603
  "src": "studio-process.tsx",
604
604
  "isDynamicEntry": true,
@@ -606,11 +606,11 @@
606
606
  "_rolldown-runtime-XKyaHtl9.js",
607
607
  "_react-Dss-ouuy.js",
608
608
  "_markdown-0ngRuTpW.js",
609
- "_canvas-BXhC8RDZ.js",
609
+ "_canvas-D8rDdfDz.js",
610
610
  "index.html",
611
- "_console-Dbdo-5oO.js",
612
- "_timeline-events-DmX1BCh3.js",
613
- "_notes-meaning-DdPbtNzJ.js",
611
+ "_console-Trqc0swD.js",
612
+ "_timeline-events-Chj2Gbx7.js",
613
+ "_notes-meaning-DcVGUBBY.js",
614
614
  "_answer-board-CBkGbSLD.js",
615
615
  "shell/workspace.tsx"
616
616
  ],