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

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.
@@ -541,17 +541,17 @@ async function compactCommandContext(context, instructions) {
541
541
  function listCommandContextReferences(context) {
542
542
  return context.listContextReferences?.() ?? [];
543
543
  }
544
- async function addCommandContextReference(context, path) {
544
+ async function addCommandContextReference(context, path3) {
545
545
  if (!context.addContextReference) {
546
546
  return {
547
547
  evicted: [],
548
548
  diagnostics: ["Command host does not support context reference additions."]
549
549
  };
550
550
  }
551
- return context.addContextReference(path);
551
+ return context.addContextReference(path3);
552
552
  }
553
- function removeCommandContextReference(context, path) {
554
- return context.removeContextReference?.(path) ?? {};
553
+ function removeCommandContextReference(context, path3) {
554
+ return context.removeContextReference?.(path3) ?? {};
555
555
  }
556
556
  function clearCommandContextReferences(context) {
557
557
  return context.clearContextReferences?.() ?? { removed: [] };
@@ -1461,17 +1461,17 @@ var ProjectMemoryStore = class {
1461
1461
  return join5(memoryRoot2(this.cwd), TOPICS_DIRNAME);
1462
1462
  }
1463
1463
  loadStartupMemory() {
1464
- const path = this.getIndexPath();
1465
- if (!existsSync3(path)) {
1466
- return { content: "", path, lineCount: 0, truncated: false };
1464
+ const path3 = this.getIndexPath();
1465
+ if (!existsSync3(path3)) {
1466
+ return { content: "", path: path3, lineCount: 0, truncated: false };
1467
1467
  }
1468
- const raw = readFileSync3(path, "utf8");
1468
+ const raw = readFileSync3(path3, "utf8");
1469
1469
  const byBytes = truncateToUtf8Bytes(raw, MEMORY_INDEX_MAX_BYTES);
1470
1470
  const byteTruncated = Buffer.byteLength(raw, "utf8") > MEMORY_INDEX_MAX_BYTES;
1471
1471
  const byLines = limitLines(byBytes, MEMORY_INDEX_MAX_LINES);
1472
1472
  return {
1473
1473
  content: byLines.content,
1474
- path,
1474
+ path: path3,
1475
1475
  lineCount: byLines.content.length === 0 ? 0 : byLines.content.split(/\r?\n/).length,
1476
1476
  truncated: byteTruncated || byLines.truncated
1477
1477
  };
@@ -1490,9 +1490,9 @@ var ProjectMemoryStore = class {
1490
1490
  }
1491
1491
  readTopic(topic) {
1492
1492
  const normalized = sanitizeTopic(topic);
1493
- const path = join5(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1494
- if (!existsSync3(path)) return "";
1495
- return readFileSync3(path, "utf8").trimEnd();
1493
+ const path3 = join5(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
1494
+ if (!existsSync3(path3)) return "";
1495
+ return readFileSync3(path3, "utf8").trimEnd();
1496
1496
  }
1497
1497
  append(input) {
1498
1498
  const topic = sanitizeTopic(input.topic);
@@ -2050,6 +2050,516 @@ function createInProcessSubagentRunner(deps) {
2050
2050
  };
2051
2051
  }
2052
2052
 
2053
+ // src/background-tasks/index.ts
2054
+ import { BackgroundTaskManager } from "@robota-sdk/agent-runtime";
2055
+
2056
+ // src/background-tasks/background-job-orchestrator.ts
2057
+ import {
2058
+ isTerminalBackgroundTaskStatus
2059
+ } from "@robota-sdk/agent-runtime";
2060
+ var DEFAULT_SUMMARY_LENGTH = 1e3;
2061
+ var BackgroundJobOrchestrator = class {
2062
+ manager;
2063
+ now;
2064
+ idFactory;
2065
+ unsubscribeManager;
2066
+ listeners = /* @__PURE__ */ new Set();
2067
+ groups = /* @__PURE__ */ new Map();
2068
+ sequence = 0;
2069
+ constructor(options) {
2070
+ this.manager = options.manager;
2071
+ this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
2072
+ this.idFactory = options.idFactory ?? (() => this.nextGroupId());
2073
+ this.sequence = options.initialGroups?.length ?? 0;
2074
+ for (const group of options.initialGroups ?? []) this.restoreGroup(group);
2075
+ this.unsubscribeManager = this.manager.subscribe((event) => this.handleTaskEvent(event));
2076
+ }
2077
+ createGroup(request) {
2078
+ const now = this.now();
2079
+ const state = {
2080
+ id: this.idFactory(request),
2081
+ parentSessionId: request.parentSessionId,
2082
+ waitPolicy: request.waitPolicy,
2083
+ taskIds: [...request.taskIds],
2084
+ status: "running",
2085
+ createdAt: now,
2086
+ updatedAt: now,
2087
+ results: [],
2088
+ ...request.label ? { label: request.label } : {}
2089
+ };
2090
+ const record = this.createRecord(state);
2091
+ this.groups.set(state.id, record);
2092
+ this.captureExistingTerminalTasks(record);
2093
+ this.emit({ type: "background_job_group_created", group: cloneGroup(record.state) });
2094
+ this.evaluateCompletion(record);
2095
+ return cloneGroup(record.state);
2096
+ }
2097
+ listGroups() {
2098
+ return [...this.groups.values()].map((record) => cloneGroup(record.state));
2099
+ }
2100
+ getGroup(groupId) {
2101
+ const record = this.groups.get(groupId);
2102
+ return record ? cloneGroup(record.state) : void 0;
2103
+ }
2104
+ waitGroup(groupId) {
2105
+ const record = this.groups.get(groupId);
2106
+ if (!record) return Promise.reject(new Error(`Unknown background job group: ${groupId}`));
2107
+ return record.completion;
2108
+ }
2109
+ subscribe(listener) {
2110
+ this.listeners.add(listener);
2111
+ return () => {
2112
+ this.listeners.delete(listener);
2113
+ };
2114
+ }
2115
+ dispose() {
2116
+ this.unsubscribeManager();
2117
+ this.listeners.clear();
2118
+ }
2119
+ nextGroupId() {
2120
+ this.sequence += 1;
2121
+ return `group_${this.sequence}`;
2122
+ }
2123
+ restoreGroup(group) {
2124
+ const record = this.createRecord(cloneGroup(group));
2125
+ this.groups.set(group.id, record);
2126
+ if (group.status === "completed") record.resolve(cloneGroup(group));
2127
+ }
2128
+ createRecord(state) {
2129
+ let resolveGroup = () => {
2130
+ };
2131
+ const completion = new Promise((resolve6) => {
2132
+ resolveGroup = resolve6;
2133
+ });
2134
+ return { state, completion, resolve: resolveGroup };
2135
+ }
2136
+ captureExistingTerminalTasks(record) {
2137
+ for (const taskId of record.state.taskIds) {
2138
+ const task = this.manager.get(taskId);
2139
+ if (task && isTerminalBackgroundTaskStatus(task.status)) this.captureTask(record, task);
2140
+ }
2141
+ }
2142
+ handleTaskEvent(event) {
2143
+ const task = getTerminalTask(event);
2144
+ if (!task) return;
2145
+ for (const record of this.groups.values()) {
2146
+ if (!record.state.taskIds.includes(task.id)) continue;
2147
+ if (!this.captureTask(record, task)) continue;
2148
+ if (record.state.status === "running") this.evaluateCompletion(record);
2149
+ else this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2150
+ }
2151
+ }
2152
+ captureTask(record, task) {
2153
+ if (record.state.results.some((result) => result.taskId === task.id)) return false;
2154
+ record.state.results = [...record.state.results, createResultEnvelope(task)];
2155
+ record.state.updatedAt = this.now();
2156
+ return true;
2157
+ }
2158
+ evaluateCompletion(record) {
2159
+ if (record.state.status === "completed") return;
2160
+ if (!shouldComplete(record.state)) {
2161
+ this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2162
+ return;
2163
+ }
2164
+ const now = this.now();
2165
+ record.state.status = "completed";
2166
+ record.state.completedAt = now;
2167
+ record.state.updatedAt = now;
2168
+ const completed = cloneGroup(record.state);
2169
+ record.resolve(completed);
2170
+ this.emit({ type: "background_job_group_completed", group: completed });
2171
+ }
2172
+ emit(event) {
2173
+ for (const listener of this.listeners) listener(event);
2174
+ }
2175
+ };
2176
+ function getTerminalTask(event) {
2177
+ if (event.type === "background_task_completed" || event.type === "background_task_failed" || event.type === "background_task_cancelled") {
2178
+ return event.task;
2179
+ }
2180
+ return void 0;
2181
+ }
2182
+ function shouldComplete(group) {
2183
+ if (group.waitPolicy === "manual") return false;
2184
+ if (group.waitPolicy === "wait_any") return group.results.length > 0;
2185
+ return group.taskIds.every((taskId) => group.results.some((result) => result.taskId === taskId));
2186
+ }
2187
+ function createResultEnvelope(task) {
2188
+ return {
2189
+ taskId: task.id,
2190
+ label: task.label,
2191
+ status: task.status,
2192
+ ...task.result?.output ? { summary: summarizeOutput(task.result.output) } : {},
2193
+ ...task.transcriptPath || task.logPath ? { outputRef: task.transcriptPath ?? task.logPath } : {},
2194
+ ...task.error ? { error: { ...task.error } } : {},
2195
+ ...task.startedAt ? { startedAt: task.startedAt } : {},
2196
+ ...task.completedAt ? { completedAt: task.completedAt } : {}
2197
+ };
2198
+ }
2199
+ function summarizeOutput(output) {
2200
+ const trimmed = output.trim();
2201
+ if (trimmed.length <= DEFAULT_SUMMARY_LENGTH) return trimmed;
2202
+ return `${trimmed.slice(0, DEFAULT_SUMMARY_LENGTH)}...`;
2203
+ }
2204
+ function summarizeBackgroundJobGroup(group) {
2205
+ const completed = countResults(group, "completed");
2206
+ const failed = countResults(group, "failed");
2207
+ const cancelled = countResults(group, "cancelled");
2208
+ return {
2209
+ groupId: group.id,
2210
+ status: group.status,
2211
+ total: group.taskIds.length,
2212
+ completed,
2213
+ failed,
2214
+ cancelled,
2215
+ pending: Math.max(group.taskIds.length - group.results.length, 0),
2216
+ lines: group.results.map((result) => formatResultLine(result))
2217
+ };
2218
+ }
2219
+ function countResults(group, status) {
2220
+ return group.results.filter((result) => result.status === status).length;
2221
+ }
2222
+ function formatResultLine(result) {
2223
+ const detail = normalizeResultDetail(result);
2224
+ const output = result.outputRef && result.summary ? ` (output: ${result.outputRef})` : "";
2225
+ return `[${result.status}] ${result.label} ${result.taskId}: ${detail}${output}`;
2226
+ }
2227
+ function normalizeResultDetail(result) {
2228
+ const detail = result.error?.message ?? result.summary ?? "";
2229
+ const normalized = detail.replace(/\s+/g, " ").trim();
2230
+ return normalized.length > 0 ? normalized : "(no summary)";
2231
+ }
2232
+ function cloneGroup(group) {
2233
+ return {
2234
+ ...group,
2235
+ taskIds: [...group.taskIds],
2236
+ results: group.results.map((result) => ({
2237
+ ...result,
2238
+ ...result.error ? { error: { ...result.error } } : {}
2239
+ }))
2240
+ };
2241
+ }
2242
+
2243
+ // src/background-tasks/execution-workspace-projection.ts
2244
+ import { isTerminalBackgroundTaskStatus as isTerminalBackgroundTaskStatus2 } from "@robota-sdk/agent-runtime";
2245
+
2246
+ // src/background-tasks/execution-workspace-types.ts
2247
+ var MAIN_THREAD_ENTRY_PREFIX = "main";
2248
+ var BACKGROUND_TASK_ENTRY_PREFIX = "task";
2249
+ var BACKGROUND_GROUP_ENTRY_PREFIX = "group";
2250
+ var ENTRY_ID_SEPARATOR = ":";
2251
+ var EXECUTION_ORIGIN_METADATA_KEYS = {
2252
+ kind: "executionOriginKind",
2253
+ sessionId: "executionOriginSessionId",
2254
+ turnId: "executionOriginTurnId",
2255
+ commandName: "executionOriginCommandName",
2256
+ toolCallId: "executionOriginToolCallId",
2257
+ skillId: "executionOriginSkillId",
2258
+ label: "executionOriginLabel"
2259
+ };
2260
+ function createMainThreadExecutionEntryId(sessionId) {
2261
+ return [MAIN_THREAD_ENTRY_PREFIX, sessionId].join(ENTRY_ID_SEPARATOR);
2262
+ }
2263
+ function createBackgroundTaskExecutionEntryId(taskId) {
2264
+ return [BACKGROUND_TASK_ENTRY_PREFIX, taskId].join(ENTRY_ID_SEPARATOR);
2265
+ }
2266
+ function createBackgroundGroupExecutionEntryId(groupId) {
2267
+ return [BACKGROUND_GROUP_ENTRY_PREFIX, groupId].join(ENTRY_ID_SEPARATOR);
2268
+ }
2269
+ function parseExecutionWorkspaceEntryId(entryId) {
2270
+ const [prefix, sourceId] = entryId.split(ENTRY_ID_SEPARATOR, 2);
2271
+ if (!sourceId) return void 0;
2272
+ if (prefix === MAIN_THREAD_ENTRY_PREFIX) return { kind: "main_thread", sourceId };
2273
+ if (prefix === BACKGROUND_TASK_ENTRY_PREFIX) return { kind: "background_task", sourceId };
2274
+ if (prefix === BACKGROUND_GROUP_ENTRY_PREFIX) return { kind: "background_group", sourceId };
2275
+ return void 0;
2276
+ }
2277
+ function createExecutionOriginMetadata(origin) {
2278
+ return {
2279
+ [EXECUTION_ORIGIN_METADATA_KEYS.kind]: origin.kind,
2280
+ [EXECUTION_ORIGIN_METADATA_KEYS.sessionId]: origin.sessionId,
2281
+ ...origin.turnId ? { [EXECUTION_ORIGIN_METADATA_KEYS.turnId]: origin.turnId } : {},
2282
+ ...origin.commandName ? { [EXECUTION_ORIGIN_METADATA_KEYS.commandName]: origin.commandName } : {},
2283
+ ...origin.toolCallId ? { [EXECUTION_ORIGIN_METADATA_KEYS.toolCallId]: origin.toolCallId } : {},
2284
+ ...origin.skillId ? { [EXECUTION_ORIGIN_METADATA_KEYS.skillId]: origin.skillId } : {},
2285
+ ...origin.label ? { [EXECUTION_ORIGIN_METADATA_KEYS.label]: origin.label } : {}
2286
+ };
2287
+ }
2288
+
2289
+ // src/background-tasks/execution-workspace-projection.ts
2290
+ var PREVIEW_MAX_LENGTH = 120;
2291
+ var SUCCESS_EXIT_CODE = 0;
2292
+ function createExecutionWorkspaceSnapshot(input) {
2293
+ const taskGroupIds = createTaskGroupIdMap(input.groups);
2294
+ const entries = [
2295
+ createMainThreadEntry(input.mainThread),
2296
+ ...sortGroups(input.groups).map((group) => createBackgroundGroupEntry(group)),
2297
+ ...sortTasks(input.tasks).map(
2298
+ (task) => createBackgroundTaskEntry(task, taskGroupIds.get(task.id))
2299
+ )
2300
+ ].filter((entry) => matchesExecutionWorkspaceFilter(entry, input.filter));
2301
+ return {
2302
+ sessionId: input.sessionId,
2303
+ selectedEntryId: input.selectedEntryId ?? entries.find((entry) => entry.kind === "main_thread")?.id ?? createMainThreadExecutionEntryId(input.sessionId),
2304
+ updatedAt: entries[0]?.updatedAt ?? input.mainThread.updatedAt,
2305
+ entries
2306
+ };
2307
+ }
2308
+ function createMainThreadEntry(input) {
2309
+ return {
2310
+ id: createMainThreadExecutionEntryId(input.sessionId),
2311
+ sourceId: input.sessionId,
2312
+ kind: "main_thread",
2313
+ origin: { kind: "user_prompt", sessionId: input.sessionId },
2314
+ status: input.isExecuting ? "active" : "idle",
2315
+ title: "Main thread",
2316
+ subtitle: input.hasPendingPrompt ? "prompt queued" : `${input.historyLength} history entries`,
2317
+ preview: trimPreview(input.preview),
2318
+ unread: false,
2319
+ attention: "none",
2320
+ visibility: "default",
2321
+ updatedAt: input.updatedAt,
2322
+ controls: ["select"]
2323
+ };
2324
+ }
2325
+ function createBackgroundTaskEntry(state, groupId) {
2326
+ return {
2327
+ id: createBackgroundTaskExecutionEntryId(state.id),
2328
+ sourceId: state.id,
2329
+ kind: "background_task",
2330
+ parentId: state.parentTaskId ? createBackgroundTaskExecutionEntryId(state.parentTaskId) : createMainThreadExecutionEntryId(state.parentSessionId),
2331
+ ...groupId ? { groupId: createBackgroundGroupExecutionEntryId(groupId) } : {},
2332
+ origin: readExecutionOrigin(state.metadata, {
2333
+ kind: "system",
2334
+ sessionId: state.parentSessionId
2335
+ }),
2336
+ taskKind: state.kind,
2337
+ status: state.status,
2338
+ title: state.label,
2339
+ subtitle: createTaskSubtitle(state),
2340
+ preview: createTaskPreview(state),
2341
+ currentAction: state.currentAction,
2342
+ unread: state.unread,
2343
+ attention: createTaskAttention(state),
2344
+ visibility: createTaskVisibility(state),
2345
+ updatedAt: state.lastActivityAt ?? state.updatedAt,
2346
+ controls: createTaskControls(state)
2347
+ };
2348
+ }
2349
+ function createBackgroundGroupEntry(group) {
2350
+ const preview = trimPreview(
2351
+ group.results.map((result) => result.summary ?? result.error?.message).join(" ")
2352
+ );
2353
+ return {
2354
+ id: createBackgroundGroupExecutionEntryId(group.id),
2355
+ sourceId: group.id,
2356
+ kind: "background_group",
2357
+ parentId: createMainThreadExecutionEntryId(group.parentSessionId),
2358
+ origin: { kind: "system", sessionId: group.parentSessionId, label: group.label },
2359
+ status: group.status,
2360
+ title: group.label ?? group.id,
2361
+ subtitle: `${group.results.length}/${group.taskIds.length} tasks`,
2362
+ preview,
2363
+ unread: false,
2364
+ attention: createGroupAttention(group),
2365
+ visibility: group.status === "completed" ? "collapsed" : "default",
2366
+ updatedAt: group.updatedAt,
2367
+ controls: group.status === "running" ? ["select", "wait"] : ["select"]
2368
+ };
2369
+ }
2370
+ function readExecutionOrigin(metadata, fallback) {
2371
+ const kind = toExecutionOriginKind(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.kind]);
2372
+ const sessionId = toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.sessionId]);
2373
+ return {
2374
+ kind: kind ?? fallback.kind,
2375
+ sessionId: sessionId ?? fallback.sessionId,
2376
+ turnId: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.turnId]) ?? fallback.turnId,
2377
+ commandName: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.commandName]) ?? fallback.commandName,
2378
+ toolCallId: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.toolCallId]) ?? fallback.toolCallId,
2379
+ skillId: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.skillId]) ?? fallback.skillId,
2380
+ label: toStringValue(metadata?.[EXECUTION_ORIGIN_METADATA_KEYS.label]) ?? fallback.label
2381
+ };
2382
+ }
2383
+ function createTaskGroupIdMap(groups) {
2384
+ return new Map(groups.flatMap((group) => group.taskIds.map((taskId) => [taskId, group.id])));
2385
+ }
2386
+ function createTaskControls(state) {
2387
+ const controls = ["select"];
2388
+ if (isTerminalBackgroundTaskStatus2(state.status)) controls.push("close");
2389
+ else controls.push("cancel");
2390
+ if (state.logPath || state.transcriptPath) controls.push("read_log");
2391
+ return controls;
2392
+ }
2393
+ function createTaskSubtitle(state) {
2394
+ if (state.kind === "agent") return state.agentType ?? state.cwd;
2395
+ return state.cwd;
2396
+ }
2397
+ function createTaskPreview(state) {
2398
+ if (state.status === "failed") return trimPreview(state.error?.message);
2399
+ if (state.status === "completed") return trimPreview(state.result?.output);
2400
+ return trimPreview(state.promptPreview ?? state.commandPreview);
2401
+ }
2402
+ function createTaskAttention(state) {
2403
+ if (state.status === "failed") return "failed";
2404
+ if (state.status === "waiting_permission") return "permission";
2405
+ if (state.unread) return "unread";
2406
+ if (state.status === "completed") return "completed";
2407
+ return "none";
2408
+ }
2409
+ function createTaskVisibility(state) {
2410
+ if (state.status === "completed" && !state.unread && !state.error && (state.result?.exitCode ?? SUCCESS_EXIT_CODE) === SUCCESS_EXIT_CODE && !state.result?.signalCode && !state.worktreePath && !state.branchName) {
2411
+ return "collapsed";
2412
+ }
2413
+ return "default";
2414
+ }
2415
+ function createGroupAttention(group) {
2416
+ if (group.results.some((result) => result.status === "failed")) return "failed";
2417
+ if (group.status === "completed") return "completed";
2418
+ return "none";
2419
+ }
2420
+ function matchesExecutionWorkspaceFilter(entry, filter) {
2421
+ if (!filter) return true;
2422
+ if (filter.includeMainThread === false && entry.kind === "main_thread") return false;
2423
+ if (filter.kinds && !filter.kinds.includes(entry.kind)) return false;
2424
+ if (filter.visibility && !filter.visibility.includes(entry.visibility)) return false;
2425
+ return true;
2426
+ }
2427
+ function sortTasks(tasks) {
2428
+ return [...tasks].sort(
2429
+ (left, right) => (right.lastActivityAt ?? right.updatedAt).localeCompare(left.lastActivityAt ?? left.updatedAt)
2430
+ );
2431
+ }
2432
+ function sortGroups(groups) {
2433
+ return [...groups].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
2434
+ }
2435
+ function trimPreview(value) {
2436
+ const normalized = value?.trim().replace(/\s+/g, " ");
2437
+ if (!normalized) return void 0;
2438
+ return normalized.length > PREVIEW_MAX_LENGTH ? `${normalized.slice(0, PREVIEW_MAX_LENGTH)}...` : normalized;
2439
+ }
2440
+ function toStringValue(value) {
2441
+ return typeof value === "string" ? value : void 0;
2442
+ }
2443
+ function toExecutionOriginKind(value) {
2444
+ if (value === "user_prompt" || value === "slash_command" || value === "model_command" || value === "tool_call" || value === "skill" || value === "transport" || value === "system") {
2445
+ return value;
2446
+ }
2447
+ return void 0;
2448
+ }
2449
+
2450
+ // src/background-tasks/execution-workspace-detail.ts
2451
+ var EXECUTION_DETAIL_PAGE_SIZE = 80;
2452
+ function createMainThreadDetailPage(input) {
2453
+ const offset = normalizeOffset(input.cursor?.offset);
2454
+ const page = input.history.slice(offset, offset + EXECUTION_DETAIL_PAGE_SIZE);
2455
+ const records = page.map((entry) => ({
2456
+ id: entry.id,
2457
+ kind: entry.category === "chat" ? "message" : "progress",
2458
+ text: formatHistoryEntry(entry),
2459
+ timestamp: entry.timestamp.toISOString(),
2460
+ sourceId: entry.type
2461
+ }));
2462
+ return {
2463
+ entryId: input.entryId,
2464
+ ...input.cursor ? { cursor: input.cursor } : {},
2465
+ ...offset + page.length < input.history.length ? { nextCursor: { offset: offset + page.length } } : {},
2466
+ records
2467
+ };
2468
+ }
2469
+ function createLineDetailPage(input) {
2470
+ const offset = input.cursor?.offset ?? 0;
2471
+ const records = input.lines.map((line, index) => ({
2472
+ id: `${input.entryId}:${offset}:${index}`,
2473
+ kind: input.kind ?? "process_output",
2474
+ text: line
2475
+ }));
2476
+ return {
2477
+ entryId: input.entryId,
2478
+ ...input.cursor ? { cursor: input.cursor } : {},
2479
+ ...input.nextCursor ? { nextCursor: input.nextCursor } : {},
2480
+ records
2481
+ };
2482
+ }
2483
+ function normalizeOffset(offset) {
2484
+ return typeof offset === "number" && Number.isFinite(offset) && offset > 0 ? Math.floor(offset) : 0;
2485
+ }
2486
+ function formatHistoryEntry(entry) {
2487
+ if (typeof entry.data === "string") return entry.data;
2488
+ return entry.type;
2489
+ }
2490
+
2491
+ // src/background-tasks/execution-workspace-spawner.ts
2492
+ function createExecutionWorkspaceTaskSpawner(options) {
2493
+ return {
2494
+ spawnAgent: (request) => options.manager.spawn(createAgentRequest(options, request)),
2495
+ spawnProcess: (request) => options.manager.spawn(createProcessRequest(options, request)),
2496
+ createGroup: (request) => options.groupOrchestrator.createGroup({
2497
+ parentSessionId: options.sessionId,
2498
+ waitPolicy: request.waitPolicy,
2499
+ taskIds: [...request.taskIds],
2500
+ label: request.label
2501
+ })
2502
+ };
2503
+ }
2504
+ function createAgentRequest(options, request) {
2505
+ return {
2506
+ kind: "agent",
2507
+ label: request.label,
2508
+ mode: request.mode ?? "background",
2509
+ parentSessionId: options.sessionId,
2510
+ parentTaskId: request.parentTaskId,
2511
+ depth: request.depth ?? 1,
2512
+ cwd: request.cwd ?? options.cwd,
2513
+ agentType: request.agentType,
2514
+ prompt: request.prompt,
2515
+ model: request.model,
2516
+ isolation: request.isolation,
2517
+ allowedTools: request.allowedTools ? [...request.allowedTools] : void 0,
2518
+ disallowedTools: request.disallowedTools ? [...request.disallowedTools] : void 0,
2519
+ permissionPolicy: request.permissionPolicy ?? "inherit-allowlist",
2520
+ timeoutMs: request.timeoutMs,
2521
+ idleTimeoutMs: request.idleTimeoutMs,
2522
+ maxRuntimeMs: request.maxRuntimeMs,
2523
+ outputLimitBytes: request.outputLimitBytes,
2524
+ maxTextDeltas: request.maxTextDeltas,
2525
+ repetitionWindow: request.repetitionWindow,
2526
+ repetitionThreshold: request.repetitionThreshold,
2527
+ metadata: createExecutionOriginMetadata(options.origin)
2528
+ };
2529
+ }
2530
+ function createProcessRequest(options, request) {
2531
+ return {
2532
+ kind: "process",
2533
+ label: request.label ?? request.command,
2534
+ mode: request.mode ?? "background",
2535
+ parentSessionId: options.sessionId,
2536
+ parentTaskId: request.parentTaskId,
2537
+ depth: request.depth ?? 0,
2538
+ cwd: request.cwd ?? options.cwd,
2539
+ command: request.command,
2540
+ shell: request.shell,
2541
+ env: request.env,
2542
+ stdin: request.stdin,
2543
+ timeoutMs: request.timeoutMs,
2544
+ idleTimeoutMs: request.idleTimeoutMs,
2545
+ maxRuntimeMs: request.maxRuntimeMs,
2546
+ outputLimitBytes: request.outputLimitBytes,
2547
+ metadata: createExecutionOriginMetadata(options.origin)
2548
+ };
2549
+ }
2550
+
2551
+ // src/background-tasks/index.ts
2552
+ import {
2553
+ getBackgroundTaskTransitions,
2554
+ isTerminalBackgroundTaskStatus as isTerminalBackgroundTaskStatus3,
2555
+ transitionBackgroundTaskStatus,
2556
+ appendPrefixedLogLines,
2557
+ createBackgroundTaskLogPage,
2558
+ createLimitedOutputCapture,
2559
+ DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE
2560
+ } from "@robota-sdk/agent-runtime";
2561
+ import { BackgroundTaskError } from "@robota-sdk/agent-runtime";
2562
+
2053
2563
  // src/tools/agent-tool-batch.ts
2054
2564
  function stringifyAgentBatchResult(input) {
2055
2565
  const successfulJobs = input.jobs.filter((job) => job.success);
@@ -2244,7 +2754,12 @@ function createSpawnRequest(args, agentType, agentDef, deps, label = agentDef.na
2244
2754
  cwd: deps.cwd ?? process.cwd(),
2245
2755
  prompt: args.prompt,
2246
2756
  model: args.model,
2247
- isolation: args.isolation
2757
+ isolation: args.isolation,
2758
+ metadata: createExecutionOriginMetadata({
2759
+ kind: "tool_call",
2760
+ sessionId: deps.parentSessionId ?? "unknown-session",
2761
+ label
2762
+ })
2248
2763
  };
2249
2764
  }
2250
2765
  function stringifyUnknownAgentType(agentType) {
@@ -2281,290 +2796,88 @@ function stringifyAgentSuccess(result) {
2281
2796
  provenance: {
2282
2797
  source: "agent-tool-single",
2283
2798
  requestedJobCount: 1,
2284
- startedJobCount: 1,
2285
- failedJobCount: 0
2286
- },
2287
- metadata: result.metadata,
2288
- ...typeof worktreePath === "string" ? { worktreePath } : {},
2289
- ...typeof branchName === "string" ? { branchName } : {},
2290
- ...typeof worktreeStatus === "string" ? { worktreeStatus } : {},
2291
- ...typeof worktreeNextAction === "string" ? { worktreeNextAction } : {}
2292
- });
2293
- }
2294
- function stringifyAgentError(message, agentId) {
2295
- const startedJobCount = agentId === void 0 ? 0 : 1;
2296
- return JSON.stringify({
2297
- success: false,
2298
- mode: "single",
2299
- requestedJobCount: 1,
2300
- startedJobCount,
2301
- failedJobCount: 1,
2302
- output: "",
2303
- error: `Sub-agent error: ${message}`,
2304
- agentId,
2305
- ...agentId !== void 0 ? { agentIds: [agentId] } : {},
2306
- provenance: {
2307
- source: "agent-tool-single",
2308
- requestedJobCount: 1,
2309
- startedJobCount,
2310
- failedJobCount: 1
2311
- }
2312
- });
2313
- }
2314
- async function runManagedAgent(args, deps, manager) {
2315
- if (typeof args.prompt !== "string" || args.prompt.length === 0) {
2316
- return stringifyAgentError("prompt is required when jobs is omitted");
2317
- }
2318
- const singleArgs = { ...args, prompt: args.prompt };
2319
- const agentType = args.subagent_type ?? "general-purpose";
2320
- const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
2321
- if (!agentDef) {
2322
- return stringifyUnknownAgentType(agentType);
2323
- }
2324
- let agentId;
2325
- try {
2326
- const state = await manager.spawn(createSpawnRequest(singleArgs, agentType, agentDef, deps));
2327
- agentId = state.id;
2328
- const response = await manager.wait(state.id);
2329
- return stringifyAgentSuccess(response);
2330
- } catch (err) {
2331
- const message = err instanceof Error ? err.message : String(err);
2332
- return stringifyAgentError(message, agentId);
2333
- }
2334
- }
2335
- function createAgentTool(deps) {
2336
- const manager = createSubagentManager(deps);
2337
- return createZodFunctionTool2(
2338
- "Agent",
2339
- AGENT_TOOL_DESCRIPTION,
2340
- asZodSchema2(AgentSchema),
2341
- async (params) => {
2342
- const args = params;
2343
- if (Array.isArray(args.jobs) && args.jobs.length > 0) {
2344
- return runManagedAgentBatch({
2345
- jobs: args.jobs,
2346
- deps,
2347
- manager,
2348
- resolveAgentDefinition: resolveAgentDefinition2,
2349
- createSpawnRequest
2350
- });
2351
- }
2352
- return runManagedAgent(
2353
- {
2354
- prompt: args.prompt,
2355
- ...args.subagent_type !== void 0 ? { subagent_type: args.subagent_type } : {},
2356
- ...args.model !== void 0 ? { model: args.model } : {},
2357
- ...args.isolation !== void 0 ? { isolation: args.isolation } : {}
2358
- },
2359
- deps,
2360
- manager
2361
- );
2362
- }
2363
- );
2364
- }
2365
-
2366
- // src/background-tasks/index.ts
2367
- import { BackgroundTaskManager } from "@robota-sdk/agent-runtime";
2368
-
2369
- // src/background-tasks/background-job-orchestrator.ts
2370
- import {
2371
- isTerminalBackgroundTaskStatus
2372
- } from "@robota-sdk/agent-runtime";
2373
- var DEFAULT_SUMMARY_LENGTH = 1e3;
2374
- var BackgroundJobOrchestrator = class {
2375
- manager;
2376
- now;
2377
- idFactory;
2378
- unsubscribeManager;
2379
- listeners = /* @__PURE__ */ new Set();
2380
- groups = /* @__PURE__ */ new Map();
2381
- sequence = 0;
2382
- constructor(options) {
2383
- this.manager = options.manager;
2384
- this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
2385
- this.idFactory = options.idFactory ?? (() => this.nextGroupId());
2386
- this.sequence = options.initialGroups?.length ?? 0;
2387
- for (const group of options.initialGroups ?? []) this.restoreGroup(group);
2388
- this.unsubscribeManager = this.manager.subscribe((event) => this.handleTaskEvent(event));
2389
- }
2390
- createGroup(request) {
2391
- const now = this.now();
2392
- const state = {
2393
- id: this.idFactory(request),
2394
- parentSessionId: request.parentSessionId,
2395
- waitPolicy: request.waitPolicy,
2396
- taskIds: [...request.taskIds],
2397
- status: "running",
2398
- createdAt: now,
2399
- updatedAt: now,
2400
- results: [],
2401
- ...request.label ? { label: request.label } : {}
2402
- };
2403
- const record = this.createRecord(state);
2404
- this.groups.set(state.id, record);
2405
- this.captureExistingTerminalTasks(record);
2406
- this.emit({ type: "background_job_group_created", group: cloneGroup(record.state) });
2407
- this.evaluateCompletion(record);
2408
- return cloneGroup(record.state);
2409
- }
2410
- listGroups() {
2411
- return [...this.groups.values()].map((record) => cloneGroup(record.state));
2412
- }
2413
- getGroup(groupId) {
2414
- const record = this.groups.get(groupId);
2415
- return record ? cloneGroup(record.state) : void 0;
2416
- }
2417
- waitGroup(groupId) {
2418
- const record = this.groups.get(groupId);
2419
- if (!record) return Promise.reject(new Error(`Unknown background job group: ${groupId}`));
2420
- return record.completion;
2421
- }
2422
- subscribe(listener) {
2423
- this.listeners.add(listener);
2424
- return () => {
2425
- this.listeners.delete(listener);
2426
- };
2427
- }
2428
- dispose() {
2429
- this.unsubscribeManager();
2430
- this.listeners.clear();
2431
- }
2432
- nextGroupId() {
2433
- this.sequence += 1;
2434
- return `group_${this.sequence}`;
2435
- }
2436
- restoreGroup(group) {
2437
- const record = this.createRecord(cloneGroup(group));
2438
- this.groups.set(group.id, record);
2439
- if (group.status === "completed") record.resolve(cloneGroup(group));
2440
- }
2441
- createRecord(state) {
2442
- let resolveGroup = () => {
2443
- };
2444
- const completion = new Promise((resolve6) => {
2445
- resolveGroup = resolve6;
2446
- });
2447
- return { state, completion, resolve: resolveGroup };
2448
- }
2449
- captureExistingTerminalTasks(record) {
2450
- for (const taskId of record.state.taskIds) {
2451
- const task = this.manager.get(taskId);
2452
- if (task && isTerminalBackgroundTaskStatus(task.status)) this.captureTask(record, task);
2453
- }
2454
- }
2455
- handleTaskEvent(event) {
2456
- const task = getTerminalTask(event);
2457
- if (!task) return;
2458
- for (const record of this.groups.values()) {
2459
- if (!record.state.taskIds.includes(task.id)) continue;
2460
- if (!this.captureTask(record, task)) continue;
2461
- if (record.state.status === "running") this.evaluateCompletion(record);
2462
- else this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2463
- }
2464
- }
2465
- captureTask(record, task) {
2466
- if (record.state.results.some((result) => result.taskId === task.id)) return false;
2467
- record.state.results = [...record.state.results, createResultEnvelope(task)];
2468
- record.state.updatedAt = this.now();
2469
- return true;
2470
- }
2471
- evaluateCompletion(record) {
2472
- if (record.state.status === "completed") return;
2473
- if (!shouldComplete(record.state)) {
2474
- this.emit({ type: "background_job_group_updated", group: cloneGroup(record.state) });
2475
- return;
2476
- }
2477
- const now = this.now();
2478
- record.state.status = "completed";
2479
- record.state.completedAt = now;
2480
- record.state.updatedAt = now;
2481
- const completed = cloneGroup(record.state);
2482
- record.resolve(completed);
2483
- this.emit({ type: "background_job_group_completed", group: completed });
2484
- }
2485
- emit(event) {
2486
- for (const listener of this.listeners) listener(event);
2487
- }
2488
- };
2489
- function getTerminalTask(event) {
2490
- if (event.type === "background_task_completed" || event.type === "background_task_failed" || event.type === "background_task_cancelled") {
2491
- return event.task;
2492
- }
2493
- return void 0;
2494
- }
2495
- function shouldComplete(group) {
2496
- if (group.waitPolicy === "manual") return false;
2497
- if (group.waitPolicy === "wait_any") return group.results.length > 0;
2498
- return group.taskIds.every((taskId) => group.results.some((result) => result.taskId === taskId));
2499
- }
2500
- function createResultEnvelope(task) {
2501
- return {
2502
- taskId: task.id,
2503
- label: task.label,
2504
- status: task.status,
2505
- ...task.result?.output ? { summary: summarizeOutput(task.result.output) } : {},
2506
- ...task.transcriptPath || task.logPath ? { outputRef: task.transcriptPath ?? task.logPath } : {},
2507
- ...task.error ? { error: { ...task.error } } : {},
2508
- ...task.startedAt ? { startedAt: task.startedAt } : {},
2509
- ...task.completedAt ? { completedAt: task.completedAt } : {}
2510
- };
2511
- }
2512
- function summarizeOutput(output) {
2513
- const trimmed = output.trim();
2514
- if (trimmed.length <= DEFAULT_SUMMARY_LENGTH) return trimmed;
2515
- return `${trimmed.slice(0, DEFAULT_SUMMARY_LENGTH)}...`;
2516
- }
2517
- function summarizeBackgroundJobGroup(group) {
2518
- const completed = countResults(group, "completed");
2519
- const failed = countResults(group, "failed");
2520
- const cancelled = countResults(group, "cancelled");
2521
- return {
2522
- groupId: group.id,
2523
- status: group.status,
2524
- total: group.taskIds.length,
2525
- completed,
2526
- failed,
2527
- cancelled,
2528
- pending: Math.max(group.taskIds.length - group.results.length, 0),
2529
- lines: group.results.map((result) => formatResultLine(result))
2530
- };
2531
- }
2532
- function countResults(group, status) {
2533
- return group.results.filter((result) => result.status === status).length;
2799
+ startedJobCount: 1,
2800
+ failedJobCount: 0
2801
+ },
2802
+ metadata: result.metadata,
2803
+ ...typeof worktreePath === "string" ? { worktreePath } : {},
2804
+ ...typeof branchName === "string" ? { branchName } : {},
2805
+ ...typeof worktreeStatus === "string" ? { worktreeStatus } : {},
2806
+ ...typeof worktreeNextAction === "string" ? { worktreeNextAction } : {}
2807
+ });
2534
2808
  }
2535
- function formatResultLine(result) {
2536
- const detail = normalizeResultDetail(result);
2537
- const output = result.outputRef && result.summary ? ` (output: ${result.outputRef})` : "";
2538
- return `[${result.status}] ${result.label} ${result.taskId}: ${detail}${output}`;
2809
+ function stringifyAgentError(message, agentId) {
2810
+ const startedJobCount = agentId === void 0 ? 0 : 1;
2811
+ return JSON.stringify({
2812
+ success: false,
2813
+ mode: "single",
2814
+ requestedJobCount: 1,
2815
+ startedJobCount,
2816
+ failedJobCount: 1,
2817
+ output: "",
2818
+ error: `Sub-agent error: ${message}`,
2819
+ agentId,
2820
+ ...agentId !== void 0 ? { agentIds: [agentId] } : {},
2821
+ provenance: {
2822
+ source: "agent-tool-single",
2823
+ requestedJobCount: 1,
2824
+ startedJobCount,
2825
+ failedJobCount: 1
2826
+ }
2827
+ });
2539
2828
  }
2540
- function normalizeResultDetail(result) {
2541
- const detail = result.error?.message ?? result.summary ?? "";
2542
- const normalized = detail.replace(/\s+/g, " ").trim();
2543
- return normalized.length > 0 ? normalized : "(no summary)";
2829
+ async function runManagedAgent(args, deps, manager) {
2830
+ if (typeof args.prompt !== "string" || args.prompt.length === 0) {
2831
+ return stringifyAgentError("prompt is required when jobs is omitted");
2832
+ }
2833
+ const singleArgs = { ...args, prompt: args.prompt };
2834
+ const agentType = args.subagent_type ?? "general-purpose";
2835
+ const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
2836
+ if (!agentDef) {
2837
+ return stringifyUnknownAgentType(agentType);
2838
+ }
2839
+ let agentId;
2840
+ try {
2841
+ const state = await manager.spawn(createSpawnRequest(singleArgs, agentType, agentDef, deps));
2842
+ agentId = state.id;
2843
+ const response = await manager.wait(state.id);
2844
+ return stringifyAgentSuccess(response);
2845
+ } catch (err) {
2846
+ const message = err instanceof Error ? err.message : String(err);
2847
+ return stringifyAgentError(message, agentId);
2848
+ }
2544
2849
  }
2545
- function cloneGroup(group) {
2546
- return {
2547
- ...group,
2548
- taskIds: [...group.taskIds],
2549
- results: group.results.map((result) => ({
2550
- ...result,
2551
- ...result.error ? { error: { ...result.error } } : {}
2552
- }))
2553
- };
2850
+ function createAgentTool(deps) {
2851
+ const manager = createSubagentManager(deps);
2852
+ return createZodFunctionTool2(
2853
+ "Agent",
2854
+ AGENT_TOOL_DESCRIPTION,
2855
+ asZodSchema2(AgentSchema),
2856
+ async (params) => {
2857
+ const args = params;
2858
+ if (Array.isArray(args.jobs) && args.jobs.length > 0) {
2859
+ return runManagedAgentBatch({
2860
+ jobs: args.jobs,
2861
+ deps,
2862
+ manager,
2863
+ resolveAgentDefinition: resolveAgentDefinition2,
2864
+ createSpawnRequest
2865
+ });
2866
+ }
2867
+ return runManagedAgent(
2868
+ {
2869
+ prompt: args.prompt,
2870
+ ...args.subagent_type !== void 0 ? { subagent_type: args.subagent_type } : {},
2871
+ ...args.model !== void 0 ? { model: args.model } : {},
2872
+ ...args.isolation !== void 0 ? { isolation: args.isolation } : {}
2873
+ },
2874
+ deps,
2875
+ manager
2876
+ );
2877
+ }
2878
+ );
2554
2879
  }
2555
2880
 
2556
- // src/background-tasks/index.ts
2557
- import {
2558
- getBackgroundTaskTransitions,
2559
- isTerminalBackgroundTaskStatus as isTerminalBackgroundTaskStatus2,
2560
- transitionBackgroundTaskStatus,
2561
- appendPrefixedLogLines,
2562
- createBackgroundTaskLogPage,
2563
- createLimitedOutputCapture,
2564
- DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE
2565
- } from "@robota-sdk/agent-runtime";
2566
- import { BackgroundTaskError } from "@robota-sdk/agent-runtime";
2567
-
2568
2881
  // src/background-tasks/session-background-store.ts
2569
2882
  var sessionBackgroundTaskManagers = /* @__PURE__ */ new WeakMap();
2570
2883
  function storeSessionBackgroundTaskManager(key, manager) {
@@ -3622,10 +3935,10 @@ async function loadConfig(cwd) {
3622
3935
  rawEntries.push({ raw, path: filePath });
3623
3936
  }
3624
3937
  }
3625
- const parsedLayers = rawEntries.map(({ raw, path }) => {
3938
+ const parsedLayers = rawEntries.map(({ raw, path: path3 }) => {
3626
3939
  const result = SettingsSchema.safeParse(raw);
3627
3940
  if (!result.success) {
3628
- throw new Error(`Invalid settings in ${path}: ${result.error.message}`);
3941
+ throw new Error(`Invalid settings in ${path3}: ${result.error.message}`);
3629
3942
  }
3630
3943
  return resolveEnvRefs(result.data);
3631
3944
  });
@@ -3998,7 +4311,8 @@ async function startBackgroundProcess(args, deps) {
3998
4311
  command: args.command,
3999
4312
  stdin: args.stdin,
4000
4313
  timeoutMs: args.timeout ?? DEFAULT_PROCESS_TIMEOUT_MS,
4001
- outputLimitBytes: args.outputLimitBytes
4314
+ outputLimitBytes: args.outputLimitBytes,
4315
+ metadata: deps.metadata
4002
4316
  });
4003
4317
  return stringifyStarted(state.id, state.status, args.command);
4004
4318
  } catch (error) {
@@ -4541,7 +4855,12 @@ function createSession(options) {
4541
4855
  backgroundProcessToolDeps = {
4542
4856
  backgroundTaskManager,
4543
4857
  cwd,
4544
- parentSessionId: sessionId
4858
+ parentSessionId: sessionId,
4859
+ metadata: createExecutionOriginMetadata({
4860
+ kind: "tool_call",
4861
+ sessionId,
4862
+ label: "BackgroundProcess"
4863
+ })
4545
4864
  };
4546
4865
  tools.push(createBackgroundProcessTool(backgroundProcessToolDeps));
4547
4866
  }
@@ -4817,7 +5136,7 @@ function formatTaskContext(tasks) {
4817
5136
  }
4818
5137
  function loadTaskContext(cwd, options = {}) {
4819
5138
  const currentBranch = options.currentBranch ?? readCurrentGitBranch(cwd);
4820
- const tasks = discoverTaskFiles(cwd).map((path) => parseTaskFile(path, cwd));
5139
+ const tasks = discoverTaskFiles(cwd).map((path3) => parseTaskFile(path3, cwd));
4821
5140
  return formatTaskContext(selectRelevantTasks(tasks, { ...options, currentBranch }));
4822
5141
  }
4823
5142
  function updateTaskFileStatus(taskPath, status, options = {}) {
@@ -5165,9 +5484,9 @@ var BundlePluginLoader = class {
5165
5484
  return results;
5166
5485
  }
5167
5486
  /** Read and validate a plugin.json manifest. Returns null on failure. */
5168
- readManifest(path) {
5487
+ readManifest(path3) {
5169
5488
  try {
5170
- const raw = readFileSync11(path, "utf-8");
5489
+ const raw = readFileSync11(path3, "utf-8");
5171
5490
  const data = JSON.parse(raw);
5172
5491
  return validateManifest(data);
5173
5492
  } catch {
@@ -5725,8 +6044,8 @@ var MarketplaceClient = class {
5725
6044
  }
5726
6045
  }
5727
6046
  /** Read and parse a marketplace.json from a file path. */
5728
- readManifestFromPath(path) {
5729
- const raw = readFileSync14(path, "utf-8");
6047
+ readManifestFromPath(path3) {
6048
+ const raw = readFileSync14(path3, "utf-8");
5730
6049
  const data = JSON.parse(raw);
5731
6050
  if (typeof data !== "object" || data === null) {
5732
6051
  throw new Error("Invalid marketplace manifest: not an object");
@@ -5997,8 +6316,8 @@ function isRestoredTerminalStatus(status) {
5997
6316
  }
5998
6317
 
5999
6318
  // src/interactive/interactive-session-context-references.ts
6000
- async function addInteractiveContextReference(references, path, cwd) {
6001
- const result = await resolvePromptFileReferencePaths([path], {
6319
+ async function addInteractiveContextReference(references, path3, cwd) {
6320
+ const result = await resolvePromptFileReferencePaths([path3], {
6002
6321
  cwd,
6003
6322
  reason: "manual"
6004
6323
  });
@@ -6091,9 +6410,9 @@ function toInspectionPlan(manifests) {
6091
6410
  fileCount: manifests.reduce((count, manifest) => count + manifest.fileCount, 0)
6092
6411
  };
6093
6412
  }
6094
- function statSafe(path) {
6413
+ function statSafe(path3) {
6095
6414
  try {
6096
- return statSync2(path);
6415
+ return statSync2(path3);
6097
6416
  } catch {
6098
6417
  return void 0;
6099
6418
  }
@@ -6264,10 +6583,10 @@ var EditCheckpointStore = class {
6264
6583
  }
6265
6584
  async writeManifest(dir, manifest) {
6266
6585
  await mkdir(dir, { recursive: true });
6267
- const path = join19(dir, MANIFEST_FILE);
6268
- const tmp = `${path}.tmp`;
6586
+ const path3 = join19(dir, MANIFEST_FILE);
6587
+ const tmp = `${path3}.tmp`;
6269
6588
  await writeFile(tmp, JSON.stringify(manifest, null, 2), "utf8");
6270
- await rename(tmp, path);
6589
+ await rename(tmp, path3);
6271
6590
  }
6272
6591
  sessionDir(sessionId) {
6273
6592
  return join19(this.rootDir, safePathSegment(sessionId));
@@ -6293,9 +6612,9 @@ function isInside(parent, child) {
6293
6612
  const rel = relative3(parent, child);
6294
6613
  return rel.length === 0 || !rel.startsWith("..") && !rel.startsWith("/");
6295
6614
  }
6296
- async function pathExists(path) {
6615
+ async function pathExists(path3) {
6297
6616
  try {
6298
- await access(path, constants.F_OK);
6617
+ await access(path3, constants.F_OK);
6299
6618
  return true;
6300
6619
  } catch {
6301
6620
  return false;
@@ -6308,9 +6627,9 @@ function readDirSyncSafe(dir) {
6308
6627
  return [];
6309
6628
  }
6310
6629
  }
6311
- function readJsonManifest(path) {
6630
+ function readJsonManifest(path3) {
6312
6631
  try {
6313
- const raw = readFileSync15(path, "utf8");
6632
+ const raw = readFileSync15(path3, "utf8");
6314
6633
  return JSON.parse(raw);
6315
6634
  } catch {
6316
6635
  return void 0;
@@ -6333,6 +6652,11 @@ function getQualifiedSkillName(rawInput) {
6333
6652
  const firstToken = rawInput.slice(1).trim().split(/\s+/)[0];
6334
6653
  return firstToken && firstToken.length > 0 ? firstToken : void 0;
6335
6654
  }
6655
+ function getBackgroundTaskEventEntryId(event) {
6656
+ if ("task" in event) return createBackgroundTaskExecutionEntryId(event.task.id);
6657
+ if ("taskId" in event) return createBackgroundTaskExecutionEntryId(event.taskId);
6658
+ return void 0;
6659
+ }
6336
6660
  var InteractiveSession = class {
6337
6661
  session = null;
6338
6662
  commandExecutor;
@@ -6776,18 +7100,18 @@ var InteractiveSession = class {
6776
7100
  listContextReferences() {
6777
7101
  return [...this.contextReferences];
6778
7102
  }
6779
- async addContextReference(path) {
7103
+ async addContextReference(path3) {
6780
7104
  const { references, result } = await addInteractiveContextReference(
6781
7105
  this.contextReferences,
6782
- path,
7106
+ path3,
6783
7107
  this.getCwd()
6784
7108
  );
6785
7109
  this.contextReferences = references;
6786
7110
  this.persistCurrentSession();
6787
7111
  return result;
6788
7112
  }
6789
- removeContextReference(path) {
6790
- const result = removeContextReference(this.contextReferences, path);
7113
+ removeContextReference(path3) {
7114
+ const result = removeContextReference(this.contextReferences, path3);
6791
7115
  this.contextReferences = result.references;
6792
7116
  this.persistCurrentSession();
6793
7117
  return result.result;
@@ -6837,6 +7161,53 @@ var InteractiveSession = class {
6837
7161
  await this.ensureInitialized();
6838
7162
  return this.getBackgroundJobOrchestratorOrThrow().waitGroup(groupId);
6839
7163
  }
7164
+ getExecutionWorkspaceSnapshot(options = {}) {
7165
+ const session = this.getSessionOrThrow();
7166
+ const sessionId = session.getSessionId();
7167
+ return createExecutionWorkspaceSnapshot({
7168
+ sessionId,
7169
+ mainThread: {
7170
+ sessionId,
7171
+ isExecuting: this.executing,
7172
+ hasPendingPrompt: this.pendingPrompt !== null,
7173
+ historyLength: this.history.length,
7174
+ updatedAt: this.getMainThreadUpdatedAt(),
7175
+ preview: this.getMainThreadPreview()
7176
+ },
7177
+ tasks: this.getBackgroundTaskSnapshots(),
7178
+ groups: this.getBackgroundJobGroupSnapshots(),
7179
+ selectedEntryId: options.selectedEntryId,
7180
+ filter: options.filter
7181
+ });
7182
+ }
7183
+ listExecutionWorkspaceEntries(filter) {
7184
+ return [...this.getExecutionWorkspaceSnapshot({ filter }).entries];
7185
+ }
7186
+ getExecutionWorkspaceEntry(entryId) {
7187
+ return this.getExecutionWorkspaceSnapshot().entries.find((entry) => entry.id === entryId);
7188
+ }
7189
+ async readExecutionWorkspaceDetail(entryId, cursor) {
7190
+ await this.ensureInitialized();
7191
+ const entryRef = parseExecutionWorkspaceEntryId(entryId);
7192
+ if (!entryRef) throw new Error(`Unknown execution workspace entry: ${entryId}`);
7193
+ if (entryRef.kind === "main_thread") {
7194
+ return createMainThreadDetailPage({ entryId, history: this.history, cursor });
7195
+ }
7196
+ if (entryRef.kind === "background_group") {
7197
+ return this.readBackgroundGroupDetail(entryId, entryRef.sourceId);
7198
+ }
7199
+ return this.readBackgroundTaskDetail(entryId, entryRef.sourceId, cursor);
7200
+ }
7201
+ createExecutionWorkspaceTaskSpawner(origin) {
7202
+ const sessionId = this.getSessionOrThrow().getSessionId();
7203
+ return createExecutionWorkspaceTaskSpawner({
7204
+ manager: this.getBackgroundTaskManagerOrThrow(),
7205
+ groupOrchestrator: this.getBackgroundJobOrchestratorOrThrow(),
7206
+ sessionId,
7207
+ cwd: this.getCwd(),
7208
+ origin: { ...origin, sessionId: origin.sessionId || sessionId }
7209
+ });
7210
+ }
6840
7211
  listAgentDefinitions() {
6841
7212
  const deps = retrieveAgentToolDeps(this.getSessionOrThrow());
6842
7213
  return (deps?.agentDefinitions ?? []).map((agent) => ({
@@ -6851,10 +7222,11 @@ var InteractiveSession = class {
6851
7222
  await this.ensureInitialized();
6852
7223
  const deps = this.getAgentToolDepsOrThrow();
6853
7224
  const definition = this.resolveAgentDefinition(input.agentType, deps);
7225
+ const sessionId = this.getSessionOrThrow().getSessionId();
6854
7226
  return this.getSubagentManagerOrThrow().spawn({
6855
7227
  type: input.agentType,
6856
7228
  label: input.label,
6857
- parentSessionId: this.getSessionOrThrow().getSessionId(),
7229
+ parentSessionId: sessionId,
6858
7230
  mode: input.mode,
6859
7231
  depth: (deps.subagentDepth ?? 0) + 1,
6860
7232
  cwd: deps.cwd ?? this.cwd ?? process.cwd(),
@@ -6862,7 +7234,13 @@ var InteractiveSession = class {
6862
7234
  model: input.model ?? definition.model,
6863
7235
  isolation: input.isolation,
6864
7236
  allowedTools: definition.tools,
6865
- disallowedTools: definition.disallowedTools
7237
+ disallowedTools: definition.disallowedTools,
7238
+ metadata: createExecutionOriginMetadata({
7239
+ kind: this.commandInvocationSource === "model" ? "model_command" : "slash_command",
7240
+ sessionId,
7241
+ commandName: "agent",
7242
+ label: input.label
7243
+ })
6866
7244
  });
6867
7245
  }
6868
7246
  async waitAgentJob(jobId) {
@@ -6965,6 +7343,51 @@ var InteractiveSession = class {
6965
7343
  this.finishForkSkillExecution();
6966
7344
  }
6967
7345
  }
7346
+ async readBackgroundTaskDetail(entryId, taskId, cursor) {
7347
+ const task = this.getBackgroundTaskManagerOrThrow().get(taskId);
7348
+ if (!task) throw new Error(`Unknown background task: ${taskId}`);
7349
+ if (task.logPath || task.transcriptPath) {
7350
+ const page = await this.getBackgroundTaskManagerOrThrow().readLog(taskId, cursor);
7351
+ return createLineDetailPage({
7352
+ entryId,
7353
+ lines: page.lines,
7354
+ cursor: page.cursor,
7355
+ nextCursor: page.nextCursor,
7356
+ kind: task.kind === "process" ? "process_output" : "progress"
7357
+ });
7358
+ }
7359
+ const detailKind = task.status === "failed" ? "error" : task.status === "completed" ? "result" : "progress";
7360
+ const text = task.error?.message ?? task.result?.output ?? task.currentAction ?? task.promptPreview ?? task.commandPreview ?? task.status;
7361
+ return createLineDetailPage({ entryId, lines: [text], cursor, kind: detailKind });
7362
+ }
7363
+ readBackgroundGroupDetail(entryId, groupId) {
7364
+ const group = this.getBackgroundJobOrchestratorOrThrow().getGroup(groupId);
7365
+ if (!group) throw new Error(`Unknown background job group: ${groupId}`);
7366
+ const summary = summarizeBackgroundJobGroup(group);
7367
+ return createLineDetailPage({
7368
+ entryId,
7369
+ lines: summary.lines,
7370
+ kind: "group_summary"
7371
+ });
7372
+ }
7373
+ getMainThreadUpdatedAt() {
7374
+ return this.history.at(-1)?.timestamp.toISOString() ?? (/* @__PURE__ */ new Date(0)).toISOString();
7375
+ }
7376
+ getMainThreadPreview() {
7377
+ if (this.streamingText.trim().length > 0) return this.streamingText;
7378
+ const latest = this.history.at(-1);
7379
+ if (!latest) return void 0;
7380
+ return latest.type;
7381
+ }
7382
+ emitExecutionWorkspaceUpdated(cause, entryId) {
7383
+ if (!this.session) return;
7384
+ this.emit("execution_workspace_event", {
7385
+ type: "execution_workspace_updated",
7386
+ cause,
7387
+ ...entryId ? { entryId } : {},
7388
+ snapshot: this.getExecutionWorkspaceSnapshot()
7389
+ });
7390
+ }
6968
7391
  getBackgroundTaskManagerOrThrow() {
6969
7392
  const manager = this.getBackgroundTaskManager();
6970
7393
  if (!manager) {
@@ -7030,11 +7453,16 @@ var InteractiveSession = class {
7030
7453
  this.backgroundTasks = this.getBackgroundTaskSnapshots();
7031
7454
  this.backgroundTaskEvents.push(event);
7032
7455
  this.persistCurrentSession();
7456
+ this.emitExecutionWorkspaceUpdated("background_task", getBackgroundTaskEventEntryId(event));
7033
7457
  }
7034
7458
  recordBackgroundJobGroupEvent(event) {
7035
7459
  this.backgroundJobGroups = this.getBackgroundJobGroupSnapshots();
7036
7460
  this.backgroundJobGroupEvents.push(event);
7037
7461
  this.persistCurrentSession();
7462
+ this.emitExecutionWorkspaceUpdated(
7463
+ "background_group",
7464
+ createBackgroundGroupExecutionEntryId(event.group.id)
7465
+ );
7038
7466
  }
7039
7467
  getBackgroundTaskSnapshots() {
7040
7468
  try {
@@ -7098,10 +7526,12 @@ var InteractiveSession = class {
7098
7526
  this.clearStreaming();
7099
7527
  this.emit("thinking", true);
7100
7528
  this.history.push(messageToHistoryEntry(createUserMessage(displayInput)));
7529
+ this.emitExecutionWorkspaceUpdated("main_thread");
7101
7530
  }
7102
7531
  finishForkSkillExecution() {
7103
7532
  this.executing = false;
7104
7533
  this.emit("thinking", false);
7534
+ this.emitExecutionWorkspaceUpdated("main_thread");
7105
7535
  this.persistCurrentSession();
7106
7536
  if (!this.shuttingDown && this.pendingPrompt) {
7107
7537
  const queued = this.pendingPrompt;
@@ -7171,6 +7601,7 @@ var InteractiveSession = class {
7171
7601
  this.executing = true;
7172
7602
  this.clearStreaming();
7173
7603
  this.emit("thinking", true);
7604
+ this.emitExecutionWorkspaceUpdated("main_thread");
7174
7605
  try {
7175
7606
  const result = await this.commandExecutor.executeCommand(command, this, args);
7176
7607
  this.emit("context_update", this.getContextState());
@@ -7184,6 +7615,7 @@ var InteractiveSession = class {
7184
7615
  } finally {
7185
7616
  this.executing = false;
7186
7617
  this.emit("thinking", false);
7618
+ this.emitExecutionWorkspaceUpdated("main_thread");
7187
7619
  this.persistCurrentSession();
7188
7620
  if (!this.shuttingDown && this.pendingPrompt) {
7189
7621
  const queued = this.pendingPrompt;
@@ -7197,8 +7629,10 @@ var InteractiveSession = class {
7197
7629
  async executePrompt(input, displayInput, rawInput) {
7198
7630
  this.executing = true;
7199
7631
  this.clearStreaming();
7632
+ this.emit("user_message", displayInput ?? input);
7200
7633
  this.emit("thinking", true);
7201
7634
  this.history.push(messageToHistoryEntry(createUserMessage(displayInput ?? input)));
7635
+ this.emitExecutionWorkspaceUpdated("main_thread");
7202
7636
  const historyBefore = this.getSessionOrThrow().getHistory().length;
7203
7637
  this.usedMemoryReferences = [];
7204
7638
  try {
@@ -7260,6 +7694,7 @@ var InteractiveSession = class {
7260
7694
  await this.finalizeEditCheckpointTurn();
7261
7695
  this.executing = false;
7262
7696
  this.emit("thinking", false);
7697
+ this.emitExecutionWorkspaceUpdated("main_thread");
7263
7698
  this.persistCurrentSession();
7264
7699
  if (!this.shuttingDown && this.pendingPrompt) {
7265
7700
  const queued = this.pendingPrompt;
@@ -7558,6 +7993,404 @@ function createQuery(options) {
7558
7993
  };
7559
7994
  }
7560
7995
 
7996
+ // src/user-local/storage.ts
7997
+ import { promises as fs } from "fs";
7998
+ import { homedir as homedir6 } from "os";
7999
+ import path from "path";
8000
+ var USER_LOCAL_STORAGE_CATEGORIES = [
8001
+ "preferences",
8002
+ "view-state",
8003
+ "memory-projections",
8004
+ "task-associations",
8005
+ "workflow-metadata",
8006
+ "inspection-index"
8007
+ ];
8008
+ var USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS = [
8009
+ {
8010
+ category: "preferences",
8011
+ purpose: "User-local UI and display preferences.",
8012
+ mayExecuteCommands: false
8013
+ },
8014
+ {
8015
+ category: "view-state",
8016
+ purpose: "Last selected panels, filters, and navigation state.",
8017
+ mayExecuteCommands: false
8018
+ },
8019
+ {
8020
+ category: "memory-projections",
8021
+ purpose: "Inspectable local memory item projections and user choices.",
8022
+ mayExecuteCommands: false
8023
+ },
8024
+ {
8025
+ category: "task-associations",
8026
+ purpose: "User-local associations between sessions, tasks, and background items.",
8027
+ mayExecuteCommands: false
8028
+ },
8029
+ {
8030
+ category: "workflow-metadata",
8031
+ purpose: "Transparent workflow metadata that is not repo-owned.",
8032
+ mayExecuteCommands: false
8033
+ },
8034
+ {
8035
+ category: "inspection-index",
8036
+ purpose: "Category and item summaries for user inspection and deletion.",
8037
+ mayExecuteCommands: false
8038
+ }
8039
+ ];
8040
+ function formatIsoDate(date) {
8041
+ return date.toISOString();
8042
+ }
8043
+ function assertAbsolutePath(name, value) {
8044
+ if (value.trim().length === 0) {
8045
+ throw new Error(`${name} must not be empty.`);
8046
+ }
8047
+ if (!path.isAbsolute(value)) {
8048
+ throw new Error(`${name} must be an absolute path: ${value}`);
8049
+ }
8050
+ }
8051
+ function resolveDefaultHomeDir() {
8052
+ return process.env.HOME ?? homedir6();
8053
+ }
8054
+ function isEqualOrInside(parentPath, candidatePath) {
8055
+ const relative4 = path.relative(parentPath, candidatePath);
8056
+ return relative4 === "" || !relative4.startsWith("..") && !path.isAbsolute(relative4);
8057
+ }
8058
+ async function resolveForComparison(absPath) {
8059
+ let current = absPath;
8060
+ while (path.dirname(current) !== current) {
8061
+ try {
8062
+ const realCurrent = await fs.realpath(current);
8063
+ const relativeMissingPath = path.relative(current, absPath);
8064
+ return path.resolve(realCurrent, relativeMissingPath);
8065
+ } catch {
8066
+ current = path.dirname(current);
8067
+ }
8068
+ }
8069
+ try {
8070
+ return await fs.realpath(current);
8071
+ } catch {
8072
+ return path.resolve(absPath);
8073
+ }
8074
+ }
8075
+ async function resolveUserLocalStorageRoot(options) {
8076
+ const activeRepositoryRoot = path.resolve(options.activeRepositoryRoot);
8077
+ assertAbsolutePath("activeRepositoryRoot", activeRepositoryRoot);
8078
+ const candidateRoot = options.storageRoot !== void 0 ? options.storageRoot : path.join(options.homeDir ?? resolveDefaultHomeDir(), ".robota");
8079
+ assertAbsolutePath("userLocalStorageRoot", candidateRoot);
8080
+ const resolvedRoot = path.resolve(candidateRoot);
8081
+ const comparableRoot = await resolveForComparison(resolvedRoot);
8082
+ const comparableRepositoryRoot = await resolveForComparison(activeRepositoryRoot);
8083
+ if (isEqualOrInside(comparableRepositoryRoot, comparableRoot)) {
8084
+ throw new Error(
8085
+ `User-local storage root must be outside the active repository: ${resolvedRoot}`
8086
+ );
8087
+ }
8088
+ return resolvedRoot;
8089
+ }
8090
+ function resolveCategoryLocation(root, category) {
8091
+ return path.join(root, category);
8092
+ }
8093
+ async function listItemSummaries(root, category) {
8094
+ const storageLocation = resolveCategoryLocation(root, category);
8095
+ let entries;
8096
+ try {
8097
+ entries = await fs.readdir(storageLocation, { withFileTypes: true });
8098
+ } catch {
8099
+ return [];
8100
+ }
8101
+ const summaries = await Promise.all(
8102
+ entries.map(async (entry) => {
8103
+ const itemLocation = path.join(storageLocation, entry.name);
8104
+ const stats = await fs.stat(itemLocation);
8105
+ const key = entry.name;
8106
+ return {
8107
+ root,
8108
+ category,
8109
+ key,
8110
+ summary: `${category}/${key}`,
8111
+ source: "user-local-storage",
8112
+ scope: "user",
8113
+ storageLocation: itemLocation,
8114
+ createdAt: formatIsoDate(stats.birthtime),
8115
+ lastUsedAt: formatIsoDate(stats.mtime),
8116
+ enabled: true,
8117
+ deleteAvailable: true,
8118
+ disableAvailable: false
8119
+ };
8120
+ })
8121
+ );
8122
+ return summaries.sort((left, right) => left.key.localeCompare(right.key));
8123
+ }
8124
+ async function inspectUserLocalStorage(options) {
8125
+ const root = await resolveUserLocalStorageRoot(options);
8126
+ const activeRepositoryRoot = path.resolve(options.activeRepositoryRoot);
8127
+ const createDirectories = options.createDirectories ?? true;
8128
+ if (createDirectories) {
8129
+ await fs.mkdir(root, { recursive: true });
8130
+ }
8131
+ const categories = await Promise.all(
8132
+ USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS.map(
8133
+ async (definition) => {
8134
+ const storageLocation = resolveCategoryLocation(root, definition.category);
8135
+ if (createDirectories) {
8136
+ await fs.mkdir(storageLocation, { recursive: true });
8137
+ }
8138
+ const items = await listItemSummaries(root, definition.category);
8139
+ return {
8140
+ category: definition.category,
8141
+ purpose: definition.purpose,
8142
+ mayExecuteCommands: definition.mayExecuteCommands,
8143
+ storageLocation,
8144
+ itemCount: items.length,
8145
+ items
8146
+ };
8147
+ }
8148
+ )
8149
+ );
8150
+ return {
8151
+ root,
8152
+ activeRepositoryRoot,
8153
+ categories,
8154
+ generatedAt: formatIsoDate((options.now ?? (() => /* @__PURE__ */ new Date()))())
8155
+ };
8156
+ }
8157
+
8158
+ // src/user-local/memory.ts
8159
+ import { promises as fs2 } from "fs";
8160
+ import path2 from "path";
8161
+
8162
+ // src/user-local/memory-types.ts
8163
+ var USER_LOCAL_MEMORY_CATEGORIES = [
8164
+ "view-preference",
8165
+ "last-visible-cwd",
8166
+ "background-selection",
8167
+ "task-association",
8168
+ "display-preference",
8169
+ "inspection-choice"
8170
+ ];
8171
+
8172
+ // src/user-local/memory.ts
8173
+ var MEMORY_STORAGE_CATEGORY = "memory-projections";
8174
+ var FILE_EXTENSION = ".json";
8175
+ var MEMORY_SCHEMA_VERSION = 1;
8176
+ var MAX_SEGMENT_LENGTH = 80;
8177
+ var MAX_SUMMARY_LENGTH = 240;
8178
+ var MAX_SOURCE_LENGTH = 80;
8179
+ var MAX_SCOPE_LENGTH = 120;
8180
+ var MAX_VALUE_SUMMARY_LENGTH = 240;
8181
+ var DEFAULT_SCOPE = "user";
8182
+ var SAFE_SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]*$/u;
8183
+ var DISPLAY_NAVIGATION_RULES = {
8184
+ "view-preference": "May affect UI panel, filter, density, or sorting display/navigation only.",
8185
+ "last-visible-cwd": "May display or preselect an already visible workspace context only.",
8186
+ "background-selection": "May restore the selected background entry in local UI only.",
8187
+ "task-association": "May group visible tasks by a local association only.",
8188
+ "display-preference": "May affect local text wrapping, compactness, or visibility only.",
8189
+ "inspection-choice": "May affect inspection display choices only."
8190
+ };
8191
+ function formatIsoDate2(date) {
8192
+ return date.toISOString();
8193
+ }
8194
+ function isUserLocalMemoryCategory(value) {
8195
+ return USER_LOCAL_MEMORY_CATEGORIES.includes(value);
8196
+ }
8197
+ function assertUserLocalMemoryCategory(value) {
8198
+ if (!isUserLocalMemoryCategory(value)) {
8199
+ throw new Error(`Unsupported user-local memory category: ${value}`);
8200
+ }
8201
+ return value;
8202
+ }
8203
+ function assertSafeSegment(name, value) {
8204
+ const trimmed = value.trim();
8205
+ if (trimmed.length === 0) {
8206
+ throw new Error(`${name} must not be empty.`);
8207
+ }
8208
+ if (trimmed.length > MAX_SEGMENT_LENGTH || !SAFE_SEGMENT_PATTERN.test(trimmed)) {
8209
+ throw new Error(
8210
+ `${name} must use lowercase letters, numbers, dots, underscores, or hyphens: ${value}`
8211
+ );
8212
+ }
8213
+ return trimmed;
8214
+ }
8215
+ function boundedText(name, value, maxLength) {
8216
+ const normalized = value.trim().replace(/\s+/g, " ");
8217
+ if (normalized.length === 0) {
8218
+ throw new Error(`${name} must not be empty.`);
8219
+ }
8220
+ if (normalized.length > maxLength) {
8221
+ return normalized.slice(0, maxLength);
8222
+ }
8223
+ return normalized;
8224
+ }
8225
+ function summarizeValue(value) {
8226
+ return boundedText("value", value, MAX_VALUE_SUMMARY_LENGTH);
8227
+ }
8228
+ function memoryFileName(category, key) {
8229
+ return `${category}__${key}${FILE_EXTENSION}`;
8230
+ }
8231
+ async function resolveMemoryRoot(options) {
8232
+ const root = await resolveUserLocalStorageRoot(options);
8233
+ return {
8234
+ root,
8235
+ memoryRoot: path2.join(root, MEMORY_STORAGE_CATEGORY)
8236
+ };
8237
+ }
8238
+ function parseMemoryRecord(raw, storageLocation) {
8239
+ const record = JSON.parse(raw);
8240
+ const category = readString(record, "category");
8241
+ const schemaVersion = record["schemaVersion"];
8242
+ if (schemaVersion !== MEMORY_SCHEMA_VERSION) {
8243
+ throw new Error(`Unsupported user-local memory schema at ${storageLocation}`);
8244
+ }
8245
+ return {
8246
+ schemaVersion: MEMORY_SCHEMA_VERSION,
8247
+ category: assertUserLocalMemoryCategory(category),
8248
+ key: readString(record, "key"),
8249
+ value: readString(record, "value"),
8250
+ summary: readString(record, "summary"),
8251
+ source: readString(record, "source"),
8252
+ scope: readString(record, "scope"),
8253
+ createdAt: readString(record, "createdAt"),
8254
+ lastUsedAt: readString(record, "lastUsedAt"),
8255
+ enabled: readBoolean(record, "enabled")
8256
+ };
8257
+ }
8258
+ function readString(record, key) {
8259
+ const value = record[key];
8260
+ if (typeof value !== "string") {
8261
+ throw new Error(`Invalid user-local memory field: ${key}`);
8262
+ }
8263
+ return value;
8264
+ }
8265
+ function readBoolean(record, key) {
8266
+ const value = record[key];
8267
+ if (typeof value !== "boolean") {
8268
+ throw new Error(`Invalid user-local memory field: ${key}`);
8269
+ }
8270
+ return value;
8271
+ }
8272
+ function projectMemoryItem(root, storageLocation, item) {
8273
+ return {
8274
+ root,
8275
+ category: item.category,
8276
+ key: item.key,
8277
+ summary: item.summary,
8278
+ valueSummary: summarizeValue(item.value),
8279
+ source: item.source,
8280
+ scope: item.scope,
8281
+ storageLocation,
8282
+ createdAt: item.createdAt,
8283
+ lastUsedAt: item.lastUsedAt,
8284
+ enabled: item.enabled,
8285
+ displayNavigationRule: DISPLAY_NAVIGATION_RULES[item.category],
8286
+ commandExecutionEffect: "none",
8287
+ deleteAvailable: true,
8288
+ disableAvailable: true
8289
+ };
8290
+ }
8291
+ async function readMemoryFile(root, storageLocation) {
8292
+ return projectMemoryItem(
8293
+ root,
8294
+ storageLocation,
8295
+ parseMemoryRecord(await fs2.readFile(storageLocation, "utf8"), storageLocation)
8296
+ );
8297
+ }
8298
+ async function resolveMemoryFile(options) {
8299
+ const category = assertUserLocalMemoryCategory(options.category);
8300
+ const key = assertSafeSegment("key", options.key);
8301
+ const { root, memoryRoot: memoryRoot3 } = await resolveMemoryRoot(options);
8302
+ return {
8303
+ root,
8304
+ storageLocation: path2.join(memoryRoot3, memoryFileName(category, key))
8305
+ };
8306
+ }
8307
+ async function setUserLocalMemoryItem(options) {
8308
+ const category = assertUserLocalMemoryCategory(options.category);
8309
+ const key = assertSafeSegment("key", options.key);
8310
+ const summary = boundedText("summary", options.summary, MAX_SUMMARY_LENGTH);
8311
+ const source = boundedText("source", options.source, MAX_SOURCE_LENGTH);
8312
+ const scope = boundedText("scope", options.scope ?? DEFAULT_SCOPE, MAX_SCOPE_LENGTH);
8313
+ const value = summarizeValue(options.value);
8314
+ const now = formatIsoDate2((options.now ?? (() => /* @__PURE__ */ new Date()))());
8315
+ const { root, memoryRoot: memoryRoot3 } = await resolveMemoryRoot(options);
8316
+ const storageLocation = path2.join(memoryRoot3, memoryFileName(category, key));
8317
+ let createdAt = now;
8318
+ try {
8319
+ const existing = parseMemoryRecord(await fs2.readFile(storageLocation, "utf8"), storageLocation);
8320
+ createdAt = existing.createdAt;
8321
+ } catch (error) {
8322
+ if (error instanceof Error && error.message.includes("ENOENT")) {
8323
+ createdAt = now;
8324
+ } else {
8325
+ throw error;
8326
+ }
8327
+ }
8328
+ const item = {
8329
+ schemaVersion: MEMORY_SCHEMA_VERSION,
8330
+ category,
8331
+ key,
8332
+ value,
8333
+ summary,
8334
+ source,
8335
+ scope,
8336
+ createdAt,
8337
+ lastUsedAt: now,
8338
+ enabled: true
8339
+ };
8340
+ await fs2.mkdir(memoryRoot3, { recursive: true });
8341
+ await fs2.writeFile(storageLocation, `${JSON.stringify(item, null, 2)}
8342
+ `, "utf8");
8343
+ return projectMemoryItem(root, storageLocation, item);
8344
+ }
8345
+ async function listUserLocalMemoryItems(options) {
8346
+ const { root, memoryRoot: memoryRoot3 } = await resolveMemoryRoot(options);
8347
+ let entries;
8348
+ try {
8349
+ entries = await fs2.readdir(memoryRoot3, { withFileTypes: true });
8350
+ } catch {
8351
+ entries = [];
8352
+ }
8353
+ const items = await Promise.all(
8354
+ entries.filter((entry) => entry.isFile() && entry.name.endsWith(FILE_EXTENSION)).map((entry) => readMemoryFile(root, path2.join(memoryRoot3, entry.name)))
8355
+ );
8356
+ return {
8357
+ root,
8358
+ activeRepositoryRoot: path2.resolve(options.activeRepositoryRoot),
8359
+ items: items.sort(
8360
+ (left, right) => `${left.category}/${left.key}`.localeCompare(`${right.category}/${right.key}`)
8361
+ )
8362
+ };
8363
+ }
8364
+ async function inspectUserLocalMemoryItem(options) {
8365
+ const { root, storageLocation } = await resolveMemoryFile(options);
8366
+ return readMemoryFile(root, storageLocation);
8367
+ }
8368
+ async function disableUserLocalMemoryItem(options) {
8369
+ const { root, storageLocation } = await resolveMemoryFile(options);
8370
+ const existing = parseMemoryRecord(await fs2.readFile(storageLocation, "utf8"), storageLocation);
8371
+ const disabled = {
8372
+ ...existing,
8373
+ enabled: false,
8374
+ lastUsedAt: formatIsoDate2((options.now ?? (() => /* @__PURE__ */ new Date()))())
8375
+ };
8376
+ await fs2.writeFile(storageLocation, `${JSON.stringify(disabled, null, 2)}
8377
+ `, "utf8");
8378
+ return projectMemoryItem(root, storageLocation, disabled);
8379
+ }
8380
+ async function deleteUserLocalMemoryItem(options) {
8381
+ const { storageLocation } = await resolveMemoryFile(options);
8382
+ await fs2.rm(storageLocation);
8383
+ return {
8384
+ category: options.category,
8385
+ key: options.key,
8386
+ deleted: true
8387
+ };
8388
+ }
8389
+ async function readEnabledUserLocalMemoryItem(options) {
8390
+ const item = await inspectUserLocalMemoryItem(options);
8391
+ return item.enabled ? item : null;
8392
+ }
8393
+
7561
8394
  // src/self-hosting/self-hosting-verification.ts
7562
8395
  var DEFAULT_BASE_REF = "origin/develop";
7563
8396
  var PACKAGE_VERIFY_COMMANDS = ["test", "typecheck", "build"];
@@ -7776,6 +8609,7 @@ export {
7776
8609
  DEFAULT_AUTO_COMPACT_THRESHOLD,
7777
8610
  DEFAULT_BACKGROUND_TASK_LOG_PAGE_SIZE,
7778
8611
  DEFAULT_STATUS_LINE_COMMAND_SETTINGS,
8612
+ EXECUTION_ORIGIN_METADATA_KEYS,
7779
8613
  EXIT_COMMAND_DESCRIPTION,
7780
8614
  EditCheckpointStore,
7781
8615
  HELP_COMMAND_DESCRIPTION,
@@ -7813,6 +8647,9 @@ export {
7813
8647
  SkillCommandSource,
7814
8648
  SubagentManager3 as SubagentManager,
7815
8649
  SystemCommandExecutor,
8650
+ USER_LOCAL_MEMORY_CATEGORIES,
8651
+ USER_LOCAL_STORAGE_CATEGORIES,
8652
+ USER_LOCAL_STORAGE_CATEGORY_DEFINITIONS,
7816
8653
  VALIDATE_SESSION_COMMAND_DESCRIPTION,
7817
8654
  VALID_PERMISSION_MODES,
7818
8655
  WorktreeSubagentRunner,
@@ -7837,7 +8674,9 @@ export {
7837
8674
  closeCommandBackgroundTask,
7838
8675
  compactCommandContext,
7839
8676
  createAgentTool,
8677
+ createBackgroundGroupExecutionEntryId,
7840
8678
  createBackgroundProcessTool,
8679
+ createBackgroundTaskExecutionEntryId,
7841
8680
  createBackgroundTaskLogPage,
7842
8681
  createBuiltinCommandModule,
7843
8682
  createCommandExecutionTool,
@@ -7846,7 +8685,13 @@ export {
7846
8685
  createCommandProjectMemoryStore,
7847
8686
  createContextReferenceItem,
7848
8687
  createDefaultTools,
8688
+ createExecutionOriginMetadata,
8689
+ createExecutionWorkspaceSnapshot,
8690
+ createExecutionWorkspaceTaskSpawner,
7849
8691
  createLimitedOutputCapture,
8692
+ createLineDetailPage,
8693
+ createMainThreadDetailPage,
8694
+ createMainThreadExecutionEntryId,
7850
8695
  createModelCommandToolProjection,
7851
8696
  createPluginRegistryReloadRequestedEffect,
7852
8697
  createPluginTuiRequestedEffect,
@@ -7864,6 +8709,8 @@ export {
7864
8709
  createSystemCommands,
7865
8710
  createWorktreeSubagentRunner,
7866
8711
  deleteProviderProfile,
8712
+ deleteUserLocalMemoryItem,
8713
+ disableUserLocalMemoryItem,
7867
8714
  discoverTaskFiles,
7868
8715
  evaluateReversibleToolSafety,
7869
8716
  executeSkill,
@@ -7893,12 +8740,14 @@ export {
7893
8740
  hasSensitiveCommandMemoryContent,
7894
8741
  hasUsableSecretReference,
7895
8742
  inspectCommandEditCheckpoint,
8743
+ inspectUserLocalMemoryItem,
8744
+ inspectUserLocalStorage,
7896
8745
  isCommandMemoryType,
7897
8746
  isEnvReference,
7898
8747
  isMemoryType,
7899
8748
  isPermissionMode,
7900
8749
  isStatusLineCommandSettingsPatch,
7901
- isTerminalBackgroundTaskStatus2 as isTerminalBackgroundTaskStatus,
8750
+ isTerminalBackgroundTaskStatus3 as isTerminalBackgroundTaskStatus,
7902
8751
  listActiveContextReferences,
7903
8752
  listCommandBackgroundTasks,
7904
8753
  listCommandContextReferences,
@@ -7906,10 +8755,12 @@ export {
7906
8755
  listCommandSessionAllowedTools,
7907
8756
  listCommandUsedMemoryReferences,
7908
8757
  listResumableSessionSummaries,
8758
+ listUserLocalMemoryItems,
7909
8759
  loadTaskContext,
7910
8760
  mergeProviderPatch,
7911
8761
  normalizeModelCommandName,
7912
8762
  parseCommandBackgroundLogCursor,
8763
+ parseExecutionWorkspaceEntryId,
7913
8764
  parseFrontmatter,
7914
8765
  parseLanguageArgument,
7915
8766
  parsePermissionModeArgument,
@@ -7929,6 +8780,7 @@ export {
7929
8780
  readCommandPermissionsState,
7930
8781
  readCommandSessionInfo,
7931
8782
  readCurrentGitBranch,
8783
+ readEnabledUserLocalMemoryItem,
7932
8784
  recordCommandMemoryEvent,
7933
8785
  removeCommandContextReference,
7934
8786
  removeContextReference,
@@ -7944,6 +8796,7 @@ export {
7944
8796
  resolveProviderSetupSelection,
7945
8797
  resolveSessionIdByIdOrName,
7946
8798
  resolveSubagentLogDir,
8799
+ resolveUserLocalStorageRoot,
7947
8800
  restoreCommandEditCheckpoint,
7948
8801
  retrieveAgentToolDeps,
7949
8802
  rollbackCommandEditCheckpoint,
@@ -7952,6 +8805,7 @@ export {
7952
8805
  selectRelevantTasks,
7953
8806
  setCommandAutoCompactThreshold,
7954
8807
  setCurrentProvider,
8808
+ setUserLocalMemoryItem,
7955
8809
  storeAgentToolDeps,
7956
8810
  submitProviderSetupValue,
7957
8811
  substituteVariables,