@robota-sdk/agent-sdk 3.0.0-beta.61 → 3.0.0-beta.63

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.
@@ -47,6 +47,7 @@ __export(index_exports, {
47
47
  DEFAULT_AUTO_COMPACT_THRESHOLD: () => DEFAULT_AUTO_COMPACT_THRESHOLD,
48
48
  DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE: () => import_agent_runtime4.DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE,
49
49
  DEFAULT_STATUS_LINE_COMMAND_SETTINGS: () => DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
50
+ EXECUTION_ORIGIN_METADATA_KEYS: () => EXECUTION_ORIGIN_METADATA_KEYS,
50
51
  EXIT_COMMAND_DESCRIPTION: () => EXIT_COMMAND_DESCRIPTION,
51
52
  EditCheckpointStore: () => EditCheckpointStore,
52
53
  HELP_COMMAND_DESCRIPTION: () => HELP_COMMAND_DESCRIPTION,
@@ -82,11 +83,14 @@ __export(index_exports, {
82
83
  STATUSLINE_COMMAND_ARGUMENT_HINT: () => STATUSLINE_COMMAND_ARGUMENT_HINT,
83
84
  STATUSLINE_COMMAND_DESCRIPTION: () => STATUSLINE_COMMAND_DESCRIPTION,
84
85
  SkillCommandSource: () => SkillCommandSource,
85
- SubagentManager: () => import_agent_runtime7.SubagentManager,
86
+ SubagentManager: () => import_agent_runtime8.SubagentManager,
86
87
  SystemCommandExecutor: () => SystemCommandExecutor,
88
+ USER_LOCAL_MEMORY_CATEGORIES: () => USER_LOCAL_MEMORY_CATEGORIES,
89
+ USER_LOCAL_STORAGE_CATEGORIES: () => USER_LOCAL_STORAGE_CATEGORIES,
90
+ USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS: () => USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS,
87
91
  VALIDATE_SESSION_COMMAND_DESCRIPTION: () => VALIDATE_SESSION_COMMAND_DESCRIPTION,
88
92
  VALID_PERMISSION_MODES: () => VALID_PERMISSION_MODES,
89
- WorktreeSubagentRunner: () => import_agent_runtime8.WorktreeSubagentRunner,
93
+ WorktreeSubagentRunner: () => import_agent_runtime9.WorktreeSubagentRunner,
90
94
  addCommandContextReference: () => addCommandContextReference,
91
95
  appendPrefixedLogLines: () => import_agent_runtime4.appendPrefixedLogLines,
92
96
  assembleSubagentPrompt: () => assembleSubagentPrompt,
@@ -108,7 +112,9 @@ __export(index_exports, {
108
112
  closeCommandBackgroundTask: () => closeCommandBackgroundTask,
109
113
  compactCommandContext: () => compactCommandContext,
110
114
  createAgentTool: () => createAgentTool,
115
+ createBackgroundGroupExecutionEntryId: () => createBackgroundGroupExecutionEntryId,
111
116
  createBackgroundProcessTool: () => createBackgroundProcessTool,
117
+ createBackgroundTaskExecutionEntryId: () => createBackgroundTaskExecutionEntryId,
112
118
  createBackgroundTaskLogPage: () => import_agent_runtime4.createBackgroundTaskLogPage,
113
119
  createBuiltinCommandModule: () => createBuiltinCommandModule,
114
120
  createCommandExecutionTool: () => createCommandExecutionTool,
@@ -117,7 +123,13 @@ __export(index_exports, {
117
123
  createCommandProjectMemoryStore: () => createCommandProjectMemoryStore,
118
124
  createContextReferenceItem: () => createContextReferenceItem,
119
125
  createDefaultTools: () => createDefaultTools,
126
+ createExecutionOriginMetadata: () => createExecutionOriginMetadata,
127
+ createExecutionWorkspaceSnapshot: () => createExecutionWorkspaceSnapshot,
128
+ createExecutionWorkspaceTaskSpawner: () => createExecutionWorkspaceTaskSpawner,
120
129
  createLimitedOutputCapture: () => import_agent_runtime4.createLimitedOutputCapture,
130
+ createLineDetailPage: () => createLineDetailPage,
131
+ createMainThreadDetailPage: () => createMainThreadDetailPage,
132
+ createMainThreadExecutionEntryId: () => createMainThreadExecutionEntryId,
121
133
  createModelCommandToolProjection: () => createModelCommandToolProjection,
122
134
  createPluginRegistryReloadRequestedEffect: () => createPluginRegistryReloadRequestedEffect,
123
135
  createPluginTuiRequestedEffect: () => createPluginTuiRequestedEffect,
@@ -133,8 +145,10 @@ __export(index_exports, {
133
145
  createSubagentLogger: () => createSubagentLogger,
134
146
  createSubagentSession: () => createSubagentSession,
135
147
  createSystemCommands: () => createSystemCommands,
136
- createWorktreeSubagentRunner: () => import_agent_runtime8.createWorktreeSubagentRunner,
148
+ createWorktreeSubagentRunner: () => import_agent_runtime9.createWorktreeSubagentRunner,
137
149
  deleteProviderProfile: () => deleteProviderProfile,
150
+ deleteUserLocalMemoryItem: () => deleteUserLocalMemoryItem,
151
+ disableUserLocalMemoryItem: () => disableUserLocalMemoryItem,
138
152
  discoverTaskFiles: () => discoverTaskFiles,
139
153
  evaluateReversibleToolSafety: () => evaluateReversibleToolSafety,
140
154
  executeSkill: () => executeSkill,
@@ -164,6 +178,8 @@ __export(index_exports, {
164
178
  hasSensitiveCommandMemoryContent: () => hasSensitiveCommandMemoryContent,
165
179
  hasUsableSecretReference: () => hasUsableSecretReference,
166
180
  inspectCommandEditCheckpoint: () => inspectCommandEditCheckpoint,
181
+ inspectUserLocalMemoryItem: () => inspectUserLocalMemoryItem,
182
+ inspectUserLocalStorage: () => inspectUserLocalStorage,
167
183
  isCommandMemoryType: () => isCommandMemoryType,
168
184
  isEnvReference: () => isEnvReference,
169
185
  isMemoryType: () => isMemoryType,
@@ -177,10 +193,12 @@ __export(index_exports, {
177
193
  listCommandSessionAllowedTools: () => listCommandSessionAllowedTools,
178
194
  listCommandUsedMemoryReferences: () => listCommandUsedMemoryReferences,
179
195
  listResumableSessionSummaries: () => listResumableSessionSummaries,
196
+ listUserLocalMemoryItems: () => listUserLocalMemoryItems,
180
197
  loadTaskContext: () => loadTaskContext,
181
198
  mergeProviderPatch: () => mergeProviderPatch,
182
199
  normalizeModelCommandName: () => normalizeModelCommandName,
183
200
  parseCommandBackgroundLogCursor: () => parseCommandBackgroundLogCursor,
201
+ parseExecutionWorkspaceEntryId: () => parseExecutionWorkspaceEntryId,
184
202
  parseFrontmatter: () => parseFrontmatter,
185
203
  parseLanguageArgument: () => parseLanguageArgument,
186
204
  parsePermissionModeArgument: () => parsePermissionModeArgument,
@@ -200,6 +218,7 @@ __export(index_exports, {
200
218
  readCommandPermissionsState: () => readCommandPermissionsState,
201
219
  readCommandSessionInfo: () => readCommandSessionInfo,
202
220
  readCurrentGitBranch: () => readCurrentGitBranch,
221
+ readEnabledUserLocalMemoryItem: () => readEnabledUserLocalMemoryItem,
203
222
  recordCommandMemoryEvent: () => recordCommandMemoryEvent,
204
223
  removeCommandContextReference: () => removeCommandContextReference,
205
224
  removeContextReference: () => removeContextReference,
@@ -215,6 +234,7 @@ __export(index_exports, {
215
234
  resolveProviderSetupSelection: () => resolveProviderSetupSelection,
216
235
  resolveSessionIdByIdOrName: () => resolveSessionIdByIdOrName,
217
236
  resolveSubagentLogDir: () => resolveSubagentLogDir,
237
+ resolveUserLocalStorageRoot: () => resolveUserLocalStorageRoot,
218
238
  restoreCommandEditCheckpoint: () => restoreCommandEditCheckpoint,
219
239
  retrieveAgentToolDeps: () => retrieveAgentToolDeps,
220
240
  rollbackCommandEditCheckpoint: () => rollbackCommandEditCheckpoint,
@@ -223,6 +243,7 @@ __export(index_exports, {
223
243
  selectRelevantTasks: () => selectRelevantTasks,
224
244
  setCommandAutoCompactThreshold: () => setCommandAutoCompactThreshold,
225
245
  setCurrentProvider: () => setCurrentProvider,
246
+ setUserLocalMemoryItem: () => setUserLocalMemoryItem,
226
247
  storeAgentToolDeps: () => storeAgentToolDeps,
227
248
  submitProviderSetupValue: () => submitProviderSetupValue,
228
249
  substituteVariables: () => substituteVariables,
@@ -785,17 +806,17 @@ async function compactCommandContext(context, instructions) {
785
806
  function listCommandContextReferences(context) {
786
807
  return context.listContextReferences?.() ?? [];
787
808
  }
788
- async function addCommandContextReference(context, path) {
809
+ async function addCommandContextReference(context, path3) {
789
810
  if (!context.addContextReference) {
790
811
  return {
791
812
  evicted: [],
792
813
  diagnostics: ["Command host does not support context reference additions."]
793
814
  };
794
815
  }
795
- return context.addContextReference(path);
816
+ return context.addContextReference(path3);
796
817
  }
797
- function removeCommandContextReference(context, path) {
798
- return context.removeContextReference?.(path) ?? {};
818
+ function removeCommandContextReference(context, path3) {
819
+ return context.removeContextReference?.(path3) ?? {};
799
820
  }
800
821
  function clearCommandContextReferences(context) {
801
822
  return context.clearContextReferences?.() ?? { removed: [] };
@@ -1694,17 +1715,17 @@ var ProjectMemoryStore = class {
1694
1715
  return (0, import_path.join)(memoryRoot2(this.cwd), TOPICS_DIRNAME);
1695
1716
  }
1696
1717
  loadStartupMemory() {
1697
- const path = this.getIndexPath();
1698
- if (!(0, import_fs.existsSync)(path)) {
1699
- return { content: "", path, lineCount: 0, truncated: false };
1718
+ const path3 = this.getIndexPath();
1719
+ if (!(0, import_fs.existsSync)(path3)) {
1720
+ return { content: "", path: path3, lineCount: 0, truncated: false };
1700
1721
  }
1701
- const raw = (0, import_fs.readFileSync)(path, "utf8");
1722
+ const raw = (0, import_fs.readFileSync)(path3, "utf8");
1702
1723
  const byBytes = truncateToUtf8Bytes(raw, MEMORY_INDEX_MAX_BYTES);
1703
1724
  const byteTruncated = Buffer.byteLength(raw, "utf8") > MEMORY_INDEX_MAX_BYTES;
1704
1725
  const byLines = limitLines(byBytes, MEMORY_INDEX_MAX_LINES);
1705
1726
  return {
1706
1727
  content: byLines.content,
1707
- path,
1728
+ path: path3,
1708
1729
  lineCount: byLines.content.length === 0 ? 0 : byLines.content.split(/\r?\n/).length,
1709
1730
  truncated: byteTruncated || byLines.truncated
1710
1731
  };
@@ -1723,9 +1744,9 @@ var ProjectMemoryStore = class {
1723
1744
  }
1724
1745
  readTopic(topic) {
1725
1746
  const normalized = sanitizeTopic(topic);
1726
- const path = (0, import_path.join)(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1727
- if (!(0, import_fs.existsSync)(path)) return "";
1728
- return (0, import_fs.readFileSync)(path, "utf8").trimEnd();
1747
+ const path3 = (0, import_path.join)(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1748
+ if (!(0, import_fs.existsSync)(path3)) return "";
1749
+ return (0, import_fs.readFileSync)(path3, "utf8").trimEnd();
1729
1750
  }
1730
1751
  append(input) {
1731
1752
  const topic = sanitizeTopic(input.topic);
@@ -2199,7 +2220,7 @@ function getBuiltInAgent(name) {
2199
2220
  // src/tools/agent-tool.ts
2200
2221
  var import_zod2 = require("zod");
2201
2222
  var import_agent_tools2 = require("@robota-sdk/agent-tools");
2202
- var import_agent_runtime = require("@robota-sdk/agent-runtime");
2223
+ var import_agent_runtime6 = require("@robota-sdk/agent-runtime");
2203
2224
 
2204
2225
  // src/subagents/in-process-subagent-runner.ts
2205
2226
  function resolveAgentDefinition(agentType, customRegistry) {
@@ -2283,6 +2304,506 @@ function createInProcessSubagentRunner(deps) {
2283
2304
  };
2284
2305
  }
2285
2306
 
2307
+ // src/background-tasks/index.ts
2308
+ var import_agent_runtime3 = require("@robota-sdk/agent-runtime");
2309
+
2310
+ // src/background-tasks/background-job-orchestrator.ts
2311
+ var import_agent_runtime = require("@robota-sdk/agent-runtime");
2312
+ var DEFAULT_SUMMARY_LENGTH = 1e3;
2313
+ var BackgroundJobOrchestrator = class {
2314
+ manager;
2315
+ now;
2316
+ idFactory;
2317
+ unsubscribeManager;
2318
+ listeners = /* @__PURE__ */ new Set();
2319
+ groups = /* @__PURE__ */ new Map();
2320
+ sequence = 0;
2321
+ constructor(options) {
2322
+ this.manager = options.manager;
2323
+ this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
2324
+ this.idFactory = options.idFactory ?? (() => this.nextGroupId());
2325
+ this.sequence = options.initialGroups?.length ?? 0;
2326
+ for (const group of options.initialGroups ?? []) this.restoreGroup(group);
2327
+ this.unsubscribeManager = this.manager.subscribe((event) => this.handleTaskEvent(event));
2328
+ }
2329
+ createGroup(request) {
2330
+ const now = this.now();
2331
+ const state = {
2332
+ id: this.idFactory(request),
2333
+ parentSessionId: request.parentSessionId,
2334
+ waitPolicy: request.waitPolicy,
2335
+ taskIds: [...request.taskIds],
2336
+ status: "running",
2337
+ createdAt: now,
2338
+ updatedAt: now,
2339
+ results: [],
2340
+ ...request.label ? { label: request.label } : {}
2341
+ };
2342
+ const record = this.createRecord(state);
2343
+ this.groups.set(state.id, record);
2344
+ this.captureExistingTerminalTasks(record);
2345
+ this.emit({ type: "background_job_group_created", group: cloneGroup(record.state) });
2346
+ this.evaluateCompletion(record);
2347
+ return cloneGroup(record.state);
2348
+ }
2349
+ listGroups() {
2350
+ return [...this.groups.values()].map((record) => cloneGroup(record.state));
2351
+ }
2352
+ getGroup(groupId) {
2353
+ const record = this.groups.get(groupId);
2354
+ return record ? cloneGroup(record.state) : void 0;
2355
+ }
2356
+ waitGroup(groupId) {
2357
+ const record = this.groups.get(groupId);
2358
+ if (!record) return Promise.reject(new Error(`Unknown background job group: ${groupId}`));
2359
+ return record.completion;
2360
+ }
2361
+ subscribe(listener) {
2362
+ this.listeners.add(listener);
2363
+ return () => {
2364
+ this.listeners.delete(listener);
2365
+ };
2366
+ }
2367
+ dispose() {
2368
+ this.unsubscribeManager();
2369
+ this.listeners.clear();
2370
+ }
2371
+ nextGroupId() {
2372
+ this.sequence += 1;
2373
+ return `group_${this.sequence}`;
2374
+ }
2375
+ restoreGroup(group) {
2376
+ const record = this.createRecord(cloneGroup(group));
2377
+ this.groups.set(group.id, record);
2378
+ if (group.status === "completed") record.resolve(cloneGroup(group));
2379
+ }
2380
+ createRecord(state) {
2381
+ let resolveGroup = () => {
2382
+ };
2383
+ const completion = new Promise((resolve6) => {
2384
+ resolveGroup = resolve6;
2385
+ });
2386
+ return { state, completion, resolve: resolveGroup };
2387
+ }
2388
+ captureExistingTerminalTasks(record) {
2389
+ for (const taskId of record.state.taskIds) {
2390
+ const task = this.manager.get(taskId);
2391
+ if (task && (0, import_agent_runtime.isTerminalBackgroundTaskStatus)(task.status)) this.captureTask(record, task);
2392
+ }
2393
+ }
2394
+ handleTaskEvent(event) {
2395
+ const task = getTerminalTask(event);
2396
+ if (!task) return;
2397
+ for (const record of this.groups.values()) {
2398
+ if (!record.state.taskIds.includes(task.id)) continue;
2399
+ if (!this.captureTask(record, task)) continue;
2400
+ if (record.state.status === "running") this.evaluateCompletion(record);
2401
+ else this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2402
+ }
2403
+ }
2404
+ captureTask(record, task) {
2405
+ if (record.state.results.some((result) => result.taskId === task.id)) return false;
2406
+ record.state.results = [...record.state.results, createResultEnvelope(task)];
2407
+ record.state.updatedAt = this.now();
2408
+ return true;
2409
+ }
2410
+ evaluateCompletion(record) {
2411
+ if (record.state.status === "completed") return;
2412
+ if (!shouldComplete(record.state)) {
2413
+ this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2414
+ return;
2415
+ }
2416
+ const now = this.now();
2417
+ record.state.status = "completed";
2418
+ record.state.completedAt = now;
2419
+ record.state.updatedAt = now;
2420
+ const completed = cloneGroup(record.state);
2421
+ record.resolve(completed);
2422
+ this.emit({ type: "background_job_group_completed", group: completed });
2423
+ }
2424
+ emit(event) {
2425
+ for (const listener of this.listeners) listener(event);
2426
+ }
2427
+ };
2428
+ function getTerminalTask(event) {
2429
+ if (event.type === "background_task_completed" || event.type === "background_task_failed" || event.type === "background_task_cancelled") {
2430
+ return event.task;
2431
+ }
2432
+ return void 0;
2433
+ }
2434
+ function shouldComplete(group) {
2435
+ if (group.waitPolicy === "manual") return false;
2436
+ if (group.waitPolicy === "wait_any") return group.results.length > 0;
2437
+ return group.taskIds.every((taskId) => group.results.some((result) => result.taskId === taskId));
2438
+ }
2439
+ function createResultEnvelope(task) {
2440
+ return {
2441
+ taskId: task.id,
2442
+ label: task.label,
2443
+ status: task.status,
2444
+ ...task.result?.output ? { summary: summarizeOutput(task.result.output) } : {},
2445
+ ...task.transcriptPath || task.logPath ? { outputRef: task.transcriptPath ?? task.logPath } : {},
2446
+ ...task.error ? { error: { ...task.error } } : {},
2447
+ ...task.startedAt ? { startedAt: task.startedAt } : {},
2448
+ ...task.completedAt ? { completedAt: task.completedAt } : {}
2449
+ };
2450
+ }
2451
+ function summarizeOutput(output) {
2452
+ const trimmed = output.trim();
2453
+ if (trimmed.length <= DEFAULT_SUMMARY_LENGTH) return trimmed;
2454
+ return `${trimmed.slice(0, DEFAULT_SUMMARY_LENGTH)}...`;
2455
+ }
2456
+ function summarizeBackgroundJobGroup(group) {
2457
+ const completed = countResults(group, "completed");
2458
+ const failed = countResults(group, "failed");
2459
+ const cancelled = countResults(group, "cancelled");
2460
+ return {
2461
+ groupId: group.id,
2462
+ status: group.status,
2463
+ total: group.taskIds.length,
2464
+ completed,
2465
+ failed,
2466
+ cancelled,
2467
+ pending: Math.max(group.taskIds.length - group.results.length, 0),
2468
+ lines: group.results.map((result) => formatResultLine(result))
2469
+ };
2470
+ }
2471
+ function countResults(group, status) {
2472
+ return group.results.filter((result) => result.status === status).length;
2473
+ }
2474
+ function formatResultLine(result) {
2475
+ const detail = normalizeResultDetail(result);
2476
+ const output = result.outputRef && result.summary ? ` (output: ${result.outputRef})` : "";
2477
+ return `[${result.status}] ${result.label} ${result.taskId}: ${detail}${output}`;
2478
+ }
2479
+ function normalizeResultDetail(result) {
2480
+ const detail = result.error?.message ?? result.summary ?? "";
2481
+ const normalized = detail.replace(/\s+/g, " ").trim();
2482
+ return normalized.length > 0 ? normalized : "(no summary)";
2483
+ }
2484
+ function cloneGroup(group) {
2485
+ return {
2486
+ ...group,
2487
+ taskIds: [...group.taskIds],
2488
+ results: group.results.map((result) => ({
2489
+ ...result,
2490
+ ...result.error ? { error: { ...result.error } } : {}
2491
+ }))
2492
+ };
2493
+ }
2494
+
2495
+ // src/background-tasks/execution-workspace-projection.ts
2496
+ var import_agent_runtime2 = require("@robota-sdk/agent-runtime");
2497
+
2498
+ // src/background-tasks/execution-workspace-types.ts
2499
+ var MAIN_THREAD_ENTRY_PREFIX = "main";
2500
+ var BACKGROUND_TASK_ENTRY_PREFIX = "task";
2501
+ var BACKGROUND_GROUP_ENTRY_PREFIX = "group";
2502
+ var ENTRY_ID_SEPARATOR = ":";
2503
+ var EXECUTION_ORIGIN_METADATA_KEYS = {
2504
+ kind: "executionOriginKind",
2505
+ sessionId: "executionOriginSessionId",
2506
+ turnId: "executionOriginTurnId",
2507
+ commandName: "executionOriginCommandName",
2508
+ toolCallId: "executionOriginToolCallId",
2509
+ skillId: "executionOriginSkillId",
2510
+ label: "executionOriginLabel"
2511
+ };
2512
+ function createMainThreadExecutionEntryId(sessionId) {
2513
+ return [MAIN_THREAD_ENTRY_PREFIX, sessionId].join(ENTRY_ID_SEPARATOR);
2514
+ }
2515
+ function createBackgroundTaskExecutionEntryId(taskId) {
2516
+ return [BACKGROUND_TASK_ENTRY_PREFIX, taskId].join(ENTRY_ID_SEPARATOR);
2517
+ }
2518
+ function createBackgroundGroupExecutionEntryId(groupId) {
2519
+ return [BACKGROUND_GROUP_ENTRY_PREFIX, groupId].join(ENTRY_ID_SEPARATOR);
2520
+ }
2521
+ function parseExecutionWorkspaceEntryId(entryId) {
2522
+ const [prefix, sourceId] = entryId.split(ENTRY_ID_SEPARATOR, 2);
2523
+ if (!sourceId) return void 0;
2524
+ if (prefix === MAIN_THREAD_ENTRY_PREFIX) return { kind: "main_thread", sourceId };
2525
+ if (prefix === BACKGROUND_TASK_ENTRY_PREFIX) return { kind: "background_task", sourceId };
2526
+ if (prefix === BACKGROUND_GROUP_ENTRY_PREFIX) return { kind: "background_group", sourceId };
2527
+ return void 0;
2528
+ }
2529
+ function createExecutionOriginMetadata(origin) {
2530
+ return {
2531
+ [EXECUTION_ORIGIN_METADATA_KEYS.kind]: origin.kind,
2532
+ [EXECUTION_ORIGIN_METADATA_KEYS.sessionId]: origin.sessionId,
2533
+ ...origin.turnId ? { [EXECUTION_ORIGIN_METADATA_KEYS.turnId]: origin.turnId } : {},
2534
+ ...origin.commandName ? { [EXECUTION_ORIGIN_METADATA_KEYS.commandName]: origin.commandName } : {},
2535
+ ...origin.toolCallId ? { [EXECUTION_ORIGIN_METADATA_KEYS.toolCallId]: origin.toolCallId } : {},
2536
+ ...origin.skillId ? { [EXECUTION_ORIGIN_METADATA_KEYS.skillId]: origin.skillId } : {},
2537
+ ...origin.label ? { [EXECUTION_ORIGIN_METADATA_KEYS.label]: origin.label } : {}
2538
+ };
2539
+ }
2540
+
2541
+ // src/background-tasks/execution-workspace-projection.ts
2542
+ var PREVIEW_MAX_LENGTH = 120;
2543
+ var SUCCESS_EXIT_CODE = 0;
2544
+ function createExecutionWorkspaceSnapshot(input) {
2545
+ const taskGroupIds = createTaskGroupIdMap(input.groups);
2546
+ const entries = [
2547
+ createMainThreadEntry(input.mainThread),
2548
+ ...sortGroups(input.groups).map((group) => createBackgroundGroupEntry(group)),
2549
+ ...sortTasks(input.tasks).map(
2550
+ (task) => createBackgroundTaskEntry(task, taskGroupIds.get(task.id))
2551
+ )
2552
+ ].filter((entry) => matchesExecutionWorkspaceFilter(entry, input.filter));
2553
+ return {
2554
+ sessionId: input.sessionId,
2555
+ selectedEntryId: input.selectedEntryId ?? entries.find((entry) => entry.kind === "main_thread")?.id ?? createMainThreadExecutionEntryId(input.sessionId),
2556
+ updatedAt: entries[0]?.updatedAt ?? input.mainThread.updatedAt,
2557
+ entries
2558
+ };
2559
+ }
2560
+ function createMainThreadEntry(input) {
2561
+ return {
2562
+ id: createMainThreadExecutionEntryId(input.sessionId),
2563
+ sourceId: input.sessionId,
2564
+ kind: "main_thread",
2565
+ origin: { kind: "user_prompt", sessionId: input.sessionId },
2566
+ status: input.isExecuting ? "active" : "idle",
2567
+ title: "Main thread",
2568
+ subtitle: input.hasPendingPrompt ? "prompt queued" : `${input.historyLength} history entries`,
2569
+ preview: trimPreview(input.preview),
2570
+ unread: false,
2571
+ attention: "none",
2572
+ visibility: "default",
2573
+ updatedAt: input.updatedAt,
2574
+ controls: ["select"]
2575
+ };
2576
+ }
2577
+ function createBackgroundTaskEntry(state, groupId) {
2578
+ return {
2579
+ id: createBackgroundTaskExecutionEntryId(state.id),
2580
+ sourceId: state.id,
2581
+ kind: "background_task",
2582
+ parentId: state.parentTaskId ? createBackgroundTaskExecutionEntryId(state.parentTaskId) : createMainThreadExecutionEntryId(state.parentSessionId),
2583
+ ...groupId ? { groupId: createBackgroundGroupExecutionEntryId(groupId) } : {},
2584
+ origin: readExecutionOrigin(state.metadata, {
2585
+ kind: "system",
2586
+ sessionId: state.parentSessionId
2587
+ }),
2588
+ taskKind: state.kind,
2589
+ status: state.status,
2590
+ title: state.label,
2591
+ subtitle: createTaskSubtitle(state),
2592
+ preview: createTaskPreview(state),
2593
+ currentAction: state.currentAction,
2594
+ unread: state.unread,
2595
+ attention: createTaskAttention(state),
2596
+ visibility: createTaskVisibility(state),
2597
+ updatedAt: state.lastActivityAt ?? state.updatedAt,
2598
+ controls: createTaskControls(state)
2599
+ };
2600
+ }
2601
+ function createBackgroundGroupEntry(group) {
2602
+ const preview = trimPreview(
2603
+ group.results.map((result) => result.summary ?? result.error?.message).join(" ")
2604
+ );
2605
+ return {
2606
+ id: createBackgroundGroupExecutionEntryId(group.id),
2607
+ sourceId: group.id,
2608
+ kind: "background_group",
2609
+ parentId: createMainThreadExecutionEntryId(group.parentSessionId),
2610
+ origin: { kind: "system", sessionId: group.parentSessionId, label: group.label },
2611
+ status: group.status,
2612
+ title: group.label ?? group.id,
2613
+ subtitle: `${group.results.length}/${group.taskIds.length} tasks`,
2614
+ preview,
2615
+ unread: false,
2616
+ attention: createGroupAttention(group),
2617
+ visibility: group.status === "completed" ? "collapsed" : "default",
2618
+ updatedAt: group.updatedAt,
2619
+ controls: group.status === "running" ? ["select", "wait"] : ["select"]
2620
+ };
2621
+ }
2622
+ function readExecutionOrigin(metadata, fallback) {
2623
+ const kind = toExecutionOriginKind(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.kind]);
2624
+ const sessionId = toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.sessionId]);
2625
+ return {
2626
+ kind: kind ?? fallback.kind,
2627
+ sessionId: sessionId ?? fallback.sessionId,
2628
+ turnId: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.turnId]) ?? fallback.turnId,
2629
+ commandName: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.commandName]) ?? fallback.commandName,
2630
+ toolCallId: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.toolCallId]) ?? fallback.toolCallId,
2631
+ skillId: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.skillId]) ?? fallback.skillId,
2632
+ label: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.label]) ?? fallback.label
2633
+ };
2634
+ }
2635
+ function createTaskGroupIdMap(groups) {
2636
+ return new Map(groups.flatMap((group) => group.taskIds.map((taskId) => [taskId, group.id])));
2637
+ }
2638
+ function createTaskControls(state) {
2639
+ const controls = ["select"];
2640
+ if ((0, import_agent_runtime2.isTerminalBackgroundTaskStatus)(state.status)) controls.push("close");
2641
+ else controls.push("cancel");
2642
+ if (state.logPath || state.transcriptPath) controls.push("read_log");
2643
+ return controls;
2644
+ }
2645
+ function createTaskSubtitle(state) {
2646
+ if (state.kind === "agent") return state.agentType ?? state.cwd;
2647
+ return state.cwd;
2648
+ }
2649
+ function createTaskPreview(state) {
2650
+ if (state.status === "failed") return trimPreview(state.error?.message);
2651
+ if (state.status === "completed") return trimPreview(state.result?.output);
2652
+ return trimPreview(state.promptPreview ?? state.commandPreview);
2653
+ }
2654
+ function createTaskAttention(state) {
2655
+ if (state.status === "failed") return "failed";
2656
+ if (state.status === "waiting_permission") return "permission";
2657
+ if (state.unread) return "unread";
2658
+ if (state.status === "completed") return "completed";
2659
+ return "none";
2660
+ }
2661
+ function createTaskVisibility(state) {
2662
+ if (state.status === "completed" && !state.unread && !state.error && (state.result?.exitCode ?? SUCCESS_EXIT_CODE) === SUCCESS_EXIT_CODE && !state.result?.signalCode && !state.worktreePath && !state.branchName) {
2663
+ return "collapsed";
2664
+ }
2665
+ return "default";
2666
+ }
2667
+ function createGroupAttention(group) {
2668
+ if (group.results.some((result) => result.status === "failed")) return "failed";
2669
+ if (group.status === "completed") return "completed";
2670
+ return "none";
2671
+ }
2672
+ function matchesExecutionWorkspaceFilter(entry, filter) {
2673
+ if (!filter) return true;
2674
+ if (filter.includeMainThread === false && entry.kind === "main_thread") return false;
2675
+ if (filter.kinds && !filter.kinds.includes(entry.kind)) return false;
2676
+ if (filter.visibility && !filter.visibility.includes(entry.visibility)) return false;
2677
+ return true;
2678
+ }
2679
+ function sortTasks(tasks) {
2680
+ return [...tasks].sort(
2681
+ (left, right) => (right.lastActivityAt ?? right.updatedAt).localeCompare(left.lastActivityAt ?? left.updatedAt)
2682
+ );
2683
+ }
2684
+ function sortGroups(groups) {
2685
+ return [...groups].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
2686
+ }
2687
+ function trimPreview(value) {
2688
+ const normalized = value?.trim().replace(/\s+/g, " ");
2689
+ if (!normalized) return void 0;
2690
+ return normalized.length > PREVIEW_MAX_LENGTH ? `${normalized.slice(0, PREVIEW_MAX_LENGTH)}...` : normalized;
2691
+ }
2692
+ function toStringValue(value) {
2693
+ return typeof value === "string" ? value : void 0;
2694
+ }
2695
+ function toExecutionOriginKind(value) {
2696
+ if (value === "user_prompt" || value === "slash_command" || value === "model_command" || value === "tool_call" || value === "skill" || value === "transport" || value === "system") {
2697
+ return value;
2698
+ }
2699
+ return void 0;
2700
+ }
2701
+
2702
+ // src/background-tasks/execution-workspace-detail.ts
2703
+ var EXECUTION_DETAIL_PAGE_SIZE = 80;
2704
+ function createMainThreadDetailPage(input) {
2705
+ const offset = normalizeOffset(input.cursor?.offset);
2706
+ const page = input.history.slice(offset, offset + EXECUTION_DETAIL_PAGE_SIZE);
2707
+ const records = page.map((entry) => ({
2708
+ id: entry.id,
2709
+ kind: entry.category === "chat" ? "message" : "progress",
2710
+ text: formatHistoryEntry(entry),
2711
+ timestamp: entry.timestamp.toISOString(),
2712
+ sourceId: entry.type
2713
+ }));
2714
+ return {
2715
+ entryId: input.entryId,
2716
+ ...input.cursor ? { cursor: input.cursor } : {},
2717
+ ...offset + page.length < input.history.length ? { nextCursor: { offset: offset + page.length } } : {},
2718
+ records
2719
+ };
2720
+ }
2721
+ function createLineDetailPage(input) {
2722
+ const offset = input.cursor?.offset ?? 0;
2723
+ const records = input.lines.map((line, index) => ({
2724
+ id: `${input.entryId}:${offset}:${index}`,
2725
+ kind: input.kind ?? "process_output",
2726
+ text: line
2727
+ }));
2728
+ return {
2729
+ entryId: input.entryId,
2730
+ ...input.cursor ? { cursor: input.cursor } : {},
2731
+ ...input.nextCursor ? { nextCursor: input.nextCursor } : {},
2732
+ records
2733
+ };
2734
+ }
2735
+ function normalizeOffset(offset) {
2736
+ return typeof offset === "number" && Number.isFinite(offset) && offset > 0 ? Math.floor(offset) : 0;
2737
+ }
2738
+ function formatHistoryEntry(entry) {
2739
+ if (typeof entry.data === "string") return entry.data;
2740
+ return entry.type;
2741
+ }
2742
+
2743
+ // src/background-tasks/execution-workspace-spawner.ts
2744
+ function createExecutionWorkspaceTaskSpawner(options) {
2745
+ return {
2746
+ spawnAgent: (request) => options.manager.spawn(createAgentRequest(options, request)),
2747
+ spawnProcess: (request) => options.manager.spawn(createProcessRequest(options, request)),
2748
+ createGroup: (request) => options.groupOrchestrator.createGroup({
2749
+ parentSessionId: options.sessionId,
2750
+ waitPolicy: request.waitPolicy,
2751
+ taskIds: [...request.taskIds],
2752
+ label: request.label
2753
+ })
2754
+ };
2755
+ }
2756
+ function createAgentRequest(options, request) {
2757
+ return {
2758
+ kind: "agent",
2759
+ label: request.label,
2760
+ mode: request.mode ?? "background",
2761
+ parentSessionId: options.sessionId,
2762
+ parentTaskId: request.parentTaskId,
2763
+ depth: request.depth ?? 1,
2764
+ cwd: request.cwd ?? options.cwd,
2765
+ agentType: request.agentType,
2766
+ prompt: request.prompt,
2767
+ model: request.model,
2768
+ isolation: request.isolation,
2769
+ allowedTools: request.allowedTools ? [...request.allowedTools] : void 0,
2770
+ disallowedTools: request.disallowedTools ? [...request.disallowedTools] : void 0,
2771
+ permissionPolicy: request.permissionPolicy ?? "inherit-allowlist",
2772
+ timeoutMs: request.timeoutMs,
2773
+ idleTimeoutMs: request.idleTimeoutMs,
2774
+ maxRuntimeMs: request.maxRuntimeMs,
2775
+ outputLimitBytes: request.outputLimitBytes,
2776
+ maxTextDeltas: request.maxTextDeltas,
2777
+ repetitionWindow: request.repetitionWindow,
2778
+ repetitionThreshold: request.repetitionThreshold,
2779
+ metadata: createExecutionOriginMetadata(options.origin)
2780
+ };
2781
+ }
2782
+ function createProcessRequest(options, request) {
2783
+ return {
2784
+ kind: "process",
2785
+ label: request.label ?? request.command,
2786
+ mode: request.mode ?? "background",
2787
+ parentSessionId: options.sessionId,
2788
+ parentTaskId: request.parentTaskId,
2789
+ depth: request.depth ?? 0,
2790
+ cwd: request.cwd ?? options.cwd,
2791
+ command: request.command,
2792
+ shell: request.shell,
2793
+ env: request.env,
2794
+ stdin: request.stdin,
2795
+ timeoutMs: request.timeoutMs,
2796
+ idleTimeoutMs: request.idleTimeoutMs,
2797
+ maxRuntimeMs: request.maxRuntimeMs,
2798
+ outputLimitBytes: request.outputLimitBytes,
2799
+ metadata: createExecutionOriginMetadata(options.origin)
2800
+ };
2801
+ }
2802
+
2803
+ // src/background-tasks/index.ts
2804
+ var import_agent_runtime4 = require("@robota-sdk/agent-runtime");
2805
+ var import_agent_runtime5 = require("@robota-sdk/agent-runtime");
2806
+
2286
2807
  // src/tools/agent-tool-batch.ts
2287
2808
  function stringifyAgentBatchResult(input) {
2288
2809
  const successfulJobs = input.jobs.filter((job) => job.success);
@@ -2463,7 +2984,7 @@ function resolveAgentDefinition2(agentType, customRegistry) {
2463
2984
  return void 0;
2464
2985
  }
2465
2986
  function createSubagentManager(deps) {
2466
- return deps.subagentManager ?? new import_agent_runtime.SubagentManager({
2987
+ return deps.subagentManager ?? new import_agent_runtime6.SubagentManager({
2467
2988
  runner: createInProcessSubagentRunner(deps)
2468
2989
  });
2469
2990
  }
@@ -2477,7 +2998,12 @@ function createSpawnRequest(args, agentType, agentDef, deps, label = agentDef.na
2477
2998
  cwd: deps.cwd ?? process.cwd(),
2478
2999
  prompt: args.prompt,
2479
3000
  model: args.model,
2480
- isolation: args.isolation
3001
+ isolation: args.isolation,
3002
+ metadata: createExecutionOriginMetadata({
3003
+ kind: "tool_call",
3004
+ sessionId: deps.parentSessionId ?? "unknown-session",
3005
+ label
3006
+ })
2481
3007
  };
2482
3008
  }
2483
3009
  function stringifyUnknownAgentType(agentType) {
@@ -2544,250 +3070,58 @@ function stringifyAgentError(message, agentId) {
2544
3070
  }
2545
3071
  });
2546
3072
  }
2547
- async function runManagedAgent(args, deps, manager) {
2548
- if (typeof args.prompt !== "string" || args.prompt.length === 0) {
2549
- return stringifyAgentError("prompt is required when jobs is omitted");
2550
- }
2551
- const singleArgs = { ...args, prompt: args.prompt };
2552
- const agentType = args.subagent_type ?? "general-purpose";
2553
- const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
2554
- if (!agentDef) {
2555
- return stringifyUnknownAgentType(agentType);
2556
- }
2557
- let agentId;
2558
- try {
2559
- const state = await manager.spawn(createSpawnRequest(singleArgs, agentType, agentDef, deps));
2560
- agentId = state.id;
2561
- const response = await manager.wait(state.id);
2562
- return stringifyAgentSuccess(response);
2563
- } catch (err) {
2564
- const message = err instanceof Error ? err.message : String(err);
2565
- return stringifyAgentError(message, agentId);
2566
- }
2567
- }
2568
- function createAgentTool(deps) {
2569
- const manager = createSubagentManager(deps);
2570
- return (0, import_agent_tools2.createZodFunctionTool)(
2571
- "Agent",
2572
- AGENT_TOOL_DESCRIPTION,
2573
- asZodSchema2(AgentSchema),
2574
- async (params) => {
2575
- const args = params;
2576
- if (Array.isArray(args.jobs) && args.jobs.length > 0) {
2577
- return runManagedAgentBatch({
2578
- jobs: args.jobs,
2579
- deps,
2580
- manager,
2581
- resolveAgentDefinition: resolveAgentDefinition2,
2582
- createSpawnRequest
2583
- });
2584
- }
2585
- return runManagedAgent(
2586
- {
2587
- prompt: args.prompt,
2588
- ...args.subagent_type !== void 0 ? { subagent_type: args.subagent_type } : {},
2589
- ...args.model !== void 0 ? { model: args.model } : {},
2590
- ...args.isolation !== void 0 ? { isolation: args.isolation } : {}
2591
- },
2592
- deps,
2593
- manager
2594
- );
2595
- }
2596
- );
2597
- }
2598
-
2599
- // src/background-tasks/index.ts
2600
- var import_agent_runtime3 = require("@robota-sdk/agent-runtime");
2601
-
2602
- // src/background-tasks/background-job-orchestrator.ts
2603
- var import_agent_runtime2 = require("@robota-sdk/agent-runtime");
2604
- var DEFAULT_SUMMARY_LENGTH = 1e3;
2605
- var BackgroundJobOrchestrator = class {
2606
- manager;
2607
- now;
2608
- idFactory;
2609
- unsubscribeManager;
2610
- listeners = /* @__PURE__ */ new Set();
2611
- groups = /* @__PURE__ */ new Map();
2612
- sequence = 0;
2613
- constructor(options) {
2614
- this.manager = options.manager;
2615
- this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
2616
- this.idFactory = options.idFactory ?? (() => this.nextGroupId());
2617
- this.sequence = options.initialGroups?.length ?? 0;
2618
- for (const group of options.initialGroups ?? []) this.restoreGroup(group);
2619
- this.unsubscribeManager = this.manager.subscribe((event) => this.handleTaskEvent(event));
2620
- }
2621
- createGroup(request) {
2622
- const now = this.now();
2623
- const state = {
2624
- id: this.idFactory(request),
2625
- parentSessionId: request.parentSessionId,
2626
- waitPolicy: request.waitPolicy,
2627
- taskIds: [...request.taskIds],
2628
- status: "running",
2629
- createdAt: now,
2630
- updatedAt: now,
2631
- results: [],
2632
- ...request.label ? { label: request.label } : {}
2633
- };
2634
- const record = this.createRecord(state);
2635
- this.groups.set(state.id, record);
2636
- this.captureExistingTerminalTasks(record);
2637
- this.emit({ type: "background_job_group_created", group: cloneGroup(record.state) });
2638
- this.evaluateCompletion(record);
2639
- return cloneGroup(record.state);
2640
- }
2641
- listGroups() {
2642
- return [...this.groups.values()].map((record) => cloneGroup(record.state));
2643
- }
2644
- getGroup(groupId) {
2645
- const record = this.groups.get(groupId);
2646
- return record ? cloneGroup(record.state) : void 0;
2647
- }
2648
- waitGroup(groupId) {
2649
- const record = this.groups.get(groupId);
2650
- if (!record) return Promise.reject(new Error(`Unknown background job group: ${groupId}`));
2651
- return record.completion;
2652
- }
2653
- subscribe(listener) {
2654
- this.listeners.add(listener);
2655
- return () => {
2656
- this.listeners.delete(listener);
2657
- };
2658
- }
2659
- dispose() {
2660
- this.unsubscribeManager();
2661
- this.listeners.clear();
2662
- }
2663
- nextGroupId() {
2664
- this.sequence += 1;
2665
- return `group_${this.sequence}`;
2666
- }
2667
- restoreGroup(group) {
2668
- const record = this.createRecord(cloneGroup(group));
2669
- this.groups.set(group.id, record);
2670
- if (group.status === "completed") record.resolve(cloneGroup(group));
2671
- }
2672
- createRecord(state) {
2673
- let resolveGroup = () => {
2674
- };
2675
- const completion = new Promise((resolve6) => {
2676
- resolveGroup = resolve6;
2677
- });
2678
- return { state, completion, resolve: resolveGroup };
2679
- }
2680
- captureExistingTerminalTasks(record) {
2681
- for (const taskId of record.state.taskIds) {
2682
- const task = this.manager.get(taskId);
2683
- if (task && (0, import_agent_runtime2.isTerminalBackgroundTaskStatus)(task.status)) this.captureTask(record, task);
2684
- }
2685
- }
2686
- handleTaskEvent(event) {
2687
- const task = getTerminalTask(event);
2688
- if (!task) return;
2689
- for (const record of this.groups.values()) {
2690
- if (!record.state.taskIds.includes(task.id)) continue;
2691
- if (!this.captureTask(record, task)) continue;
2692
- if (record.state.status === "running") this.evaluateCompletion(record);
2693
- else this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2694
- }
2695
- }
2696
- captureTask(record, task) {
2697
- if (record.state.results.some((result) => result.taskId === task.id)) return false;
2698
- record.state.results = [...record.state.results, createResultEnvelope(task)];
2699
- record.state.updatedAt = this.now();
2700
- return true;
2701
- }
2702
- evaluateCompletion(record) {
2703
- if (record.state.status === "completed") return;
2704
- if (!shouldComplete(record.state)) {
2705
- this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2706
- return;
2707
- }
2708
- const now = this.now();
2709
- record.state.status = "completed";
2710
- record.state.completedAt = now;
2711
- record.state.updatedAt = now;
2712
- const completed = cloneGroup(record.state);
2713
- record.resolve(completed);
2714
- this.emit({ type: "background_job_group_completed", group: completed });
2715
- }
2716
- emit(event) {
2717
- for (const listener of this.listeners) listener(event);
2718
- }
2719
- };
2720
- function getTerminalTask(event) {
2721
- if (event.type === "background_task_completed" || event.type === "background_task_failed" || event.type === "background_task_cancelled") {
2722
- return event.task;
2723
- }
2724
- return void 0;
2725
- }
2726
- function shouldComplete(group) {
2727
- if (group.waitPolicy === "manual") return false;
2728
- if (group.waitPolicy === "wait_any") return group.results.length > 0;
2729
- return group.taskIds.every((taskId) => group.results.some((result) => result.taskId === taskId));
2730
- }
2731
- function createResultEnvelope(task) {
2732
- return {
2733
- taskId: task.id,
2734
- label: task.label,
2735
- status: task.status,
2736
- ...task.result?.output ? { summary: summarizeOutput(task.result.output) } : {},
2737
- ...task.transcriptPath || task.logPath ? { outputRef: task.transcriptPath ?? task.logPath } : {},
2738
- ...task.error ? { error: { ...task.error } } : {},
2739
- ...task.startedAt ? { startedAt: task.startedAt } : {},
2740
- ...task.completedAt ? { completedAt: task.completedAt } : {}
2741
- };
2742
- }
2743
- function summarizeOutput(output) {
2744
- const trimmed = output.trim();
2745
- if (trimmed.length <= DEFAULT_SUMMARY_LENGTH) return trimmed;
2746
- return `${trimmed.slice(0, DEFAULT_SUMMARY_LENGTH)}...`;
2747
- }
2748
- function summarizeBackgroundJobGroup(group) {
2749
- const completed = countResults(group, "completed");
2750
- const failed = countResults(group, "failed");
2751
- const cancelled = countResults(group, "cancelled");
2752
- return {
2753
- groupId: group.id,
2754
- status: group.status,
2755
- total: group.taskIds.length,
2756
- completed,
2757
- failed,
2758
- cancelled,
2759
- pending: Math.max(group.taskIds.length - group.results.length, 0),
2760
- lines: group.results.map((result) => formatResultLine(result))
2761
- };
2762
- }
2763
- function countResults(group, status) {
2764
- return group.results.filter((result) => result.status === status).length;
2765
- }
2766
- function formatResultLine(result) {
2767
- const detail = normalizeResultDetail(result);
2768
- const output = result.outputRef && result.summary ? ` (output: ${result.outputRef})` : "";
2769
- return `[${result.status}] ${result.label} ${result.taskId}: ${detail}${output}`;
2770
- }
2771
- function normalizeResultDetail(result) {
2772
- const detail = result.error?.message ?? result.summary ?? "";
2773
- const normalized = detail.replace(/\s+/g, " ").trim();
2774
- return normalized.length > 0 ? normalized : "(no summary)";
3073
+ async function runManagedAgent(args, deps, manager) {
3074
+ if (typeof args.prompt !== "string" || args.prompt.length === 0) {
3075
+ return stringifyAgentError("prompt is required when jobs is omitted");
3076
+ }
3077
+ const singleArgs = { ...args, prompt: args.prompt };
3078
+ const agentType = args.subagent_type ?? "general-purpose";
3079
+ const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
3080
+ if (!agentDef) {
3081
+ return stringifyUnknownAgentType(agentType);
3082
+ }
3083
+ let agentId;
3084
+ try {
3085
+ const state = await manager.spawn(createSpawnRequest(singleArgs, agentType, agentDef, deps));
3086
+ agentId = state.id;
3087
+ const response = await manager.wait(state.id);
3088
+ return stringifyAgentSuccess(response);
3089
+ } catch (err) {
3090
+ const message = err instanceof Error ? err.message : String(err);
3091
+ return stringifyAgentError(message, agentId);
3092
+ }
2775
3093
  }
2776
- function cloneGroup(group) {
2777
- return {
2778
- ...group,
2779
- taskIds: [...group.taskIds],
2780
- results: group.results.map((result) => ({
2781
- ...result,
2782
- ...result.error ? { error: { ...result.error } } : {}
2783
- }))
2784
- };
3094
+ function createAgentTool(deps) {
3095
+ const manager = createSubagentManager(deps);
3096
+ return (0, import_agent_tools2.createZodFunctionTool)(
3097
+ "Agent",
3098
+ AGENT_TOOL_DESCRIPTION,
3099
+ asZodSchema2(AgentSchema),
3100
+ async (params) => {
3101
+ const args = params;
3102
+ if (Array.isArray(args.jobs) && args.jobs.length > 0) {
3103
+ return runManagedAgentBatch({
3104
+ jobs: args.jobs,
3105
+ deps,
3106
+ manager,
3107
+ resolveAgentDefinition: resolveAgentDefinition2,
3108
+ createSpawnRequest
3109
+ });
3110
+ }
3111
+ return runManagedAgent(
3112
+ {
3113
+ prompt: args.prompt,
3114
+ ...args.subagent_type !== void 0 ? { subagent_type: args.subagent_type } : {},
3115
+ ...args.model !== void 0 ? { model: args.model } : {},
3116
+ ...args.isolation !== void 0 ? { isolation: args.isolation } : {}
3117
+ },
3118
+ deps,
3119
+ manager
3120
+ );
3121
+ }
3122
+ );
2785
3123
  }
2786
3124
 
2787
- // src/background-tasks/index.ts
2788
- var import_agent_runtime4 = require("@robota-sdk/agent-runtime");
2789
- var import_agent_runtime5 = require("@robota-sdk/agent-runtime");
2790
-
2791
3125
  // src/background-tasks/session-background-store.ts
2792
3126
  var sessionBackgroundTaskManagers = /* @__PURE__ */ new WeakMap();
2793
3127
  function storeSessionBackgroundTaskManager(key, manager) {
@@ -3647,6 +3981,10 @@ var MarketplaceSourceSchema = import_zod3.z.object({
3647
3981
  });
3648
3982
  var ExtraKnownMarketplacesSchema = import_zod3.z.record(MarketplaceSourceSchema).optional().catch(void 0);
3649
3983
  var AutoCompactThresholdSchema = import_zod3.z.union([import_zod3.z.number().gt(0).lte(1), import_zod3.z.literal(false)]).optional();
3984
+ var TransportSettingsSchema = import_zod3.z.object({
3985
+ enabled: import_zod3.z.boolean().optional(),
3986
+ options: import_zod3.z.record(UniversalValueSchema).optional()
3987
+ });
3650
3988
  var SettingsSchema = import_zod3.z.object({
3651
3989
  /** Trust level used when no --permission-mode flag is given */
3652
3990
  defaultTrustLevel: import_zod3.z.enum(["safe", "moderate", "full"]).optional(),
@@ -3666,7 +4004,9 @@ var SettingsSchema = import_zod3.z.object({
3666
4004
  /** Extra marketplace URLs for BundlePlugin discovery */
3667
4005
  extraKnownMarketplaces: ExtraKnownMarketplacesSchema,
3668
4006
  /** Auto-compact threshold as a 0-1 fraction. Set false to disable automatic compaction. */
3669
- autoCompactThreshold: AutoCompactThresholdSchema
4007
+ autoCompactThreshold: AutoCompactThresholdSchema,
4008
+ /** Transport enable/disable + options: transport name -> config */
4009
+ transports: import_zod3.z.record(TransportSettingsSchema).optional()
3670
4010
  });
3671
4011
 
3672
4012
  // src/config/config-loader.ts
@@ -3769,7 +4109,12 @@ function resolveProvider(merged) {
3769
4109
  if (merged.currentProvider !== void 0) {
3770
4110
  return resolveActiveProviderProfile2(merged);
3771
4111
  }
3772
- return resolveLegacyProvider(merged);
4112
+ if (merged.provider !== void 0) {
4113
+ throw new Error(
4114
+ 'Legacy flat "provider" settings are not supported. Migrate to "currentProvider" + "providers" format.'
4115
+ );
4116
+ }
4117
+ return { ...DEFAULTS.provider };
3773
4118
  }
3774
4119
  function resolveActiveProviderProfile2(merged) {
3775
4120
  const currentProvider = merged.currentProvider;
@@ -3792,16 +4137,6 @@ function resolveActiveProviderProfile2(merged) {
3792
4137
  ...profile.options !== void 0 && { options: profile.options }
3793
4138
  };
3794
4139
  }
3795
- function resolveLegacyProvider(merged) {
3796
- return {
3797
- name: merged.provider?.name ?? DEFAULTS.provider.name,
3798
- model: merged.provider?.model ?? DEFAULTS.provider.model,
3799
- apiKey: merged.provider?.apiKey ?? DEFAULTS.provider.apiKey,
3800
- ...merged.provider?.baseURL !== void 0 && { baseURL: merged.provider.baseURL },
3801
- ...merged.provider?.timeout !== void 0 && { timeout: merged.provider.timeout },
3802
- ...merged.provider?.options !== void 0 && { options: merged.provider.options }
3803
- };
3804
- }
3805
4140
  function toResolvedConfig(merged) {
3806
4141
  return {
3807
4142
  defaultTrustLevel: merged.defaultTrustLevel ?? DEFAULTS.defaultTrustLevel,
@@ -3845,10 +4180,10 @@ async function loadConfig(cwd) {
3845
4180
  rawEntries.push({ raw, path: filePath });
3846
4181
  }
3847
4182
  }
3848
- const parsedLayers = rawEntries.map(({ raw, path }) => {
4183
+ const parsedLayers = rawEntries.map(({ raw, path: path3 }) => {
3849
4184
  const result = SettingsSchema.safeParse(raw);
3850
4185
  if (!result.success) {
3851
- throw new Error(`Invalid settings in ${path}: ${result.error.message}`);
4186
+ throw new Error(`Invalid settings in ${path3}: ${result.error.message}`);
3852
4187
  }
3853
4188
  return resolveEnvRefs(result.data);
3854
4189
  });
@@ -4212,7 +4547,8 @@ async function startBackgroundProcess(args, deps) {
4212
4547
  command: args.command,
4213
4548
  stdin: args.stdin,
4214
4549
  timeoutMs: args.timeout ?? DEFAULT_PROCESS_TIMEOUT_MS,
4215
- outputLimitBytes: args.outputLimitBytes
4550
+ outputLimitBytes: args.outputLimitBytes,
4551
+ metadata: deps.metadata
4216
4552
  });
4217
4553
  return stringifyStarted(state.id, state.status, args.command);
4218
4554
  } catch (error) {
@@ -4469,7 +4805,7 @@ function createBlockedResult(report) {
4469
4805
  }
4470
4806
 
4471
4807
  // src/assembly/create-session.ts
4472
- var import_agent_runtime6 = require("@robota-sdk/agent-runtime");
4808
+ var import_agent_runtime7 = require("@robota-sdk/agent-runtime");
4473
4809
 
4474
4810
  // src/agents/agent-definition-loader.ts
4475
4811
  var import_node_fs4 = require("fs");
@@ -4722,7 +5058,7 @@ function createSession(options) {
4722
5058
  customAgentRegistry: (name) => agentLoader.getAgent(name),
4723
5059
  agentDefinitions
4724
5060
  };
4725
- const subagentManager = new import_agent_runtime6.SubagentManager({
5061
+ const subagentManager = new import_agent_runtime7.SubagentManager({
4726
5062
  runner: (options.subagentRunnerFactory ?? createInProcessSubagentRunner)(agentToolDeps),
4727
5063
  backgroundTaskRunners: options.backgroundTaskRunners
4728
5064
  });
@@ -4730,7 +5066,7 @@ function createSession(options) {
4730
5066
  backgroundTaskManager = subagentManager.getBackgroundTaskManager();
4731
5067
  agentToolDeps.backgroundTaskManager = backgroundTaskManager;
4732
5068
  } else {
4733
- backgroundTaskManager = new import_agent_runtime6.BackgroundTaskManager({
5069
+ backgroundTaskManager = new import_agent_runtime7.BackgroundTaskManager({
4734
5070
  runners: options.backgroundTaskRunners ?? []
4735
5071
  });
4736
5072
  }
@@ -4755,7 +5091,12 @@ function createSession(options) {
4755
5091
  backgroundProcessToolDeps = {
4756
5092
  backgroundTaskManager,
4757
5093
  cwd,
4758
- parentSessionId: sessionId
5094
+ parentSessionId: sessionId,
5095
+ metadata: createExecutionOriginMetadata({
5096
+ kind: "tool_call",
5097
+ sessionId,
5098
+ label: "BackgroundProcess"
5099
+ })
4759
5100
  };
4760
5101
  tools.push(createBackgroundProcessTool(backgroundProcessToolDeps));
4761
5102
  }
@@ -5031,7 +5372,7 @@ function formatTaskContext(tasks) {
5031
5372
  }
5032
5373
  function loadTaskContext(cwd, options = {}) {
5033
5374
  const currentBranch = options.currentBranch ?? readCurrentGitBranch(cwd);
5034
- const tasks = discoverTaskFiles(cwd).map((path) => parseTaskFile(path, cwd));
5375
+ const tasks = discoverTaskFiles(cwd).map((path3) => parseTaskFile(path3, cwd));
5035
5376
  return formatTaskContext(selectRelevantTasks(tasks, { ...options, currentBranch }));
5036
5377
  }
5037
5378
  function updateTaskFileStatus(taskPath, status, options = {}) {
@@ -5378,15 +5719,11 @@ var BundlePluginLoader = class {
5378
5719
  }
5379
5720
  return results;
5380
5721
  }
5381
- /** Read and validate a plugin.json manifest. Returns null on failure. */
5382
- readManifest(path) {
5383
- try {
5384
- const raw = (0, import_node_fs9.readFileSync)(path, "utf-8");
5385
- const data = JSON.parse(raw);
5386
- return validateManifest(data);
5387
- } catch {
5388
- return null;
5389
- }
5722
+ /** Read and validate a plugin.json manifest. Returns null if the manifest structure is invalid. */
5723
+ readManifest(path3) {
5724
+ const raw = (0, import_node_fs9.readFileSync)(path3, "utf-8");
5725
+ const data = JSON.parse(raw);
5726
+ return validateManifest(data);
5390
5727
  }
5391
5728
  /**
5392
5729
  * Check if a plugin is explicitly disabled.
@@ -5462,40 +5799,26 @@ var BundlePluginLoader = class {
5462
5799
  loadHooks(pluginDir) {
5463
5800
  const hooksPath = (0, import_node_path11.join)(pluginDir, "hooks", "hooks.json");
5464
5801
  if (!(0, import_node_fs9.existsSync)(hooksPath)) return {};
5465
- try {
5466
- const raw = (0, import_node_fs9.readFileSync)(hooksPath, "utf-8");
5467
- const data = JSON.parse(raw);
5468
- if (typeof data === "object" && data !== null) {
5469
- return data;
5470
- }
5471
- return {};
5472
- } catch {
5473
- return {};
5802
+ const raw = (0, import_node_fs9.readFileSync)(hooksPath, "utf-8");
5803
+ const data = JSON.parse(raw);
5804
+ if (typeof data === "object" && data !== null) {
5805
+ return data;
5474
5806
  }
5807
+ return {};
5475
5808
  }
5476
- /** Load MCP server configuration if present. Checks `.mcp.json` at plugin root first. */
5809
+ /** Load MCP server configuration from `.mcp.json` at the plugin root if present. */
5477
5810
  loadMcpConfig(pluginDir) {
5478
- const primaryPath = (0, import_node_path11.join)(pluginDir, ".mcp.json");
5479
- const fallbackPath = (0, import_node_path11.join)(pluginDir, ".claude-plugin", "mcp.json");
5480
- const mcpPath = (0, import_node_fs9.existsSync)(primaryPath) ? primaryPath : fallbackPath;
5811
+ const mcpPath = (0, import_node_path11.join)(pluginDir, ".mcp.json");
5481
5812
  if (!(0, import_node_fs9.existsSync)(mcpPath)) return void 0;
5482
- try {
5483
- const raw = (0, import_node_fs9.readFileSync)(mcpPath, "utf-8");
5484
- return JSON.parse(raw);
5485
- } catch {
5486
- return void 0;
5487
- }
5813
+ const raw = (0, import_node_fs9.readFileSync)(mcpPath, "utf-8");
5814
+ return JSON.parse(raw);
5488
5815
  }
5489
5816
  /** Load agent definitions from agents/ directory if present. */
5490
5817
  loadAgents(pluginDir) {
5491
5818
  const agentsDir = (0, import_node_path11.join)(pluginDir, "agents");
5492
5819
  if (!(0, import_node_fs9.existsSync)(agentsDir)) return [];
5493
- try {
5494
- const entries = (0, import_node_fs9.readdirSync)(agentsDir, { withFileTypes: true });
5495
- return entries.filter((e) => e.isDirectory() || e.name.endsWith(".md")).map((e) => e.name.replace(/\.md$/, ""));
5496
- } catch {
5497
- return [];
5498
- }
5820
+ const entries = (0, import_node_fs9.readdirSync)(agentsDir, { withFileTypes: true });
5821
+ return entries.filter((e) => e.isDirectory() || e.name.endsWith(".md")).map((e) => e.name.replace(/\.md$/, ""));
5499
5822
  }
5500
5823
  };
5501
5824
 
@@ -5939,8 +6262,8 @@ var MarketplaceClient = class {
5939
6262
  }
5940
6263
  }
5941
6264
  /** Read and parse a marketplace.json from a file path. */
5942
- readManifestFromPath(path) {
5943
- const raw = (0, import_node_fs12.readFileSync)(path, "utf-8");
6265
+ readManifestFromPath(path3) {
6266
+ const raw = (0, import_node_fs12.readFileSync)(path3, "utf-8");
5944
6267
  const data = JSON.parse(raw);
5945
6268
  if (typeof data !== "object" || data === null) {
5946
6269
  throw new Error("Invalid marketplace manifest: not an object");
@@ -6032,18 +6355,18 @@ async function createInteractiveSession(options) {
6032
6355
  options.bare ? Promise.resolve({ agentsMd: "", claudeMd: "" }) : loadContext(cwd),
6033
6356
  options.bare ? Promise.resolve({ type: "unknown", language: "unknown" }) : detectProject(cwd)
6034
6357
  ]);
6358
+ let mergedConfig = options.language ? { ...config, language: options.language } : config;
6035
6359
  const pluginsDir = (0, import_node_path16.join)((0, import_node_os5.homedir)(), ".robota", "plugins");
6036
6360
  const pluginLoader = new BundlePluginLoader(pluginsDir);
6037
- let mergedConfig = config;
6038
6361
  if (!options.bare) {
6039
6362
  try {
6040
6363
  const plugins = pluginLoader.loadPluginsSync();
6041
6364
  if (plugins.length > 0) {
6042
6365
  const pluginHooks = mergePluginHooks(plugins);
6043
6366
  mergedConfig = {
6044
- ...config,
6367
+ ...mergedConfig,
6045
6368
  hooks: mergeHooksIntoConfig(
6046
- config.hooks,
6369
+ mergedConfig.hooks,
6047
6370
  pluginHooks
6048
6371
  )
6049
6372
  };
@@ -6211,8 +6534,8 @@ function isRestoredTerminalStatus(status) {
6211
6534
  }
6212
6535
 
6213
6536
  // src/interactive/interactive-session-context-references.ts
6214
- async function addInteractiveContextReference(references, path, cwd) {
6215
- const result = await resolvePromptFileReferencePaths([path], {
6537
+ async function addInteractiveContextReference(references, path3, cwd) {
6538
+ const result = await resolvePromptFileReferencePaths([path3], {
6216
6539
  cwd,
6217
6540
  reason: "manual"
6218
6541
  });
@@ -6305,9 +6628,9 @@ function toInspectionPlan(manifests) {
6305
6628
  fileCount: manifests.reduce((count, manifest) => count + manifest.fileCount, 0)
6306
6629
  };
6307
6630
  }
6308
- function statSafe(path) {
6631
+ function statSafe(path3) {
6309
6632
  try {
6310
- return (0, import_node_fs13.statSync)(path);
6633
+ return (0, import_node_fs13.statSync)(path3);
6311
6634
  } catch {
6312
6635
  return void 0;
6313
6636
  }
@@ -6478,10 +6801,10 @@ var EditCheckpointStore = class {
6478
6801
  }
6479
6802
  async writeManifest(dir, manifest) {
6480
6803
  await (0, import_promises2.mkdir)(dir, { recursive: true });
6481
- const path = (0, import_node_path18.join)(dir, MANIFEST_FILE);
6482
- const tmp = `${path}.tmp`;
6804
+ const path3 = (0, import_node_path18.join)(dir, MANIFEST_FILE);
6805
+ const tmp = `${path3}.tmp`;
6483
6806
  await (0, import_promises2.writeFile)(tmp, JSON.stringify(manifest, null, 2), "utf8");
6484
- await (0, import_promises2.rename)(tmp, path);
6807
+ await (0, import_promises2.rename)(tmp, path3);
6485
6808
  }
6486
6809
  sessionDir(sessionId) {
6487
6810
  return (0, import_node_path18.join)(this.rootDir, safePathSegment(sessionId));
@@ -6507,9 +6830,9 @@ function isInside(parent, child) {
6507
6830
  const rel = (0, import_node_path18.relative)(parent, child);
6508
6831
  return rel.length === 0 || !rel.startsWith("..") && !rel.startsWith("/");
6509
6832
  }
6510
- async function pathExists(path) {
6833
+ async function pathExists(path3) {
6511
6834
  try {
6512
- await (0, import_promises2.access)(path, import_node_fs14.constants.F_OK);
6835
+ await (0, import_promises2.access)(path3, import_node_fs14.constants.F_OK);
6513
6836
  return true;
6514
6837
  } catch {
6515
6838
  return false;
@@ -6522,9 +6845,9 @@ function readDirSyncSafe(dir) {
6522
6845
  return [];
6523
6846
  }
6524
6847
  }
6525
- function readJsonManifest(path) {
6848
+ function readJsonManifest(path3) {
6526
6849
  try {
6527
- const raw = (0, import_node_fs14.readFileSync)(path, "utf8");
6850
+ const raw = (0, import_node_fs14.readFileSync)(path3, "utf8");
6528
6851
  return JSON.parse(raw);
6529
6852
  } catch {
6530
6853
  return void 0;
@@ -6547,6 +6870,11 @@ function getQualifiedSkillName(rawInput) {
6547
6870
  const firstToken = rawInput.slice(1).trim().split(/\s+/)[0];
6548
6871
  return firstToken && firstToken.length > 0 ? firstToken : void 0;
6549
6872
  }
6873
+ function getBackgroundTaskEventEntryId(event) {
6874
+ if ("task" in event) return createBackgroundTaskExecutionEntryId(event.task.id);
6875
+ if ("taskId" in event) return createBackgroundTaskExecutionEntryId(event.taskId);
6876
+ return void 0;
6877
+ }
6550
6878
  var InteractiveSession = class {
6551
6879
  session = null;
6552
6880
  commandExecutor;
@@ -6664,6 +6992,7 @@ var InteractiveSession = class {
6664
6992
  bare: options.bare,
6665
6993
  allowedTools: options.allowedTools,
6666
6994
  appendSystemPrompt: options.appendSystemPrompt,
6995
+ language: options.language,
6667
6996
  backgroundTaskRunners: options.backgroundTaskRunners,
6668
6997
  subagentRunnerFactory: options.subagentRunnerFactory,
6669
6998
  ...options.commandModules ? { commandModules: options.commandModules } : {},
@@ -6695,6 +7024,9 @@ var InteractiveSession = class {
6695
7024
  throw new Error("InteractiveSession not initialized. Call submit() or await initialization.");
6696
7025
  return this.session;
6697
7026
  }
7027
+ get sessionId() {
7028
+ return this.session?.getSessionId() ?? "";
7029
+ }
6698
7030
  on(event, handler) {
6699
7031
  if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
6700
7032
  this.listeners.get(event).add(handler);
@@ -6906,6 +7238,9 @@ var InteractiveSession = class {
6906
7238
  getActiveTools() {
6907
7239
  return this.activeTools;
6908
7240
  }
7241
+ get isInitialized() {
7242
+ return this.initialized;
7243
+ }
6909
7244
  getContextState() {
6910
7245
  return this.getSessionOrThrow().getContextState();
6911
7246
  }
@@ -6990,18 +7325,18 @@ var InteractiveSession = class {
6990
7325
  listContextReferences() {
6991
7326
  return [...this.contextReferences];
6992
7327
  }
6993
- async addContextReference(path) {
7328
+ async addContextReference(path3) {
6994
7329
  const { references, result } = await addInteractiveContextReference(
6995
7330
  this.contextReferences,
6996
- path,
7331
+ path3,
6997
7332
  this.getCwd()
6998
7333
  );
6999
7334
  this.contextReferences = references;
7000
7335
  this.persistCurrentSession();
7001
7336
  return result;
7002
7337
  }
7003
- removeContextReference(path) {
7004
- const result = removeContextReference(this.contextReferences, path);
7338
+ removeContextReference(path3) {
7339
+ const result = removeContextReference(this.contextReferences, path3);
7005
7340
  this.contextReferences = result.references;
7006
7341
  this.persistCurrentSession();
7007
7342
  return result.result;
@@ -7051,6 +7386,53 @@ var InteractiveSession = class {
7051
7386
  await this.ensureInitialized();
7052
7387
  return this.getBackgroundJobOrchestratorOrThrow().waitGroup(groupId);
7053
7388
  }
7389
+ getExecutionWorkspaceSnapshot(options = {}) {
7390
+ const session = this.getSessionOrThrow();
7391
+ const sessionId = session.getSessionId();
7392
+ return createExecutionWorkspaceSnapshot({
7393
+ sessionId,
7394
+ mainThread: {
7395
+ sessionId,
7396
+ isExecuting: this.executing,
7397
+ hasPendingPrompt: this.pendingPrompt !== null,
7398
+ historyLength: this.history.length,
7399
+ updatedAt: this.getMainThreadUpdatedAt(),
7400
+ preview: this.getMainThreadPreview()
7401
+ },
7402
+ tasks: this.getBackgroundTaskSnapshots(),
7403
+ groups: this.getBackgroundJobGroupSnapshots(),
7404
+ selectedEntryId: options.selectedEntryId,
7405
+ filter: options.filter
7406
+ });
7407
+ }
7408
+ listExecutionWorkspaceEntries(filter) {
7409
+ return [...this.getExecutionWorkspaceSnapshot({ filter }).entries];
7410
+ }
7411
+ getExecutionWorkspaceEntry(entryId) {
7412
+ return this.getExecutionWorkspaceSnapshot().entries.find((entry) => entry.id === entryId);
7413
+ }
7414
+ async readExecutionWorkspaceDetail(entryId, cursor) {
7415
+ await this.ensureInitialized();
7416
+ const entryRef = parseExecutionWorkspaceEntryId(entryId);
7417
+ if (!entryRef) throw new Error(`Unknown execution workspace entry: ${entryId}`);
7418
+ if (entryRef.kind === "main_thread") {
7419
+ return createMainThreadDetailPage({ entryId, history: this.history, cursor });
7420
+ }
7421
+ if (entryRef.kind === "background_group") {
7422
+ return this.readBackgroundGroupDetail(entryId, entryRef.sourceId);
7423
+ }
7424
+ return this.readBackgroundTaskDetail(entryId, entryRef.sourceId, cursor);
7425
+ }
7426
+ createExecutionWorkspaceTaskSpawner(origin) {
7427
+ const sessionId = this.getSessionOrThrow().getSessionId();
7428
+ return createExecutionWorkspaceTaskSpawner({
7429
+ manager: this.getBackgroundTaskManagerOrThrow(),
7430
+ groupOrchestrator: this.getBackgroundJobOrchestratorOrThrow(),
7431
+ sessionId,
7432
+ cwd: this.getCwd(),
7433
+ origin: { ...origin, sessionId: origin.sessionId || sessionId }
7434
+ });
7435
+ }
7054
7436
  listAgentDefinitions() {
7055
7437
  const deps = retrieveAgentToolDeps(this.getSessionOrThrow());
7056
7438
  return (deps?.agentDefinitions ?? []).map((agent) => ({
@@ -7065,10 +7447,11 @@ var InteractiveSession = class {
7065
7447
  await this.ensureInitialized();
7066
7448
  const deps = this.getAgentToolDepsOrThrow();
7067
7449
  const definition = this.resolveAgentDefinition(input.agentType, deps);
7450
+ const sessionId = this.getSessionOrThrow().getSessionId();
7068
7451
  return this.getSubagentManagerOrThrow().spawn({
7069
7452
  type: input.agentType,
7070
7453
  label: input.label,
7071
- parentSessionId: this.getSessionOrThrow().getSessionId(),
7454
+ parentSessionId: sessionId,
7072
7455
  mode: input.mode,
7073
7456
  depth: (deps.subagentDepth ?? 0) + 1,
7074
7457
  cwd: deps.cwd ?? this.cwd ?? process.cwd(),
@@ -7076,7 +7459,13 @@ var InteractiveSession = class {
7076
7459
  model: input.model ?? definition.model,
7077
7460
  isolation: input.isolation,
7078
7461
  allowedTools: definition.tools,
7079
- disallowedTools: definition.disallowedTools
7462
+ disallowedTools: definition.disallowedTools,
7463
+ metadata: createExecutionOriginMetadata({
7464
+ kind: this.commandInvocationSource === "model" ? "model_command" : "slash_command",
7465
+ sessionId,
7466
+ commandName: "agent",
7467
+ label: input.label
7468
+ })
7080
7469
  });
7081
7470
  }
7082
7471
  async waitAgentJob(jobId) {
@@ -7179,6 +7568,51 @@ var InteractiveSession = class {
7179
7568
  this.finishForkSkillExecution();
7180
7569
  }
7181
7570
  }
7571
+ async readBackgroundTaskDetail(entryId, taskId, cursor) {
7572
+ const task = this.getBackgroundTaskManagerOrThrow().get(taskId);
7573
+ if (!task) throw new Error(`Unknown background task: ${taskId}`);
7574
+ if (task.logPath || task.transcriptPath) {
7575
+ const page = await this.getBackgroundTaskManagerOrThrow().readLog(taskId, cursor);
7576
+ return createLineDetailPage({
7577
+ entryId,
7578
+ lines: page.lines,
7579
+ cursor: page.cursor,
7580
+ nextCursor: page.nextCursor,
7581
+ kind: task.kind === "process" ? "process_output" : "progress"
7582
+ });
7583
+ }
7584
+ const detailKind = task.status === "failed" ? "error" : task.status === "completed" ? "result" : "progress";
7585
+ const text = task.error?.message ?? task.result?.output ?? task.currentAction ?? task.promptPreview ?? task.commandPreview ?? task.status;
7586
+ return createLineDetailPage({ entryId, lines: [text], cursor, kind: detailKind });
7587
+ }
7588
+ readBackgroundGroupDetail(entryId, groupId) {
7589
+ const group = this.getBackgroundJobOrchestratorOrThrow().getGroup(groupId);
7590
+ if (!group) throw new Error(`Unknown background job group: ${groupId}`);
7591
+ const summary = summarizeBackgroundJobGroup(group);
7592
+ return createLineDetailPage({
7593
+ entryId,
7594
+ lines: summary.lines,
7595
+ kind: "group_summary"
7596
+ });
7597
+ }
7598
+ getMainThreadUpdatedAt() {
7599
+ return this.history.at(-1)?.timestamp.toISOString() ?? (/* @__PURE__ */ new Date(0)).toISOString();
7600
+ }
7601
+ getMainThreadPreview() {
7602
+ if (this.streamingText.trim().length > 0) return this.streamingText;
7603
+ const latest = this.history.at(-1);
7604
+ if (!latest) return void 0;
7605
+ return latest.type;
7606
+ }
7607
+ emitExecutionWorkspaceUpdated(cause, entryId) {
7608
+ if (!this.session) return;
7609
+ this.emit("execution_workspace_event", {
7610
+ type: "execution_workspace_updated",
7611
+ cause,
7612
+ ...entryId ? { entryId } : {},
7613
+ snapshot: this.getExecutionWorkspaceSnapshot()
7614
+ });
7615
+ }
7182
7616
  getBackgroundTaskManagerOrThrow() {
7183
7617
  const manager = this.getBackgroundTaskManager();
7184
7618
  if (!manager) {
@@ -7244,11 +7678,16 @@ var InteractiveSession = class {
7244
7678
  this.backgroundTasks = this.getBackgroundTaskSnapshots();
7245
7679
  this.backgroundTaskEvents.push(event);
7246
7680
  this.persistCurrentSession();
7681
+ this.emitExecutionWorkspaceUpdated("background_task", getBackgroundTaskEventEntryId(event));
7247
7682
  }
7248
7683
  recordBackgroundJobGroupEvent(event) {
7249
7684
  this.backgroundJobGroups = this.getBackgroundJobGroupSnapshots();
7250
7685
  this.backgroundJobGroupEvents.push(event);
7251
7686
  this.persistCurrentSession();
7687
+ this.emitExecutionWorkspaceUpdated(
7688
+ "background_group",
7689
+ createBackgroundGroupExecutionEntryId(event.group.id)
7690
+ );
7252
7691
  }
7253
7692
  getBackgroundTaskSnapshots() {
7254
7693
  try {
@@ -7312,10 +7751,12 @@ var InteractiveSession = class {
7312
7751
  this.clearStreaming();
7313
7752
  this.emit("thinking", true);
7314
7753
  this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createUserMessage)(displayInput)));
7754
+ this.emitExecutionWorkspaceUpdated("main_thread");
7315
7755
  }
7316
7756
  finishForkSkillExecution() {
7317
7757
  this.executing = false;
7318
7758
  this.emit("thinking", false);
7759
+ this.emitExecutionWorkspaceUpdated("main_thread");
7319
7760
  this.persistCurrentSession();
7320
7761
  if (!this.shuttingDown && this.pendingPrompt) {
7321
7762
  const queued = this.pendingPrompt;
@@ -7385,6 +7826,7 @@ var InteractiveSession = class {
7385
7826
  this.executing = true;
7386
7827
  this.clearStreaming();
7387
7828
  this.emit("thinking", true);
7829
+ this.emitExecutionWorkspaceUpdated("main_thread");
7388
7830
  try {
7389
7831
  const result = await this.commandExecutor.executeCommand(command, this, args);
7390
7832
  this.emit("context_update", this.getContextState());
@@ -7398,6 +7840,7 @@ var InteractiveSession = class {
7398
7840
  } finally {
7399
7841
  this.executing = false;
7400
7842
  this.emit("thinking", false);
7843
+ this.emitExecutionWorkspaceUpdated("main_thread");
7401
7844
  this.persistCurrentSession();
7402
7845
  if (!this.shuttingDown && this.pendingPrompt) {
7403
7846
  const queued = this.pendingPrompt;
@@ -7411,8 +7854,10 @@ var InteractiveSession = class {
7411
7854
  async executePrompt(input, displayInput, rawInput) {
7412
7855
  this.executing = true;
7413
7856
  this.clearStreaming();
7857
+ this.emit("user_message", displayInput ?? input);
7414
7858
  this.emit("thinking", true);
7415
7859
  this.history.push((0, import_agent_core7.messageToHistoryEntry)((0, import_agent_core7.createUserMessage)(displayInput ?? input)));
7860
+ this.emitExecutionWorkspaceUpdated("main_thread");
7416
7861
  const historyBefore = this.getSessionOrThrow().getHistory().length;
7417
7862
  this.usedMemoryReferences = [];
7418
7863
  try {
@@ -7474,6 +7919,7 @@ var InteractiveSession = class {
7474
7919
  await this.finalizeEditCheckpointTurn();
7475
7920
  this.executing = false;
7476
7921
  this.emit("thinking", false);
7922
+ this.emitExecutionWorkspaceUpdated("main_thread");
7477
7923
  this.persistCurrentSession();
7478
7924
  if (!this.shuttingDown && this.pendingPrompt) {
7479
7925
  const queued = this.pendingPrompt;
@@ -7768,6 +8214,404 @@ function createQuery(options) {
7768
8214
  };
7769
8215
  }
7770
8216
 
8217
+ // src/user-local/storage.ts
8218
+ var import_node_fs16 = require("fs");
8219
+ var import_node_os6 = require("os");
8220
+ var import_node_path20 = __toESM(require("path"), 1);
8221
+ var USER_LOCAL_STORAGE_CATEGORIES = [
8222
+ "preferences",
8223
+ "view-state",
8224
+ "memory-projections",
8225
+ "task-associations",
8226
+ "workflow-metadata",
8227
+ "inspection-index"
8228
+ ];
8229
+ var USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS = [
8230
+ {
8231
+ category: "preferences",
8232
+ purpose: "User-local UI and display preferences.",
8233
+ mayExecuteCommands: false
8234
+ },
8235
+ {
8236
+ category: "view-state",
8237
+ purpose: "Last selected panels, filters, and navigation state.",
8238
+ mayExecuteCommands: false
8239
+ },
8240
+ {
8241
+ category: "memory-projections",
8242
+ purpose: "Inspectable local memory item projections and user choices.",
8243
+ mayExecuteCommands: false
8244
+ },
8245
+ {
8246
+ category: "task-associations",
8247
+ purpose: "User-local associations between sessions, tasks, and background items.",
8248
+ mayExecuteCommands: false
8249
+ },
8250
+ {
8251
+ category: "workflow-metadata",
8252
+ purpose: "Transparent workflow metadata that is not repo-owned.",
8253
+ mayExecuteCommands: false
8254
+ },
8255
+ {
8256
+ category: "inspection-index",
8257
+ purpose: "Category and item summaries for user inspection and deletion.",
8258
+ mayExecuteCommands: false
8259
+ }
8260
+ ];
8261
+ function formatIsoDate(date) {
8262
+ return date.toISOString();
8263
+ }
8264
+ function assertAbsolutePath(name, value) {
8265
+ if (value.trim().length === 0) {
8266
+ throw new Error(`${name} must not be empty.`);
8267
+ }
8268
+ if (!import_node_path20.default.isAbsolute(value)) {
8269
+ throw new Error(`${name} must be an absolute path: ${value}`);
8270
+ }
8271
+ }
8272
+ function resolveDefaultHomeDir() {
8273
+ return process.env.HOME ?? (0, import_node_os6.homedir)();
8274
+ }
8275
+ function isEqualOrInside(parentPath, candidatePath) {
8276
+ const relative4 = import_node_path20.default.relative(parentPath, candidatePath);
8277
+ return relative4 === "" || !relative4.startsWith("..") && !import_node_path20.default.isAbsolute(relative4);
8278
+ }
8279
+ async function resolveForComparison(absPath) {
8280
+ let current = absPath;
8281
+ while (import_node_path20.default.dirname(current) !== current) {
8282
+ try {
8283
+ const realCurrent = await import_node_fs16.promises.realpath(current);
8284
+ const relativeMissingPath = import_node_path20.default.relative(current, absPath);
8285
+ return import_node_path20.default.resolve(realCurrent, relativeMissingPath);
8286
+ } catch {
8287
+ current = import_node_path20.default.dirname(current);
8288
+ }
8289
+ }
8290
+ try {
8291
+ return await import_node_fs16.promises.realpath(current);
8292
+ } catch {
8293
+ return import_node_path20.default.resolve(absPath);
8294
+ }
8295
+ }
8296
+ async function resolveUserLocalStorageRoot(options) {
8297
+ const activeRepositoryRoot = import_node_path20.default.resolve(options.activeRepositoryRoot);
8298
+ assertAbsolutePath("activeRepositoryRoot", activeRepositoryRoot);
8299
+ const candidateRoot = options.storageRoot !== void 0 ? options.storageRoot : import_node_path20.default.join(options.homeDir ?? resolveDefaultHomeDir(), ".robota");
8300
+ assertAbsolutePath("userLocalStorageRoot", candidateRoot);
8301
+ const resolvedRoot = import_node_path20.default.resolve(candidateRoot);
8302
+ const comparableRoot = await resolveForComparison(resolvedRoot);
8303
+ const comparableRepositoryRoot = await resolveForComparison(activeRepositoryRoot);
8304
+ if (isEqualOrInside(comparableRepositoryRoot, comparableRoot)) {
8305
+ throw new Error(
8306
+ `User-local storage root must be outside the active repository: ${resolvedRoot}`
8307
+ );
8308
+ }
8309
+ return resolvedRoot;
8310
+ }
8311
+ function resolveCategoryLocation(root, category) {
8312
+ return import_node_path20.default.join(root, category);
8313
+ }
8314
+ async function listItemSummaries(root, category) {
8315
+ const storageLocation = resolveCategoryLocation(root, category);
8316
+ let entries;
8317
+ try {
8318
+ entries = await import_node_fs16.promises.readdir(storageLocation, { withFileTypes: true });
8319
+ } catch {
8320
+ return [];
8321
+ }
8322
+ const summaries = await Promise.all(
8323
+ entries.map(async (entry) => {
8324
+ const itemLocation = import_node_path20.default.join(storageLocation, entry.name);
8325
+ const stats = await import_node_fs16.promises.stat(itemLocation);
8326
+ const key = entry.name;
8327
+ return {
8328
+ root,
8329
+ category,
8330
+ key,
8331
+ summary: `${category}/${key}`,
8332
+ source: "user-local-storage",
8333
+ scope: "user",
8334
+ storageLocation: itemLocation,
8335
+ createdAt: formatIsoDate(stats.birthtime),
8336
+ lastUsedAt: formatIsoDate(stats.mtime),
8337
+ enabled: true,
8338
+ deleteAvailable: true,
8339
+ disableAvailable: false
8340
+ };
8341
+ })
8342
+ );
8343
+ return summaries.sort((left, right) => left.key.localeCompare(right.key));
8344
+ }
8345
+ async function inspectUserLocalStorage(options) {
8346
+ const root = await resolveUserLocalStorageRoot(options);
8347
+ const activeRepositoryRoot = import_node_path20.default.resolve(options.activeRepositoryRoot);
8348
+ const createDirectories = options.createDirectories ?? true;
8349
+ if (createDirectories) {
8350
+ await import_node_fs16.promises.mkdir(root, { recursive: true });
8351
+ }
8352
+ const categories = await Promise.all(
8353
+ USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS.map(
8354
+ async (definition) => {
8355
+ const storageLocation = resolveCategoryLocation(root, definition.category);
8356
+ if (createDirectories) {
8357
+ await import_node_fs16.promises.mkdir(storageLocation, { recursive: true });
8358
+ }
8359
+ const items = await listItemSummaries(root, definition.category);
8360
+ return {
8361
+ category: definition.category,
8362
+ purpose: definition.purpose,
8363
+ mayExecuteCommands: definition.mayExecuteCommands,
8364
+ storageLocation,
8365
+ itemCount: items.length,
8366
+ items
8367
+ };
8368
+ }
8369
+ )
8370
+ );
8371
+ return {
8372
+ root,
8373
+ activeRepositoryRoot,
8374
+ categories,
8375
+ generatedAt: formatIsoDate((options.now ?? (() => /* @__PURE__ */ new Date()))())
8376
+ };
8377
+ }
8378
+
8379
+ // src/user-local/memory.ts
8380
+ var import_node_fs17 = require("fs");
8381
+ var import_node_path21 = __toESM(require("path"), 1);
8382
+
8383
+ // src/user-local/memory-types.ts
8384
+ var USER_LOCAL_MEMORY_CATEGORIES = [
8385
+ "view-preference",
8386
+ "last-visible-cwd",
8387
+ "background-selection",
8388
+ "task-association",
8389
+ "display-preference",
8390
+ "inspection-choice"
8391
+ ];
8392
+
8393
+ // src/user-local/memory.ts
8394
+ var MEMORY_STORAGE_CATEGORY = "memory-projections";
8395
+ var FILE_EXTENSION = ".json";
8396
+ var MEMORY_SCHEMA_VERSION = 1;
8397
+ var MAX_SEGMENT_LENGTH = 80;
8398
+ var MAX_SUMMARY_LENGTH = 240;
8399
+ var MAX_SOURCE_LENGTH = 80;
8400
+ var MAX_SCOPE_LENGTH = 120;
8401
+ var MAX_VALUE_SUMMARY_LENGTH = 240;
8402
+ var DEFAULT_SCOPE = "user";
8403
+ var SAFE_SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/u;
8404
+ var DISPLAY_NAVIGATION_RULES = {
8405
+ "view-preference": "May affect UI panel, filter, density, or sorting display/navigation only.",
8406
+ "last-visible-cwd": "May display or preselect an already visible workspace context only.",
8407
+ "background-selection": "May restore the selected background entry in local UI only.",
8408
+ "task-association": "May group visible tasks by a local association only.",
8409
+ "display-preference": "May affect local text wrapping, compactness, or visibility only.",
8410
+ "inspection-choice": "May affect inspection display choices only."
8411
+ };
8412
+ function formatIsoDate2(date) {
8413
+ return date.toISOString();
8414
+ }
8415
+ function isUserLocalMemoryCategory(value) {
8416
+ return USER_LOCAL_MEMORY_CATEGORIES.includes(value);
8417
+ }
8418
+ function assertUserLocalMemoryCategory(value) {
8419
+ if (!isUserLocalMemoryCategory(value)) {
8420
+ throw new Error(`Unsupported user-local memory category: ${value}`);
8421
+ }
8422
+ return value;
8423
+ }
8424
+ function assertSafeSegment(name, value) {
8425
+ const trimmed = value.trim();
8426
+ if (trimmed.length === 0) {
8427
+ throw new Error(`${name} must not be empty.`);
8428
+ }
8429
+ if (trimmed.length > MAX_SEGMENT_LENGTH || !SAFE_SEGMENT_PATTERN.test(trimmed)) {
8430
+ throw new Error(
8431
+ `${name} must use lowercase letters, numbers, dots, underscores, or hyphens: ${value}`
8432
+ );
8433
+ }
8434
+ return trimmed;
8435
+ }
8436
+ function boundedText(name, value, maxLength) {
8437
+ const normalized = value.trim().replace(/\s+/g, " ");
8438
+ if (normalized.length === 0) {
8439
+ throw new Error(`${name} must not be empty.`);
8440
+ }
8441
+ if (normalized.length > maxLength) {
8442
+ return normalized.slice(0, maxLength);
8443
+ }
8444
+ return normalized;
8445
+ }
8446
+ function summarizeValue(value) {
8447
+ return boundedText("value", value, MAX_VALUE_SUMMARY_LENGTH);
8448
+ }
8449
+ function memoryFileName(category, key) {
8450
+ return `${category}__${key}${FILE_EXTENSION}`;
8451
+ }
8452
+ async function resolveMemoryRoot(options) {
8453
+ const root = await resolveUserLocalStorageRoot(options);
8454
+ return {
8455
+ root,
8456
+ memoryRoot: import_node_path21.default.join(root, MEMORY_STORAGE_CATEGORY)
8457
+ };
8458
+ }
8459
+ function parseMemoryRecord(raw, storageLocation) {
8460
+ const record = JSON.parse(raw);
8461
+ const category = readString(record, "category");
8462
+ const schemaVersion = record["schemaVersion"];
8463
+ if (schemaVersion !== MEMORY_SCHEMA_VERSION) {
8464
+ throw new Error(`Unsupported user-local memory schema at ${storageLocation}`);
8465
+ }
8466
+ return {
8467
+ schemaVersion: MEMORY_SCHEMA_VERSION,
8468
+ category: assertUserLocalMemoryCategory(category),
8469
+ key: readString(record, "key"),
8470
+ value: readString(record, "value"),
8471
+ summary: readString(record, "summary"),
8472
+ source: readString(record, "source"),
8473
+ scope: readString(record, "scope"),
8474
+ createdAt: readString(record, "createdAt"),
8475
+ lastUsedAt: readString(record, "lastUsedAt"),
8476
+ enabled: readBoolean(record, "enabled")
8477
+ };
8478
+ }
8479
+ function readString(record, key) {
8480
+ const value = record[key];
8481
+ if (typeof value !== "string") {
8482
+ throw new Error(`Invalid user-local memory field: ${key}`);
8483
+ }
8484
+ return value;
8485
+ }
8486
+ function readBoolean(record, key) {
8487
+ const value = record[key];
8488
+ if (typeof value !== "boolean") {
8489
+ throw new Error(`Invalid user-local memory field: ${key}`);
8490
+ }
8491
+ return value;
8492
+ }
8493
+ function projectMemoryItem(root, storageLocation, item) {
8494
+ return {
8495
+ root,
8496
+ category: item.category,
8497
+ key: item.key,
8498
+ summary: item.summary,
8499
+ valueSummary: summarizeValue(item.value),
8500
+ source: item.source,
8501
+ scope: item.scope,
8502
+ storageLocation,
8503
+ createdAt: item.createdAt,
8504
+ lastUsedAt: item.lastUsedAt,
8505
+ enabled: item.enabled,
8506
+ displayNavigationRule: DISPLAY_NAVIGATION_RULES[item.category],
8507
+ commandExecutionEffect: "none",
8508
+ deleteAvailable: true,
8509
+ disableAvailable: true
8510
+ };
8511
+ }
8512
+ async function readMemoryFile(root, storageLocation) {
8513
+ return projectMemoryItem(
8514
+ root,
8515
+ storageLocation,
8516
+ parseMemoryRecord(await import_node_fs17.promises.readFile(storageLocation, "utf8"), storageLocation)
8517
+ );
8518
+ }
8519
+ async function resolveMemoryFile(options) {
8520
+ const category = assertUserLocalMemoryCategory(options.category);
8521
+ const key = assertSafeSegment("key", options.key);
8522
+ const { root, memoryRoot: memoryRoot3 } = await resolveMemoryRoot(options);
8523
+ return {
8524
+ root,
8525
+ storageLocation: import_node_path21.default.join(memoryRoot3, memoryFileName(category, key))
8526
+ };
8527
+ }
8528
+ async function setUserLocalMemoryItem(options) {
8529
+ const category = assertUserLocalMemoryCategory(options.category);
8530
+ const key = assertSafeSegment("key", options.key);
8531
+ const summary = boundedText("summary", options.summary, MAX_SUMMARY_LENGTH);
8532
+ const source = boundedText("source", options.source, MAX_SOURCE_LENGTH);
8533
+ const scope = boundedText("scope", options.scope ?? DEFAULT_SCOPE, MAX_SCOPE_LENGTH);
8534
+ const value = summarizeValue(options.value);
8535
+ const now = formatIsoDate2((options.now ?? (() => /* @__PURE__ */ new Date()))());
8536
+ const { root, memoryRoot: memoryRoot3 } = await resolveMemoryRoot(options);
8537
+ const storageLocation = import_node_path21.default.join(memoryRoot3, memoryFileName(category, key));
8538
+ let createdAt = now;
8539
+ try {
8540
+ const existing = parseMemoryRecord(await import_node_fs17.promises.readFile(storageLocation, "utf8"), storageLocation);
8541
+ createdAt = existing.createdAt;
8542
+ } catch (error) {
8543
+ if (error instanceof Error && error.message.includes("ENOENT")) {
8544
+ createdAt = now;
8545
+ } else {
8546
+ throw error;
8547
+ }
8548
+ }
8549
+ const item = {
8550
+ schemaVersion: MEMORY_SCHEMA_VERSION,
8551
+ category,
8552
+ key,
8553
+ value,
8554
+ summary,
8555
+ source,
8556
+ scope,
8557
+ createdAt,
8558
+ lastUsedAt: now,
8559
+ enabled: true
8560
+ };
8561
+ await import_node_fs17.promises.mkdir(memoryRoot3, { recursive: true });
8562
+ await import_node_fs17.promises.writeFile(storageLocation, `${JSON.stringify(item, null, 2)}
8563
+ `, "utf8");
8564
+ return projectMemoryItem(root, storageLocation, item);
8565
+ }
8566
+ async function listUserLocalMemoryItems(options) {
8567
+ const { root, memoryRoot: memoryRoot3 } = await resolveMemoryRoot(options);
8568
+ let entries;
8569
+ try {
8570
+ entries = await import_node_fs17.promises.readdir(memoryRoot3, { withFileTypes: true });
8571
+ } catch {
8572
+ entries = [];
8573
+ }
8574
+ const items = await Promise.all(
8575
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(FILE_EXTENSION)).map((entry) => readMemoryFile(root, import_node_path21.default.join(memoryRoot3, entry.name)))
8576
+ );
8577
+ return {
8578
+ root,
8579
+ activeRepositoryRoot: import_node_path21.default.resolve(options.activeRepositoryRoot),
8580
+ items: items.sort(
8581
+ (left, right) => `${left.category}/${left.key}`.localeCompare(`${right.category}/${right.key}`)
8582
+ )
8583
+ };
8584
+ }
8585
+ async function inspectUserLocalMemoryItem(options) {
8586
+ const { root, storageLocation } = await resolveMemoryFile(options);
8587
+ return readMemoryFile(root, storageLocation);
8588
+ }
8589
+ async function disableUserLocalMemoryItem(options) {
8590
+ const { root, storageLocation } = await resolveMemoryFile(options);
8591
+ const existing = parseMemoryRecord(await import_node_fs17.promises.readFile(storageLocation, "utf8"), storageLocation);
8592
+ const disabled = {
8593
+ ...existing,
8594
+ enabled: false,
8595
+ lastUsedAt: formatIsoDate2((options.now ?? (() => /* @__PURE__ */ new Date()))())
8596
+ };
8597
+ await import_node_fs17.promises.writeFile(storageLocation, `${JSON.stringify(disabled, null, 2)}
8598
+ `, "utf8");
8599
+ return projectMemoryItem(root, storageLocation, disabled);
8600
+ }
8601
+ async function deleteUserLocalMemoryItem(options) {
8602
+ const { storageLocation } = await resolveMemoryFile(options);
8603
+ await import_node_fs17.promises.rm(storageLocation);
8604
+ return {
8605
+ category: options.category,
8606
+ key: options.key,
8607
+ deleted: true
8608
+ };
8609
+ }
8610
+ async function readEnabledUserLocalMemoryItem(options) {
8611
+ const item = await inspectUserLocalMemoryItem(options);
8612
+ return item.enabled ? item : null;
8613
+ }
8614
+
7771
8615
  // src/self-hosting/self-hosting-verification.ts
7772
8616
  var DEFAULT_BASE_REF = "origin/develop";
7773
8617
  var PACKAGE_VERIFY_COMMANDS = ["test", "typecheck", "build"];
@@ -7946,8 +8790,8 @@ function createCommandExecutionTool(deps) {
7946
8790
  }
7947
8791
 
7948
8792
  // src/subagents/index.ts
7949
- var import_agent_runtime7 = require("@robota-sdk/agent-runtime");
7950
8793
  var import_agent_runtime8 = require("@robota-sdk/agent-runtime");
8794
+ var import_agent_runtime9 = require("@robota-sdk/agent-runtime");
7951
8795
 
7952
8796
  // src/permissions/permission-prompt.ts
7953
8797
  var import_chalk = __toESM(require("chalk"), 1);
@@ -7987,6 +8831,7 @@ async function promptForApproval(terminal, toolName, toolArgs) {
7987
8831
  DEFAULT_AUTO_COMPACT_THRESHOLD,
7988
8832
  DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE,
7989
8833
  DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
8834
+ EXECUTION_ORIGIN_METADATA_KEYS,
7990
8835
  EXIT_COMMAND_DESCRIPTION,
7991
8836
  EditCheckpointStore,
7992
8837
  HELP_COMMAND_DESCRIPTION,
@@ -8024,6 +8869,9 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8024
8869
  SkillCommandSource,
8025
8870
  SubagentManager,
8026
8871
  SystemCommandExecutor,
8872
+ USER_LOCAL_MEMORY_CATEGORIES,
8873
+ USER_LOCAL_STORAGE_CATEGORIES,
8874
+ USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS,
8027
8875
  VALIDATE_SESSION_COMMAND_DESCRIPTION,
8028
8876
  VALID_PERMISSION_MODES,
8029
8877
  WorktreeSubagentRunner,
@@ -8048,7 +8896,9 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8048
8896
  closeCommandBackgroundTask,
8049
8897
  compactCommandContext,
8050
8898
  createAgentTool,
8899
+ createBackgroundGroupExecutionEntryId,
8051
8900
  createBackgroundProcessTool,
8901
+ createBackgroundTaskExecutionEntryId,
8052
8902
  createBackgroundTaskLogPage,
8053
8903
  createBuiltinCommandModule,
8054
8904
  createCommandExecutionTool,
@@ -8057,7 +8907,13 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8057
8907
  createCommandProjectMemoryStore,
8058
8908
  createContextReferenceItem,
8059
8909
  createDefaultTools,
8910
+ createExecutionOriginMetadata,
8911
+ createExecutionWorkspaceSnapshot,
8912
+ createExecutionWorkspaceTaskSpawner,
8060
8913
  createLimitedOutputCapture,
8914
+ createLineDetailPage,
8915
+ createMainThreadDetailPage,
8916
+ createMainThreadExecutionEntryId,
8061
8917
  createModelCommandToolProjection,
8062
8918
  createPluginRegistryReloadRequestedEffect,
8063
8919
  createPluginTuiRequestedEffect,
@@ -8075,6 +8931,8 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8075
8931
  createSystemCommands,
8076
8932
  createWorktreeSubagentRunner,
8077
8933
  deleteProviderProfile,
8934
+ deleteUserLocalMemoryItem,
8935
+ disableUserLocalMemoryItem,
8078
8936
  discoverTaskFiles,
8079
8937
  evaluateReversibleToolSafety,
8080
8938
  executeSkill,
@@ -8104,6 +8962,8 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8104
8962
  hasSensitiveCommandMemoryContent,
8105
8963
  hasUsableSecretReference,
8106
8964
  inspectCommandEditCheckpoint,
8965
+ inspectUserLocalMemoryItem,
8966
+ inspectUserLocalStorage,
8107
8967
  isCommandMemoryType,
8108
8968
  isEnvReference,
8109
8969
  isMemoryType,
@@ -8117,10 +8977,12 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8117
8977
  listCommandSessionAllowedTools,
8118
8978
  listCommandUsedMemoryReferences,
8119
8979
  listResumableSessionSummaries,
8980
+ listUserLocalMemoryItems,
8120
8981
  loadTaskContext,
8121
8982
  mergeProviderPatch,
8122
8983
  normalizeModelCommandName,
8123
8984
  parseCommandBackgroundLogCursor,
8985
+ parseExecutionWorkspaceEntryId,
8124
8986
  parseFrontmatter,
8125
8987
  parseLanguageArgument,
8126
8988
  parsePermissionModeArgument,
@@ -8140,6 +9002,7 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8140
9002
  readCommandPermissionsState,
8141
9003
  readCommandSessionInfo,
8142
9004
  readCurrentGitBranch,
9005
+ readEnabledUserLocalMemoryItem,
8143
9006
  recordCommandMemoryEvent,
8144
9007
  removeCommandContextReference,
8145
9008
  removeContextReference,
@@ -8155,6 +9018,7 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8155
9018
  resolveProviderSetupSelection,
8156
9019
  resolveSessionIdByIdOrName,
8157
9020
  resolveSubagentLogDir,
9021
+ resolveUserLocalStorageRoot,
8158
9022
  restoreCommandEditCheckpoint,
8159
9023
  retrieveAgentToolDeps,
8160
9024
  rollbackCommandEditCheckpoint,
@@ -8163,6 +9027,7 @@ async function promptForApproval(terminal, toolName, toolArgs) {
8163
9027
  selectRelevantTasks,
8164
9028
  setCommandAutoCompactThreshold,
8165
9029
  setCurrentProvider,
9030
+ setUserLocalMemoryItem,
8166
9031
  storeAgentToolDeps,
8167
9032
  submitProviderSetupValue,
8168
9033
  substituteVariables,