@ai-workbench/remote-agent 0.8.19 → 0.8.23

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 (95) hide show
  1. package/README.md +27 -134
  2. package/dist/acp.d.ts +23 -16
  3. package/dist/acp.js +209 -226
  4. package/dist/agents.d.ts +0 -1
  5. package/dist/agents.js +2 -2
  6. package/dist/broker-runtime.d.ts +3 -5
  7. package/dist/broker-runtime.js +45 -342
  8. package/dist/broker.d.ts +6 -31
  9. package/dist/broker.js +42 -113
  10. package/dist/catalog-ssh.d.ts +2 -31
  11. package/dist/catalog-ssh.js +9 -39
  12. package/dist/claude-local.d.ts +1 -1
  13. package/dist/claude-local.js +41 -105
  14. package/dist/client.js +34 -126
  15. package/dist/close-diagnostics.d.ts +6 -20
  16. package/dist/close-diagnostics.js +13 -57
  17. package/dist/connect-contract.d.ts +4 -8
  18. package/dist/conversation-details.d.ts +0 -29
  19. package/dist/conversation-details.js +8 -99
  20. package/dist/employee-endpoint.d.ts +1 -1
  21. package/dist/employee-endpoint.js +21 -19
  22. package/dist/employee-exec.d.ts +4 -3
  23. package/dist/employee-exec.js +25 -13
  24. package/dist/employee-info.d.ts +7 -1
  25. package/dist/employee-info.js +24 -3
  26. package/dist/employee-location.js +3 -4
  27. package/dist/employee-mcp.js +44 -69
  28. package/dist/employee-native.d.ts +1 -3
  29. package/dist/employee-native.js +6 -27
  30. package/dist/employee-presentation.d.ts +0 -5
  31. package/dist/employee-presentation.js +0 -15
  32. package/dist/employee-provider.d.ts +3 -11
  33. package/dist/employee-provider.js +69 -205
  34. package/dist/employee-reasons.js +1 -5
  35. package/dist/employee-shell.d.ts +2 -1
  36. package/dist/employee-shell.js +10 -13
  37. package/dist/employee-ssh.d.ts +1 -3
  38. package/dist/employee-ssh.js +13 -16
  39. package/dist/employee-tools.d.ts +5 -5
  40. package/dist/failure-evidence.d.ts +2 -10
  41. package/dist/failure-evidence.js +12 -61
  42. package/dist/host-workspace.d.ts +4 -2
  43. package/dist/host-workspace.js +6 -2
  44. package/dist/index.d.ts +13 -43
  45. package/dist/index.js +192 -484
  46. package/dist/input.js +2 -3
  47. package/dist/local-user-turn.js +5 -6
  48. package/dist/mapping.d.ts +5 -3
  49. package/dist/mapping.js +31 -36
  50. package/dist/model-catalog.d.ts +2 -41
  51. package/dist/model-catalog.js +24 -282
  52. package/dist/model-configuration.d.ts +0 -3
  53. package/dist/model-configuration.js +8 -47
  54. package/dist/model-presentation.d.ts +1 -0
  55. package/dist/model-presentation.js +2 -2
  56. package/dist/permissions.d.ts +15 -0
  57. package/dist/permissions.js +30 -0
  58. package/dist/preflight-diagnostic.js +11 -22
  59. package/dist/preflight-payload.d.ts +1 -1
  60. package/dist/preflight-payload.js +2 -2
  61. package/dist/presentation.js +21 -41
  62. package/dist/provider.d.ts +12 -34
  63. package/dist/provider.js +17 -92
  64. package/dist/readiness.js +1 -7
  65. package/dist/remote-details.d.ts +41 -17
  66. package/dist/remote-details.js +84 -381
  67. package/dist/workspace-source.d.ts +1 -25
  68. package/dist/workspace-source.js +1 -138
  69. package/package.json +11 -12
  70. package/dist/catalog-diagnostics.d.ts +0 -16
  71. package/dist/catalog-diagnostics.js +0 -108
  72. package/dist/host-layout.d.ts +0 -8
  73. package/dist/host-layout.js +0 -9
  74. package/dist/job.d.ts +0 -17
  75. package/dist/job.js +0 -57
  76. package/dist/model-defaults.d.ts +0 -29
  77. package/dist/model-defaults.js +0 -62
  78. package/dist/oneshot.d.ts +0 -13
  79. package/dist/oneshot.js +0 -78
  80. package/dist/protocol-boundary.d.ts +0 -13
  81. package/dist/protocol-boundary.js +0 -49
  82. package/dist/provider-locale.d.ts +0 -19
  83. package/dist/provider-locale.js +0 -73
  84. package/dist/recovery-checkpoint.d.ts +0 -6
  85. package/dist/recovery-checkpoint.js +0 -71
  86. package/dist/recovery.d.ts +0 -51
  87. package/dist/recovery.js +0 -61
  88. package/dist/sdk-ssh-wrapper.d.ts +0 -2
  89. package/dist/sdk-ssh-wrapper.js +0 -34
  90. package/dist/stage-timing.d.ts +0 -31
  91. package/dist/stage-timing.js +0 -61
  92. package/dist/workspace-notice.d.ts +0 -47
  93. package/dist/workspace-notice.js +0 -273
  94. package/dist/workspace-source-confirmation.d.ts +0 -4
  95. package/dist/workspace-source-confirmation.js +0 -12
package/dist/provider.js CHANGED
@@ -4,8 +4,6 @@ import { loginDiagnostic, loginReason } from "./login-diagnostic.js";
4
4
  import { NeedError } from "./remote.js";
5
5
  import { CONNECTION_REQUIRED, TEST_HOST_NOTICE } from "./presentation.js";
6
6
  import { CODEX_AGENT } from "./agents.js";
7
- import { StageTiming } from "./stage-timing.js";
8
- import { confirmLegacyWorkspaceSource } from "./workspace-source.js";
9
7
  export function requireLoginCoordinator(api) {
10
8
  if (!['getConnectionState', 'getLoginPromptState', 'requestLoginPrompt', 'refreshLoginPrompts'].every(key => typeof api[key] === 'function'))
11
9
  throw new NeedError('CONNECT_API_MISMATCH', '我需要 connect-api 0.6.1 的统一登录询问与连接状态能力', 'L >=0.6.1');
@@ -138,10 +136,10 @@ export function identity(t) { return `${t.username}@${t.host}:${t.port}`; }
138
136
  /** Reject draft.3 and legacy runtime rather than inventing workspace bindings. */
139
137
  export function requireNativeWorkspace(api) {
140
138
  if (typeof api.getContractInfo !== 'function')
141
- throw new NeedError('DEPENDENCY_REQUIRED', '我需要新版远程主机连接组件提供原生工作区绑定', 'L connect-api 0.7.0 / native-local-v1');
139
+ throw new NeedError('DEPENDENCY_REQUIRED', '我需要新版远程主机连接组件提供原生工作区绑定', 'L connect-api 0.7.0 / ensureReady / resolveSessionProject');
142
140
  const info = api.getContractInfo();
143
- if (info?.apiVersion !== '0.7.0' || info.status !== 'implemented' || info.workspaceBinding !== 'native-local-v1' || !['ensureReady', 'resolveSessionProject', 'acknowledgeWorkspaceNotice'].every(key => typeof api[key] === 'function'))
144
- throw new NeedError('DEPENDENCY_REQUIRED', '我需要新版远程主机连接组件提供原生工作区绑定', 'L connect-api 0.7.0 / native-local-v1');
141
+ if (info?.apiVersion !== '0.7.0' || info.status !== 'implemented' || !['ensureReady', 'resolveSessionProject'].every(key => typeof api[key] === 'function'))
142
+ throw new NeedError('DEPENDENCY_REQUIRED', '我需要新版远程主机连接组件提供原生工作区绑定', 'L connect-api 0.7.0 / ensureReady / resolveSessionProject');
145
143
  }
146
144
  /** Authorization stays in L; ensureReady only checks and records the need. */
147
145
  export async function offerLogin(connect, request, currentApi, agent = CODEX_AGENT) {
@@ -189,32 +187,20 @@ export function connectProvider(get, options = {}) {
189
187
  let employee;
190
188
  const admissions = new WeakMap();
191
189
  const preflight = async (request) => {
192
- request.timing ??= new StageTiming();
193
190
  request.signal?.throwIfAborted();
194
191
  const api = get();
195
192
  if (!api)
196
193
  throw new NeedError('DEPENDENCY_REQUIRED', CONNECTION_REQUIRED, 'aiWorkbenchConnect');
197
194
  requireNativeWorkspace(api);
198
195
  requireLoginCoordinator(api);
199
- if (request.mode === 'one-shot' && !agent.oneShot)
200
- throw new NeedError('MODE_UNSUPPORTED', '此远程模型仅支持会话模式', '使用会话模式');
201
- const confirmedSource = options.workspaceSource ? await confirmLegacyWorkspaceSource(get, api, request, options.workspaceSource) : undefined;
202
196
  let sourceStage = 'input-acceptance';
203
- if (confirmedSource && !request.recordEarlyFailure)
204
- request.recordEarlyFailure = (error, stage) => confirmedSource.recordFailure(error, stage);
205
197
  try {
206
- confirmedSource?.assertCurrent();
207
198
  if (options.employee) {
208
199
  const module = await import("./employee-provider.js");
209
- request.localAcceptance = await module.acceptEmployeeUserTurn(get, options.employee, agent, api, request);
210
- }
211
- confirmedSource?.assertCurrent();
212
- if (confirmedSource) {
213
- const previous = request.localAdmissionCheck;
214
- request.localAdmissionCheck = () => { confirmedSource.assertCurrent(); previous?.(); };
200
+ request.localContext = await module.inspectEmployeeWorkspace(get, options.employee, agent, api, request);
215
201
  }
216
202
  sourceStage = 'login-readiness';
217
- const { target, connection } = await request.timing.run('login-ready', async () => {
203
+ const { target, connection } = await (async () => {
218
204
  request.localAdmissionCheck?.();
219
205
  const before = api.getConnectionState();
220
206
  const target = await ensureReady(api, agent.loginProvider, request.signal);
@@ -224,11 +210,9 @@ export function connectProvider(get, options = {}) {
224
210
  throw new NeedError('CONNECTION_LOST', '远程主机连接组件已更换', '当前员工连接');
225
211
  const connection = await waitForLogin(api, agent.loginProvider, before, get, request.signal);
226
212
  return { target, connection };
227
- });
213
+ })();
228
214
  if (request.identity && request.identity !== identity(target))
229
215
  throw new NeedError('SESSION_CONTEXT_MISMATCH', '员工主机与原会话不一致,请新建会话', '原员工主机');
230
- if (options.employee && request.localAcceptance)
231
- await (await import("./employee-provider.js")).validateEmployeeUserTurn(get, options.employee, api, request, connection);
232
216
  request.localAdmissionCheck?.();
233
217
  admissions.set(request, { api, target, connection });
234
218
  sourceStage = 'local-admission';
@@ -236,7 +220,6 @@ export function connectProvider(get, options = {}) {
236
220
  if (locations && (locations.phase === 'failed' || locations.phase === 'disposed') && locations.instanceId === connection.instanceId && locations.epoch === connection.epoch && locations.need)
237
221
  throw connectNeedError(locations.need);
238
222
  await options.local?.admit?.(request, api, connection, target);
239
- confirmedSource?.assertCurrent();
240
223
  }
241
224
  catch (error) {
242
225
  admissions.delete(request);
@@ -244,8 +227,6 @@ export function connectProvider(get, options = {}) {
244
227
  request.recordEarlyFailure = undefined;
245
228
  if (record)
246
229
  await record(error, sourceStage);
247
- else
248
- await confirmedSource?.recordFailure(error, sourceStage);
249
230
  throw error;
250
231
  }
251
232
  };
@@ -255,16 +236,13 @@ export function connectProvider(get, options = {}) {
255
236
  const admitted = admissions.get(request);
256
237
  admissions.delete(request);
257
238
  const { api, target, connection } = admitted;
258
- const stable = () => request.timing.run('connection-confirm', () => waitForLogin(api, agent.loginProvider, connection, get, request.signal));
259
- await stable();
260
- request.localAdmissionCheck?.();
261
239
  if (!request.sessionId)
262
240
  throw new NeedError('PROJECT_BINDING_REQUIRED', '我需要当前会话和已选择的工作区,请使用原生工作区入口', 'DSH会话与原生工作区');
263
- const host = await hostWorkspaceGuard(get, api, connection, target, request, options.workspaceSource?.workspace, agent.loginProvider);
241
+ const host = await hostWorkspaceGuard(get, api, connection, target, request, options.workspace, agent.loginProvider);
264
242
  try {
265
243
  if (!host && options.employee) {
266
244
  employee ??= import("./employee-provider.js").then(module => module.createEmployeeProvider(get, options, agent));
267
- const local = await (await employee)({ api, target, connection, request, stable: signal => request.timing.run('connection-confirm', () => waitForLogin(api, agent.loginProvider, connection, get, signal)) });
245
+ const local = await (await employee)({ api, target, connection, request });
268
246
  if (local) {
269
247
  local.loginRequired = () => offerLogin(api, request, get, agent);
270
248
  return local;
@@ -272,79 +250,33 @@ export function connectProvider(get, options = {}) {
272
250
  }
273
251
  if (!host && agent.loginProvider === 'claude' && options.local) {
274
252
  const runtime = await options.local(request, api, connection, target);
275
- if (runtime) {
276
- try {
277
- await stable();
278
- }
279
- catch (error) {
280
- await runtime.dispose?.();
281
- throw error;
282
- }
253
+ if (runtime)
283
254
  return runtime;
284
- }
285
255
  }
286
- if (!host) {
287
- await options.notice?.reconcile(request, api);
288
- await stable();
289
- }
290
- const resolved = await request.timing.run('workspace-resolve', async () => host ? host.resolve() : unwrap(await awaitL(() => api.resolveSessionProject(request.sessionId, { provider: agent.loginProvider, purpose: 'user-turn' }), request.signal)));
291
- await stable();
292
- host?.assertCurrent();
293
- if (!resolved || resolved.instanceId !== connection.instanceId || resolved.epoch !== connection.epoch)
294
- throw new NeedError('CONNECTION_LOST', '工作区解析回复已失效', '当前连接代次');
295
- validateTarget(resolved.target);
256
+ // A local source must have been handled by its employee provider above.
257
+ // Host execution requires an explicit host location; no name-based resolver.
258
+ if (!host)
259
+ throw new NeedError('WORKSPACE_LOCATION_REQUIRED', '请选择文件夹来源;改变来源后请新建会话。', '已选择的本机或主机文件夹');
260
+ const resolved = await host.resolve();
296
261
  const project = resolved.project;
297
- const source = resolved.source;
298
- if (resolved.sessionId !== request.sessionId || !resolved.workspaceId || !resolved.bindingId || !Number.isSafeInteger(resolved.bindingRevision) || resolved.bindingRevision < 1 || !sameTarget(target, resolved.target) || !project || (!host && (source !== undefined && source !== 'legacy-host' || typeof project.name !== 'string' || !project.name || project.name === '.' || project.name === '..' || /[\\/\x00-\x1f\x7f]/.test(project.name) || project.path !== resolved.target.projectRoot + '/' + project.name)))
299
- throw new NeedError('PROJECT_BINDING_INVALID', '工作区绑定与当前会话或可信主机不一致', 'L核验的原生工作区绑定');
300
262
  if (request.cwd && request.cwd !== project.path || request.bindingId && request.bindingId !== resolved.bindingId || request.workspaceId && request.workspaceId !== resolved.workspaceId)
301
263
  throw new NeedError(host ? 'PROJECT_BINDING_INVALID' : 'SESSION_CONTEXT_MISMATCH', host ? '文件来源已改,请新建会话继续;原会话历史仍可查看。' : '原会话的工作区绑定已改变,请新建会话', '原工作区绑定');
302
- const details = await request.timing.run('details-open', async () => options.details?.(request, api, connection, target));
264
+ const details = await options.details?.(request, api, connection, target);
303
265
  try {
304
- if (details)
305
- request.timing.bind(detail => details.record(detail));
306
- await stable();
307
- host?.assertCurrent();
308
- let workspaceNotice = undefined;
309
- const notice = !host && 'notice' in resolved ? resolved.notice : undefined;
310
- if (notice) {
311
- if (!options.notice)
312
- throw new NeedError('DEPENDENCY_REQUIRED', '我需要官方会话持久记录来确认工作区说明', '官方会话与持久化服务');
313
- workspaceNotice = await request.timing.run('workspace-notice', () => options.notice.deliver(notice, resolved, request, api));
314
- await stable();
315
- }
316
266
  if (!options.open)
317
267
  throw new NeedError('RUNTIME_REQUIRED', '我需要主机运行适配器', '主机broker适配');
318
- const observedBinding = host ? undefined : api.getWorkspaceBindingState?.();
319
- const validateContext = async (ignoreCancellation = false) => {
320
- const check = () => waitForLogin(api, agent.loginProvider, connection, get, ignoreCancellation ? undefined : request.signal);
321
- await check();
322
- if (host && !ignoreCancellation)
323
- await host.resolve();
324
- if (observedBinding) {
325
- const current = api.getWorkspaceBindingState();
326
- if (current.instanceId !== observedBinding.instanceId || !current.items.some(item => item.bindingId === resolved.bindingId && item.workspaceId === resolved.workspaceId && item.status === 'ready'))
327
- throw new NeedError('SESSION_CONTEXT_MISMATCH', '当前工作区绑定已改变,原会话操作未执行', '原生会话原绑定');
328
- }
329
- await check();
330
- if (!ignoreCancellation)
331
- host?.assertCurrent();
332
- };
333
- host?.assertCurrent();
334
- const runtime = await options.open(resolved.target, project, { ...request, ...(host ? { signal: host.signal } : {}), agent, bindingId: resolved.bindingId, workspaceId: resolved.workspaceId, bindingRevision: resolved.bindingRevision, detailChannel: details, validateContext });
268
+ const runtime = await options.open(resolved.target, project, { ...request, ...(host ? { signal: host.signal } : {}), agent, bindingId: resolved.bindingId, workspaceId: resolved.workspaceId, bindingRevision: resolved.bindingRevision, detailChannel: details });
335
269
  try {
336
- await stable();
337
270
  host?.observeRuntime(runtime);
338
271
  }
339
272
  catch (error) {
340
- await runtime.dispose?.();
273
+ void runtime.dispose?.().catch(() => console.warn('HOST_CLEANUP_FAILED'));
341
274
  throw error;
342
275
  }
343
276
  if (host)
344
277
  retainHostScope(runtime, host);
345
278
  runtime.hostWorkspace = host && 'directory' in resolved ? Object.freeze({ cwd: resolved.directory.path }) : undefined;
346
279
  // The transport can outlive a turn; presentation belongs only to this invocation.
347
- runtime.workspaceNotice = workspaceNotice || undefined;
348
280
  runtime.details = details ?? runtime.details;
349
281
  runtime.binding = { bindingId: resolved.bindingId, workspaceId: resolved.workspaceId, revision: resolved.bindingRevision };
350
282
  runtime.connection = { ...connection };
@@ -352,13 +284,6 @@ export function connectProvider(get, options = {}) {
352
284
  return runtime;
353
285
  }
354
286
  catch (error) {
355
- try {
356
- await details?.flush();
357
- }
358
- catch (diagnostic) {
359
- const code = (value) => value instanceof NeedError && /^[A-Z][A-Z0-9_]*$/.test(value.code) ? value.code : 'UNKNOWN_FAILURE';
360
- throw new NeedError('CONVERSATION_DETAILS_FAILED', '技术详情未能保存;本轮已停止', `原错误代码 ${code(error)};诊断错误代码 ${code(diagnostic)}`);
361
- }
362
287
  throw error;
363
288
  }
364
289
  }
package/dist/readiness.js CHANGED
@@ -39,12 +39,6 @@ import { unwrap, awaitL, requireLoginCoordinator, requireLoginState } from "./pr
39
39
  import { NeedError } from "./remote.js";
40
40
  import { CONNECTION_REQUIRED, employeeFailure } from "./presentation.js";
41
41
  import { CODEX_AGENT } from "./agents.js";
42
- function details(target) {
43
- const h = target.hostContext;
44
- if (!h)
45
- return [];
46
- return [{ label: '主机配置', value: h.enforcement }, { label: '检查退出码', value: String(h.checkExitCode) }, ...h.failedChecks.map(item => ({ label: '未通过检查', value: `${item.id}(${item.status})` })), ...h.unverifiedChecks.map(item => ({ label: '未核实检查', value: `${item.id}(${item.status})` }))];
47
- }
48
42
  function blocked(code, technical = [], agent = CODEX_AGENT) {
49
43
  return { phase: 'blocked', loginStatus: 'unknown', title: `无法确认 ${agent.name.zh} 登录状态`, message: employeeFailure(code, agent.loginProvider), technical: [...technical, { label: '诊断代码', value: code }] };
50
44
  }
@@ -61,7 +55,7 @@ function snapshot(api, agent = CODEX_AGENT) {
61
55
  if (!connection.instanceId || state.instanceId !== connection.instanceId)
62
56
  return denied('AUTH_STATUS_INVALID', [diagnostic('LOGIN_INSTANCE_MISMATCH')]);
63
57
  requireLoginState(state);
64
- const technical = details({ hostContext: state.technicalDetails?.hostContext });
58
+ const technical = [];
65
59
  if (state.phase === 'blocked' || state.phase === 'disposed')
66
60
  return denied(state.technicalDetails?.code ?? 'AUTH_STATUS_INVALID', [...technical, diagnostic(state.phase === 'disposed' ? 'LOGIN_PHASE_DISPOSED' : 'LOGIN_PHASE_BLOCKED')]);
67
61
  if (state.queuedProviders?.includes(brand) || state.checkingProviders.includes(brand) || state.phase === 'authorizing' && state.provider === brand)
@@ -1,9 +1,30 @@
1
- import { type DetailObservation } from './conversation-details.ts';
1
+ import { type DetailObservation, type JsonValue } from './conversation-details.ts';
2
2
  import type { LoginDiagnostic } from './login-diagnostic.ts';
3
- import type { ConnectApi as LConnectApi, ConnectionState } from '@ai-workbench/connect/api';
4
- export type { RemoteConversationDetail as RemoteDetail } from '@ai-workbench/connect/api';
5
- type Connection = Pick<ConnectionState, 'instanceId' | 'epoch' | 'phase'>;
6
- export type RemoteDetailsApi = Pick<LConnectApi, 'getConnectionState'> & Partial<Pick<LConnectApi, 'getContractInfo' | 'appendRemoteConversationDetail' | 'getRemoteConversationDetailReceipt' | 'listRemoteConversationDetails' | 'appendLoginDiagnostic' | 'getLoginDiagnosticReceipt' | 'listLoginDiagnostics'>>;
3
+ type Connection = {
4
+ instanceId: string;
5
+ epoch: number;
6
+ phase: string;
7
+ };
8
+ export interface RemoteDetail {
9
+ version: 1;
10
+ eventId: string;
11
+ instanceId: string | null;
12
+ epoch: number | null;
13
+ sessionId: string;
14
+ provider: 'claude' | 'codex';
15
+ turn: string | number | null;
16
+ step: string | number | null;
17
+ sequence: number;
18
+ kind: string;
19
+ severity: 'info' | 'warning' | 'action-required';
20
+ code: string;
21
+ summary: string;
22
+ method?: string;
23
+ payload: JsonValue;
24
+ }
25
+ export interface RemoteDetailsApi {
26
+ getConnectionState(): Connection;
27
+ }
7
28
  export interface DetailChannel {
8
29
  record(observation: DetailObservation): void;
9
30
  beginTurn(ids: {
@@ -11,26 +32,31 @@ export interface DetailChannel {
11
32
  step: string | number | null;
12
33
  }): void;
13
34
  endTurn(): void;
14
- flush(): Promise<void>;
15
35
  }
16
36
  export interface DetailRequest {
17
37
  sessionId: string;
18
38
  provider: 'claude' | 'codex';
19
39
  identity: string;
20
- connection: Connection;
21
- readonly localAcceptanceId?: string;
40
+ connection?: Connection;
22
41
  }
23
42
  export declare function privateDirectory(path: string): Promise<void>;
24
- export declare function durableWrite(path: string, value: unknown): Promise<void>;
25
- export declare function readJournal(path: string): Promise<unknown>;
26
43
  export interface DiagnosticBinding {
27
44
  api: RemoteDetailsApi | undefined;
28
45
  connection: Connection | undefined;
29
46
  }
47
+ /** Diagnostics are best effort. No delivery journal, receipt lookup, replay or turn gate. */
30
48
  export declare function createRemoteDetails(options: {
31
- profileDir: string;
32
- getApi: () => RemoteDetailsApi | undefined;
49
+ profileDir?: string;
50
+ getApi?: () => unknown;
51
+ warn?: (line: string) => void;
33
52
  }): {
53
+ /** Await queued best-effort writes only when releasing the profile, never before dispatch. */
54
+ dispose(): Promise<void>;
55
+ releaseSession(sessionId: string): void;
56
+ read(query: {
57
+ sessionId: string;
58
+ provider: "claude" | "codex";
59
+ }): Promise<RemoteDetail[]>;
34
60
  recordLocalFailure(request: {
35
61
  sessionId?: string;
36
62
  provider: "claude" | "codex";
@@ -46,8 +72,7 @@ export declare function createRemoteDetails(options: {
46
72
  step: string | number | null;
47
73
  };
48
74
  }): Promise<{
49
- eventId: string;
50
- recorded: true;
75
+ eventId: `${string}-${string}-${string}-${string}-${string}`;
51
76
  }>;
52
77
  recordPreflightCheck(request: {
53
78
  sessionId?: string;
@@ -58,10 +83,9 @@ export declare function createRemoteDetails(options: {
58
83
  step: string | number | null;
59
84
  };
60
85
  binding?: DiagnosticBinding;
61
- assertScope?: () => void;
62
86
  }): Promise<{
63
- eventId: string;
64
- recorded: true;
87
+ eventId: `${string}-${string}-${string}-${string}-${string}`;
65
88
  }>;
66
89
  open(request: DetailRequest): Promise<DetailChannel>;
67
90
  };
91
+ export {};