@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.
- package/dist/node/index.cjs +1196 -321
- package/dist/node/index.d.cts +299 -3
- package/dist/node/index.d.ts +299 -3
- package/dist/node/index.js +1173 -319
- package/package.json +5 -5
package/dist/node/index.js
CHANGED
|
@@ -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,
|
|
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(
|
|
551
|
+
return context.addContextReference(path3);
|
|
552
552
|
}
|
|
553
|
-
function removeCommandContextReference(context,
|
|
554
|
-
return context.removeContextReference?.(
|
|
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
|
|
1465
|
-
if (!existsSync3(
|
|
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(
|
|
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
|
|
1494
|
-
if (!existsSync3(
|
|
1495
|
-
return readFileSync3(
|
|
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
|
|
2536
|
-
const
|
|
2537
|
-
|
|
2538
|
-
|
|
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
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
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
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
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 ${
|
|
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((
|
|
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(
|
|
5487
|
+
readManifest(path3) {
|
|
5169
5488
|
try {
|
|
5170
|
-
const raw = readFileSync11(
|
|
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(
|
|
5729
|
-
const raw = readFileSync14(
|
|
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,
|
|
6001
|
-
const result = await resolvePromptFileReferencePaths([
|
|
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(
|
|
6413
|
+
function statSafe(path3) {
|
|
6095
6414
|
try {
|
|
6096
|
-
return statSync2(
|
|
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
|
|
6268
|
-
const 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,
|
|
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(
|
|
6615
|
+
async function pathExists(path3) {
|
|
6297
6616
|
try {
|
|
6298
|
-
await access(
|
|
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(
|
|
6630
|
+
function readJsonManifest(path3) {
|
|
6312
6631
|
try {
|
|
6313
|
-
const raw = readFileSync15(
|
|
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(
|
|
7103
|
+
async addContextReference(path3) {
|
|
6780
7104
|
const { references, result } = await addInteractiveContextReference(
|
|
6781
7105
|
this.contextReferences,
|
|
6782
|
-
|
|
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(
|
|
6790
|
-
const result = removeContextReference(this.contextReferences,
|
|
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:
|
|
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
|
-
|
|
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,
|