@orion-agents/orion-code 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +73 -14
  3. package/README.zh-CN.md +63 -13
  4. package/bin/orion +15 -4
  5. package/dist/cli.js +51 -172
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/model-command-handlers.d.ts +2 -2
  8. package/dist/commands/model-command-handlers.d.ts.map +1 -1
  9. package/dist/commands/model-command-handlers.js +113 -32
  10. package/dist/commands/model-command-handlers.js.map +1 -1
  11. package/dist/commands/session-command-handlers.d.ts +1 -1
  12. package/dist/commands/session-command-handlers.d.ts.map +1 -1
  13. package/dist/commands/session-command-handlers.js +121 -16
  14. package/dist/commands/session-command-handlers.js.map +1 -1
  15. package/dist/commands/types.d.ts +14 -2
  16. package/dist/commands/types.d.ts.map +1 -1
  17. package/dist/commands/types.js +1 -1
  18. package/dist/commands/types.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/runtime/agent-loop.d.ts +2 -0
  22. package/dist/runtime/agent-loop.d.ts.map +1 -1
  23. package/dist/runtime/agent-loop.js +4 -3
  24. package/dist/runtime/agent-loop.js.map +1 -1
  25. package/dist/runtime/agent-runtime-controller.d.ts +32 -1
  26. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  27. package/dist/runtime/agent-runtime-controller.js +250 -31
  28. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  29. package/dist/runtime/agent-runtime-runner.d.ts +3 -0
  30. package/dist/runtime/agent-runtime-runner.d.ts.map +1 -1
  31. package/dist/runtime/goal-runtime-coordinator.d.ts +6 -0
  32. package/dist/runtime/goal-runtime-coordinator.d.ts.map +1 -1
  33. package/dist/runtime/goal-runtime-coordinator.js +5 -0
  34. package/dist/runtime/goal-runtime-coordinator.js.map +1 -1
  35. package/dist/runtime/legacy-thread-materializer.d.ts +18 -0
  36. package/dist/runtime/legacy-thread-materializer.d.ts.map +1 -1
  37. package/dist/runtime/legacy-thread-materializer.js +27 -12
  38. package/dist/runtime/legacy-thread-materializer.js.map +1 -1
  39. package/dist/runtime/orion-runtime-v1.d.ts +3 -0
  40. package/dist/runtime/orion-runtime-v1.d.ts.map +1 -1
  41. package/dist/runtime/orion-runtime-v1.js +8 -1
  42. package/dist/runtime/orion-runtime-v1.js.map +1 -1
  43. package/dist/runtime/orion-session-runner.d.ts +7 -1
  44. package/dist/runtime/orion-session-runner.d.ts.map +1 -1
  45. package/dist/runtime/orion-session-runner.js +35 -3
  46. package/dist/runtime/orion-session-runner.js.map +1 -1
  47. package/dist/runtime/product-bootstrap.d.ts +22 -0
  48. package/dist/runtime/product-bootstrap.d.ts.map +1 -0
  49. package/dist/runtime/product-bootstrap.js +374 -0
  50. package/dist/runtime/product-bootstrap.js.map +1 -0
  51. package/dist/runtime/product-orion-runtime.d.ts +2 -1
  52. package/dist/runtime/product-orion-runtime.d.ts.map +1 -1
  53. package/dist/runtime/product-orion-runtime.js +114 -16
  54. package/dist/runtime/product-orion-runtime.js.map +1 -1
  55. package/dist/runtime/protocol/runtime-protocol-v1.d.ts +1 -1
  56. package/dist/runtime/protocol/runtime-protocol-v1.js +1 -1
  57. package/dist/runtime/protocol/runtime-protocol-v1.js.map +1 -1
  58. package/dist/runtime/release-receipts.d.ts +63 -2
  59. package/dist/runtime/release-receipts.d.ts.map +1 -1
  60. package/dist/runtime/release-receipts.js +298 -7
  61. package/dist/runtime/release-receipts.js.map +1 -1
  62. package/dist/runtime/session-history-recovery.d.ts +19 -0
  63. package/dist/runtime/session-history-recovery.d.ts.map +1 -0
  64. package/dist/runtime/session-history-recovery.js +45 -0
  65. package/dist/runtime/session-history-recovery.js.map +1 -0
  66. package/dist/runtime/step-snapshot.d.ts.map +1 -1
  67. package/dist/runtime/step-snapshot.js +22 -2
  68. package/dist/runtime/step-snapshot.js.map +1 -1
  69. package/dist/runtime/subagents/runtime-integration.d.ts +1 -1
  70. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  71. package/dist/runtime/subagents/runtime-integration.js +5 -2
  72. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  73. package/dist/runtime/thread-event-store.d.ts +27 -0
  74. package/dist/runtime/thread-event-store.d.ts.map +1 -1
  75. package/dist/runtime/thread-event-store.js +119 -17
  76. package/dist/runtime/thread-event-store.js.map +1 -1
  77. package/dist/runtime/thread-projection.d.ts +10 -0
  78. package/dist/runtime/thread-projection.d.ts.map +1 -1
  79. package/dist/runtime/thread-projection.js +40 -0
  80. package/dist/runtime/thread-projection.js.map +1 -1
  81. package/dist/runtime/thread-runtime.d.ts +3 -1
  82. package/dist/runtime/thread-runtime.d.ts.map +1 -1
  83. package/dist/runtime/thread-runtime.js +6 -0
  84. package/dist/runtime/thread-runtime.js.map +1 -1
  85. package/dist/runtime/thread-session-view.d.ts +88 -0
  86. package/dist/runtime/thread-session-view.d.ts.map +1 -0
  87. package/dist/runtime/thread-session-view.js +327 -0
  88. package/dist/runtime/thread-session-view.js.map +1 -0
  89. package/dist/runtime/thread-ui-adapter.d.ts +4 -0
  90. package/dist/runtime/thread-ui-adapter.d.ts.map +1 -1
  91. package/dist/runtime/thread-ui-adapter.js +193 -5
  92. package/dist/runtime/thread-ui-adapter.js.map +1 -1
  93. package/dist/runtime/ui-events.d.ts +37 -0
  94. package/dist/runtime/ui-events.d.ts.map +1 -1
  95. package/dist/runtime/ui-events.js +1 -0
  96. package/dist/runtime/ui-events.js.map +1 -1
  97. package/dist/runtime/ui-view-model.d.ts +3 -0
  98. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  99. package/dist/runtime/ui-view-model.js +10 -3
  100. package/dist/runtime/ui-view-model.js.map +1 -1
  101. package/dist/services/file-lock.d.ts.map +1 -1
  102. package/dist/services/file-lock.js +42 -17
  103. package/dist/services/file-lock.js.map +1 -1
  104. package/dist/services/global-config.d.ts +25 -0
  105. package/dist/services/global-config.d.ts.map +1 -1
  106. package/dist/services/global-config.js +373 -5
  107. package/dist/services/global-config.js.map +1 -1
  108. package/dist/services/session-storage.d.ts +67 -0
  109. package/dist/services/session-storage.d.ts.map +1 -1
  110. package/dist/services/session-storage.js +327 -61
  111. package/dist/services/session-storage.js.map +1 -1
  112. package/dist/services/settings-coordinator.d.ts +174 -0
  113. package/dist/services/settings-coordinator.d.ts.map +1 -0
  114. package/dist/services/settings-coordinator.js +605 -0
  115. package/dist/services/settings-coordinator.js.map +1 -0
  116. package/dist/services/settings-document-repository.d.ts +138 -0
  117. package/dist/services/settings-document-repository.d.ts.map +1 -0
  118. package/dist/services/settings-document-repository.js +551 -0
  119. package/dist/services/settings-document-repository.js.map +1 -0
  120. package/dist/terminal-ui/launch.d.ts.map +1 -1
  121. package/dist/terminal-ui/launch.js +7 -0
  122. package/dist/terminal-ui/launch.js.map +1 -1
  123. package/dist/tools/web.js +1 -1
  124. package/dist/tools/web.js.map +1 -1
  125. package/dist/tui-ui/chrome-view-model.d.ts.map +1 -1
  126. package/dist/tui-ui/chrome-view-model.js +21 -7
  127. package/dist/tui-ui/chrome-view-model.js.map +1 -1
  128. package/dist/tui-ui/launch.d.ts.map +1 -1
  129. package/dist/tui-ui/launch.js +13 -0
  130. package/dist/tui-ui/launch.js.map +1 -1
  131. package/dist/tui-ui/state.d.ts.map +1 -1
  132. package/dist/tui-ui/state.js +7 -0
  133. package/dist/tui-ui/state.js.map +1 -1
  134. package/dist/web/event-hub.d.ts +39 -0
  135. package/dist/web/event-hub.d.ts.map +1 -0
  136. package/dist/web/event-hub.js +263 -0
  137. package/dist/web/event-hub.js.map +1 -0
  138. package/dist/web/index.d.ts +6 -0
  139. package/dist/web/index.d.ts.map +1 -0
  140. package/dist/web/index.js +28 -0
  141. package/dist/web/index.js.map +1 -0
  142. package/dist/web/launch.d.ts +9 -0
  143. package/dist/web/launch.d.ts.map +1 -0
  144. package/dist/web/launch.js +64 -0
  145. package/dist/web/launch.js.map +1 -0
  146. package/dist/web/protocol.d.ts +346 -0
  147. package/dist/web/protocol.d.ts.map +1 -0
  148. package/dist/web/protocol.js +348 -0
  149. package/dist/web/protocol.js.map +1 -0
  150. package/dist/web/server.d.ts +20 -0
  151. package/dist/web/server.d.ts.map +1 -0
  152. package/dist/web/server.js +498 -0
  153. package/dist/web/server.js.map +1 -0
  154. package/dist/web/workbench-controller.d.ts +63 -0
  155. package/dist/web/workbench-controller.d.ts.map +1 -0
  156. package/dist/web/workbench-controller.js +774 -0
  157. package/dist/web/workbench-controller.js.map +1 -0
  158. package/dist/web-client/assets/index-BAEO71Gp.css +1 -0
  159. package/dist/web-client/assets/index-DSkFy7gM.js +13 -0
  160. package/dist/web-client/index.html +16 -0
  161. package/docs/architecture/v0.3.0-web-api.yaml +1309 -0
  162. package/docs/migration/v0.2.2-to-v0.3.0-settings.md +114 -0
  163. package/docs/migration/v0.2.2-to-v0.3.0.md +55 -0
  164. package/docs/orion.example.json +9 -2
  165. package/docs/plan/v0.3.0-node-runtime-compatibility-plan.md +57 -0
  166. package/docs/plan/v0.3.0-settings-integration-plan.md +740 -0
  167. package/docs/plan/v0.3.0-web-workbench-plan.md +325 -0
  168. package/docs/readme.md +12 -1
  169. package/npm-shrinkwrap.json +1777 -424
  170. package/package.json +33 -9
@@ -1,3 +1,4 @@
1
+ import type { AgentMode } from '../commands/types';
1
2
  import type { AgentRuntimeEventSink, AgentRuntimeInput, AgentRuntimeInputResult, AgentRuntimeInterruptResult, AgentRuntimeSubmitResult } from './agent-runtime-protocol';
2
3
  import type { AgentRuntimeRunnerV1, AgentRuntimeRunInputOptionsV1 } from './agent-runtime-runner';
3
4
  import type { OrionCodeUiRuntime, FollowupQueueItem, UiEventSink, UiRendererCapabilities } from './ui-events';
@@ -13,6 +14,20 @@ export interface AgentRuntimeToolPermissionRequest {
13
14
  reason?: string;
14
15
  abortSignal?: AbortSignal;
15
16
  }
17
+ /** Secret-free immutable read model for reconnecting renderer surfaces. */
18
+ export interface AgentRuntimePendingPermissionSnapshot {
19
+ readonly id: string;
20
+ readonly name: string;
21
+ readonly reason?: string;
22
+ readonly args: Readonly<Record<string, unknown>>;
23
+ }
24
+ /** Exact agent-mode input used by renderers with a three-state selector. */
25
+ export interface AgentRuntimeSetAgentModeInput {
26
+ readonly type: 'set_agent_mode';
27
+ readonly mode: AgentMode;
28
+ readonly source?: 'picker' | 'command' | 'programmatic';
29
+ }
30
+ export type AgentRuntimeControllerInput = AgentRuntimeInput | AgentRuntimeSetAgentModeInput;
16
31
  export interface AgentRuntimeControllerOptions extends TurnControllerOptions {
17
32
  runtime: OrionCodeUiRuntime;
18
33
  events?: UiEventSink;
@@ -54,7 +69,11 @@ export declare class AgentRuntimeController {
54
69
  private readonly agentModeLifecycle;
55
70
  private readonly pendingPermissions;
56
71
  private activeRun;
72
+ private pendingAgentMode;
57
73
  private readonly goalControlRuns;
74
+ private activeGoalRuntimeTransitions;
75
+ private goalRuntimeActive;
76
+ private settingsBoundarySynchronizations;
58
77
  private stopping;
59
78
  private nextPermissionRequestId;
60
79
  private readonly queuedCommands;
@@ -64,6 +83,11 @@ export declare class AgentRuntimeController {
64
83
  constructor(options: AgentRuntimeControllerOptions);
65
84
  hasActiveTurn(): boolean;
66
85
  getFollowupQueue(): readonly FollowupQueueItem[];
86
+ /**
87
+ * Return a detached read model for browser refresh/reconnect recovery.
88
+ * AbortSignal and resolver ownership remain private to the controller.
89
+ */
90
+ getPendingPermissions(): readonly AgentRuntimePendingPermissionSnapshot[];
67
91
  /** Thin /goal control surface; GoalRuntimeCoordinatorV2 owns every mutation. */
68
92
  handleTargetInput(rawInput: string): {
69
93
  handled: boolean;
@@ -79,7 +103,9 @@ export declare class AgentRuntimeController {
79
103
  setVerificationState(state: 'pending' | 'running' | 'passed' | 'failed' | 'gated'): void;
80
104
  getVerificationState(): 'pending' | 'running' | 'passed' | 'failed' | 'gated' | undefined;
81
105
  clearExitIntent(): void;
82
- handle(input: AgentRuntimeInput): AgentRuntimeInputResult;
106
+ handle(input: AgentRuntimeControllerInput): AgentRuntimeInputResult;
107
+ /** Set an exact mode immediately while idle, or at the next logical-request boundary. */
108
+ setAgentMode(mode: AgentMode): AgentRuntimeInputResult;
83
109
  private queueFollowup;
84
110
  private manageFollowupQueue;
85
111
  submit(input: string): AgentRuntimeSubmitResult;
@@ -92,16 +118,21 @@ export declare class AgentRuntimeController {
92
118
  waitForIdle(): Promise<void>;
93
119
  private runTurn;
94
120
  private handleRunLoopError;
121
+ private synchronizeSettingsAtLogicalBoundary;
95
122
  private emitAppend;
96
123
  private emitStatus;
97
124
  private emitProcessing;
98
125
  private emitFollowupQueue;
126
+ private agentModeSnapshot;
99
127
  private emitAgentModeSnapshot;
100
128
  private cycleAgentMode;
129
+ private applyPendingAgentMode;
101
130
  private requestIsCurrent;
102
131
  requestToolPermission(request: AgentRuntimeToolPermissionRequest): Promise<boolean>;
103
132
  private startGoalControl;
104
133
  private renderGoalControl;
134
+ private observeGoalControlResult;
135
+ private observeGoalRuntimeEvent;
105
136
  private recordPermissionDecision;
106
137
  private applyPermissionModeChange;
107
138
  private rejectPendingPermissions;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-runtime-controller.d.ts","sourceRoot":"","sources":["../../src/runtime/agent-runtime-controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-runtime-controller.d.ts","sourceRoot":"","sources":["../../src/runtime/agent-runtime-controller.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AgentRuntimeController = void 0;
4
+ const crypto_1 = require("crypto");
4
5
  const commands_1 = require("../commands");
5
6
  const parser_1 = require("../commands/parser");
6
7
  const target_command_1 = require("../commands/target-command");
@@ -8,9 +9,9 @@ const agent_runtime_protocol_1 = require("./agent-runtime-protocol");
8
9
  const agent_status_1 = require("./agent-status");
9
10
  const ui_events_1 = require("./ui-events");
10
11
  const turn_controller_1 = require("./turn-controller");
11
- const global_config_1 = require("../services/global-config");
12
12
  const tool_allowlist_1 = require("../services/tool-allowlist");
13
13
  const agent_mode_1 = require("../framework/agent-mode");
14
+ const redaction_1 = require("../services/redaction");
14
15
  const style_1 = require("../tui-core/style");
15
16
  function isExitInput(input) {
16
17
  const parsed = (0, parser_1.parseInput)(input.trim());
@@ -46,7 +47,11 @@ class AgentRuntimeController {
46
47
  this.options = options;
47
48
  this.pendingPermissions = new Map();
48
49
  this.activeRun = null;
50
+ this.pendingAgentMode = null;
49
51
  this.goalControlRuns = new Set();
52
+ this.activeGoalRuntimeTransitions = 0;
53
+ this.goalRuntimeActive = false;
54
+ this.settingsBoundarySynchronizations = 0;
50
55
  this.stopping = false;
51
56
  this.nextPermissionRequestId = 1;
52
57
  this.queuedCommands = [];
@@ -60,6 +65,8 @@ class AgentRuntimeController {
60
65
  const downstream = options.eventSink ?? (0, agent_runtime_protocol_1.createAgentRuntimeEventSinkFromUiEvents)(options.events);
61
66
  this.eventSink = {
62
67
  emit: event => {
68
+ if (event.type === 'goal_event')
69
+ this.observeGoalRuntimeEvent(event.event);
63
70
  const result = downstream.emit(event);
64
71
  if (event.type === 'session_restored') {
65
72
  if (this.followupQueue.length > 0) {
@@ -75,11 +82,18 @@ class AgentRuntimeController {
75
82
  this.agentModeLifecycle.subscribe(snapshot => {
76
83
  this.eventSink.emit({ type: 'agent_mode_changed', snapshot });
77
84
  });
85
+ options.runtime.bindSettingsRuntimeIdleProbe?.(() => (this.settingsBoundarySynchronizations > 0 || !this.turnController.hasActiveTurn()) &&
86
+ this.activeGoalRuntimeTransitions === 0 &&
87
+ !this.goalRuntimeActive);
78
88
  const events = (0, agent_runtime_protocol_1.createUiEventSinkFromAgentRuntimeEvents)(this.eventSink);
79
89
  this.runner =
80
90
  options.runner ??
81
91
  options.runtime.createAgentRunner?.(events, {
82
92
  approvalHandler: request => this.requestToolPermission(request),
93
+ // Every renderer restores history from a bounded, cursor-bound surface
94
+ // projection. Replaying the complete durable Thread here couples Runtime
95
+ // recovery to UI history size and makes /resume O(total Thread facts).
96
+ replayHistoryOnRestore: false,
83
97
  }) ??
84
98
  createUnavailableRunner();
85
99
  this.emitAgentModeSnapshot();
@@ -90,6 +104,13 @@ class AgentRuntimeController {
90
104
  getFollowupQueue() {
91
105
  return this.followupQueue;
92
106
  }
107
+ /**
108
+ * Return a detached read model for browser refresh/reconnect recovery.
109
+ * AbortSignal and resolver ownership remain private to the controller.
110
+ */
111
+ getPendingPermissions() {
112
+ return Object.freeze([...this.pendingPermissions.values()].map(entry => entry.snapshot));
113
+ }
93
114
  /** Thin /goal control surface; GoalRuntimeCoordinatorV2 owns every mutation. */
94
115
  handleTargetInput(rawInput) {
95
116
  const parsed = (0, target_command_1.parseTargetCommand)(rawInput);
@@ -162,8 +183,31 @@ class AgentRuntimeController {
162
183
  return this.applyPermissionModeChange(input.value);
163
184
  case 'cycle_agent_mode':
164
185
  return this.cycleAgentMode();
186
+ case 'set_agent_mode':
187
+ return this.setAgentMode(input.mode);
165
188
  }
166
189
  }
190
+ /** Set an exact mode immediately while idle, or at the next logical-request boundary. */
191
+ setAgentMode(mode) {
192
+ const deferred = this.turnController.hasActiveTurn();
193
+ if (!deferred) {
194
+ this.pendingAgentMode = null;
195
+ return {
196
+ type: 'agent_mode_changed',
197
+ snapshot: this.agentModeLifecycle.setMode(mode),
198
+ appliesFrom: 'immediate',
199
+ };
200
+ }
201
+ const baseMode = this.agentModeLifecycle.snapshot().baseMode;
202
+ this.pendingAgentMode = mode === baseMode ? null : mode;
203
+ const snapshot = this.agentModeSnapshot();
204
+ this.emitAgentModeSnapshot(snapshot);
205
+ return {
206
+ type: 'agent_mode_changed',
207
+ snapshot,
208
+ appliesFrom: 'next-logical-request',
209
+ };
210
+ }
167
211
  queueFollowup(input) {
168
212
  const text = input.trim();
169
213
  if (!text)
@@ -262,7 +306,11 @@ class AgentRuntimeController {
262
306
  this.turnController.requestRevision(submitted);
263
307
  // v0.1.3 (G1): echo the incremental input to the transcript immediately,
264
308
  // so the user sees their correction without waiting for the turn to abort.
265
- this.emitAppend(submittedEntry(submitted));
309
+ // A runtime-owned durable transcript disables this optimistic projection
310
+ // and emits the revision from its authoritative user item instead.
311
+ if (this.options.echoSubmittedInput ?? true) {
312
+ this.emitAppend(submittedEntry(submitted));
313
+ }
266
314
  this.emitStatus(this.options.revisionStatus ?? '已接收补充,正在中断当前轮…');
267
315
  return { type: 'revision_requested' };
268
316
  }
@@ -307,6 +355,8 @@ class AgentRuntimeController {
307
355
  this.emitStatus(`/${name} acknowledged; active turn continues.`);
308
356
  }
309
357
  async runCommand(command, args) {
358
+ if (command.risk !== 'read-only')
359
+ await this.options.runtime.synchronizeSettings?.();
310
360
  const renderer = this.options.uiRenderer ?? this.options.runtime.config.ui?.renderer ?? 'terminal';
311
361
  if (command.rendererScope && !command.rendererScope.includes(renderer)) {
312
362
  this.emitAppend({
@@ -382,7 +432,13 @@ class AgentRuntimeController {
382
432
  sessionId: this.options.runtime.getSession()?.id,
383
433
  ensureSession: this.options.runtime.ensureSession,
384
434
  setSession: session => this.options.runtime.setSession(session),
435
+ restoreSessionRuntime: this.runner.restoreSession
436
+ ? activation => this.runner.restoreSession(activation)
437
+ : undefined,
385
438
  sessionRestored: event => this.eventSink.emit({ type: 'session_restored', event }),
439
+ ...((renderer === 'terminal' || renderer === 'tui') && {
440
+ replaceTranscript: (entries) => this.eventSink.emit({ type: 'transcript_replace', entries: [...entries] }),
441
+ }),
386
442
  getSession: this.options.runtime.getSession,
387
443
  writeOutput: text => {
388
444
  if (text.trim())
@@ -398,6 +454,9 @@ class AgentRuntimeController {
398
454
  uiCapabilities: (0, ui_events_1.resolveUiRendererCapabilities)(this.options.uiCapabilities, renderer),
399
455
  agentModeLifecycle: this.agentModeLifecycle,
400
456
  getHarnessDiagnostics: this.options.runtime.getHarnessDiagnostics,
457
+ settingsCoordinator: this.options.runtime.settingsCoordinator,
458
+ describeSettings: this.options.runtime.describeSettings,
459
+ updateSettings: this.options.runtime.updateSettings,
401
460
  compact: this.runner.compact ? input => this.runner.compact(input) : undefined,
402
461
  };
403
462
  }
@@ -440,10 +499,7 @@ class AgentRuntimeController {
440
499
  this.stopping = false;
441
500
  }
442
501
  async waitForIdle() {
443
- await Promise.all([
444
- this.activeRun ?? Promise.resolve(),
445
- ...this.goalControlRuns,
446
- ]);
502
+ await Promise.all([this.activeRun ?? Promise.resolve(), ...this.goalControlRuns]);
447
503
  }
448
504
  async runTurn(firstRequest) {
449
505
  let nextRequest = firstRequest;
@@ -460,12 +516,15 @@ class AgentRuntimeController {
460
516
  }
461
517
  this.options.beforeTurn?.(nextInput);
462
518
  const turn = this.turnController.beginTurn(nextInput);
463
- this.options.runtime.store.setProcessing(true);
464
- this.emitProcessing(true);
465
- const runningStatus = statusText(this.options.runningStatus, nextInput);
466
- if (runningStatus)
467
- this.emitStatus(runningStatus);
468
519
  try {
520
+ if (this.options.runtime.synchronizeSettings) {
521
+ await this.synchronizeSettingsAtLogicalBoundary();
522
+ }
523
+ this.options.runtime.store.setProcessing(true);
524
+ this.emitProcessing(true);
525
+ const runningStatus = statusText(this.options.runningStatus, nextInput);
526
+ if (runningStatus)
527
+ this.emitStatus(runningStatus);
469
528
  if (this.runner.runRequest) {
470
529
  await this.runner.runRequest(request, {
471
530
  abortSignal: turn.abortSignal,
@@ -493,9 +552,12 @@ class AgentRuntimeController {
493
552
  }
494
553
  finally {
495
554
  const revision = this.turnController.finishTurn(turn.id);
496
- const completedPlan = this.agentModeLifecycle.completedPlanSince(planCompletionBeforeRequest) ?? undefined;
497
- if (!completedPlan)
498
- this.agentModeLifecycle.applyPending();
555
+ // Durable request runners commit and enqueue Plan execution at the Thread boundary.
556
+ // The legacy runInput path still needs the controller-owned compatibility follow-up.
557
+ const completedPlan = this.runner.runRequest
558
+ ? undefined
559
+ : (this.agentModeLifecycle.completedPlanSince(planCompletionBeforeRequest) ?? undefined);
560
+ this.applyPendingAgentMode(Boolean(completedPlan));
499
561
  if (revision?.trim()) {
500
562
  this.emitStatus(this.options.restartingStatus ?? '根据补充调整方向中…');
501
563
  nextRequest = {
@@ -571,6 +633,18 @@ class AgentRuntimeController {
571
633
  this.emitStatus(readyStatus);
572
634
  this.options.afterTurnLoop?.();
573
635
  }
636
+ async synchronizeSettingsAtLogicalBoundary() {
637
+ const synchronize = this.options.runtime.synchronizeSettings;
638
+ if (!synchronize)
639
+ return;
640
+ this.settingsBoundarySynchronizations += 1;
641
+ try {
642
+ await synchronize();
643
+ }
644
+ finally {
645
+ this.settingsBoundarySynchronizations -= 1;
646
+ }
647
+ }
574
648
  emitAppend(entry) {
575
649
  return this.eventSink.emit({ type: 'transcript_append', entry });
576
650
  }
@@ -586,21 +660,49 @@ class AgentRuntimeController {
586
660
  snapshot: { items: [...this.followupQueue], limit: this.followupQueueLimit },
587
661
  });
588
662
  }
589
- emitAgentModeSnapshot() {
663
+ agentModeSnapshot() {
664
+ const snapshot = this.agentModeLifecycle.snapshot();
665
+ return this.pendingAgentMode
666
+ ? { ...snapshot, pendingBaseMode: this.pendingAgentMode }
667
+ : snapshot;
668
+ }
669
+ emitAgentModeSnapshot(snapshot = this.agentModeSnapshot()) {
590
670
  this.eventSink.emit({
591
671
  type: 'agent_mode_changed',
592
- snapshot: this.agentModeLifecycle.snapshot(),
672
+ snapshot,
593
673
  });
594
674
  }
595
675
  cycleAgentMode() {
596
676
  const deferred = this.turnController.hasActiveTurn();
597
- const snapshot = this.agentModeLifecycle.cycle({ defer: deferred });
677
+ if (!deferred)
678
+ this.pendingAgentMode = null;
679
+ const lifecycleSnapshot = this.agentModeLifecycle.snapshot();
680
+ const nextMode = (0, agent_mode_1.nextAgentMode)(this.pendingAgentMode ?? lifecycleSnapshot.pendingBaseMode ?? lifecycleSnapshot.baseMode);
681
+ let snapshot;
682
+ if (deferred) {
683
+ this.pendingAgentMode = nextMode === lifecycleSnapshot.baseMode ? null : nextMode;
684
+ snapshot = this.agentModeSnapshot();
685
+ this.emitAgentModeSnapshot(snapshot);
686
+ }
687
+ else {
688
+ snapshot = this.agentModeLifecycle.setMode(nextMode);
689
+ }
598
690
  return {
599
691
  type: 'agent_mode_changed',
600
692
  snapshot,
601
693
  appliesFrom: deferred ? 'next-logical-request' : 'immediate',
602
694
  };
603
695
  }
696
+ applyPendingAgentMode(completedPlan) {
697
+ const pendingMode = this.pendingAgentMode;
698
+ this.pendingAgentMode = null;
699
+ if (pendingMode) {
700
+ this.agentModeLifecycle.setMode(pendingMode);
701
+ return;
702
+ }
703
+ if (!completedPlan)
704
+ this.agentModeLifecycle.applyPending();
705
+ }
604
706
  requestIsCurrent(request) {
605
707
  const activeSessionId = this.options.runtime.getSession()?.id;
606
708
  return !activeSessionId || request.sessionId === activeSessionId;
@@ -616,6 +718,7 @@ class AgentRuntimeController {
616
718
  reason: request.reason,
617
719
  abortSignal: request.abortSignal,
618
720
  };
721
+ const snapshot = createPendingPermissionSnapshot(id, request);
619
722
  return new Promise(resolve => {
620
723
  const finish = (approved) => {
621
724
  this.pendingPermissions.delete(id);
@@ -623,7 +726,7 @@ class AgentRuntimeController {
623
726
  resolve(approved);
624
727
  };
625
728
  const onAbort = () => finish(false);
626
- this.pendingPermissions.set(id, { request, finish });
729
+ this.pendingPermissions.set(id, { request, snapshot, finish });
627
730
  request.abortSignal?.addEventListener('abort', onAbort, { once: true });
628
731
  this.emitStatus((0, agent_status_1.permissionPendingStatus)(request.name));
629
732
  this.eventSink.emit({ type: 'permission_requested', request: runtimeRequest });
@@ -637,21 +740,46 @@ class AgentRuntimeController {
637
740
  this.emitStatus(message);
638
741
  return { type: 'command_handled' };
639
742
  }
640
- if ((this.turnController.hasActiveTurn() || this.goalControlRuns.size > 0) &&
743
+ if ((this.turnController.hasActiveTurn() ||
744
+ this.goalControlRuns.size > 0 ||
745
+ this.goalRuntimeActive) &&
641
746
  (goalControl.action === 'create' || goalControl.action === 'resume')) {
642
747
  const message = `/goal ${goalControl.action} is unavailable while Goal work is running; use /goal pause or /goal clear first.`;
643
748
  this.emitStatus(message);
644
749
  return { type: 'command_ignored' };
645
750
  }
646
- if (goalControl.action === 'pause' || goalControl.action === 'clear') {
751
+ const stopsGoal = goalControl.action === 'pause' || goalControl.action === 'clear';
752
+ const interruptedRun = stopsGoal ? this.activeRun : null;
753
+ if (stopsGoal) {
647
754
  this.turnController.clearExitIntent();
648
755
  this.turnController.interruptActiveTurn();
649
756
  this.runner.interrupt?.(`goal ${goalControl.action}`);
650
757
  this.rejectPendingPermissions();
651
758
  }
652
- const run = this.runner
653
- .controlGoal(goalControl)
654
- .then(result => this.renderGoalControl(result))
759
+ const run = Promise.resolve()
760
+ .then(async () => {
761
+ if (interruptedRun)
762
+ await interruptedRun.catch(() => undefined);
763
+ if (!stopsGoal)
764
+ await this.synchronizeSettingsAtLogicalBoundary();
765
+ })
766
+ .then(async () => {
767
+ this.activeGoalRuntimeTransitions += 1;
768
+ try {
769
+ return await this.runner.controlGoal(goalControl);
770
+ }
771
+ finally {
772
+ this.activeGoalRuntimeTransitions -= 1;
773
+ }
774
+ })
775
+ .then(async (result) => {
776
+ this.observeGoalControlResult(result);
777
+ this.renderGoalControl(result);
778
+ // Pause/clear must remain available while Goal work is active. Reconcile
779
+ // pending runtime-sensitive edits only after that work has stopped.
780
+ if (stopsGoal && result.accepted)
781
+ await this.synchronizeSettingsAtLogicalBoundary();
782
+ })
655
783
  .catch(error => {
656
784
  const message = error instanceof Error ? error.message : String(error);
657
785
  this.emitAppend({ role: 'error', title: 'goal', content: message, errorLayer: 'runtime' });
@@ -673,6 +801,20 @@ class AgentRuntimeController {
673
801
  });
674
802
  this.emitStatus(summary);
675
803
  }
804
+ observeGoalControlResult(result) {
805
+ if (!result.accepted)
806
+ return;
807
+ this.goalRuntimeActive =
808
+ (result.action === 'create' || result.action === 'resume') && result.scheduleContinuation;
809
+ }
810
+ observeGoalRuntimeEvent(event) {
811
+ if (event.type === 'goal_updated') {
812
+ this.goalRuntimeActive = event.goal.status === 'active';
813
+ }
814
+ else if (event.type === 'goal_cleared' || event.type === 'goal_completed') {
815
+ this.goalRuntimeActive = false;
816
+ }
817
+ }
676
818
  recordPermissionDecision(requestId, approved, scope = 'once') {
677
819
  const pending = this.pendingPermissions.get(requestId);
678
820
  if (!pending)
@@ -709,14 +851,38 @@ class AgentRuntimeController {
709
851
  const allowed = ['allow', 'ask', 'deny'];
710
852
  if (!allowed.includes(value))
711
853
  return { type: 'permission_mode_invalid' };
712
- // Persist to disk so the change survives restart...
713
- (0, global_config_1.updateGlobalConfig)({ toolConfirmation: value });
714
- // ...and mutate the live runtime config so the very next tool call uses it
715
- // immediately (chat-controller passes this.runtime.config.toolConfirmation into
716
- // the scheduler on every turn).
717
- this.options.runtime.config.toolConfirmation = value;
718
- this.emitStatus(`Tool confirmation → ${value}`);
719
- return { type: 'permission_mode_changed' };
854
+ if (this.activeRun ||
855
+ this.turnController.hasActiveTurn() ||
856
+ this.goalControlRuns.size > 0 ||
857
+ this.goalRuntimeActive) {
858
+ this.emitStatus('Tool confirmation was not changed: the runtime is busy.');
859
+ return { type: 'command_ignored' };
860
+ }
861
+ const describeSettings = this.options.runtime.describeSettings;
862
+ const updateSettings = this.options.runtime.updateSettings;
863
+ if (!describeSettings || !updateSettings) {
864
+ this.emitStatus('Tool confirmation was not changed: Settings are unavailable.');
865
+ return { type: 'command_ignored' };
866
+ }
867
+ const run = (async () => {
868
+ const before = describeSettings();
869
+ await updateSettings({
870
+ requestId: `runtime:permission-mode:${(0, crypto_1.randomUUID)()}`,
871
+ expectedRevision: before.revision,
872
+ operations: [{ op: 'set', key: 'permissions.toolConfirmation', value }],
873
+ });
874
+ this.emitStatus(`Tool confirmation → ${value}`);
875
+ })()
876
+ .catch(error => {
877
+ const reason = error instanceof Error ? error.message : String(error);
878
+ this.emitStatus(`Tool confirmation was not changed: ${reason}`);
879
+ })
880
+ .finally(() => {
881
+ if (this.activeRun === run)
882
+ this.activeRun = null;
883
+ });
884
+ this.activeRun = run;
885
+ return { type: 'started' };
720
886
  }
721
887
  rejectPendingPermissions() {
722
888
  const pending = [...this.pendingPermissions.values()];
@@ -727,6 +893,59 @@ class AgentRuntimeController {
727
893
  }
728
894
  }
729
895
  exports.AgentRuntimeController = AgentRuntimeController;
896
+ const PERMISSION_SECRET_ARG_KEY = /(?:^|[_-])(?:api[_-]?key|access[_-]?token|auth[_-]?token|accesstoken|authtoken|password|secret|authorization|cookie|credential)(?:$|[_-])/iu;
897
+ const MAX_PERMISSION_SNAPSHOT_DEPTH = 12;
898
+ function createPendingPermissionSnapshot(id, request) {
899
+ return Object.freeze({
900
+ id,
901
+ name: sanitizePermissionText(request.name),
902
+ ...(request.reason === undefined ? {} : { reason: sanitizePermissionText(request.reason) }),
903
+ args: sanitizePermissionArgs(request.args),
904
+ });
905
+ }
906
+ function sanitizePermissionArgs(args) {
907
+ const value = sanitizePermissionValue(args, undefined, new Set(), 0);
908
+ return isPlainRecord(value) ? value : Object.freeze({});
909
+ }
910
+ function sanitizePermissionValue(value, key, ancestors, depth) {
911
+ if (key && PERMISSION_SECRET_ARG_KEY.test(key))
912
+ return '[REDACTED_SECRET]';
913
+ if (typeof value === 'string')
914
+ return sanitizePermissionText(value);
915
+ if (value === null || typeof value === 'boolean')
916
+ return value;
917
+ if (typeof value === 'number')
918
+ return Number.isFinite(value) ? value : null;
919
+ if (typeof value !== 'object')
920
+ return '[NON_JSON_VALUE]';
921
+ if (depth >= MAX_PERMISSION_SNAPSHOT_DEPTH)
922
+ return '[TRUNCATED]';
923
+ if (ancestors.has(value))
924
+ return '[CIRCULAR]';
925
+ const prototype = Object.getPrototypeOf(value);
926
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {
927
+ return '[NON_JSON_VALUE]';
928
+ }
929
+ ancestors.add(value);
930
+ try {
931
+ if (Array.isArray(value)) {
932
+ return Object.freeze(value.map(entry => sanitizePermissionValue(entry, undefined, ancestors, depth + 1)));
933
+ }
934
+ return Object.freeze(Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [
935
+ sanitizePermissionText(entryKey),
936
+ sanitizePermissionValue(entryValue, entryKey, ancestors, depth + 1),
937
+ ])));
938
+ }
939
+ finally {
940
+ ancestors.delete(value);
941
+ }
942
+ }
943
+ function sanitizePermissionText(value) {
944
+ return (0, style_1.sanitizeTerminalText)((0, redaction_1.redactTraceText)(value));
945
+ }
946
+ function isPlainRecord(value) {
947
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
948
+ }
730
949
  function formatGoalRuntimeStatus(result) {
731
950
  const state = result.state;
732
951
  if (!state)