@myagentroam/node 0.1.4 → 0.1.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 (210) hide show
  1. package/README.md +9 -1
  2. package/dist/capabilities.d.ts +2 -0
  3. package/dist/capabilities.js +15 -4
  4. package/dist/claude-agent-sdk.d.ts +3 -1
  5. package/dist/claude-agent-sdk.js +9 -2
  6. package/dist/claude-channel.js +0 -1
  7. package/dist/codex-app-server.d.ts +1 -0
  8. package/dist/codex-app-server.js +8 -1
  9. package/dist/config.d.ts +3 -0
  10. package/dist/config.js +18 -2
  11. package/dist/connector/node-connector-options.d.ts +3 -0
  12. package/dist/connector/node-connector-options.js +0 -1
  13. package/dist/connector/node-operation-router.js +0 -1
  14. package/dist/connector.d.ts +3 -0
  15. package/dist/connector.js +109 -7
  16. package/dist/control-outbound-scheduler.js +0 -1
  17. package/dist/database.d.ts +4 -0
  18. package/dist/database.js +14 -9
  19. package/dist/event-buffer.js +0 -1
  20. package/dist/fake-runner.js +0 -1
  21. package/dist/health.js +0 -1
  22. package/dist/main.js +6 -1
  23. package/dist/migrations/v001.js +0 -1
  24. package/dist/migrations/v002.js +0 -1
  25. package/dist/migrations/v003.d.ts +4 -0
  26. package/dist/migrations/v003.js +44 -0
  27. package/dist/native-jsonl-reader.js +0 -1
  28. package/dist/native-session-history.d.ts +19 -1
  29. package/dist/native-session-history.js +65 -3
  30. package/dist/opencode-runtime.d.ts +33 -0
  31. package/dist/opencode-runtime.js +80 -0
  32. package/dist/opencode-server.d.ts +47 -0
  33. package/dist/opencode-server.js +250 -0
  34. package/dist/operational.js +10 -3
  35. package/dist/process-tree.js +0 -1
  36. package/dist/runner/abstract-runner.d.ts +7 -2
  37. package/dist/runner/abstract-runner.js +17 -2
  38. package/dist/runner/claude/managed-run-controller.js +20 -1
  39. package/dist/runner/claude-code-runner.d.ts +3 -1
  40. package/dist/runner/claude-code-runner.js +26 -8
  41. package/dist/runner/codex/conversation-parser.d.ts +1 -3
  42. package/dist/runner/codex/conversation-parser.js +174 -34
  43. package/dist/runner/codex/managed-run-controller.d.ts +2 -1
  44. package/dist/runner/codex/managed-run-controller.js +13 -4
  45. package/dist/runner/codex-runner.d.ts +4 -0
  46. package/dist/runner/codex-runner.js +27 -4
  47. package/dist/runner/fake-test-runner.js +0 -1
  48. package/dist/runner/opencode/conversation-parser.d.ts +27 -0
  49. package/dist/runner/opencode/conversation-parser.js +217 -0
  50. package/dist/runner/opencode/managed-run-controller.d.ts +76 -0
  51. package/dist/runner/opencode/managed-run-controller.js +451 -0
  52. package/dist/runner/opencode-runner.d.ts +60 -0
  53. package/dist/runner/opencode-runner.js +330 -0
  54. package/dist/runner/runner-registry.d.ts +3 -1
  55. package/dist/runner/runner-registry.js +12 -3
  56. package/dist/runner-command-engine.js +0 -1
  57. package/dist/runner-profiles.d.ts +4 -0
  58. package/dist/runner-profiles.js +76 -3
  59. package/dist/runner-usage.js +0 -1
  60. package/dist/runtime-state.js +20 -9
  61. package/dist/service/attachment-domain-state.js +0 -1
  62. package/dist/service/conversation-history-service.js +0 -1
  63. package/dist/service/external-session-resume-service.js +0 -1
  64. package/dist/service/fake-managed-run-service.js +0 -1
  65. package/dist/service/managed-runner-session-service.d.ts +3 -1
  66. package/dist/service/managed-runner-session-service.js +8 -4
  67. package/dist/service/native-session-projection-service.d.ts +2 -1
  68. package/dist/service/native-session-projection-service.js +8 -5
  69. package/dist/service/native-session-watch-service.js +0 -1
  70. package/dist/service/node-connection-lifecycle-service.js +3 -2
  71. package/dist/service/node-control-channel.d.ts +1 -1
  72. package/dist/service/node-control-channel.js +5 -4
  73. package/dist/service/node-control-message-service.js +0 -1
  74. package/dist/service/node-request-service.js +0 -1
  75. package/dist/service/node-run-event-bridge.d.ts +2 -0
  76. package/dist/service/node-run-event-bridge.js +4 -1
  77. package/dist/service/node-terminal-channel.js +16 -10
  78. package/dist/service/node-upgrade-coordinator.d.ts +29 -0
  79. package/dist/service/node-upgrade-coordinator.js +137 -0
  80. package/dist/service/node-workspace-coordinator.js +0 -1
  81. package/dist/service/run-attachment-service.js +0 -1
  82. package/dist/service/run-domain-state.js +0 -1
  83. package/dist/service/run-event-service.js +0 -1
  84. package/dist/service/run-workbench-service.js +0 -1
  85. package/dist/service/runner-channel-message-service.js +0 -1
  86. package/dist/service/runner-interaction-service.js +2 -1
  87. package/dist/service/runner-service.d.ts +5 -4
  88. package/dist/service/runner-service.js +19 -6
  89. package/dist/service/session-catalog-service.d.ts +16 -1
  90. package/dist/service/session-catalog-service.js +82 -3
  91. package/dist/service/session-command-service.js +0 -1
  92. package/dist/service/session-context-service.js +0 -1
  93. package/dist/service/session-domain-state.js +0 -1
  94. package/dist/service/session-identity-service.js +0 -1
  95. package/dist/service/session-lifecycle-service.js +13 -7
  96. package/dist/service/session-message-service.js +0 -1
  97. package/dist/service/session-presentation-service.js +0 -1
  98. package/dist/service/session-query-service.js +0 -1
  99. package/dist/service/terminal-relay-state.js +0 -1
  100. package/dist/service/terminal-service.js +0 -1
  101. package/dist/service/workbench-event-service.js +0 -1
  102. package/dist/service/workbench-manifest-service.d.ts +5 -4
  103. package/dist/service/workbench-manifest-service.js +3 -2
  104. package/dist/service/workspace-change-service.js +2 -2
  105. package/dist/service/workspace-content-search-service.d.ts +14 -0
  106. package/dist/service/workspace-content-search-service.js +477 -0
  107. package/dist/service/workspace-domain-state.js +0 -1
  108. package/dist/service/workspace-file-service.d.ts +3 -0
  109. package/dist/service/workspace-file-service.js +35 -3
  110. package/dist/service/workspace-queue-workbench-service.js +0 -1
  111. package/dist/service/workspace-service.js +23 -10
  112. package/dist/service/workspace-session-service.js +0 -1
  113. package/dist/service/workspace-upload-service.js +0 -1
  114. package/dist/service/workspace-watch-service.js +0 -1
  115. package/dist/service/workspace-workbench-service.d.ts +9 -0
  116. package/dist/service/workspace-workbench-service.js +69 -2
  117. package/dist/service.js +2 -3
  118. package/dist/storage.js +0 -1
  119. package/dist/supervisor.d.ts +1 -0
  120. package/dist/supervisor.js +154 -0
  121. package/dist/terminal.js +0 -1
  122. package/dist/util/node-operation-parsers.d.ts +1 -0
  123. package/dist/util/node-operation-parsers.js +3 -1
  124. package/dist/util/runner-native-session-parsers.js +117 -73
  125. package/dist/util/secret-environment.js +0 -1
  126. package/dist/workspace.d.ts +62 -2
  127. package/dist/workspace.js +539 -57
  128. package/package.json +3 -2
  129. package/dist/capabilities.js.map +0 -1
  130. package/dist/claude-agent-sdk.js.map +0 -1
  131. package/dist/claude-channel.js.map +0 -1
  132. package/dist/codex-app-server.js.map +0 -1
  133. package/dist/config.js.map +0 -1
  134. package/dist/connector/node-connector-options.js.map +0 -1
  135. package/dist/connector/node-operation-router.js.map +0 -1
  136. package/dist/connector.js.map +0 -1
  137. package/dist/control-outbound-scheduler.js.map +0 -1
  138. package/dist/database.js.map +0 -1
  139. package/dist/event-buffer.js.map +0 -1
  140. package/dist/fake-runner.js.map +0 -1
  141. package/dist/health.js.map +0 -1
  142. package/dist/main.js.map +0 -1
  143. package/dist/migrations/v001.js.map +0 -1
  144. package/dist/migrations/v002.js.map +0 -1
  145. package/dist/native-jsonl-reader.js.map +0 -1
  146. package/dist/native-session-history.js.map +0 -1
  147. package/dist/operational.js.map +0 -1
  148. package/dist/process-tree.js.map +0 -1
  149. package/dist/runner/abstract-runner.js.map +0 -1
  150. package/dist/runner/claude/managed-run-controller.js.map +0 -1
  151. package/dist/runner/claude-code-runner.js.map +0 -1
  152. package/dist/runner/codex/conversation-parser.js.map +0 -1
  153. package/dist/runner/codex/managed-run-controller.js.map +0 -1
  154. package/dist/runner/codex-runner.js.map +0 -1
  155. package/dist/runner/fake-test-runner.js.map +0 -1
  156. package/dist/runner/runner-registry.js.map +0 -1
  157. package/dist/runner-command-engine.js.map +0 -1
  158. package/dist/runner-profiles.js.map +0 -1
  159. package/dist/runner-usage.js.map +0 -1
  160. package/dist/runtime-state.js.map +0 -1
  161. package/dist/service/attachment-domain-state.js.map +0 -1
  162. package/dist/service/conversation-history-service.js.map +0 -1
  163. package/dist/service/external-session-resume-service.js.map +0 -1
  164. package/dist/service/fake-managed-run-service.js.map +0 -1
  165. package/dist/service/managed-runner-session-service.js.map +0 -1
  166. package/dist/service/native-session-projection-service.js.map +0 -1
  167. package/dist/service/native-session-watch-service.js.map +0 -1
  168. package/dist/service/node-connection-lifecycle-service.js.map +0 -1
  169. package/dist/service/node-control-channel.js.map +0 -1
  170. package/dist/service/node-control-message-service.js.map +0 -1
  171. package/dist/service/node-request-service.js.map +0 -1
  172. package/dist/service/node-run-event-bridge.js.map +0 -1
  173. package/dist/service/node-terminal-channel.js.map +0 -1
  174. package/dist/service/node-workspace-coordinator.js.map +0 -1
  175. package/dist/service/run-attachment-service.js.map +0 -1
  176. package/dist/service/run-domain-state.js.map +0 -1
  177. package/dist/service/run-event-service.js.map +0 -1
  178. package/dist/service/run-workbench-service.js.map +0 -1
  179. package/dist/service/runner-channel-message-service.js.map +0 -1
  180. package/dist/service/runner-interaction-service.js.map +0 -1
  181. package/dist/service/runner-service.js.map +0 -1
  182. package/dist/service/session-catalog-service.js.map +0 -1
  183. package/dist/service/session-command-service.js.map +0 -1
  184. package/dist/service/session-context-service.js.map +0 -1
  185. package/dist/service/session-domain-state.js.map +0 -1
  186. package/dist/service/session-identity-service.js.map +0 -1
  187. package/dist/service/session-lifecycle-service.js.map +0 -1
  188. package/dist/service/session-message-service.js.map +0 -1
  189. package/dist/service/session-presentation-service.js.map +0 -1
  190. package/dist/service/session-query-service.js.map +0 -1
  191. package/dist/service/terminal-relay-state.js.map +0 -1
  192. package/dist/service/terminal-service.js.map +0 -1
  193. package/dist/service/workbench-event-service.js.map +0 -1
  194. package/dist/service/workbench-manifest-service.js.map +0 -1
  195. package/dist/service/workspace-change-service.js.map +0 -1
  196. package/dist/service/workspace-domain-state.js.map +0 -1
  197. package/dist/service/workspace-file-service.js.map +0 -1
  198. package/dist/service/workspace-queue-workbench-service.js.map +0 -1
  199. package/dist/service/workspace-service.js.map +0 -1
  200. package/dist/service/workspace-session-service.js.map +0 -1
  201. package/dist/service/workspace-upload-service.js.map +0 -1
  202. package/dist/service/workspace-watch-service.js.map +0 -1
  203. package/dist/service/workspace-workbench-service.js.map +0 -1
  204. package/dist/service.js.map +0 -1
  205. package/dist/storage.js.map +0 -1
  206. package/dist/terminal.js.map +0 -1
  207. package/dist/util/node-operation-parsers.js.map +0 -1
  208. package/dist/util/runner-native-session-parsers.js.map +0 -1
  209. package/dist/util/secret-environment.js.map +0 -1
  210. package/dist/workspace.js.map +0 -1
@@ -19,9 +19,10 @@ export declare abstract class AbstractRunner<TName extends RegisteredRunnerName
19
19
  readonly interceptsRuns: boolean;
20
20
  abstract readonly discoveryScope: 'ALL_WORKSPACES' | 'WORKSPACE_REQUIRED';
21
21
  abstract profile(capabilities: NodeCapabilities): RunnerProfile | undefined;
22
+ refreshProfile(capabilities: NodeCapabilities, workspace?: NodeWorkspace, environment?: Readonly<Record<string, string>>): Promise<RunnerProfile | undefined>;
22
23
  abstract available(capabilities: NodeCapabilities): boolean;
23
- abstract defaultConfiguration(): RunnerDefaultConfiguration;
24
- supportsConfiguration(configuration: RunnerDefaultConfiguration): boolean;
24
+ abstract defaultConfiguration(workspace?: NodeWorkspace): RunnerDefaultConfiguration;
25
+ supportsConfiguration(configuration: RunnerDefaultConfiguration, workspace?: NodeWorkspace): boolean;
25
26
  protected abstract profileForValidation(): RunnerProfile;
26
27
  abstract resumeExternal(session: NodeAgentSession, context: ExternalResumeContext, force?: boolean): Promise<ExternalResumeResult>;
27
28
  abstract discoverSessions(context: RunnerDiscoveryContext, workspace?: NodeWorkspace): Promise<readonly NodeAgentSession[]>;
@@ -37,6 +38,8 @@ export declare abstract class AbstractRunner<TName extends RegisteredRunnerName
37
38
  readonly title?: string | null;
38
39
  readonly pinned?: boolean;
39
40
  }, database: NodeDatabase): Promise<void>;
41
+ removeNative(session: NodeAgentSession, nativeSessionId: string): Promise<boolean>;
42
+ forkNative(session: NodeAgentSession, boundary: string | null, title: string): Promise<string | null>;
40
43
  projectedRunnerTitle(metadata: ReturnType<NodeDatabase['getNativeSessionMetadata']>, input: RunnerProjectionTitleInput, database: NodeDatabase | undefined): string | null;
41
44
  managedAliasId(nativeSessionId: string): string | undefined;
42
45
  nativeAliasesFor(managedSessionId: string): readonly string[];
@@ -57,6 +60,7 @@ export declare abstract class AbstractRunner<TName extends RegisteredRunnerName
57
60
  startManagedRun(envelope: NodeEnvelope): void;
58
61
  cancelManagedRun(runId: string, intent: RunnerCancellationIntent): boolean;
59
62
  decideApproval(input: RunnerApprovalDecision): boolean;
63
+ respondUserInput(runId: string, requestId: string, answers: Record<string, unknown>): boolean;
60
64
  bindCommandControl(control: RunnerCommandControl): void;
61
65
  executeCommand(session: NodeAgentSession, command: RunnerCommandDescriptor, input: string, context: {
62
66
  readonly secretEnvironment: Readonly<Record<string, string>>;
@@ -67,6 +71,7 @@ export interface RunnerControl {
67
71
  start(envelope: NodeEnvelope): void;
68
72
  cancel(runId: string, intent: RunnerCancellationIntent): boolean;
69
73
  decideApproval?(input: RunnerApprovalDecision): boolean;
74
+ respondUserInput?(runId: string, requestId: string, answers: Record<string, unknown>): boolean;
70
75
  }
71
76
  export interface RunnerCommandControl {
72
77
  execute(session: NodeAgentSession, command: RunnerCommandDescriptor, input: string, context: {
@@ -11,7 +11,12 @@ export class AbstractRunner {
11
11
  /** Test-only runners are registered explicitly but never advertised. */
12
12
  advertised = true;
13
13
  interceptsRuns = false;
14
- supportsConfiguration(configuration) {
14
+ async refreshProfile(capabilities, workspace, environment = {}) {
15
+ void [workspace, environment];
16
+ return this.profile(capabilities);
17
+ }
18
+ supportsConfiguration(configuration, workspace) {
19
+ void workspace;
15
20
  const profile = this.profileForValidation();
16
21
  const model = profile.models.find((candidate) => candidate.id === configuration.model);
17
22
  return (configuration.runner === this.name &&
@@ -56,6 +61,14 @@ export class AbstractRunner {
56
61
  ...(input.pinned === undefined ? {} : { pinned: input.pinned })
57
62
  });
58
63
  }
64
+ async removeNative(session, nativeSessionId) {
65
+ void [session, nativeSessionId];
66
+ return false;
67
+ }
68
+ async forkNative(session, boundary, title) {
69
+ void [session, boundary, title];
70
+ throw new RunnerCapabilityError(this.name, 'session.rewind');
71
+ }
59
72
  projectedRunnerTitle(metadata, input, database) {
60
73
  void database;
61
74
  return input.title ?? metadata?.runnerTitle ?? null;
@@ -116,6 +129,9 @@ export class AbstractRunner {
116
129
  decideApproval(input) {
117
130
  return this.control?.decideApproval?.(input) === true;
118
131
  }
132
+ respondUserInput(runId, requestId, answers) {
133
+ return this.control?.respondUserInput?.(runId, requestId, answers) === true;
134
+ }
119
135
  bindCommandControl(control) {
120
136
  if (this.commandControl !== undefined)
121
137
  throw new Error(`RUNNER_COMMAND_CONTROL_ALREADY_BOUND:${this.name}`);
@@ -136,4 +152,3 @@ export class RunnerCapabilityError extends Error {
136
152
  this.capability = capability;
137
153
  }
138
154
  }
139
- //# sourceMappingURL=abstract-runner.js.map
@@ -2,6 +2,7 @@ import { createEnvelope } from '@myagentroam/protocol';
2
2
  import { ClaudeChannelGate } from '../../claude-channel.js';
3
3
  import { boundedConversationItemId, claudePlanText, compactRunnerText, compactRunnerValue, extractClaudeText, extractClaudeThinkingSummaries, extractClaudeToolResults, extractClaudeToolUses, isClaudeCommandTool } from '../codex/conversation-parser.js';
4
4
  import { isTerminalRunStatus } from '../../util/node-operation-parsers.js';
5
+ import { claudeContentBlocks } from '../../util/node-operation-parsers.js';
5
6
  import { parseSecretEnvironment } from '../../util/secret-environment.js';
6
7
  export class ClaudeManagedRunController {
7
8
  runner;
@@ -229,6 +230,25 @@ export class ClaudeManagedRunController {
229
230
  }
230
231
  });
231
232
  }
233
+ for (const [index, block] of claudeContentBlocks(record).entries()) {
234
+ const type = typeof block.type === 'string' ? block.type : 'unknown';
235
+ if (type === 'text' ||
236
+ type === 'thinking' ||
237
+ type === 'redacted_thinking' ||
238
+ type === 'encrypted_thinking' ||
239
+ type === 'tool_use' ||
240
+ type === 'tool_result')
241
+ continue;
242
+ this.host.emitItem(runId, {
243
+ itemId: boundedConversationItemId('claude-item', `${typeof record.uuid === 'string' ? record.uuid : runId}:${index}`),
244
+ kind: 'unknown',
245
+ status: 'COMPLETED',
246
+ payload: {
247
+ sourceEventType: `claude-code:${type}`,
248
+ label: `Claude Code ${compactRunnerText(type, 128)}`
249
+ }
250
+ });
251
+ }
232
252
  }
233
253
  if (record.type === 'tool_progress' && typeof record.tool_use_id === 'string') {
234
254
  const kind = toolKinds.get(record.tool_use_id);
@@ -304,4 +324,3 @@ export class ClaudeManagedRunController {
304
324
  }
305
325
  }
306
326
  }
307
- //# sourceMappingURL=managed-run-controller.js.map
@@ -8,10 +8,11 @@ import type { NodeAgentSession, NodeWorkspace } from '../database.js';
8
8
  import { type NativeSessionHistory } from '../native-session-history.js';
9
9
  export declare class ClaudeCodeRunner extends AbstractRunner<'claude-code'> {
10
10
  private readonly client;
11
+ private readonly environment;
11
12
  readonly name: "claude-code";
12
13
  readonly discoveryScope: "WORKSPACE_REQUIRED";
13
14
  readonly execution: ClaudeExecutionState;
14
- constructor(client?: ClaudeAgentSdkAdapter);
15
+ constructor(client?: ClaudeAgentSdkAdapter, environment?: NodeJS.ProcessEnv);
15
16
  profile(capabilities: NodeCapabilities): RunnerProfile;
16
17
  available(capabilities: NodeCapabilities): boolean;
17
18
  protected profileForValidation(): RunnerProfile;
@@ -19,6 +20,7 @@ export declare class ClaudeCodeRunner extends AbstractRunner<'claude-code'> {
19
20
  resumeExternal(external: NodeAgentSession, context: ExternalResumeContext): Promise<ExternalResumeResult>;
20
21
  discoverSessions(context: RunnerDiscoveryContext, workspace?: NodeWorkspace): Promise<readonly NodeAgentSession[]>;
21
22
  readContextUsage(session: NodeAgentSession): Promise<import("../native-session-history.js").NativeClaudeContextUsage | undefined>;
23
+ forkNative(session: NodeAgentSession, boundary: string | null, title: string): Promise<string | null>;
22
24
  presentSession(session: NodeAgentSession, capabilities: NodeCapabilities, context: RunnerSessionPresentationContext): RunnerSessionPresentation;
23
25
  prepareMessageInput(input: string, collaborationMode: 'default' | 'plan'): string;
24
26
  channelToken(sessionId: string): string | undefined;
@@ -1,22 +1,26 @@
1
1
  import { ClaudeAgentSdkAdapter } from '../claude-agent-sdk.js';
2
2
  import { AbstractRunner } from './abstract-runner.js';
3
- import { declaredRunnerProfiles } from '../runner-profiles.js';
3
+ import { claudeDefaultModel, declaredRunnerProfiles } from '../runner-profiles.js';
4
4
  import { withClaudePlanTag } from '../runner-command-engine.js';
5
5
  import { discoverNativeSessions, readNativeSession, readClaudeNativeContextUsage } from '../native-session-history.js';
6
6
  import { claudeDiscoveredSession, deduplicateDirectSessions, externalResumeFailureDetail, isNativeHistory, isWithinWorkspace, latestNativeActivity } from './codex/conversation-parser.js';
7
7
  export class ClaudeCodeRunner extends AbstractRunner {
8
8
  client;
9
+ environment;
9
10
  name = 'claude-code';
10
11
  discoveryScope = 'WORKSPACE_REQUIRED';
11
12
  execution = new ClaudeExecutionState();
12
- constructor(client = new ClaudeAgentSdkAdapter()) {
13
+ constructor(client = new ClaudeAgentSdkAdapter(), environment = process.env) {
13
14
  super();
14
15
  this.client = client;
16
+ this.environment = environment;
15
17
  }
16
18
  profile(capabilities) {
17
19
  return declaredRunnerProfiles({
18
20
  codexAvailable: capabilities.codex.available,
19
- claudeCodeAvailable: capabilities.claudeCode.available
21
+ claudeCodeAvailable: capabilities.claudeCode.available,
22
+ environment: this.environment,
23
+ openCodeAvailable: capabilities.openCode?.available === true
20
24
  }).find((profile) => profile.runner === this.name);
21
25
  }
22
26
  available(capabilities) {
@@ -29,11 +33,17 @@ export class ClaudeCodeRunner extends AbstractRunner {
29
33
  nodeAppVersion: 'validation',
30
34
  nodeVersion: 'validation',
31
35
  codex: { available: false },
32
- claudeCode: { available: true }
36
+ claudeCode: { available: true },
37
+ openCode: { available: false }
33
38
  });
34
39
  }
35
40
  defaultConfiguration() {
36
- return { runner: this.name, model: 'sonnet', effort: 'medium', access: 'default' };
41
+ return {
42
+ runner: this.name,
43
+ model: claudeDefaultModel(this.environment),
44
+ effort: 'medium',
45
+ access: 'default'
46
+ };
37
47
  }
38
48
  async resumeExternal(external, context) {
39
49
  if (external.runner !== this.name ||
@@ -112,6 +122,13 @@ export class ClaudeCodeRunner extends AbstractRunner {
112
122
  ? Promise.resolve(undefined)
113
123
  : readClaudeNativeContextUsage(session.cwd, session.externalSessionId);
114
124
  }
125
+ forkNative(session, boundary, title) {
126
+ if (session.externalSessionId === null)
127
+ throw new Error('SESSION_REWIND_UNAVAILABLE');
128
+ return boundary === null
129
+ ? Promise.resolve(null)
130
+ : this.client.forkSession(session.externalSessionId, session.cwd, boundary, title);
131
+ }
115
132
  presentSession(session, capabilities, context) {
116
133
  if (capabilities.claudeCode.available && session.nativeControl === 'MAR_MANAGED') {
117
134
  const runtimeCapabilities = [
@@ -124,7 +141,8 @@ export class ClaudeCodeRunner extends AbstractRunner {
124
141
  'approval.respond',
125
142
  'session.rename',
126
143
  'session.remove',
127
- 'session.pin'
144
+ 'session.pin',
145
+ ...(session.externalSessionId === null ? [] : ['session.rewind'])
128
146
  ];
129
147
  return {
130
148
  activity: context.managedActive ? 'MANAGED_ACTIVE' : 'IDLE',
@@ -142,7 +160,8 @@ export class ClaudeCodeRunner extends AbstractRunner {
142
160
  'turn.start',
143
161
  'session.rename',
144
162
  'session.remove',
145
- 'session.pin'
163
+ 'session.pin',
164
+ 'session.rewind'
146
165
  ];
147
166
  return {
148
167
  activity: 'IDLE',
@@ -265,4 +284,3 @@ export class ClaudeExecutionState {
265
284
  approvals = new Map();
266
285
  userInputs = new Map();
267
286
  }
268
- //# sourceMappingURL=claude-code-runner.js.map
@@ -1,7 +1,7 @@
1
1
  import type { NodeAgentSession, NodeConversationItem, NodeConversationTurn, NodeMessageAttachmentInput } from '../../database.js';
2
2
  export type PublicConversationItem = {
3
3
  readonly itemId: string;
4
- readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan';
4
+ readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'unknown';
5
5
  readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'DECLINED';
6
6
  readonly payload: Record<string, unknown>;
7
7
  readonly merge?: boolean;
@@ -27,8 +27,6 @@ export declare function codexNativeItemIds(values: readonly unknown[]): Readonly
27
27
  export declare function conversationItemNativeId(itemId: string): string | undefined;
28
28
  /** Keep a custom tool invocation and its output in one Workbench card. */
29
29
  export declare function codexOfficialItems(session: NodeAgentSession, nativeTurnId: string, values: readonly unknown[], turnSequence: number, startedAt: number | null, completedAt: number | null): NodeConversationItem[];
30
- /** Keep history-only and history-plus-live projections in the same narrative order. */
31
- export declare function orderCodexConversationItems(items: readonly NodeConversationItem[]): NodeConversationItem[];
32
30
  export declare function codexPairedToolCallId(value: unknown): string | undefined;
33
31
  export declare function mergeCodexCustomToolItems(invocation: NodeConversationItem, result: NodeConversationItem): NodeConversationItem;
34
32
  export declare function coalesceImageGenerationItems(items: readonly NodeConversationItem[]): readonly NodeConversationItem[];
@@ -7,14 +7,17 @@ export function codexOfficialConversationPage(session, result, input, managedTur
7
7
  const thread = result.thread;
8
8
  if (thread.id !== session.externalSessionId || !Array.isArray(thread.turns))
9
9
  return undefined;
10
- const allTurns = thread.turns.flatMap((value, sequence) => {
11
- const turn = codexOfficialTurn(session, value, sequence, typeof value === 'object' &&
12
- value !== null &&
13
- typeof value.id === 'string'
14
- ? managedTurnForNative(value.id)
15
- : undefined);
16
- return turn === undefined ? [] : [turn];
10
+ const parsedTurns = thread.turns.flatMap((value, sequence) => {
11
+ const nativeTurnId = typeof value === 'object' && value !== null && typeof value.id === 'string'
12
+ ? value.id
13
+ : undefined;
14
+ const turn = codexOfficialTurn(session, value, sequence, nativeTurnId === undefined ? undefined : managedTurnForNative(nativeTurnId));
15
+ return turn === undefined || nativeTurnId === undefined ? [] : [{ nativeTurnId, turn }];
17
16
  });
17
+ const allTurns = parsedTurns.map(({ nativeTurnId, turn }, index) => ({
18
+ ...turn,
19
+ rewind: { before: parsedTurns[index - 1]?.nativeTurnId ?? null, after: nativeTurnId }
20
+ }));
18
21
  if (allTurns.length === 0)
19
22
  return undefined;
20
23
  const limit = Math.min(Math.max(input.limit ?? 30, 1), 500);
@@ -38,23 +41,31 @@ export function codexOfficialTurn(session, value, sequence, managedTurn) {
38
41
  if (managedTurn !== undefined) {
39
42
  const localUser = managedTurn.items.find((item) => item.kind === 'user_message');
40
43
  const officialNativeItemIds = codexNativeItemIds(value.items);
41
- const officialAssistantMessage = items.some((item) => item.kind === 'assistant_message');
44
+ const officialAssistantCount = items.filter((item) => item.kind === 'assistant_message').length;
45
+ const officialAssistantMessage = officialAssistantCount > 0;
46
+ const managedAssistants = managedTurn.items.filter((item) => item.kind === 'assistant_message');
47
+ const managedAssistantCandidates = officialAssistantCount === 0 ? [] : managedAssistants.slice(-officialAssistantCount);
42
48
  const assistantLength = (values) => values.reduce((length, item) => {
43
49
  if (item.kind !== 'assistant_message' || !isPlainRecord(item.payload))
44
50
  return length;
45
51
  return length + (typeof item.payload.text === 'string' ? item.payload.text.length : 0);
46
52
  }, 0);
47
53
  const preferLocalAssistant = officialAssistantMessage &&
48
- (assistantLength(managedTurn.items) > assistantLength(items) ||
54
+ (assistantLength(managedAssistantCandidates) > assistantLength(items) ||
49
55
  ((managedTurn.completedAt ?? 0) > (completedAt ?? 0) &&
50
- assistantLength(managedTurn.items) > 0));
56
+ assistantLength(managedAssistantCandidates) > 0));
57
+ const replacedManagedAssistantIds = new Set(preferLocalAssistant
58
+ ? []
59
+ : officialAssistantCount === 0
60
+ ? []
61
+ : managedAssistantCandidates.map((item) => item.id));
51
62
  const localLiveItems = managedTurn.items.filter((item) => {
52
63
  if (item.kind === 'user_message')
53
64
  return false;
54
65
  // `item/agentMessage/delta` uses a synthetic runtime ID. Once
55
66
  // `thread/read` returns the final Agent message, it is the same reply
56
67
  // without a shared native item ID and must replace that transient item.
57
- if (item.kind === 'assistant_message' && officialAssistantMessage && !preferLocalAssistant)
68
+ if (item.kind === 'assistant_message' && replacedManagedAssistantIds.has(item.id))
58
69
  return false;
59
70
  const nativeItemId = conversationItemNativeId(item.id);
60
71
  return nativeItemId === undefined || !officialNativeItemIds.has(nativeItemId);
@@ -68,14 +79,50 @@ export function codexOfficialTurn(session, value, sequence, managedTurn) {
68
79
  ];
69
80
  if (localUser !== undefined && !officialItems.some((item) => item.kind === 'user_message'))
70
81
  officialItems.unshift({ ...localUser, turnId: managedTurn.id });
82
+ const retainedLocalIds = new Set(localLiveItems.map((item) => item.id));
83
+ const consumedOfficialIds = new Set();
84
+ const officialUser = officialItems.find((item) => item.kind === 'user_message');
85
+ const officialAssistants = officialItems.filter((item) => item.kind === 'assistant_message');
86
+ const officialItemMarker = `:official:${value.id}:`;
87
+ const officialByNativeId = new Map(officialItems.flatMap((item) => {
88
+ const markerIndex = item.id.lastIndexOf(officialItemMarker);
89
+ return markerIndex < 0
90
+ ? []
91
+ : [[item.id.slice(markerIndex + officialItemMarker.length), item]];
92
+ }));
93
+ const reconciledItems = [];
94
+ for (const managedItem of managedTurn.items) {
95
+ let replacement;
96
+ if (managedItem.kind === 'user_message')
97
+ replacement = officialUser;
98
+ else {
99
+ const nativeId = conversationItemNativeId(managedItem.id);
100
+ if (nativeId !== undefined)
101
+ replacement = officialByNativeId.get(nativeId);
102
+ if (replacement === undefined &&
103
+ managedItem.kind === 'assistant_message' &&
104
+ replacedManagedAssistantIds.has(managedItem.id))
105
+ replacement = officialAssistants.find((item) => !consumedOfficialIds.has(item.id));
106
+ }
107
+ if (replacement !== undefined) {
108
+ if (!consumedOfficialIds.has(replacement.id)) {
109
+ reconciledItems.push(replacement);
110
+ consumedOfficialIds.add(replacement.id);
111
+ }
112
+ }
113
+ else if (retainedLocalIds.has(managedItem.id))
114
+ reconciledItems.push(managedItem);
115
+ }
116
+ for (const item of officialItems)
117
+ if (!consumedOfficialIds.has(item.id))
118
+ reconciledItems.push(item);
71
119
  return {
72
120
  ...managedTurn,
73
121
  status: 'SUCCEEDED',
74
- // App Server history is authoritative, but can lag a live item that is
75
- // not represented in `thread/read`. A planning result is terminal for
76
- // this turn, so any such retained tool card belongs before it; never
77
- // append it after the plan/Implement affordance.
78
- items: orderCodexConversationItems([...officialItems, ...localLiveItems]),
122
+ // Reconcile against the managed runtime order. Official items replace
123
+ // matching live projections in place; newly visible terminal items such
124
+ // as a plan are appended after the commentary and tools that preceded it.
125
+ items: reconciledItems,
79
126
  startedAt,
80
127
  completedAt
81
128
  };
@@ -172,20 +219,7 @@ export function codexOfficialItems(session, nativeTurnId, values, turnSequence,
172
219
  const result = invocation === item ? previous : item;
173
220
  items[existingIndex] = mergeCodexCustomToolItems(invocation, result);
174
221
  }
175
- // A tool card is evidence for the reply. Keep the prompt first, then show
176
- // every command/tool action before Agent prose so the visible narrative does
177
- // not claim a result before its supporting execution is available.
178
- return orderCodexConversationItems(items);
179
- }
180
- /** Keep history-only and history-plus-live projections in the same narrative order. */
181
- export function orderCodexConversationItems(items) {
182
- return [
183
- ...items.filter((item) => item.kind === 'user_message'),
184
- ...items.filter((item) => item.kind === 'command_execution' || item.kind === 'tool_call'),
185
- ...items.filter((item) => item.kind !== 'user_message' &&
186
- item.kind !== 'command_execution' &&
187
- item.kind !== 'tool_call')
188
- ];
222
+ return items;
189
223
  }
190
224
  export function codexPairedToolCallId(value) {
191
225
  if (!isPlainRecord(value))
@@ -311,6 +345,38 @@ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, it
311
345
  kind: 'assistant_message',
312
346
  payload: { text: value.text, format: 'markdown', source: 'codex-app-server' }
313
347
  };
348
+ if (value.type === 'reasoning') {
349
+ const sections = Array.isArray(value.summary)
350
+ ? value.summary.flatMap((text, index) => typeof text === 'string' && text.trim().length > 0
351
+ ? [{ index, text: compactRunnerText(text, 10_000) }]
352
+ : [])
353
+ : [];
354
+ return { ...base, kind: 'reasoning_summary', payload: { sections } };
355
+ }
356
+ if (value.type === 'commandExecution') {
357
+ const output = typeof value.aggregatedOutput === 'string' ? value.aggregatedOutput : '';
358
+ return {
359
+ ...base,
360
+ kind: 'command_execution',
361
+ payload: {
362
+ command: typeof value.command === 'string'
363
+ ? compactRunnerText(value.command, 10_000)
364
+ : '(未提供命令)',
365
+ cwd: typeof value.cwd === 'string' ? compactRunnerText(value.cwd, 4_096) : null,
366
+ outputPreview: compactRunnerText(output, 10_000),
367
+ outputRef: null,
368
+ exitCode: typeof value.exitCode === 'number' && Number.isInteger(value.exitCode)
369
+ ? value.exitCode
370
+ : null,
371
+ durationMs: typeof value.durationMs === 'number' &&
372
+ Number.isInteger(value.durationMs) &&
373
+ value.durationMs >= 0
374
+ ? value.durationMs
375
+ : null,
376
+ truncated: output.length > 10_000
377
+ }
378
+ };
379
+ }
314
380
  if (value.type === 'mcpToolCall')
315
381
  return {
316
382
  ...base,
@@ -387,8 +453,12 @@ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, it
387
453
  if (value.type === 'fileChange' && Array.isArray(value.changes))
388
454
  return { ...base, kind: 'file_change', payload: { changes: value.changes } };
389
455
  if (value.type === 'contextCompaction')
390
- return { ...base, kind: 'context_compaction', payload: { summary: '上下文已整理' } };
391
- return undefined;
456
+ return {
457
+ ...base,
458
+ kind: 'context_compaction',
459
+ payload: { phase: 'COMPLETED', summary: '上下文已整理' }
460
+ };
461
+ return codexUnknownOfficialItem(base, value);
392
462
  }
393
463
  export function codexLiveConversationItem(value, completed, imageAttachments = []) {
394
464
  if (typeof value.type !== 'string')
@@ -469,6 +539,57 @@ export function codexLiveConversationItem(value, completed, imageAttachments = [
469
539
  }
470
540
  };
471
541
  }
542
+ if (value.type === 'webSearch')
543
+ return {
544
+ itemId,
545
+ kind: 'tool_call',
546
+ status: completed ? 'COMPLETED' : 'IN_PROGRESS',
547
+ payload: {
548
+ namespace: 'web',
549
+ toolName: 'search',
550
+ title: 'Web Search',
551
+ inputSummary: typeof value.query === 'string' ? compactRunnerText(value.query, 10_000) : null,
552
+ outputSummary: null,
553
+ progressLabel: completed ? null : '正在搜索',
554
+ errorCode: null,
555
+ truncated: false
556
+ }
557
+ };
558
+ if (value.type === 'fileChange' && Array.isArray(value.changes))
559
+ return {
560
+ itemId,
561
+ kind: 'file_change',
562
+ status: completed ? 'COMPLETED' : 'IN_PROGRESS',
563
+ payload: { changes: value.changes },
564
+ merge: true
565
+ };
566
+ if (value.type === 'imageGeneration')
567
+ return {
568
+ itemId,
569
+ kind: 'tool_call',
570
+ status: codexItemStatus(value.status, completed),
571
+ payload: {
572
+ namespace: 'codex',
573
+ toolName: 'imagegen',
574
+ title: 'imagegen',
575
+ inputSummary: typeof value.revisedPrompt === 'string'
576
+ ? compactRunnerText(value.revisedPrompt, 10_000)
577
+ : null,
578
+ outputSummary: completed ? '图片生成完成' : null,
579
+ progressLabel: completed ? null : '正在生成图片',
580
+ errorCode: value.status === 'failed' ? 'IMAGE_GENERATION_FAILED' : null,
581
+ truncated: false,
582
+ ...(imageAttachments.length === 0 ? {} : { attachments: imageAttachments })
583
+ },
584
+ merge: true
585
+ };
586
+ if (value.type === 'contextCompaction')
587
+ return {
588
+ itemId,
589
+ kind: 'context_compaction',
590
+ status: completed ? 'COMPLETED' : 'IN_PROGRESS',
591
+ payload: { phase: completed ? 'COMPLETED' : 'STARTED', summary: null }
592
+ };
472
593
  if (value.type === 'dynamicToolCall' ||
473
594
  value.type === 'custom_tool_call' ||
474
595
  value.type === 'custom_tool_call_output' ||
@@ -516,7 +637,27 @@ export function codexLiveConversationItem(value, completed, imageAttachments = [
516
637
  }
517
638
  };
518
639
  }
519
- return undefined;
640
+ return codexUnknownLiveItem(itemId, value.type, completed);
641
+ }
642
+ function codexUnknownOfficialItem(base, value) {
643
+ if (value.type === 'userMessage' || value.type === 'agentMessage')
644
+ return undefined;
645
+ const type = typeof value.type === 'string' ? value.type : 'unknown';
646
+ return {
647
+ ...base,
648
+ kind: 'unknown',
649
+ payload: { sourceEventType: `codex:${type}`, label: `Codex ${compactRunnerText(type, 128)}` }
650
+ };
651
+ }
652
+ function codexUnknownLiveItem(itemId, type, completed) {
653
+ if (type === 'userMessage' || type === 'agentMessage')
654
+ return undefined;
655
+ return {
656
+ itemId,
657
+ kind: 'unknown',
658
+ status: completed ? 'COMPLETED' : 'IN_PROGRESS',
659
+ payload: { sourceEventType: `codex:${type}`, label: `Codex ${compactRunnerText(type, 128)}` }
660
+ };
520
661
  }
521
662
  export function codexImageAttachments(value) {
522
663
  const found = [];
@@ -673,4 +814,3 @@ export function isCodexImageBlock(value) {
673
814
  }
674
815
  import { codexTimestamp, compactRunnerText, compactRunnerValue, boundedConversationItemId, isCanonicalBase64, isPlainRecord, nativePageEnd } from '../../util/node-operation-parsers.js';
675
816
  export * from '../../util/node-operation-parsers.js';
676
- //# sourceMappingURL=conversation-parser.js.map
@@ -44,7 +44,7 @@ export interface CodexManagedRunHost<TAttachment> {
44
44
  }): void;
45
45
  emitItem(runId: string, item: {
46
46
  readonly itemId: string;
47
- readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan';
47
+ readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'unknown';
48
48
  readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'DECLINED';
49
49
  readonly payload: Record<string, unknown>;
50
50
  readonly merge?: boolean;
@@ -52,6 +52,7 @@ export interface CodexManagedRunHost<TAttachment> {
52
52
  }): void;
53
53
  appendImages(runId: string, images: readonly NodeMessageAttachmentInput[]): readonly Record<string, unknown>[];
54
54
  captureSnapshot(runId: string, cwd: string): Promise<void>;
55
+ syncTitle(sessionId: string, nativeSessionId: string, cwd: string): Promise<void>;
55
56
  commandState(sessionId: string, commandId: string): RunnerCommandState | undefined;
56
57
  setCommandState(sessionId: string, state: RunnerCommandState): void;
57
58
  clearCommandState(sessionId: string, commandId: string): void;
@@ -70,7 +70,8 @@ export class CodexManagedRunController {
70
70
  this.runner.execution.runs.set(runId, {
71
71
  sessionId: session.id,
72
72
  threadId,
73
- cwd: session.cwd
73
+ cwd: session.cwd,
74
+ refreshTitle: false
74
75
  });
75
76
  this.host.emit(runId, 'run.started', { command: 'compact' }, 'STARTING');
76
77
  try {
@@ -184,10 +185,19 @@ export class CodexManagedRunController {
184
185
  const terminal = status === 'completed' ? 'SUCCEEDED' : status === 'interrupted' ? 'INTERRUPTED' : 'FAILED';
185
186
  this.host.emit(runId, 'run.completed', { status: status ?? 'unknown' }, terminal);
186
187
  const active = this.runner.execution.runs.get(runId);
187
- if (active !== undefined)
188
+ const titleRefresh = active === undefined ||
189
+ active.refreshTitle === false ||
190
+ this.host.session(active.sessionId)?.titleSource !== 'AUTO'
191
+ ? undefined
192
+ : this.host.syncTitle(active.sessionId, active.threadId, active.cwd);
193
+ if (active !== undefined) {
188
194
  void this.host.captureSnapshot(runId, active.cwd);
195
+ }
189
196
  this.runner.execution.runs.delete(runId);
190
- this.runner.releaseEnvironment(runId);
197
+ if (titleRefresh === undefined)
198
+ this.runner.releaseEnvironment(runId);
199
+ else
200
+ void titleRefresh.finally(() => this.runner.releaseEnvironment(runId));
191
201
  this.host.removeActive(runId);
192
202
  }
193
203
  }
@@ -376,4 +386,3 @@ export class CodexManagedRunController {
376
386
  }
377
387
  }
378
388
  }
379
- //# sourceMappingURL=managed-run-controller.js.map
@@ -31,6 +31,7 @@ export declare class CodexRunner extends AbstractRunner<'codex'> {
31
31
  } | undefined>;
32
32
  readExternalActivity(session: NodeAgentSession): Promise<"UNAVAILABLE" | "MANAGED_ACTIVE" | "EXTERNAL_ACTIVE" | "IDLE" | undefined>;
33
33
  acceptsTruncatedNativeHistory(): boolean;
34
+ readManagedRunnerTitle(session: NodeAgentSession, nativeSessionId: string): Promise<string | undefined>;
34
35
  nativeImageRoot(session: NodeAgentSession): string | undefined;
35
36
  managedRunForNativeTurn(nativeTurnId: string): string | undefined;
36
37
  protected profileForValidation(): RunnerProfile;
@@ -49,6 +50,8 @@ export declare class CodexRunner extends AbstractRunner<'codex'> {
49
50
  listThreads(): Promise<unknown>;
50
51
  readThread(threadId: string, includeTurns?: boolean): Promise<unknown>;
51
52
  startThread(cwd: string, configuration?: CodexRunConfiguration): Promise<unknown>;
53
+ forkThread(threadId: string, cwd: string, lastTurnId: string, configuration?: CodexRunConfiguration): Promise<unknown>;
54
+ forkNative(session: NodeAgentSession, boundary: string | null, title: string): Promise<string>;
52
55
  resumeThread(threadId: string, cwd: string, configuration?: CodexRunConfiguration): Promise<unknown>;
53
56
  startTurn(threadId: string, text: string, cwd: string, configuration?: CodexRunConfiguration, attachments?: readonly Extract<CodexComposerInput, {
54
57
  readonly type: 'localImage';
@@ -63,6 +66,7 @@ export declare class CodexExecutionState {
63
66
  threadId: string;
64
67
  turnId?: string;
65
68
  cwd: string;
69
+ refreshTitle?: boolean;
66
70
  }>;
67
71
  readonly managedTurns: Map<string, {
68
72
  sessionId: string;