@rho-workspace/rho 0.5.5 → 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 (106) 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 +1 -1
  4. package/dist/cli.js +38 -8
  5. package/dist/contract.generated.d.ts +148 -5
  6. package/dist/contract.generated.js +1 -1
  7. package/dist/contracts/owners.generated.js +107 -12
  8. package/dist/conversations.d.ts +157 -4
  9. package/dist/conversations.js +69 -6
  10. package/dist/discovery.js +1 -1
  11. package/dist/protocol.d.ts +1 -0
  12. package/dist/protocol.js +12 -5
  13. package/dist/server.d.ts +2 -10
  14. package/dist/server.js +71 -8
  15. package/dist/web/.vite/manifest.json +61 -61
  16. package/dist/web/assets/{choices-b0XhrGQV.js → choices-D-YfnFP6.js} +1 -1
  17. package/dist/web/assets/{console-BSjLGe0T.js → console-Trqc0swD.js} +1 -1
  18. package/dist/web/assets/{dist-Buk0lwzI.js → dist-DZmszrjG.js} +1 -1
  19. package/dist/web/assets/{dist-Cw8hRIlT.js → dist-DpIHRk3B.js} +1 -1
  20. package/dist/web/assets/{dist-foH9IKc6.js → dist-eMx6b8N1.js} +1 -1
  21. package/dist/web/assets/{dist-Tzoe_zm-.js → dist-pF902jHA.js} +1 -1
  22. package/dist/web/assets/{explore-in-BVUy3ZW_.js → explore-in-BCHqjJ7B.js} +1 -1
  23. package/dist/web/assets/{graph-1OdIJ9l7.js → graph-lENgfQNH.js} +1 -1
  24. package/dist/web/assets/index-B3_OVy91.css +1 -0
  25. package/dist/web/assets/{index-CxmItXqa.js → index-BpL_Kl_s.js} +84 -83
  26. package/dist/web/assets/{notes-meaning-pVbbQUGP.js → notes-meaning-DcVGUBBY.js} +1 -1
  27. package/dist/web/assets/{overview-B9UtVJ32.js → overview-CDnVKlOt.js} +3 -3
  28. package/dist/web/assets/{preview-CksD_5KS.js → preview-BEC1E9MK.js} +1 -1
  29. package/dist/web/assets/{review-CMxQlQ-C.js → review-DYP0aCXb.js} +1 -1
  30. package/dist/web/assets/{skills-BFNSyrnD.js → skills-1ec0Z-jx.js} +1 -1
  31. package/dist/web/assets/{skills-work-BGPSnF_I.js → skills-work-DNexV4OJ.js} +1 -1
  32. package/dist/web/assets/{studio-process-CsRoTHOh.js → studio-process-EYQgikxq.js} +1 -1
  33. package/dist/web/assets/{timeline-events-BbuuFWHV.js → timeline-events-Chj2Gbx7.js} +1 -1
  34. package/dist/web/assets/{work-turns-BvJlIMmA.js → work-turns-CT9RVcWY.js} +1 -1
  35. package/dist/web/assets/{workspace-CWlkjLNx.js → workspace-COmCbGV3.js} +1 -1
  36. package/dist/web/composition.json +58 -58
  37. package/dist/web/index.html +2 -2
  38. package/dist/web/renderer.json +1 -1
  39. package/docs/FRONTEND.md +26 -18
  40. package/docs/HEADLESS.md +37 -27
  41. package/node_modules/@rho-workspace/plugin-agent/README.md +29 -0
  42. package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.d.ts +1 -0
  43. package/node_modules/@rho-workspace/plugin-agent/dist/acp-command.js +9 -1
  44. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.d.ts +1 -0
  45. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +10 -0
  46. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.js +10 -5
  47. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.d.ts +12 -1
  48. package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.d.ts +70 -0
  49. package/node_modules/@rho-workspace/plugin-agent/dist/native-sessions.js +538 -0
  50. package/node_modules/@rho-workspace/plugin-agent/package.json +2 -1
  51. package/node_modules/hono/dist/adapter/aws-lambda/handler.js +1 -1
  52. package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +1 -1
  53. package/node_modules/hono/dist/cjs/adapter/bun/serve-static.js +1 -1
  54. package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +1 -1
  55. package/node_modules/hono/dist/cjs/client/fetch-result-please.js +1 -1
  56. package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +2 -1
  57. package/node_modules/hono/dist/cjs/helper/ssg/ssg.js +5 -3
  58. package/node_modules/hono/dist/cjs/jsx/base.js +49 -30
  59. package/node_modules/hono/dist/cjs/jsx/components.js +2 -2
  60. package/node_modules/hono/dist/cjs/jsx/constants.js +2 -0
  61. package/node_modules/hono/dist/cjs/jsx/jsx-runtime.js +13 -17
  62. package/node_modules/hono/dist/cjs/middleware/etag/index.js +3 -1
  63. package/node_modules/hono/dist/cjs/middleware/pretty-json/index.js +1 -0
  64. package/node_modules/hono/dist/cjs/middleware/timing/timing.js +4 -3
  65. package/node_modules/hono/dist/cjs/utils/cookie.js +2 -2
  66. package/node_modules/hono/dist/cjs/utils/mime.js +1 -1
  67. package/node_modules/hono/dist/cjs/utils/url.js +1 -1
  68. package/node_modules/hono/dist/client/fetch-result-please.js +1 -1
  69. package/node_modules/hono/dist/helper/accepts/accepts.js +2 -1
  70. package/node_modules/hono/dist/helper/ssg/ssg.js +5 -3
  71. package/node_modules/hono/dist/jsx/base.js +49 -32
  72. package/node_modules/hono/dist/jsx/components.js +2 -2
  73. package/node_modules/hono/dist/jsx/constants.js +2 -1
  74. package/node_modules/hono/dist/jsx/jsx-runtime.js +15 -19
  75. package/node_modules/hono/dist/middleware/etag/index.js +3 -1
  76. package/node_modules/hono/dist/middleware/language/language.js +1 -1
  77. package/node_modules/hono/dist/middleware/pretty-json/index.js +1 -0
  78. package/node_modules/hono/dist/middleware/timing/timing.js +4 -3
  79. package/node_modules/hono/dist/utils/cookie.js +2 -2
  80. package/node_modules/hono/dist/utils/mime.js +1 -1
  81. package/node_modules/hono/dist/utils/url.js +1 -1
  82. package/node_modules/hono/package.json +1 -1
  83. package/package.json +2 -2
  84. package/protocol/index.json +39 -33
  85. package/protocol/operations/agent.sessions.list.json +49 -3
  86. package/protocol/operations/agent.sessions.read.json +53 -4
  87. package/protocol/operations/conversation.configure.json +29 -0
  88. package/protocol/operations/conversation.decide.json +29 -0
  89. package/protocol/operations/conversation.list.json +29 -0
  90. package/protocol/operations/conversation.permission.json +29 -0
  91. package/protocol/operations/conversation.read.json +29 -0
  92. package/protocol/operations/conversation.restore.json +29 -0
  93. package/protocol/operations/conversation.send.json +29 -0
  94. package/protocol/operations/conversation.settings.check.json +92 -0
  95. package/protocol/operations/conversation.settings.read.json +92 -0
  96. package/protocol/operations/conversation.settings.update.json +92 -0
  97. package/protocol/operations/conversation.start.json +46 -1
  98. package/protocol/operations/conversation.stop.json +29 -0
  99. package/protocol/operations/conversation.trash.json +29 -0
  100. package/protocol/operations/observation.snapshot.json +29 -0
  101. package/protocol/operations/session.instructions.json +43 -0
  102. package/vendor/composition.json +74 -74
  103. package/vendor/rho-workspace-plugin-agent-0.4.30.tgz +0 -0
  104. package/web/theme.css +12 -0
  105. package/dist/web/assets/index-CsC3sTRq.css +0 -1
  106. package/vendor/rho-workspace-plugin-agent-0.4.29.tgz +0 -0
@@ -429,3 +429,32 @@ local storage and observation work; they do not limit the native Agent.
429
429
  `test/external-session.test.mjs` checks identity, prefix conflicts, omissions,
430
430
  missing outcomes, redaction, project containment, retained failure and pagination.
431
431
  The Rho application records its separate real Harness/browser acceptance.
432
+
433
+ ### Native Claude Code and Codex sessions
434
+
435
+ Agent 0.4.30 exports `native-sessions`. `listNativeSessions(root, nativeSources(env))`
436
+ lists the Claude Code and Codex sessions whose recorded working folder is `root`,
437
+ read from the Agents' own records: `CLAUDE_CONFIG_DIR` (or `~/.claude`)
438
+ `/projects/<folder>/<id>.jsonl` and `CODEX_HOME` (or `~/.codex`)
439
+ `/sessions/**/rollout-*.jsonl`. Each summary keeps the native session ID, title,
440
+ times, turn counts, where it started (Claude Code's `entrypoint`, Codex's
441
+ `originator`), whether another process holds it now (Claude Code's live
442
+ `sessions/<pid>.json` with a running PID, Codex's `thread-writer-locks/<id>.lock`)
443
+ and the terminal resume command. `readNativeSession` streams one record into the
444
+ same turn shape as `readExternalSession`, with each turn's tools, results and
445
+ reply. Reading starts no Agent, takes no lock and writes nothing.
446
+ `nativeSessionLimits` names the budgets: 64 sessions per listing, 4,096 files
447
+ scanned per Claude Code folder and across Codex's sessions, 256 KiB read from each end of a file for a summary, at most 256 MiB
448
+ streamed from the end for a read, 200 turns, 256 tools per turn, and the text and
449
+ tool field limits above. Sidechains, injected reminders and local command output
450
+ are excluded. A recorded interruption is stopped. A last turn without an end record
451
+ is running while its file was written in the last minute; after that it is completed
452
+ when it has a reply and no unanswered tool, and unknown otherwise.
453
+
454
+ To continue such a session, the application passes its ID as `sessionId` (ACP
455
+ `session/load`). `forkFrom` instead asks the Agent for a separate copy through
456
+ `session/fork`; the connection is refused before sending when the Agent does not
457
+ advertise fork, or returns the same ID. `acpEnvironment` drops inherited Claude Code
458
+ session markers (`CLAUDECODE`, `CLAUDE_CODE_CHILD_SESSION` and related variables):
459
+ a Claude Code started under them saves no transcript, so its session could not be
460
+ listed or continued anywhere else.
@@ -7,6 +7,7 @@ export declare function acpCommand(agent: AcpAgent): {
7
7
  * optional dependencies that an application need not install, so name the selected
8
8
  * executable, else the one already named in the environment, else the client on PATH. */
9
9
  export declare function acpEnvironment(agent: AcpAgent, env: NodeJS.ProcessEnv, executable?: string): NodeJS.ProcessEnv;
10
+ export declare function withoutSessionMarkers(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
10
11
  /** Why the adapter could not start the person's client, or null when its executable is
11
12
  * there. The adapters report a missing client only as a closed connection. */
12
13
  export declare function missingClient(agent: AcpAgent, env: NodeJS.ProcessEnv): string | null;
@@ -14,7 +14,15 @@ const clientName = { claude: 'Claude Code', codex: 'Codex' };
14
14
  * executable, else the one already named in the environment, else the client on PATH. */
15
15
  export function acpEnvironment(agent, env, executable) {
16
16
  const name = executableVariable[agent];
17
- return { ...env, [name]: executable || env[name] || agent };
17
+ return { ...withoutSessionMarkers(env), [name]: executable || env[name] || agent };
18
+ }
19
+ // When Rho itself was started from inside a Claude Code session (an Agent ran the setup), the
20
+ // environment carries that session's markers. A Claude Code started with them takes itself for
21
+ // its child: it saves no transcript (so its session cannot be continued anywhere) and reports to
22
+ // the parent's socket. Rho's sessions are the person's own, so those markers are not passed on.
23
+ const sessionMarkers = /^(CLAUDECODE|CLAUDE_CODE_(CHILD_SESSION|ENTRYPOINT|SESSION_ID|SESSION_ATTENDED|MESSAGING_SOCKET|MESSAGING_TOKEN|EXECPATH|SSE_PORT)|CLAUDE_PID)$/;
24
+ export function withoutSessionMarkers(env) {
25
+ return Object.fromEntries(Object.entries(env).filter(([key]) => !sessionMarkers.test(key)));
18
26
  }
19
27
  /** Why the adapter could not start the person's client, or null when its executable is
20
28
  * there. The adapters report a missing client only as a closed connection. */
@@ -8,6 +8,7 @@ export interface AcpConversationOptions {
8
8
  mcpServers: AgentMcpServer[];
9
9
  limits: AgentProcessLimits;
10
10
  sessionId?: string;
11
+ forkFrom?: string;
11
12
  command: {
12
13
  file: string;
13
14
  args: string[];
@@ -211,6 +211,16 @@ export class AcpConversation {
211
211
  throw new Error('This Agent cannot load the original session. Nothing was resent.');
212
212
  }
213
213
  }
214
+ else if (o.forkFrom) {
215
+ const caps = initialized.agentCapabilities;
216
+ if (!caps?.sessionCapabilities?.fork)
217
+ throw new Error('This Agent cannot continue a copy of a session. Nothing was sent.');
218
+ const forked = await connection.agent.request('session/fork', { ...params, sessionId: o.forkFrom });
219
+ if (typeof forked?.sessionId !== 'string' || forked.sessionId === o.forkFrom)
220
+ throw new Error('The Agent did not create a separate copy of the session. Nothing was sent.');
221
+ this.sessionId = forked.sessionId;
222
+ this.settings = forked.configOptions ?? [];
223
+ }
214
224
  else {
215
225
  const created = await connection.agent.request(acp.methods.agent.session.new, params);
216
226
  this.sessionId = created.sessionId;
@@ -1,4 +1,5 @@
1
- // A retained observation of another client's conversation. It has no input operation.
1
+ // A conversation an Agent holds in its own record: a retained observation of another client's
2
+ // conversation, or a session the Agent keeps in its own files. Reading it starts nothing.
2
3
  const text = { type: 'string' }, count = { type: 'integer', minimum: 0 };
3
4
  const obj = (properties, required = Object.keys(properties)) => ({ type: 'object', properties, required, additionalProperties: false });
4
5
  const array = (items, maxItems) => ({ type: 'array', items, maxItems });
@@ -6,10 +7,14 @@ export const externalSessionLimits = { maxSessions: 64, maxTurns: 200, maxTools:
6
7
  const state = { enum: ['running', 'completed', 'failed', 'stopped', 'unknown'] };
7
8
  export const externalResultSchema = obj({ path: text, id: text, version: text, projectId: text, toolId: text }, ['path', 'toolId']);
8
9
  export const externalToolSchema = obj({ id: text, at: text, name: text, detail: text, output: text, outcome: { enum: ['requested', 'returned', 'failed', 'unknown'] }, exitCode: { type: 'integer' }, paths: array(text, 32) }, ['id', 'at', 'name', 'detail', 'output', 'outcome', 'paths']);
9
- export const externalTurnSchema = obj({ id: text, at: text, endedAt: text, state, prompt: text, reply: text, messages: array(obj({ at: text, text }), 200), tools: array(externalToolSchema, externalSessionLimits.maxTools), results: array(externalResultSchema, 64), omittedTools: count, omittedChars: count }, ['id', 'at', 'state', 'prompt', 'reply', 'messages', 'tools', 'results', 'omittedTools', 'omittedChars']);
10
- export const externalSessionSummarySchema = obj({ id: { type: 'string', pattern: '^x-[a-f0-9]{64}$' }, producer: text, sessionId: text, title: text, lastAt: text, observedAt: text, state, turns: count, sourceCursor: count, omittedTurns: count, problem: text, inputOwner: { const: 'external' } }, ['id', 'producer', 'sessionId', 'title', 'lastAt', 'observedAt', 'state', 'turns', 'sourceCursor', 'omittedTurns', 'inputOwner']);
10
+ export const externalTurnSchema = obj({ id: text, at: text, endedAt: text, state, prompt: text, reply: text, messages: array(obj({ at: text, text }), 200), tools: array(externalToolSchema, externalSessionLimits.maxTools), results: array(externalResultSchema, 64), omittedTools: count, omittedChars: count, where: text }, ['id', 'at', 'state', 'prompt', 'reply', 'messages', 'tools', 'results', 'omittedTools', 'omittedChars']);
11
+ export const externalSessionSummarySchema = obj({ id: { type: 'string', pattern: '^x-[a-f0-9]{64}$' }, producer: text, sessionId: text, title: text, lastAt: text, observedAt: text, state, turns: count, sourceCursor: count, omittedTurns: count, problem: text, inputOwner: { const: 'external' },
12
+ // Native sessions: where it was started, a live process holding it, the command that continues it in a terminal
13
+ // and its size. The application adds the Agent it continues with in Rho and the Rho conversation that continued it.
14
+ where: text, open: { anyOf: [{ type: 'null' }, obj({ where: text, since: text, pid: count }, ['where'])] }, resume: text, bytes: count,
15
+ continueWith: { enum: ['claude-acp', 'codex-acp', 'acp', null] }, conversationId: text }, ['id', 'producer', 'sessionId', 'title', 'lastAt', 'observedAt', 'state', 'turns', 'sourceCursor', 'omittedTurns']);
11
16
  export const externalSessionSchemas = { summary: externalSessionSummarySchema, turn: externalTurnSchema };
12
17
  export const externalSessionOperations = {
13
- 'agent.sessions.list': { inputSchema: obj({}), outputSchema: obj({ sessions: array(externalSessionSummarySchema, 64), omitted: count }), requires: [], effect: 'read' },
14
- 'agent.sessions.read': { inputSchema: obj({ session: { type: 'string', pattern: '^x-[a-f0-9]{64}$' }, before: count, limit: { type: 'integer', minimum: 1, maximum: 20 } }, ['session']), outputSchema: obj({ session: externalSessionSummarySchema, first: count, turns: array(externalTurnSchema, 20) }), requires: [], effect: 'read' },
18
+ 'agent.sessions.list': { inputSchema: obj({}), outputSchema: obj({ sessions: array(externalSessionSummarySchema, 128), omitted: count }), requires: [], effect: 'read' },
19
+ 'agent.sessions.read': { inputSchema: obj({ session: { type: 'string', pattern: '^x-[a-f0-9]{64}$' }, before: count, limit: { type: 'integer', minimum: 1, maximum: 50 } }, ['session']), outputSchema: obj({ session: externalSessionSummarySchema, first: count, turns: array(externalTurnSchema, 50) }), requires: [], effect: 'read' },
15
20
  };
@@ -31,6 +31,7 @@ export interface ExternalTurn {
31
31
  results: ExternalResult[];
32
32
  omittedTools: number;
33
33
  omittedChars: number;
34
+ where?: string;
34
35
  }
35
36
  export interface ExternalSessionSummary {
36
37
  id: string;
@@ -44,7 +45,17 @@ export interface ExternalSessionSummary {
44
45
  sourceCursor: number;
45
46
  omittedTurns: number;
46
47
  problem?: string;
47
- inputOwner: 'external';
48
+ inputOwner?: 'external';
49
+ where?: string;
50
+ open?: {
51
+ where: string;
52
+ since?: string;
53
+ pid?: number;
54
+ } | null;
55
+ resume?: string;
56
+ bytes?: number;
57
+ continueWith?: 'claude-acp' | 'codex-acp' | 'acp' | null;
58
+ conversationId?: string;
48
59
  }
49
60
  export interface ExternalSessionRecord {
50
61
  format: 1;
@@ -0,0 +1,70 @@
1
+ import { type ExternalSessionSummary, type ExternalTurn } from './external-session.js';
2
+ export declare const nativeSessionLimits: {
3
+ maxSessions: number;
4
+ maxScanFiles: number;
5
+ maxHeadBytes: number;
6
+ maxTailBytes: number;
7
+ maxReadBytes: number;
8
+ maxTurns: number;
9
+ maxTools: number;
10
+ maxTextChars: number;
11
+ maxDetailChars: number;
12
+ activeMs: number;
13
+ };
14
+ export type NativeProducer = 'claude-code' | 'codex';
15
+ export interface NativeSessionSources {
16
+ claudeConfigDir?: string;
17
+ codexHome?: string;
18
+ }
19
+ export interface NativeSessionSummary extends ExternalSessionSummary {
20
+ producer: NativeProducer;
21
+ where: string;
22
+ open: {
23
+ where: string;
24
+ since?: string;
25
+ pid?: number;
26
+ } | null;
27
+ resume: string;
28
+ bytes: number;
29
+ }
30
+ export declare function nativeSources(env?: NodeJS.ProcessEnv): Required<NativeSessionSources>;
31
+ /** The Agents' own sessions whose working folder is `root`, newest first. Reads files only. */
32
+ export declare function listNativeSessions(root: string, sources?: NativeSessionSources): {
33
+ sessions: NativeSessionSummary[];
34
+ omitted: number;
35
+ };
36
+ /** One session's turns, read through its file (its last maxReadBytes when larger). */
37
+ export declare function readNativeSession(root: string, input: {
38
+ session: string;
39
+ before?: number;
40
+ limit?: number;
41
+ }, sources?: NativeSessionSources): Promise<{
42
+ session: {
43
+ turns: number;
44
+ omittedTurns: number;
45
+ producer: NativeProducer;
46
+ where: string;
47
+ open: {
48
+ where: string;
49
+ since?: string;
50
+ pid?: number;
51
+ } | null;
52
+ resume: string;
53
+ bytes: number;
54
+ id: string;
55
+ sessionId: string;
56
+ title: string;
57
+ lastAt: string;
58
+ observedAt: string;
59
+ state: ExternalTurn["state"];
60
+ sourceCursor: number;
61
+ problem?: string;
62
+ inputOwner?: "external";
63
+ continueWith?: "claude-acp" | "codex-acp" | "acp" | null;
64
+ conversationId?: string;
65
+ };
66
+ first: number;
67
+ turns: ExternalTurn[];
68
+ } | null>;
69
+ /** Whether `sessionId` names a session of this Agent in `root`, and its summary. */
70
+ export declare function nativeSession(root: string, producer: NativeProducer, sessionId: string, sources?: NativeSessionSources): NativeSessionSummary | null;