@myagentroam/node 0.9.2 → 0.9.4

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 (81) hide show
  1. package/dist/codex-app-server.d.ts +24 -0
  2. package/dist/codex-app-server.js +100 -5
  3. package/dist/connector.js +18 -15
  4. package/dist/control-outbound-scheduler.d.ts +4 -1
  5. package/dist/control-outbound-scheduler.js +39 -6
  6. package/dist/database.d.ts +2 -19
  7. package/dist/database.js +1 -62
  8. package/dist/event-buffer.d.ts +2 -5
  9. package/dist/event-buffer.js +3 -12
  10. package/dist/native-session-history.js +33 -12
  11. package/dist/runner/claude/managed-run-controller.d.ts +0 -1
  12. package/dist/runner/claude/managed-run-controller.js +17 -12
  13. package/dist/runner/codex/conversation-parser.d.ts +1 -1
  14. package/dist/runner/codex/conversation-parser.js +3 -0
  15. package/dist/runner/codex/managed-run-controller.d.ts +11 -2
  16. package/dist/runner/codex/managed-run-controller.js +79 -24
  17. package/dist/runner/codex-runner.d.ts +3 -0
  18. package/dist/runner/codex-runner.js +42 -3
  19. package/dist/runner/opencode/conversation-parser.js +1 -1
  20. package/dist/runner/opencode/managed-run-controller.d.ts +7 -2
  21. package/dist/runner/opencode/managed-run-controller.js +72 -14
  22. package/dist/runner/opencode-runner.d.ts +3 -0
  23. package/dist/runner/opencode-runner.js +25 -0
  24. package/dist/runner-profiles.js +10 -6
  25. package/dist/runtime-state.d.ts +7 -12
  26. package/dist/runtime-state.js +43 -53
  27. package/dist/service/attachment-domain-state.d.ts +2 -0
  28. package/dist/service/attachment-domain-state.js +2 -0
  29. package/dist/service/conversation-history-service.d.ts +8 -0
  30. package/dist/service/conversation-history-service.js +181 -9
  31. package/dist/service/conversation-segment-service.js +17 -10
  32. package/dist/service/external-session-resume-service.js +9 -0
  33. package/dist/service/fake-managed-run-service.d.ts +0 -1
  34. package/dist/service/fake-managed-run-service.js +0 -2
  35. package/dist/service/native-session-projection-service.js +5 -0
  36. package/dist/service/native-session-watch-service.d.ts +8 -2
  37. package/dist/service/native-session-watch-service.js +28 -10
  38. package/dist/service/node-connection-lifecycle-service.d.ts +0 -2
  39. package/dist/service/node-connection-lifecycle-service.js +0 -1
  40. package/dist/service/node-control-channel.js +1 -1
  41. package/dist/service/node-control-message-service.d.ts +0 -1
  42. package/dist/service/node-control-message-service.js +9 -6
  43. package/dist/service/node-request-service.js +2 -1
  44. package/dist/service/node-workspace-coordinator.d.ts +1 -4
  45. package/dist/service/node-workspace-coordinator.js +2 -12
  46. package/dist/service/run-attachment-service.js +30 -6
  47. package/dist/service/run-event-service.d.ts +1 -0
  48. package/dist/service/run-event-service.js +80 -0
  49. package/dist/service/run-workbench-service.d.ts +1 -1
  50. package/dist/service/run-workbench-service.js +1 -5
  51. package/dist/service/runner-interaction-service.d.ts +1 -2
  52. package/dist/service/runner-interaction-service.js +1 -4
  53. package/dist/service/session-context-service.d.ts +1 -0
  54. package/dist/service/session-context-service.js +14 -0
  55. package/dist/service/session-domain-state.d.ts +1 -0
  56. package/dist/service/session-domain-state.js +1 -0
  57. package/dist/service/session-lifecycle-service.js +4 -12
  58. package/dist/service/session-message-service.d.ts +1 -0
  59. package/dist/service/session-message-service.js +109 -85
  60. package/dist/service/skill-directory-service.d.ts +3 -1
  61. package/dist/service/skill-directory-service.js +28 -4
  62. package/dist/service/skill-node-operation-service.d.ts +1 -1
  63. package/dist/service/skill-node-operation-service.js +4 -2
  64. package/dist/service/workbench-event-service.d.ts +1 -13
  65. package/dist/service/workbench-event-service.js +2 -36
  66. package/dist/service/workbench-manifest-service.d.ts +0 -1
  67. package/dist/service/workbench-manifest-service.js +0 -1
  68. package/dist/service/workspace-change-service.js +1 -1
  69. package/dist/service/workspace-domain-state.d.ts +1 -0
  70. package/dist/service/workspace-queue-workbench-service.d.ts +13 -2
  71. package/dist/service/workspace-queue-workbench-service.js +8 -2
  72. package/dist/service/workspace-upload-service.d.ts +2 -0
  73. package/dist/service/workspace-upload-service.js +28 -6
  74. package/dist/service/workspace-workbench-service.d.ts +0 -3
  75. package/dist/service/workspace-workbench-service.js +0 -17
  76. package/dist/util/runner-error.d.ts +6 -0
  77. package/dist/util/runner-error.js +52 -0
  78. package/dist/util/runner-native-session-parsers.d.ts +2 -1
  79. package/dist/util/runner-native-session-parsers.js +63 -15
  80. package/dist/workspace.js +33 -8
  81. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { CodexAppServerClient } from '../codex-app-server.js';
1
+ import { CodexAppServerClient, isCodexRolloutMissingError } from '../codex-app-server.js';
2
2
  import { AbstractRunner } from './abstract-runner.js';
3
3
  import { declaredRunnerProfiles } from '../runner-profiles.js';
4
4
  import { homedir } from 'node:os';
@@ -11,6 +11,7 @@ import { codexSessionControl } from '../codex-app-server.js';
11
11
  import { extractId } from '../util/runner-native-session-parsers.js';
12
12
  import { nodeLog } from '../operational.js';
13
13
  const CODEX_MODEL_CACHE_MS = 10 * 60 * 1_000;
14
+ const CODEX_PROFILE_ENTRY_TTL_MS = 30 * 60 * 1_000;
14
15
  const CODEX_MODEL_FAILURE_RETRY_MS = 30 * 1_000;
15
16
  const CODEX_MODEL_PAGE_SIZE = 100;
16
17
  export class CodexRunner extends AbstractRunner {
@@ -23,6 +24,7 @@ export class CodexRunner extends AbstractRunner {
23
24
  environmentFingerprint;
24
25
  environmentRuns = new Set();
25
26
  profileCache = new Map();
27
+ profileCacheTimers = new Map();
26
28
  profileRefreshes = new Map();
27
29
  profileClients = new Set();
28
30
  profileKeyByEnvironment = new Map();
@@ -74,7 +76,7 @@ export class CodexRunner extends AbstractRunner {
74
76
  successful: true,
75
77
  retryAt: 0
76
78
  };
77
- this.profileCache.set(key, cache);
79
+ this.cacheProfile(key, cache);
78
80
  if (this.selectedProfileKey === key)
79
81
  this.latestProfileCache = cache;
80
82
  return cache.profile;
@@ -88,7 +90,7 @@ export class CodexRunner extends AbstractRunner {
88
90
  cached.retryAt = Date.now() + CODEX_MODEL_FAILURE_RETRY_MS;
89
91
  return cached.profile;
90
92
  }
91
- this.profileCache.set(key, {
93
+ this.cacheProfile(key, {
92
94
  profile: { ...base, models: [] },
93
95
  defaultConfiguration: emptyCodexConfiguration(),
94
96
  fetchedAt: 0,
@@ -106,6 +108,25 @@ export class CodexRunner extends AbstractRunner {
106
108
  this.latestProfileCache = cached;
107
109
  return cached.profile;
108
110
  }
111
+ cacheProfile(key, cache) {
112
+ const previousTimer = this.profileCacheTimers.get(key);
113
+ if (previousTimer !== undefined)
114
+ clearTimeout(previousTimer);
115
+ this.profileCache.set(key, cache);
116
+ const timer = setTimeout(() => {
117
+ this.profileCacheTimers.delete(key);
118
+ this.profileCache.delete(key);
119
+ for (const [environmentKey, profileKey] of this.profileKeyByEnvironment)
120
+ if (profileKey === key)
121
+ this.profileKeyByEnvironment.delete(environmentKey);
122
+ if (this.selectedProfileKey === key) {
123
+ this.selectedProfileKey = undefined;
124
+ this.latestProfileCache = undefined;
125
+ }
126
+ }, CODEX_PROFILE_ENTRY_TTL_MS);
127
+ timer.unref();
128
+ this.profileCacheTimers.set(key, timer);
129
+ }
109
130
  async fetchCodexProfile(base, environment) {
110
131
  const client = this.profileClientFactory();
111
132
  this.profileClients.add(client);
@@ -430,6 +451,17 @@ export class CodexRunner extends AbstractRunner {
430
451
  start() {
431
452
  return this.client.start();
432
453
  }
454
+ async recoverMissingRollout(runId, error) {
455
+ if (!isCodexRolloutMissingError(error))
456
+ return false;
457
+ if ([...this.environmentRuns].some((activeRunId) => activeRunId !== runId))
458
+ return false;
459
+ if ([...this.execution.runs.keys()].some((activeRunId) => activeRunId !== runId))
460
+ return false;
461
+ nodeLog('runner.codex.rollout.recovering', { runId });
462
+ await this.client.restart();
463
+ return true;
464
+ }
433
465
  prepareEnvironment(environment, runId) {
434
466
  if (Object.keys(environment).length === 0 && this.environmentFingerprint === undefined) {
435
467
  this.environmentRuns.add(runId);
@@ -466,6 +498,13 @@ export class CodexRunner extends AbstractRunner {
466
498
  this.client.clearEnvironment();
467
499
  this.environmentFingerprint = undefined;
468
500
  this.environmentRuns.clear();
501
+ for (const timer of this.profileCacheTimers.values())
502
+ clearTimeout(timer);
503
+ this.profileCacheTimers.clear();
504
+ this.profileCache.clear();
505
+ this.profileKeyByEnvironment.clear();
506
+ this.latestProfileCache = undefined;
507
+ this.selectedProfileKey = undefined;
469
508
  }
470
509
  request(method, params) {
471
510
  return this.client.request(method, params);
@@ -128,7 +128,7 @@ function partItem(session, turnId, raw, planMode, startedAt, completedAt, sequen
128
128
  }, startedAt, completedAt, sequence);
129
129
  }
130
130
  export function openCodeQuestions(value) {
131
- if (!Array.isArray(value) || value.length === 0 || value.length > 4)
131
+ if (!Array.isArray(value) || value.length === 0)
132
132
  return [];
133
133
  return value.flatMap((value, index) => {
134
134
  const question = record(value);
@@ -17,10 +17,13 @@ interface OpenCodeManagedRunHost {
17
17
  cwd: string;
18
18
  externalSessionId?: string;
19
19
  }): void;
20
+ run(runId: string): {
21
+ readonly id: string;
22
+ };
23
+ hasActiveSessionLease(sessionId: string): boolean;
20
24
  promote(sessionId: string, nativeSessionId: string): void;
21
25
  rememberNative(nativeSessionId: string, sessionId: string): void;
22
26
  send(type: string, payload: unknown): void;
23
- captureSnapshot(runId: string, cwd: string): Promise<void>;
24
27
  createApproval(input: {
25
28
  readonly runId: string;
26
29
  readonly approvalId: string;
@@ -41,7 +44,7 @@ interface OpenCodeManagedRunHost {
41
44
  }
42
45
  type OpenCodePublicItem = {
43
46
  readonly itemId: string;
44
- readonly kind: 'assistant_message' | 'plan' | 'reasoning_summary' | 'tool_call' | 'user_input_request' | 'context_compaction' | 'unknown';
47
+ readonly kind: 'assistant_message' | 'plan' | 'reasoning_summary' | 'tool_call' | 'user_input_request' | 'context_compaction' | 'error' | 'unknown';
45
48
  readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED';
46
49
  readonly payload: Record<string, unknown>;
47
50
  readonly merge?: boolean;
@@ -60,6 +63,8 @@ export declare class OpenCodeManagedRunController {
60
63
  executeCommand(session: NodeAgentSession, command: RunnerCommandDescriptor, context: {
61
64
  readonly secretEnvironment: Readonly<Record<string, string>>;
62
65
  }): Promise<unknown>;
66
+ private compact;
67
+ private runCompact;
63
68
  start(envelope: NodeEnvelope): void;
64
69
  cancel(runId: string, intent: 'CANCEL' | 'INTERRUPT'): boolean;
65
70
  decideApproval(input: {
@@ -1,5 +1,5 @@
1
1
  import { parseSecretEnvironment } from '../../util/secret-environment.js';
2
- import { safeErrorCode } from '../../util/safe-error.js';
2
+ import { runnerErrorProjection } from '../../util/runner-error.js';
3
3
  import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '../codex/conversation-parser.js';
4
4
  import { openCodePatchToolPayload, openCodeQuestions } from './conversation-parser.js';
5
5
  export class OpenCodeManagedRunController {
@@ -19,7 +19,7 @@ export class OpenCodeManagedRunController {
19
19
  }
20
20
  async executeCommand(session, command, context) {
21
21
  if (command.id === 'compact')
22
- return this.runner.executeCompact(session, context.secretEnvironment);
22
+ return this.compact(session, context.secretEnvironment);
23
23
  if (command.id !== 'plan')
24
24
  throw new Error('RUNNER_COMMAND_UNAVAILABLE');
25
25
  const current = this.host.commandState(session.id, 'plan');
@@ -37,6 +37,53 @@ export class OpenCodeManagedRunController {
37
37
  });
38
38
  return { command: command.id, states: this.host.commandStates(session.id) };
39
39
  }
40
+ compact(session, environment) {
41
+ if (session.externalSessionId === null ||
42
+ session.model === null ||
43
+ session.nativeControl !== 'MAR_MANAGED' ||
44
+ this.host.hasActiveSessionLease(session.id))
45
+ throw new Error('RUNNER_COMMAND_UNAVAILABLE');
46
+ const runId = crypto.randomUUID();
47
+ const client = this.runner.managedClient(environment);
48
+ this.host.adopt({
49
+ runId,
50
+ sessionId: session.id,
51
+ runner: 'opencode',
52
+ cwd: session.cwd,
53
+ externalSessionId: session.externalSessionId
54
+ });
55
+ this.host.active.add(runId);
56
+ this.runner.execution.set(runId, {
57
+ runId,
58
+ sessionId: session.id,
59
+ nativeSessionId: session.externalSessionId,
60
+ cwd: session.cwd,
61
+ client,
62
+ abort: new AbortController(),
63
+ access: session.access ?? 'default',
64
+ agent: 'build'
65
+ });
66
+ this.host.emit(runId, 'run.started', { command: 'compact' }, 'STARTING');
67
+ void this.runCompact(runId, session.model);
68
+ return {
69
+ command: 'compact',
70
+ run: this.host.run(runId),
71
+ states: this.host.commandStates(session.id)
72
+ };
73
+ }
74
+ async runCompact(runId, model) {
75
+ const execution = this.runner.execution.get(runId);
76
+ if (execution === undefined)
77
+ return;
78
+ this.host.emit(runId, 'run.running', { command: 'compact' }, 'RUNNING');
79
+ try {
80
+ await execution.client.summarize(execution.cwd, execution.nativeSessionId, model);
81
+ this.finish(runId, 'SUCCEEDED', 'run.completed', { status: 'SUCCEEDED' });
82
+ }
83
+ catch (error) {
84
+ this.finish(runId, 'FAILED', 'run.failed', error, 'OPENCODE_COMPACT_FAILED');
85
+ }
86
+ }
40
87
  start(envelope) {
41
88
  const payload = envelope.payload;
42
89
  if (payload.runner !== 'opencode' ||
@@ -57,7 +104,14 @@ export class OpenCodeManagedRunController {
57
104
  attachments = this.host.parseAttachments(payload.attachments);
58
105
  }
59
106
  catch (error) {
60
- this.host.emit(payload.runId, 'run.rejected', { code: safeErrorCode(error, 'RUNNER_INPUT_INVALID') }, 'FAILED');
107
+ const projected = runnerErrorProjection(error, 'RUNNER_INPUT_INVALID');
108
+ this.host.emitItem(payload.runId, {
109
+ itemId: boundedConversationItemId('runner-error', payload.runId),
110
+ kind: 'error',
111
+ status: 'FAILED',
112
+ payload: { ...projected, recoverable: true, retryAfterMs: null }
113
+ });
114
+ this.host.emit(payload.runId, 'run.rejected', projected, 'FAILED');
61
115
  return;
62
116
  }
63
117
  void this.run({
@@ -181,9 +235,7 @@ export class OpenCodeManagedRunController {
181
235
  rejectReady(error);
182
236
  return;
183
237
  }
184
- this.finish(input.runId, 'FAILED', 'run.failed', {
185
- code: safeErrorCode(error, 'OPENCODE_EVENT_FAILED')
186
- });
238
+ this.finish(input.runId, 'FAILED', 'run.failed', error, 'OPENCODE_EVENT_FAILED');
187
239
  });
188
240
  await subscriptionReady;
189
241
  this.host.emit(input.runId, 'run.running', {}, 'RUNNING');
@@ -206,9 +258,7 @@ export class OpenCodeManagedRunController {
206
258
  this.finish(input.runId, 'SUCCEEDED', 'run.completed', { status: 'SUCCEEDED' });
207
259
  }
208
260
  catch (error) {
209
- this.finish(input.runId, 'FAILED', 'run.failed', {
210
- code: safeErrorCode(error, 'OPENCODE_RUN_START_FAILED')
211
- });
261
+ this.finish(input.runId, 'FAILED', 'run.failed', error, 'OPENCODE_RUN_START_FAILED');
212
262
  }
213
263
  }
214
264
  event(runId, nativeSessionId, value) {
@@ -231,7 +281,7 @@ export class OpenCodeManagedRunController {
231
281
  return;
232
282
  }
233
283
  if (event?.type === 'session.error') {
234
- this.finish(runId, 'FAILED', 'run.failed', { code: 'OPENCODE_SESSION_ERROR' });
284
+ this.finish(runId, 'FAILED', 'run.failed', properties?.error ?? properties);
235
285
  return;
236
286
  }
237
287
  if (event?.type === 'message.part.updated') {
@@ -309,7 +359,7 @@ export class OpenCodeManagedRunController {
309
359
  if (execution === undefined || requestId === undefined)
310
360
  return;
311
361
  const questions = openCodeQuestions(rawQuestions);
312
- if (questions.length === 0 || questions.length > 4 || this.questions.has(requestId))
362
+ if (questions.length === 0 || this.questions.has(requestId))
313
363
  return;
314
364
  const timer = setTimeout(() => {
315
365
  const pending = this.questions.get(requestId);
@@ -340,7 +390,7 @@ export class OpenCodeManagedRunController {
340
390
  payload: { requestId, questions }
341
391
  });
342
392
  }
343
- finish(runId, status, eventType, payload) {
393
+ finish(runId, status, eventType, payload, fallbackCode = 'OPENCODE_RUN_FAILED') {
344
394
  const execution = this.runner.execution.get(runId);
345
395
  const cwd = execution?.cwd ?? this.startingCwds.get(runId);
346
396
  const client = execution?.client ?? this.startingClients.get(runId);
@@ -363,11 +413,19 @@ export class OpenCodeManagedRunController {
363
413
  clearTimeout(pending.timer);
364
414
  this.questions.delete(id);
365
415
  }
416
+ if (status === 'FAILED') {
417
+ const projected = runnerErrorProjection(payload, fallbackCode);
418
+ this.host.emitItem(runId, {
419
+ itemId: boundedConversationItemId('runner-error', runId),
420
+ kind: 'error',
421
+ status: 'FAILED',
422
+ payload: { ...projected, recoverable: true, retryAfterMs: null }
423
+ });
424
+ payload = projected;
425
+ }
366
426
  this.host.emit(runId, eventType, payload, status);
367
427
  if (client !== undefined)
368
428
  this.runner.releaseManagedClient(client);
369
- if (cwd !== undefined)
370
- void this.host.captureSnapshot(runId, cwd);
371
429
  }
372
430
  }
373
431
  function openCodeImageInput(input, attachmentPaths) {
@@ -19,6 +19,7 @@ export declare class OpenCodeRunner extends AbstractRunner<'opencode'> {
19
19
  readonly discoveryScope: "WORKSPACE_REQUIRED";
20
20
  private readonly modelsByWorkspace;
21
21
  private readonly contextLimitsByWorkspace;
22
+ private readonly profileTimersByWorkspace;
22
23
  readonly execution: Map<string, OpenCodeManagedExecution>;
23
24
  readonly managedTurns: Map<string, string>;
24
25
  private readonly environmentClients;
@@ -56,6 +57,8 @@ export declare class OpenCodeRunner extends AbstractRunner<'opencode'> {
56
57
  maxTokens: number;
57
58
  } | undefined>;
58
59
  stop(): Promise<void>;
60
+ private scheduleProfileExpiry;
61
+ private clearProfileTimer;
59
62
  managedClient(environment: Readonly<Record<string, string>>, isolationKey?: string): OpenCodeServerClient;
60
63
  releaseManagedClient(client: OpenCodeServerClient): void;
61
64
  }
@@ -5,6 +5,7 @@ import { AbstractRunner } from './abstract-runner.js';
5
5
  import { isWithinWorkspace } from './codex/conversation-parser.js';
6
6
  import { createHash } from 'node:crypto';
7
7
  import { openCodeConversationPage } from './opencode/conversation-parser.js';
8
+ const PROFILE_ENTRY_TTL_MS = 30 * 60_000;
8
9
  export class OpenCodeRunner extends AbstractRunner {
9
10
  client;
10
11
  clientFactory;
@@ -12,6 +13,7 @@ export class OpenCodeRunner extends AbstractRunner {
12
13
  discoveryScope = 'WORKSPACE_REQUIRED';
13
14
  modelsByWorkspace = new Map();
14
15
  contextLimitsByWorkspace = new Map();
16
+ profileTimersByWorkspace = new Map();
15
17
  execution = new Map();
16
18
  managedTurns = new Map();
17
19
  environmentClients = new Map();
@@ -39,11 +41,13 @@ export class OpenCodeRunner extends AbstractRunner {
39
41
  const models = openCodeProfileModels(catalog);
40
42
  this.modelsByWorkspace.set(workspace.path, models);
41
43
  this.contextLimitsByWorkspace.set(workspace.path, openCodeContextLimits(catalog));
44
+ this.scheduleProfileExpiry(workspace.path);
42
45
  return { ...this.profile(capabilities), models };
43
46
  }
44
47
  catch {
45
48
  this.modelsByWorkspace.delete(workspace.path);
46
49
  this.contextLimitsByWorkspace.delete(workspace.path);
50
+ this.clearProfileTimer(workspace.path);
47
51
  }
48
52
  finally {
49
53
  this.releaseManagedClient(client);
@@ -279,6 +283,11 @@ export class OpenCodeRunner extends AbstractRunner {
279
283
  execution.abort.abort();
280
284
  this.execution.clear();
281
285
  this.managedTurns.clear();
286
+ for (const timer of this.profileTimersByWorkspace.values())
287
+ clearTimeout(timer);
288
+ this.profileTimersByWorkspace.clear();
289
+ this.modelsByWorkspace.clear();
290
+ this.contextLimitsByWorkspace.clear();
282
291
  const stopping = [
283
292
  this.client.stop(),
284
293
  ...[...this.environmentClients.values()].map(({ client }) => client.stop()),
@@ -288,6 +297,22 @@ export class OpenCodeRunner extends AbstractRunner {
288
297
  await Promise.allSettled(stopping);
289
298
  this.stoppingClients.clear();
290
299
  }
300
+ scheduleProfileExpiry(workspacePath) {
301
+ this.clearProfileTimer(workspacePath);
302
+ const timer = setTimeout(() => {
303
+ this.profileTimersByWorkspace.delete(workspacePath);
304
+ this.modelsByWorkspace.delete(workspacePath);
305
+ this.contextLimitsByWorkspace.delete(workspacePath);
306
+ }, PROFILE_ENTRY_TTL_MS);
307
+ timer.unref();
308
+ this.profileTimersByWorkspace.set(workspacePath, timer);
309
+ }
310
+ clearProfileTimer(workspacePath) {
311
+ const timer = this.profileTimersByWorkspace.get(workspacePath);
312
+ if (timer !== undefined)
313
+ clearTimeout(timer);
314
+ this.profileTimersByWorkspace.delete(workspacePath);
315
+ }
291
316
  managedClient(environment, isolationKey) {
292
317
  const entries = Object.entries(environment).sort(([left], [right]) => left.localeCompare(right));
293
318
  if (entries.length === 0 && isolationKey === undefined)
@@ -1,3 +1,7 @@
1
+ const COMMON_COMMAND_DESCRIPTIONS = {
2
+ compact: 'Compact the current session context.',
3
+ plan: 'Toggle collaborative Plan Mode.'
4
+ };
1
5
  const CLAUDE_MODEL_ENVIRONMENT = {
2
6
  opus: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
3
7
  sonnet: 'ANTHROPIC_DEFAULT_SONNET_MODEL',
@@ -35,7 +39,7 @@ const definitions = {
35
39
  {
36
40
  id: 'compact',
37
41
  label: '/compact',
38
- description: 'Compact the current session context.',
42
+ description: COMMON_COMMAND_DESCRIPTIONS.compact,
39
43
  inputHint: '/compact',
40
44
  interaction: 'IMMEDIATE_ACTION'
41
45
  },
@@ -43,7 +47,7 @@ const definitions = {
43
47
  id: 'plan',
44
48
  label: '/plan',
45
49
  stateLabel: 'Plan Mode',
46
- description: 'Toggle collaborative Plan Mode.',
50
+ description: COMMON_COMMAND_DESCRIPTIONS.plan,
47
51
  inputHint: '/plan',
48
52
  interaction: 'TOGGLE'
49
53
  },
@@ -96,7 +100,7 @@ const definitions = {
96
100
  id: 'compact',
97
101
  runner: 'claude-code',
98
102
  label: '/compact',
99
- description: 'Compact context through the Claude Agent SDK.',
103
+ description: COMMON_COMMAND_DESCRIPTIONS.compact,
100
104
  inputHint: '/compact',
101
105
  source: 'CLAUDE_AGENT_SDK',
102
106
  interaction: 'IMMEDIATE_ACTION',
@@ -108,7 +112,7 @@ const definitions = {
108
112
  runner: 'claude-code',
109
113
  label: '/plan',
110
114
  stateLabel: 'Plan Mode',
111
- description: 'Toggle read-only tagged Plan Mode.',
115
+ description: COMMON_COMMAND_DESCRIPTIONS.plan,
112
116
  inputHint: '/plan',
113
117
  source: 'CLAUDE_AGENT_SDK',
114
118
  interaction: 'TOGGLE',
@@ -137,7 +141,7 @@ const definitions = {
137
141
  id: 'compact',
138
142
  runner: 'opencode',
139
143
  label: '/compact',
140
- description: 'Compact context through OpenCode.',
144
+ description: COMMON_COMMAND_DESCRIPTIONS.compact,
141
145
  inputHint: '/compact',
142
146
  source: 'OPENCODE_SERVER',
143
147
  interaction: 'IMMEDIATE_ACTION',
@@ -149,7 +153,7 @@ const definitions = {
149
153
  runner: 'opencode',
150
154
  label: '/plan',
151
155
  stateLabel: 'Plan Mode',
152
- description: 'Toggle the native OpenCode Plan Agent.',
156
+ description: COMMON_COMMAND_DESCRIPTIONS.plan,
153
157
  inputHint: '/plan',
154
158
  source: 'OPENCODE_SERVER',
155
159
  interaction: 'TOGGLE',
@@ -1,5 +1,5 @@
1
1
  import type { AgentRunStatus, RunnerName } from '@myagentroam/protocol';
2
- import type { ConversationItemPage, ConversationPage, NativeSessionControl, NodeAgentRun, NodeAgentSession, NodeApproval, NodeConversationTurn, NodeMessageAttachmentInput, NodeRunEvent, NodeWorkspace, WorkspaceActivityPage } from './database.js';
2
+ import type { ConversationItemPage, ConversationPage, NativeSessionControl, NodeAgentRun, NodeAgentSession, NodeApproval, NodeConversationTurn, NodeMessageAttachmentInput, NodeRunEvent, NodeWorkspace } from './database.js';
3
3
  /**
4
4
  * Deliberately process-local runtime domain. No method in this class writes
5
5
  * into Node SQLite: a Node restart loses active runs, approvals, leases and
@@ -10,22 +10,22 @@ export declare class NodeRuntimeState {
10
10
  private readonly nodeId;
11
11
  private readonly getWorkspace;
12
12
  private readonly now;
13
+ private static readonly MAX_COMPLETED_TURNS_PER_SESSION;
13
14
  private readonly sessions;
14
15
  private readonly runs;
15
16
  private readonly messageRuns;
16
17
  private readonly events;
17
18
  private readonly turns;
18
19
  private readonly approvals;
19
- private readonly workspaceEvents;
20
20
  /** A Session owns at most one running turn; Workspace sessions may run concurrently. */
21
21
  private readonly leases;
22
22
  /** Session FIFO metadata is deliberately process-local with the rest of run state. */
23
23
  private readonly queuedRuns;
24
24
  private readonly queueVersions;
25
25
  private readonly pausedQueues;
26
- private readonly snapshots;
26
+ /** Bounded tombstones reject stale internal start envelopes after terminal cleanup. */
27
+ private readonly terminalRunIds;
27
28
  private nextEventId;
28
- private nextWorkspaceEventId;
29
29
  constructor(nodeId: () => string, getWorkspace: (id: string) => NodeWorkspace | undefined, now?: () => number);
30
30
  activeWorkspaceLeaseCount(): number;
31
31
  activeSessionRun(sessionId: string): NodeAgentRun | undefined;
@@ -86,9 +86,11 @@ export declare class NodeRuntimeState {
86
86
  */
87
87
  setRunnerTitleFromNative(id: string, title: string): NodeAgentSession;
88
88
  createMessageRun(input: {
89
+ readonly runId?: string;
89
90
  readonly sessionId: string;
90
91
  readonly clientMessageId: string;
91
92
  readonly content: string;
93
+ readonly initiatedByUserId?: number;
92
94
  readonly attachments?: readonly NodeMessageAttachmentInput[];
93
95
  }): {
94
96
  readonly run: NodeAgentRun;
@@ -138,11 +140,6 @@ export declare class NodeRuntimeState {
138
140
  readonly outputPreview: string;
139
141
  readonly failed?: boolean;
140
142
  }): NodeConversationTurn;
141
- listWorkspaceActivity(input: {
142
- readonly workspaceId: string;
143
- readonly cursor?: string;
144
- readonly limit?: number;
145
- }): WorkspaceActivityPage;
146
143
  createApproval(input: {
147
144
  readonly runId: string;
148
145
  readonly approvalId: string;
@@ -156,8 +153,7 @@ export declare class NodeRuntimeState {
156
153
  expireDueApprovals(): readonly NodeApproval[];
157
154
  listNonterminalRuns(): readonly NodeAgentRun[];
158
155
  lastRunSequence(id: string): number;
159
- saveSnapshot(id: string, value: unknown): void;
160
- getSnapshot(id: string): unknown | undefined;
156
+ removeTerminalRun(runId: string): void;
161
157
  hasActiveWorkspaceLease(workspaceId: string): boolean;
162
158
  /** Removes a terminal Session's process-local projection after its native history is deleted. */
163
159
  removeAgentSession(sessionId: string): void;
@@ -168,7 +164,6 @@ export declare class NodeRuntimeState {
168
164
  private requireSession;
169
165
  private requireRun;
170
166
  private requireApproval;
171
- private recordWorkspaceActivity;
172
167
  private updateTurnForRun;
173
168
  private projectEvent;
174
169
  }