@ouro.bot/cli 0.1.0-alpha.479 → 0.1.0-alpha.480
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/changelog.json +8 -0
- package/dist/heart/active-work.js +25 -0
- package/dist/heart/background-operations.js +234 -0
- package/dist/heart/daemon/cli-defaults.js +9 -0
- package/dist/heart/daemon/cli-exec.js +234 -2
- package/dist/heart/daemon/cli-help.js +2 -2
- package/dist/heart/daemon/cli-parse.js +30 -4
- package/dist/mailroom/blob-store.js +6 -1
- package/dist/mailroom/mbox-import.js +3 -0
- package/dist/repertoire/tools-session.js +7 -0
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.480",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro mail import-mbox` and `ouro mail backfill-indexes` now launch as durable background operations by default, so large delegated-mail imports and hosted index repairs no longer block ordinary conversation.",
|
|
8
|
+
"Mail background jobs now persist queued/running/succeeded/failed state with progress, show up in `query_active_work`, and wake the agent immediately on completion or failure with actionable remediation context.",
|
|
9
|
+
"The background-operation runtime and CLI lifecycle are covered back to a restored 100% statements/branches/functions/lines gate, including detached background spawn defaults, malformed persisted records, and non-Error failure paths."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
4
12
|
{
|
|
5
13
|
"version": "0.1.0-alpha.479",
|
|
6
14
|
"changes": [
|
|
@@ -513,6 +513,7 @@ function buildActiveWorkFrame(input) {
|
|
|
513
513
|
allOtherLiveSessions,
|
|
514
514
|
},
|
|
515
515
|
codingSessions: liveCodingSessions,
|
|
516
|
+
backgroundOperations: input.backgroundOperations ?? [],
|
|
516
517
|
otherCodingSessions,
|
|
517
518
|
pendingObligations,
|
|
518
519
|
targetCandidates: input.targetCandidates ?? [],
|
|
@@ -640,6 +641,30 @@ function formatActiveWorkFrame(frame, options) {
|
|
|
640
641
|
/* v8 ignore stop */
|
|
641
642
|
}
|
|
642
643
|
}
|
|
644
|
+
const backgroundOperations = frame.backgroundOperations ?? [];
|
|
645
|
+
if (backgroundOperations.length > 0) {
|
|
646
|
+
lines.push("");
|
|
647
|
+
lines.push("## background operations");
|
|
648
|
+
for (const operation of backgroundOperations) {
|
|
649
|
+
let line = `- [${operation.status}] ${operation.title}`;
|
|
650
|
+
if (operation.summary.trim().length > 0) {
|
|
651
|
+
line += `: ${operation.summary}`;
|
|
652
|
+
}
|
|
653
|
+
if (operation.detail?.trim()) {
|
|
654
|
+
line += `\n ${operation.detail.trim()}`;
|
|
655
|
+
}
|
|
656
|
+
if (operation.progress) {
|
|
657
|
+
const current = typeof operation.progress.current === "number" ? String(operation.progress.current) : "?";
|
|
658
|
+
const total = typeof operation.progress.total === "number" ? String(operation.progress.total) : null;
|
|
659
|
+
const unit = operation.progress.unit?.trim() ? ` ${operation.progress.unit.trim()}` : "";
|
|
660
|
+
line += `\n progress: ${total ? `${current}/${total}` : current}${unit}`;
|
|
661
|
+
}
|
|
662
|
+
if (operation.error?.message?.trim()) {
|
|
663
|
+
line += `\n error: ${operation.error.message.trim()}`;
|
|
664
|
+
}
|
|
665
|
+
lines.push(line);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
643
668
|
if (otherActiveSessions.length > 0) {
|
|
644
669
|
lines.push("");
|
|
645
670
|
lines.push("## other active sessions");
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readBackgroundOperation = readBackgroundOperation;
|
|
37
|
+
exports.listBackgroundOperations = listBackgroundOperations;
|
|
38
|
+
exports.startBackgroundOperation = startBackgroundOperation;
|
|
39
|
+
exports.markBackgroundOperationRunning = markBackgroundOperationRunning;
|
|
40
|
+
exports.updateBackgroundOperation = updateBackgroundOperation;
|
|
41
|
+
exports.completeBackgroundOperation = completeBackgroundOperation;
|
|
42
|
+
exports.failBackgroundOperation = failBackgroundOperation;
|
|
43
|
+
const fs = __importStar(require("node:fs"));
|
|
44
|
+
const path = __importStar(require("node:path"));
|
|
45
|
+
const runtime_1 = require("../nerves/runtime");
|
|
46
|
+
const identity_1 = require("./identity");
|
|
47
|
+
function operationsDir(agentName, agentRoot = (0, identity_1.getAgentRoot)(agentName)) {
|
|
48
|
+
return path.join(agentRoot, "state", "background-operations");
|
|
49
|
+
}
|
|
50
|
+
function operationPath(locator) {
|
|
51
|
+
return path.join(operationsDir(locator.agentName, locator.agentRoot), `${locator.id}.json`);
|
|
52
|
+
}
|
|
53
|
+
function normalizeProgress(progress) {
|
|
54
|
+
if (!progress)
|
|
55
|
+
return undefined;
|
|
56
|
+
const normalized = {};
|
|
57
|
+
if (typeof progress.current === "number" && Number.isFinite(progress.current))
|
|
58
|
+
normalized.current = progress.current;
|
|
59
|
+
if (typeof progress.total === "number" && Number.isFinite(progress.total))
|
|
60
|
+
normalized.total = progress.total;
|
|
61
|
+
if (typeof progress.unit === "string" && progress.unit.trim().length > 0)
|
|
62
|
+
normalized.unit = progress.unit.trim();
|
|
63
|
+
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
|
64
|
+
}
|
|
65
|
+
function normalizeRecord(record) {
|
|
66
|
+
if (record.schemaVersion !== 1)
|
|
67
|
+
return null;
|
|
68
|
+
if (typeof record.id !== "string" || record.id.trim().length === 0)
|
|
69
|
+
return null;
|
|
70
|
+
if (typeof record.agentName !== "string" || record.agentName.trim().length === 0)
|
|
71
|
+
return null;
|
|
72
|
+
if (typeof record.kind !== "string" || record.kind.trim().length === 0)
|
|
73
|
+
return null;
|
|
74
|
+
if (typeof record.title !== "string" || record.title.trim().length === 0)
|
|
75
|
+
return null;
|
|
76
|
+
if (typeof record.summary !== "string" || record.summary.trim().length === 0)
|
|
77
|
+
return null;
|
|
78
|
+
if (typeof record.createdAt !== "string" || record.createdAt.trim().length === 0)
|
|
79
|
+
return null;
|
|
80
|
+
if (typeof record.updatedAt !== "string" || record.updatedAt.trim().length === 0)
|
|
81
|
+
return null;
|
|
82
|
+
if (record.status !== "queued"
|
|
83
|
+
&& record.status !== "running"
|
|
84
|
+
&& record.status !== "succeeded"
|
|
85
|
+
&& record.status !== "failed") {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const normalized = {
|
|
89
|
+
schemaVersion: 1,
|
|
90
|
+
id: record.id,
|
|
91
|
+
agentName: record.agentName,
|
|
92
|
+
kind: record.kind,
|
|
93
|
+
title: record.title,
|
|
94
|
+
status: record.status,
|
|
95
|
+
summary: record.summary,
|
|
96
|
+
createdAt: record.createdAt,
|
|
97
|
+
updatedAt: record.updatedAt,
|
|
98
|
+
};
|
|
99
|
+
if (typeof record.detail === "string" && record.detail.trim().length > 0)
|
|
100
|
+
normalized.detail = record.detail.trim();
|
|
101
|
+
if (typeof record.startedAt === "string" && record.startedAt.trim().length > 0)
|
|
102
|
+
normalized.startedAt = record.startedAt;
|
|
103
|
+
if (typeof record.finishedAt === "string" && record.finishedAt.trim().length > 0)
|
|
104
|
+
normalized.finishedAt = record.finishedAt;
|
|
105
|
+
const progress = normalizeProgress(record.progress);
|
|
106
|
+
if (progress)
|
|
107
|
+
normalized.progress = progress;
|
|
108
|
+
if (record.spec && typeof record.spec === "object" && !Array.isArray(record.spec))
|
|
109
|
+
normalized.spec = { ...record.spec };
|
|
110
|
+
if (record.result && typeof record.result === "object" && !Array.isArray(record.result))
|
|
111
|
+
normalized.result = { ...record.result };
|
|
112
|
+
if (record.error && typeof record.error.message === "string" && record.error.message.trim().length > 0) {
|
|
113
|
+
normalized.error = { message: record.error.message.trim() };
|
|
114
|
+
}
|
|
115
|
+
if (Array.isArray(record.remediation)) {
|
|
116
|
+
const remediation = record.remediation.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
117
|
+
if (remediation.length > 0)
|
|
118
|
+
normalized.remediation = remediation;
|
|
119
|
+
}
|
|
120
|
+
return normalized;
|
|
121
|
+
}
|
|
122
|
+
function readRecord(filePath) {
|
|
123
|
+
try {
|
|
124
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
125
|
+
return normalizeRecord(parsed);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function writeRecord(locator, record) {
|
|
132
|
+
fs.mkdirSync(operationsDir(locator.agentName, locator.agentRoot), { recursive: true });
|
|
133
|
+
fs.writeFileSync(operationPath(locator), `${JSON.stringify(record, null, 2)}\n`, "utf-8");
|
|
134
|
+
(0, runtime_1.emitNervesEvent)({
|
|
135
|
+
component: "engine",
|
|
136
|
+
event: "engine.background_operation_written",
|
|
137
|
+
message: "background operation state written",
|
|
138
|
+
meta: { agentName: locator.agentName, id: locator.id, kind: record.kind, status: record.status },
|
|
139
|
+
});
|
|
140
|
+
return record;
|
|
141
|
+
}
|
|
142
|
+
function requireRecord(locator) {
|
|
143
|
+
const record = readBackgroundOperation(locator);
|
|
144
|
+
if (!record) {
|
|
145
|
+
throw new Error(`background operation not found: ${locator.id}`);
|
|
146
|
+
}
|
|
147
|
+
return record;
|
|
148
|
+
}
|
|
149
|
+
function readBackgroundOperation(locator) {
|
|
150
|
+
return readRecord(operationPath(locator));
|
|
151
|
+
}
|
|
152
|
+
function listBackgroundOperations(input) {
|
|
153
|
+
const dir = operationsDir(input.agentName, input.agentRoot);
|
|
154
|
+
if (!fs.existsSync(dir))
|
|
155
|
+
return [];
|
|
156
|
+
let entries;
|
|
157
|
+
try {
|
|
158
|
+
entries = fs.readdirSync(dir);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
return entries
|
|
164
|
+
.filter((entry) => entry.endsWith(".json"))
|
|
165
|
+
.map((entry) => readRecord(path.join(dir, entry)))
|
|
166
|
+
.filter((entry) => entry !== null)
|
|
167
|
+
.sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt))
|
|
168
|
+
.slice(0, input.limit ?? 10);
|
|
169
|
+
}
|
|
170
|
+
function startBackgroundOperation(input) {
|
|
171
|
+
return writeRecord(input, {
|
|
172
|
+
schemaVersion: 1,
|
|
173
|
+
id: input.id,
|
|
174
|
+
agentName: input.agentName,
|
|
175
|
+
kind: input.kind,
|
|
176
|
+
title: input.title,
|
|
177
|
+
status: "queued",
|
|
178
|
+
summary: input.summary,
|
|
179
|
+
createdAt: input.createdAt,
|
|
180
|
+
updatedAt: input.createdAt,
|
|
181
|
+
...(input.spec ? { spec: input.spec } : {}),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function markBackgroundOperationRunning(input) {
|
|
185
|
+
const current = requireRecord(input);
|
|
186
|
+
const updatedAt = input.updatedAt ?? input.startedAt;
|
|
187
|
+
return writeRecord(input, {
|
|
188
|
+
...current,
|
|
189
|
+
status: "running",
|
|
190
|
+
summary: input.summary ?? current.summary,
|
|
191
|
+
...(input.detail ? { detail: input.detail } : {}),
|
|
192
|
+
...(normalizeProgress(input.progress) ? { progress: normalizeProgress(input.progress) } : {}),
|
|
193
|
+
startedAt: input.startedAt,
|
|
194
|
+
updatedAt,
|
|
195
|
+
...(current.finishedAt ? { finishedAt: current.finishedAt } : {}),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function updateBackgroundOperation(input) {
|
|
199
|
+
const current = requireRecord(input);
|
|
200
|
+
return writeRecord(input, {
|
|
201
|
+
...current,
|
|
202
|
+
summary: input.summary ?? current.summary,
|
|
203
|
+
...(input.detail ? { detail: input.detail } : {}),
|
|
204
|
+
...(normalizeProgress(input.progress) ? { progress: normalizeProgress(input.progress) } : {}),
|
|
205
|
+
updatedAt: input.updatedAt ?? current.updatedAt,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function completeBackgroundOperation(input) {
|
|
209
|
+
const current = requireRecord(input);
|
|
210
|
+
return writeRecord(input, {
|
|
211
|
+
...current,
|
|
212
|
+
status: "succeeded",
|
|
213
|
+
summary: input.summary ?? current.summary,
|
|
214
|
+
...(input.detail ? { detail: input.detail } : {}),
|
|
215
|
+
...(normalizeProgress(input.progress) ? { progress: normalizeProgress(input.progress) } : {}),
|
|
216
|
+
...(input.result ? { result: input.result } : {}),
|
|
217
|
+
finishedAt: input.finishedAt,
|
|
218
|
+
updatedAt: input.updatedAt ?? input.finishedAt,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function failBackgroundOperation(input) {
|
|
222
|
+
const current = requireRecord(input);
|
|
223
|
+
return writeRecord(input, {
|
|
224
|
+
...current,
|
|
225
|
+
status: "failed",
|
|
226
|
+
summary: input.summary ?? current.summary,
|
|
227
|
+
...(input.detail ? { detail: input.detail } : {}),
|
|
228
|
+
...(normalizeProgress(input.progress) ? { progress: normalizeProgress(input.progress) } : {}),
|
|
229
|
+
error: { message: input.error },
|
|
230
|
+
...(input.remediation && input.remediation.length > 0 ? { remediation: input.remediation } : {}),
|
|
231
|
+
finishedAt: input.finishedAt,
|
|
232
|
+
updatedAt: input.updatedAt ?? input.finishedAt,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
@@ -171,6 +171,14 @@ async function defaultFetchCliRegistryJson(timeoutMs) {
|
|
|
171
171
|
function defaultSleep(ms) {
|
|
172
172
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
173
173
|
}
|
|
174
|
+
function defaultSpawnBackgroundCli(argv) {
|
|
175
|
+
const child = (0, child_process_1.spawn)(process.execPath, argv, {
|
|
176
|
+
detached: true,
|
|
177
|
+
stdio: "ignore",
|
|
178
|
+
});
|
|
179
|
+
child.unref();
|
|
180
|
+
return Promise.resolve({ pid: child.pid ?? null });
|
|
181
|
+
}
|
|
174
182
|
function defaultFallbackPendingMessage(command) {
|
|
175
183
|
const inboxDir = path.join((0, identity_1.getAgentBundlesRoot)(), `${command.to}.ouro`, "inbox");
|
|
176
184
|
const pendingPath = path.join(inboxDir, "pending.jsonl");
|
|
@@ -529,6 +537,7 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
|
|
|
529
537
|
readHealthUpdatedAt: defaultReadHealthUpdatedAt,
|
|
530
538
|
readRecentDaemonLogLines: defaultReadRecentDaemonLogLines,
|
|
531
539
|
sleep: defaultSleep,
|
|
540
|
+
spawnBackgroundCli: defaultSpawnBackgroundCli,
|
|
532
541
|
now: () => Date.now(),
|
|
533
542
|
updateCheckTimeoutMs: update_checker_1.CLI_UPDATE_CHECK_TIMEOUT_MS,
|
|
534
543
|
startupPollIntervalMs: 250,
|
|
@@ -82,6 +82,8 @@ const sync_1 = require("../sync");
|
|
|
82
82
|
const core_1 = require("../../mailroom/core");
|
|
83
83
|
const mbox_import_1 = require("../../mailroom/mbox-import");
|
|
84
84
|
const reader_1 = require("../../mailroom/reader");
|
|
85
|
+
const pending_1 = require("../../mind/pending");
|
|
86
|
+
const background_operations_1 = require("../background-operations");
|
|
85
87
|
const cli_parse_1 = require("./cli-parse");
|
|
86
88
|
const cli_parse_2 = require("./cli-parse");
|
|
87
89
|
const cli_help_1 = require("./cli-help");
|
|
@@ -3400,9 +3402,192 @@ function stringField(record, key) {
|
|
|
3400
3402
|
const value = record[key];
|
|
3401
3403
|
return typeof value === "string" ? value.trim() : "";
|
|
3402
3404
|
}
|
|
3405
|
+
function cliNowIso(deps) {
|
|
3406
|
+
return new Date(deps.now?.() ?? Date.now()).toISOString();
|
|
3407
|
+
}
|
|
3408
|
+
function makeBackgroundOperationId(kind) {
|
|
3409
|
+
const prefix = kind === "mail.import-mbox" ? "op_mail_import" : "op_mail_backfill";
|
|
3410
|
+
return `${prefix}_${(0, crypto_1.randomUUID)().slice(0, 8)}`;
|
|
3411
|
+
}
|
|
3412
|
+
function notifyMailOperation(agentName, record, deps) {
|
|
3413
|
+
const lines = [
|
|
3414
|
+
"[Background Operation]",
|
|
3415
|
+
`${record.title} ${record.status === "failed" ? "failed" : "finished"}.`,
|
|
3416
|
+
`operation: ${record.id}`,
|
|
3417
|
+
`status: ${record.status}`,
|
|
3418
|
+
`summary: ${record.summary}`,
|
|
3419
|
+
`detail: ${record.detail}`,
|
|
3420
|
+
...(record.error?.message ? [`error: ${record.error.message}`] : []),
|
|
3421
|
+
...(record.remediation && record.remediation.length > 0 ? ["", "next steps:", ...record.remediation.map((step) => `- ${step}`)] : []),
|
|
3422
|
+
"",
|
|
3423
|
+
"Use query_active_work for the live background-work view before drilling into mail details.",
|
|
3424
|
+
];
|
|
3425
|
+
(0, pending_1.queuePendingMessage)((0, pending_1.getInnerDialogPendingDir)(agentName), {
|
|
3426
|
+
from: "mailroom",
|
|
3427
|
+
friendId: "self",
|
|
3428
|
+
channel: "inner",
|
|
3429
|
+
key: "dialog",
|
|
3430
|
+
content: lines.join("\n"),
|
|
3431
|
+
timestamp: deps.now?.() ?? Date.now(),
|
|
3432
|
+
mode: "reflect",
|
|
3433
|
+
});
|
|
3434
|
+
return deps.sendCommand(deps.socketPath, { kind: "inner.wake", agent: agentName })
|
|
3435
|
+
.then(() => undefined)
|
|
3436
|
+
.catch(() => undefined);
|
|
3437
|
+
}
|
|
3438
|
+
function ensureTrackedMailOperation(input) {
|
|
3439
|
+
if (!input.operationId)
|
|
3440
|
+
return null;
|
|
3441
|
+
const operationId = input.operationId;
|
|
3442
|
+
const agentRoot = providerCliAgentRoot({ agent: input.agentName }, input.deps);
|
|
3443
|
+
const existing = (0, background_operations_1.readBackgroundOperation)({
|
|
3444
|
+
agentName: input.agentName,
|
|
3445
|
+
agentRoot,
|
|
3446
|
+
id: operationId,
|
|
3447
|
+
});
|
|
3448
|
+
const record = existing ?? (0, background_operations_1.startBackgroundOperation)({
|
|
3449
|
+
agentName: input.agentName,
|
|
3450
|
+
agentRoot,
|
|
3451
|
+
id: operationId,
|
|
3452
|
+
kind: input.kind,
|
|
3453
|
+
title: input.title,
|
|
3454
|
+
summary: input.queuedSummary,
|
|
3455
|
+
createdAt: cliNowIso(input.deps),
|
|
3456
|
+
...(input.spec ? { spec: input.spec } : {}),
|
|
3457
|
+
});
|
|
3458
|
+
return {
|
|
3459
|
+
record,
|
|
3460
|
+
running: (summary, detail, progress) => {
|
|
3461
|
+
(0, background_operations_1.markBackgroundOperationRunning)({
|
|
3462
|
+
agentName: input.agentName,
|
|
3463
|
+
agentRoot,
|
|
3464
|
+
id: operationId,
|
|
3465
|
+
startedAt: cliNowIso(input.deps),
|
|
3466
|
+
summary,
|
|
3467
|
+
...(detail ? { detail } : {}),
|
|
3468
|
+
...(progress ? { progress } : {}),
|
|
3469
|
+
});
|
|
3470
|
+
},
|
|
3471
|
+
update: (summary, detail, progress) => {
|
|
3472
|
+
(0, background_operations_1.updateBackgroundOperation)({
|
|
3473
|
+
agentName: input.agentName,
|
|
3474
|
+
agentRoot,
|
|
3475
|
+
id: operationId,
|
|
3476
|
+
summary,
|
|
3477
|
+
updatedAt: cliNowIso(input.deps),
|
|
3478
|
+
...(detail ? { detail } : {}),
|
|
3479
|
+
...(progress ? { progress } : {}),
|
|
3480
|
+
});
|
|
3481
|
+
},
|
|
3482
|
+
succeed: async (summary, detail, result) => {
|
|
3483
|
+
const completed = (0, background_operations_1.completeBackgroundOperation)({
|
|
3484
|
+
agentName: input.agentName,
|
|
3485
|
+
agentRoot,
|
|
3486
|
+
id: operationId,
|
|
3487
|
+
finishedAt: cliNowIso(input.deps),
|
|
3488
|
+
summary,
|
|
3489
|
+
detail,
|
|
3490
|
+
result,
|
|
3491
|
+
});
|
|
3492
|
+
await notifyMailOperation(input.agentName, { ...completed, detail }, input.deps);
|
|
3493
|
+
},
|
|
3494
|
+
fail: async (error, summary, detail, remediation) => {
|
|
3495
|
+
const failed = (0, background_operations_1.failBackgroundOperation)({
|
|
3496
|
+
agentName: input.agentName,
|
|
3497
|
+
agentRoot,
|
|
3498
|
+
id: operationId,
|
|
3499
|
+
finishedAt: cliNowIso(input.deps),
|
|
3500
|
+
summary,
|
|
3501
|
+
detail,
|
|
3502
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3503
|
+
remediation,
|
|
3504
|
+
});
|
|
3505
|
+
await notifyMailOperation(input.agentName, { ...failed, detail }, input.deps);
|
|
3506
|
+
},
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
async function launchBackgroundMailCommand(command, deps, args, title, queuedSummary, spec) {
|
|
3510
|
+
const spawnBackgroundCli = deps.spawnBackgroundCli;
|
|
3511
|
+
if (!spawnBackgroundCli) {
|
|
3512
|
+
throw new Error("background CLI launch is not available in this runtime");
|
|
3513
|
+
}
|
|
3514
|
+
const operationId = makeBackgroundOperationId(command.kind);
|
|
3515
|
+
const agentRoot = providerCliAgentRoot({ agent: command.agent }, deps);
|
|
3516
|
+
(0, background_operations_1.startBackgroundOperation)({
|
|
3517
|
+
agentName: command.agent,
|
|
3518
|
+
agentRoot,
|
|
3519
|
+
id: operationId,
|
|
3520
|
+
kind: command.kind,
|
|
3521
|
+
title,
|
|
3522
|
+
summary: queuedSummary,
|
|
3523
|
+
createdAt: cliNowIso(deps),
|
|
3524
|
+
...(spec ? { spec } : {}),
|
|
3525
|
+
});
|
|
3526
|
+
try {
|
|
3527
|
+
await spawnBackgroundCli([process.argv[1], ...args, "--foreground", "--operation-id", operationId]);
|
|
3528
|
+
}
|
|
3529
|
+
catch (error) {
|
|
3530
|
+
(0, background_operations_1.failBackgroundOperation)({
|
|
3531
|
+
agentName: command.agent,
|
|
3532
|
+
agentRoot,
|
|
3533
|
+
id: operationId,
|
|
3534
|
+
finishedAt: cliNowIso(deps),
|
|
3535
|
+
summary: `${title} could not be started`,
|
|
3536
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3537
|
+
remediation: ["retry the command once the local runtime is healthy"],
|
|
3538
|
+
});
|
|
3539
|
+
throw error;
|
|
3540
|
+
}
|
|
3541
|
+
const message = [
|
|
3542
|
+
`Started background ${title} for ${command.agent}`,
|
|
3543
|
+
`operation: ${operationId}`,
|
|
3544
|
+
...(spec ? Object.entries(spec).map(([key, value]) => `${key}: ${String(value)}`) : []),
|
|
3545
|
+
`${command.agent} will be woken on failure or completion.`,
|
|
3546
|
+
"Use query_active_work to check live progress.",
|
|
3547
|
+
].join("\n");
|
|
3548
|
+
deps.writeStdout(message);
|
|
3549
|
+
return message;
|
|
3550
|
+
}
|
|
3403
3551
|
async function executeMailImportMbox(command, deps) {
|
|
3552
|
+
const filePath = path.resolve(command.filePath);
|
|
3553
|
+
if (!command.foreground) {
|
|
3554
|
+
if (!fs.existsSync(filePath)) {
|
|
3555
|
+
throw new Error(`no such file: ${filePath}`);
|
|
3556
|
+
}
|
|
3557
|
+
return launchBackgroundMailCommand(command, deps, [
|
|
3558
|
+
"mail",
|
|
3559
|
+
"import-mbox",
|
|
3560
|
+
"--agent",
|
|
3561
|
+
command.agent,
|
|
3562
|
+
"--file",
|
|
3563
|
+
filePath,
|
|
3564
|
+
...(command.ownerEmail ? ["--owner-email", command.ownerEmail] : []),
|
|
3565
|
+
...(command.source ? ["--source", command.source] : []),
|
|
3566
|
+
], "mail import", "queued delegated mail import", {
|
|
3567
|
+
filePath,
|
|
3568
|
+
...(command.ownerEmail ? { ownerEmail: command.ownerEmail } : {}),
|
|
3569
|
+
...(command.source ? { source: command.source } : {}),
|
|
3570
|
+
});
|
|
3571
|
+
}
|
|
3404
3572
|
const progress = createHumanCommandProgress(deps, "mail import");
|
|
3573
|
+
const trackedOperation = ensureTrackedMailOperation({
|
|
3574
|
+
agentName: command.agent,
|
|
3575
|
+
deps,
|
|
3576
|
+
operationId: command.operationId,
|
|
3577
|
+
kind: "mail.import-mbox",
|
|
3578
|
+
title: "mail import",
|
|
3579
|
+
queuedSummary: "queued delegated mail import",
|
|
3580
|
+
spec: {
|
|
3581
|
+
filePath,
|
|
3582
|
+
...(command.ownerEmail ? { ownerEmail: command.ownerEmail } : {}),
|
|
3583
|
+
...(command.source ? { source: command.source } : {}),
|
|
3584
|
+
},
|
|
3585
|
+
});
|
|
3405
3586
|
try {
|
|
3587
|
+
trackedOperation?.running("reading Mailroom config", `file: ${filePath}`, {
|
|
3588
|
+
current: 0,
|
|
3589
|
+
unit: "messages",
|
|
3590
|
+
});
|
|
3406
3591
|
progress.startPhase("reading Mailroom config");
|
|
3407
3592
|
const runtime = await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(command.agent, { preserveCachedOnFailure: true });
|
|
3408
3593
|
if (!runtime.ok) {
|
|
@@ -3437,9 +3622,10 @@ async function executeMailImportMbox(command, deps) {
|
|
|
3437
3622
|
throw new Error(resolved.error);
|
|
3438
3623
|
}
|
|
3439
3624
|
progress.updateDetail("reading registry and MBOX");
|
|
3625
|
+
trackedOperation?.update("reading registry and MBOX", `file: ${filePath}`);
|
|
3440
3626
|
const registry = await (0, reader_1.readMailroomRegistry)(resolved.config);
|
|
3441
|
-
const filePath = path.resolve(command.filePath);
|
|
3442
3627
|
progress.updateDetail("importing delegated mail");
|
|
3628
|
+
trackedOperation?.update("importing delegated mail", `file: ${filePath}`);
|
|
3443
3629
|
const result = await (0, mbox_import_1.importMboxFileToStore)({
|
|
3444
3630
|
registry,
|
|
3445
3631
|
store: resolved.store,
|
|
@@ -3447,6 +3633,12 @@ async function executeMailImportMbox(command, deps) {
|
|
|
3447
3633
|
filePath,
|
|
3448
3634
|
ownerEmail: command.ownerEmail,
|
|
3449
3635
|
source: command.source,
|
|
3636
|
+
onProgress: (importProgress) => {
|
|
3637
|
+
trackedOperation?.update("importing delegated mail", `scanned ${importProgress.scanned} messages`, {
|
|
3638
|
+
current: importProgress.scanned,
|
|
3639
|
+
unit: "messages",
|
|
3640
|
+
});
|
|
3641
|
+
},
|
|
3450
3642
|
});
|
|
3451
3643
|
progress.completePhase("reading Mailroom config", "imported");
|
|
3452
3644
|
progress.end();
|
|
@@ -3461,17 +3653,44 @@ async function executeMailImportMbox(command, deps) {
|
|
|
3461
3653
|
"archive imports are historical; they do not create Screener wakeups.",
|
|
3462
3654
|
"body reads remain explicit through mail_recent/mail_search/mail_thread and are access-logged.",
|
|
3463
3655
|
].join("\n");
|
|
3656
|
+
await trackedOperation?.succeed("imported delegated mail archive", `scanned ${result.scanned}; imported ${result.imported}; duplicates ${result.duplicates}`, {
|
|
3657
|
+
scanned: result.scanned,
|
|
3658
|
+
imported: result.imported,
|
|
3659
|
+
duplicates: result.duplicates,
|
|
3660
|
+
sourceFreshThrough: result.sourceFreshThrough,
|
|
3661
|
+
});
|
|
3464
3662
|
deps.writeStdout(message);
|
|
3465
3663
|
return message;
|
|
3466
3664
|
}
|
|
3467
3665
|
catch (error) {
|
|
3468
3666
|
progress.end();
|
|
3667
|
+
await trackedOperation?.fail(error, "delegated mail import failed", `file: ${filePath}`, [
|
|
3668
|
+
"fix the reported Mailroom or MBOX problem, then rerun the import",
|
|
3669
|
+
"use query_active_work to confirm whether the operation has cleared",
|
|
3670
|
+
]);
|
|
3469
3671
|
throw error;
|
|
3470
3672
|
}
|
|
3471
3673
|
}
|
|
3472
3674
|
async function executeMailBackfillIndexes(command, deps) {
|
|
3675
|
+
if (!command.foreground) {
|
|
3676
|
+
return launchBackgroundMailCommand(command, deps, [
|
|
3677
|
+
"mail",
|
|
3678
|
+
"backfill-indexes",
|
|
3679
|
+
"--agent",
|
|
3680
|
+
command.agent,
|
|
3681
|
+
], "mail index repair", "queued hosted mail index repair");
|
|
3682
|
+
}
|
|
3473
3683
|
const progress = createHumanCommandProgress(deps, "mail index repair");
|
|
3684
|
+
const trackedOperation = ensureTrackedMailOperation({
|
|
3685
|
+
agentName: command.agent,
|
|
3686
|
+
deps,
|
|
3687
|
+
operationId: command.operationId,
|
|
3688
|
+
kind: "mail.backfill-indexes",
|
|
3689
|
+
title: "mail index repair",
|
|
3690
|
+
queuedSummary: "queued hosted mail index repair",
|
|
3691
|
+
});
|
|
3474
3692
|
try {
|
|
3693
|
+
trackedOperation?.running("resolving Mailroom store");
|
|
3475
3694
|
progress.startPhase("resolving Mailroom store");
|
|
3476
3695
|
const runtime = await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(command.agent, { preserveCachedOnFailure: true });
|
|
3477
3696
|
if (!runtime.ok) {
|
|
@@ -3491,6 +3710,7 @@ async function executeMailBackfillIndexes(command, deps) {
|
|
|
3491
3710
|
`store: ${resolved.storeLabel}`,
|
|
3492
3711
|
"This agent is using the local file Mailroom store, so recent mail reads do not depend on hosted blob indexes.",
|
|
3493
3712
|
].join("\n");
|
|
3713
|
+
await trackedOperation?.succeed("hosted mail index repair not needed", `store: ${resolved.storeLabel}`, { indexed: 0, store: resolved.storeLabel, reason: "local-file-store" });
|
|
3494
3714
|
deps.writeStdout(message);
|
|
3495
3715
|
return message;
|
|
3496
3716
|
}
|
|
@@ -3500,7 +3720,14 @@ async function executeMailBackfillIndexes(command, deps) {
|
|
|
3500
3720
|
throw new Error(`hosted Mailroom store for ${command.agent} does not expose index backfill`);
|
|
3501
3721
|
}
|
|
3502
3722
|
progress.updateDetail("backfilling hosted message indexes");
|
|
3503
|
-
|
|
3723
|
+
trackedOperation?.update("backfilling hosted message indexes");
|
|
3724
|
+
const indexed = await store.backfillMessageIndexes(command.agent, (backfillProgress) => {
|
|
3725
|
+
trackedOperation?.update("backfilling hosted message indexes", `indexed ${backfillProgress.indexed} of ${backfillProgress.total}`, {
|
|
3726
|
+
current: backfillProgress.scanned,
|
|
3727
|
+
total: backfillProgress.total,
|
|
3728
|
+
unit: "blobs",
|
|
3729
|
+
});
|
|
3730
|
+
});
|
|
3504
3731
|
progress.completePhase("resolving Mailroom store", "backfilled");
|
|
3505
3732
|
progress.end();
|
|
3506
3733
|
const message = [
|
|
@@ -3509,11 +3736,16 @@ async function executeMailBackfillIndexes(command, deps) {
|
|
|
3509
3736
|
`indexed: ${indexed}`,
|
|
3510
3737
|
"Safe to rerun. Existing index entries are rewritten in place.",
|
|
3511
3738
|
].join("\n");
|
|
3739
|
+
await trackedOperation?.succeed("hosted mail index repair finished", `indexed ${indexed} message indexes`, { indexed, store: resolved.storeLabel });
|
|
3512
3740
|
deps.writeStdout(message);
|
|
3513
3741
|
return message;
|
|
3514
3742
|
}
|
|
3515
3743
|
catch (error) {
|
|
3516
3744
|
progress.end();
|
|
3745
|
+
await trackedOperation?.fail(error, "hosted mail index repair failed", "store resolution or blob backfill failed", [
|
|
3746
|
+
"rerun the hosted index repair to retry remaining blobs",
|
|
3747
|
+
"if the same residue repeats, inspect the failed blob ids and timeouts",
|
|
3748
|
+
]);
|
|
3517
3749
|
throw error;
|
|
3518
3750
|
}
|
|
3519
3751
|
}
|
|
@@ -323,12 +323,12 @@ const SUBCOMMAND_HELP = {
|
|
|
323
323
|
},
|
|
324
324
|
"mail import-mbox": {
|
|
325
325
|
description: "Import a HEY or other MBOX export into an existing delegated Mailroom source grant",
|
|
326
|
-
usage: "ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>]",
|
|
326
|
+
usage: "ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]",
|
|
327
327
|
example: "ouro mail import-mbox --file ~/Downloads/hey.mbox --owner-email ari@mendelow.me --source hey --agent slugger",
|
|
328
328
|
},
|
|
329
329
|
"mail backfill-indexes": {
|
|
330
330
|
description: "Rebuild hosted blob mailbox indexes for faster recent-mail reads after large legacy imports or drift repair.",
|
|
331
|
-
usage: "ouro mail backfill-indexes [--agent <name>]",
|
|
331
|
+
usage: "ouro mail backfill-indexes [--agent <name>] [--foreground]",
|
|
332
332
|
example: "ouro mail backfill-indexes --agent slugger",
|
|
333
333
|
},
|
|
334
334
|
"provider refresh": {
|
|
@@ -86,8 +86,8 @@ function usage() {
|
|
|
86
86
|
" ouro auth [--agent <name>] [--provider <provider>]",
|
|
87
87
|
" ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
88
88
|
" ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
89
|
-
" ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>]",
|
|
90
|
-
" ouro mail backfill-indexes [--agent <name>]",
|
|
89
|
+
" ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]",
|
|
90
|
+
" ouro mail backfill-indexes [--agent <name>] [--foreground]",
|
|
91
91
|
" ouro auth verify [--agent <name>] [--provider <provider>]",
|
|
92
92
|
" ouro auth switch [--agent <name>] --provider <provider>",
|
|
93
93
|
" ouro vault create [--agent <name>] --email <email> [--server <url>] [--store <store>]",
|
|
@@ -885,14 +885,28 @@ function parseConnectCommand(args) {
|
|
|
885
885
|
}
|
|
886
886
|
function parseMailCommand(args) {
|
|
887
887
|
const [sub, ...subArgs] = args;
|
|
888
|
-
const usageText = "Usage: ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>]\n ouro mail backfill-indexes [--agent <name>]";
|
|
888
|
+
const usageText = "Usage: ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]\n ouro mail backfill-indexes [--agent <name>] [--foreground]";
|
|
889
889
|
if (sub === "backfill-indexes") {
|
|
890
890
|
const { agent, rest } = extractAgentFlag(subArgs);
|
|
891
|
-
|
|
891
|
+
let foreground = false;
|
|
892
|
+
let operationId;
|
|
893
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
894
|
+
const token = rest[i];
|
|
895
|
+
if (token === "--foreground") {
|
|
896
|
+
foreground = true;
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (token === "--operation-id" && rest[i + 1]) {
|
|
900
|
+
operationId = rest[++i];
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
892
903
|
throw new Error(usageText);
|
|
904
|
+
}
|
|
893
905
|
return {
|
|
894
906
|
kind: "mail.backfill-indexes",
|
|
895
907
|
...(agent ? { agent } : {}),
|
|
908
|
+
...(foreground ? { foreground: true } : {}),
|
|
909
|
+
...(operationId ? { operationId } : {}),
|
|
896
910
|
};
|
|
897
911
|
}
|
|
898
912
|
if (sub !== "import-mbox") {
|
|
@@ -902,6 +916,8 @@ function parseMailCommand(args) {
|
|
|
902
916
|
let filePath;
|
|
903
917
|
let ownerEmail;
|
|
904
918
|
let source;
|
|
919
|
+
let foreground = false;
|
|
920
|
+
let operationId;
|
|
905
921
|
for (let i = 0; i < rest.length; i += 1) {
|
|
906
922
|
const token = rest[i];
|
|
907
923
|
if (token === "--file" && rest[i + 1]) {
|
|
@@ -916,6 +932,14 @@ function parseMailCommand(args) {
|
|
|
916
932
|
source = rest[++i];
|
|
917
933
|
continue;
|
|
918
934
|
}
|
|
935
|
+
if (token === "--foreground") {
|
|
936
|
+
foreground = true;
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
if (token === "--operation-id" && rest[i + 1]) {
|
|
940
|
+
operationId = rest[++i];
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
919
943
|
throw new Error(usageText);
|
|
920
944
|
}
|
|
921
945
|
if (!filePath) {
|
|
@@ -927,6 +951,8 @@ function parseMailCommand(args) {
|
|
|
927
951
|
filePath,
|
|
928
952
|
...(ownerEmail ? { ownerEmail } : {}),
|
|
929
953
|
...(source ? { source } : {}),
|
|
954
|
+
...(foreground ? { foreground: true } : {}),
|
|
955
|
+
...(operationId ? { operationId } : {}),
|
|
930
956
|
};
|
|
931
957
|
}
|
|
932
958
|
function parseAccountCommand(args) {
|
|
@@ -273,7 +273,7 @@ class AzureBlobMailroomStore {
|
|
|
273
273
|
.sort(compareNewestFirst)
|
|
274
274
|
.slice(0, filters.limit ?? 20);
|
|
275
275
|
}
|
|
276
|
-
async backfillMessageIndexes(agentId) {
|
|
276
|
+
async backfillMessageIndexes(agentId, onProgress) {
|
|
277
277
|
await this.ensureContainer();
|
|
278
278
|
const messageBlobNames = [];
|
|
279
279
|
for await (const item of this.container.listBlobsFlat({ prefix: "messages/" })) {
|
|
@@ -281,6 +281,7 @@ class AzureBlobMailroomStore {
|
|
|
281
281
|
}
|
|
282
282
|
let indexed = 0;
|
|
283
283
|
const failures = [];
|
|
284
|
+
let scanned = 0;
|
|
284
285
|
let nextIndex = 0;
|
|
285
286
|
const worker = async () => {
|
|
286
287
|
while (nextIndex < messageBlobNames.length) {
|
|
@@ -298,6 +299,10 @@ class AzureBlobMailroomStore {
|
|
|
298
299
|
catch (error) {
|
|
299
300
|
failures.push(error instanceof Error ? error.message : String(error));
|
|
300
301
|
}
|
|
302
|
+
finally {
|
|
303
|
+
scanned += 1;
|
|
304
|
+
onProgress?.({ scanned, indexed, failures: failures.length, total: messageBlobNames.length });
|
|
305
|
+
}
|
|
301
306
|
}
|
|
302
307
|
};
|
|
303
308
|
await Promise.all(Array.from({ length: Math.min(this.backfillConcurrency, Math.max(messageBlobNames.length, 1)) }, async () => worker()));
|
|
@@ -246,6 +246,7 @@ async function importParsedMessagesToStore(input) {
|
|
|
246
246
|
imported += 1;
|
|
247
247
|
else
|
|
248
248
|
duplicates += 1;
|
|
249
|
+
input.onProgress?.({ scanned, imported, duplicates });
|
|
249
250
|
})().finally(() => {
|
|
250
251
|
inFlight.delete(task);
|
|
251
252
|
});
|
|
@@ -254,6 +255,7 @@ async function importParsedMessagesToStore(input) {
|
|
|
254
255
|
};
|
|
255
256
|
for await (const parsedMessage of input.parsedMessages) {
|
|
256
257
|
scanned += 1;
|
|
258
|
+
input.onProgress?.({ scanned, imported, duplicates });
|
|
257
259
|
enqueue(parsedMessage);
|
|
258
260
|
if (inFlight.size >= maxConcurrency) {
|
|
259
261
|
await Promise.race(inFlight);
|
|
@@ -334,5 +336,6 @@ async function importMboxFileToStore(input) {
|
|
|
334
336
|
collectMessages: false,
|
|
335
337
|
sourceFreshThrough,
|
|
336
338
|
maxConcurrency: 8,
|
|
339
|
+
onProgress: input.onProgress,
|
|
337
340
|
});
|
|
338
341
|
}
|
|
@@ -46,6 +46,7 @@ const manager_1 = require("../heart/bridges/manager");
|
|
|
46
46
|
const session_transcript_1 = require("../heart/session-transcript");
|
|
47
47
|
const session_activity_1 = require("../heart/session-activity");
|
|
48
48
|
const active_work_1 = require("../heart/active-work");
|
|
49
|
+
const background_operations_1 = require("../heart/background-operations");
|
|
49
50
|
const coding_1 = require("./coding");
|
|
50
51
|
const tasks_1 = require("./tasks");
|
|
51
52
|
const pending_1 = require("../mind/pending");
|
|
@@ -263,6 +264,11 @@ async function buildToolActiveWorkFrame(ctx) {
|
|
|
263
264
|
&& obligation.origin.channel === currentSession.channel
|
|
264
265
|
&& obligation.origin.key === currentSession.key)?.content ?? null
|
|
265
266
|
: null;
|
|
267
|
+
const backgroundOperations = (0, background_operations_1.listBackgroundOperations)({
|
|
268
|
+
agentName: (0, identity_1.getAgentName)(),
|
|
269
|
+
agentRoot,
|
|
270
|
+
limit: 5,
|
|
271
|
+
});
|
|
266
272
|
return (0, active_work_1.buildActiveWorkFrame)({
|
|
267
273
|
currentSession,
|
|
268
274
|
currentObligation,
|
|
@@ -270,6 +276,7 @@ async function buildToolActiveWorkFrame(ctx) {
|
|
|
270
276
|
inner: readActiveWorkInnerState(),
|
|
271
277
|
bridges,
|
|
272
278
|
codingSessions,
|
|
279
|
+
backgroundOperations,
|
|
273
280
|
otherCodingSessions,
|
|
274
281
|
pendingObligations,
|
|
275
282
|
taskBoard: (() => {
|