@ouro.bot/cli 0.1.0-alpha.202 → 0.1.0-alpha.204
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 +12 -0
- package/dist/heart/daemon/daemon-cli.js +7 -7
- package/dist/heart/daemon/daemon.js +31 -0
- package/dist/heart/daemon/mcp-server.js +33 -16
- package/dist/heart/obligations.js +96 -0
- package/dist/heart/turn-context.js +358 -0
- package/dist/mind/prompt.js +20 -15
- package/dist/repertoire/tools-base.js +5 -6
- package/dist/repertoire/tools.js +4 -5
- package/dist/senses/inner-dialog.js +6 -7
- package/dist/senses/pipeline.js +20 -158
- package/package.json +1 -1
- package/dist/mind/obligations.js +0 -138
package/changelog.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
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.204",
|
|
6
|
+
"changes": [
|
|
7
|
+
"refactor: introduce TurnContext snapshot — centralize state assembly from pipeline.ts into buildTurnContext(), thread pre-read state through prompt assembly to eliminate ad-hoc filesystem reads"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.203",
|
|
12
|
+
"changes": [
|
|
13
|
+
"refactor: unify obligation systems — mind/obligations.ts merged into heart/obligations.ts with prefixed ReturnObligation API"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
4
16
|
{
|
|
5
17
|
"version": "0.1.0-alpha.202",
|
|
6
18
|
"changes": [
|
|
@@ -3116,9 +3116,9 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
|
3116
3116
|
if (command.kind === "attention.list" || command.kind === "attention.show" || command.kind === "attention.history") {
|
|
3117
3117
|
try {
|
|
3118
3118
|
const agentName = command.agent ?? (0, identity_1.getAgentName)();
|
|
3119
|
-
const {
|
|
3119
|
+
const { listActiveReturnObligations, readReturnObligation } = await Promise.resolve().then(() => __importStar(require("../obligations")));
|
|
3120
3120
|
if (command.kind === "attention.list") {
|
|
3121
|
-
const obligations =
|
|
3121
|
+
const obligations = listActiveReturnObligations(agentName);
|
|
3122
3122
|
if (obligations.length === 0) {
|
|
3123
3123
|
const message = "nothing held — attention queue is empty";
|
|
3124
3124
|
deps.writeStdout(message);
|
|
@@ -3130,7 +3130,7 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
|
3130
3130
|
return message;
|
|
3131
3131
|
}
|
|
3132
3132
|
if (command.kind === "attention.show") {
|
|
3133
|
-
const obligation =
|
|
3133
|
+
const obligation = readReturnObligation(agentName, command.id);
|
|
3134
3134
|
if (!obligation) {
|
|
3135
3135
|
const message = `no obligation found with id ${command.id}`;
|
|
3136
3136
|
deps.writeStdout(message);
|
|
@@ -3141,8 +3141,8 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
|
3141
3141
|
return message;
|
|
3142
3142
|
}
|
|
3143
3143
|
// attention.history: show returned obligations
|
|
3144
|
-
const {
|
|
3145
|
-
const obligationsDir =
|
|
3144
|
+
const { getReturnObligationsDir } = await Promise.resolve().then(() => __importStar(require("../obligations")));
|
|
3145
|
+
const obligationsDir = getReturnObligationsDir(agentName);
|
|
3146
3146
|
let entries = [];
|
|
3147
3147
|
try {
|
|
3148
3148
|
entries = fs.readdirSync(obligationsDir);
|
|
@@ -3189,7 +3189,7 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
|
3189
3189
|
const { sessionPath: getSessionPath } = await Promise.resolve().then(() => __importStar(require("../config")));
|
|
3190
3190
|
const { parseCadenceToMs: parseCadenceMs, DEFAULT_CADENCE_MS } = await Promise.resolve().then(() => __importStar(require("./cadence")));
|
|
3191
3191
|
const { parseFrontmatter } = await Promise.resolve().then(() => __importStar(require("../../repertoire/tasks/parser")));
|
|
3192
|
-
const {
|
|
3192
|
+
const { listActiveReturnObligations } = await Promise.resolve().then(() => __importStar(require("../obligations")));
|
|
3193
3193
|
// Read runtime state
|
|
3194
3194
|
const innerSessionPath = getSessionPath("inner-dialog", "inner", "session");
|
|
3195
3195
|
const runtimeJsonPath = path.join(path.dirname(innerSessionPath), "runtime.json");
|
|
@@ -3242,7 +3242,7 @@ async function runOuroCli(args, deps = createDefaultOuroCliDeps()) {
|
|
|
3242
3242
|
}
|
|
3243
3243
|
catch { /* no habits — heartbeat unknown */ }
|
|
3244
3244
|
// Attention count
|
|
3245
|
-
const activeObligations =
|
|
3245
|
+
const activeObligations = listActiveReturnObligations(agentName);
|
|
3246
3246
|
const message = buildInnerStatusOutput({
|
|
3247
3247
|
agentName,
|
|
3248
3248
|
runtimeState,
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.OuroDaemon = void 0;
|
|
37
37
|
exports.killOrphanProcesses = killOrphanProcesses;
|
|
38
38
|
exports.writePidfile = writePidfile;
|
|
39
|
+
exports.handleAgentSenseTurn = handleAgentSenseTurn;
|
|
39
40
|
const fs = __importStar(require("fs"));
|
|
40
41
|
const net = __importStar(require("net"));
|
|
41
42
|
const os = __importStar(require("os"));
|
|
@@ -177,6 +178,33 @@ function parseIncomingCommand(raw) {
|
|
|
177
178
|
}
|
|
178
179
|
return parsed;
|
|
179
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Handle agent.senseTurn command: runs a full agent turn via the daemon process.
|
|
183
|
+
* Dynamic import lazy-loads shared-turn. Hot-reload works because ouro dev
|
|
184
|
+
* restarts the daemon process (fresh module cache).
|
|
185
|
+
*/
|
|
186
|
+
async function handleAgentSenseTurn(command) {
|
|
187
|
+
try {
|
|
188
|
+
const { runSenseTurn } = await Promise.resolve().then(() => __importStar(require("../../senses/shared-turn")));
|
|
189
|
+
const result = await runSenseTurn({
|
|
190
|
+
agentName: command.agent,
|
|
191
|
+
channel: command.channel,
|
|
192
|
+
sessionKey: command.sessionKey,
|
|
193
|
+
friendId: command.friendId,
|
|
194
|
+
userMessage: command.message,
|
|
195
|
+
});
|
|
196
|
+
return {
|
|
197
|
+
ok: true,
|
|
198
|
+
message: result.response,
|
|
199
|
+
data: { ponderDeferred: result.ponderDeferred },
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
/* v8 ignore next -- branch: String(error) fallback only for non-Error throws @preserve */
|
|
204
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
205
|
+
return { ok: false, error: `sense turn failed: ${errorMessage}` };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
180
208
|
class OuroDaemon {
|
|
181
209
|
socketPath;
|
|
182
210
|
processManager;
|
|
@@ -683,6 +711,9 @@ class OuroDaemon {
|
|
|
683
711
|
return (0, agent_service_1.handleAgentReportBlocker)(command);
|
|
684
712
|
case "agent.reportComplete":
|
|
685
713
|
return (0, agent_service_1.handleAgentReportComplete)(command);
|
|
714
|
+
case "agent.senseTurn":
|
|
715
|
+
return handleAgentSenseTurn(command);
|
|
716
|
+
/* v8 ignore stop */
|
|
686
717
|
case "cron.list": {
|
|
687
718
|
const jobs = this.scheduler.listJobs();
|
|
688
719
|
const summary = jobs.length === 0
|
|
@@ -38,7 +38,6 @@ exports.getToolSchemas = getToolSchemas;
|
|
|
38
38
|
const socket_client_1 = require("./socket-client");
|
|
39
39
|
const agentService = __importStar(require("./agent-service"));
|
|
40
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
-
const shared_turn_1 = require("../../senses/shared-turn");
|
|
42
41
|
const session_id_resolver_1 = require("./session-id-resolver");
|
|
43
42
|
const pending_1 = require("../../mind/pending");
|
|
44
43
|
/**
|
|
@@ -249,19 +248,22 @@ function createMcpServer(options) {
|
|
|
249
248
|
const message = toolArgs.message ?? "";
|
|
250
249
|
/* v8 ignore stop */
|
|
251
250
|
try {
|
|
252
|
-
const
|
|
253
|
-
|
|
251
|
+
const response = await (0, socket_client_1.sendDaemonCommand)(socketPath, {
|
|
252
|
+
kind: "agent.senseTurn",
|
|
253
|
+
agent,
|
|
254
|
+
friendId,
|
|
254
255
|
channel: "mcp",
|
|
255
256
|
sessionKey: sessionId,
|
|
256
|
-
|
|
257
|
-
userMessage: message,
|
|
257
|
+
message,
|
|
258
258
|
});
|
|
259
|
+
/* v8 ignore next -- branch: ?? fallback for empty daemon response @preserve */
|
|
260
|
+
const text = response.message ?? "(empty response)";
|
|
259
261
|
writeResponse({
|
|
260
262
|
jsonrpc: "2.0",
|
|
261
263
|
id: request.id,
|
|
262
264
|
result: {
|
|
263
|
-
content: [{ type: "text", text
|
|
264
|
-
isError:
|
|
265
|
+
content: [{ type: "text", text }],
|
|
266
|
+
isError: !response.ok,
|
|
265
267
|
},
|
|
266
268
|
});
|
|
267
269
|
}
|
|
@@ -269,11 +271,17 @@ function createMcpServer(options) {
|
|
|
269
271
|
/* v8 ignore start — instanceof guard defensive; thrown errors are always Error */
|
|
270
272
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
271
273
|
/* v8 ignore stop */
|
|
274
|
+
/* v8 ignore start -- daemon-down detection: only triggers with real socket I/O @preserve */
|
|
275
|
+
const isDaemonDown = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("ENOENT");
|
|
276
|
+
const userMessage = isDaemonDown
|
|
277
|
+
? "The daemon is not running. Start it with `ouro up` (production) or `ouro dev` (development), then retry."
|
|
278
|
+
: `Error: ${errorMessage}`;
|
|
279
|
+
/* v8 ignore stop */
|
|
272
280
|
writeResponse({
|
|
273
281
|
jsonrpc: "2.0",
|
|
274
282
|
id: request.id,
|
|
275
283
|
result: {
|
|
276
|
-
content: [{ type: "text", text:
|
|
284
|
+
content: [{ type: "text", text: userMessage }],
|
|
277
285
|
isError: true,
|
|
278
286
|
},
|
|
279
287
|
});
|
|
@@ -306,7 +314,7 @@ function createMcpServer(options) {
|
|
|
306
314
|
}
|
|
307
315
|
return;
|
|
308
316
|
}
|
|
309
|
-
// ── delegate: full conversation turn via
|
|
317
|
+
// ── delegate: full conversation turn via daemon ──
|
|
310
318
|
if (toolName === "delegate") {
|
|
311
319
|
/* v8 ignore start — ?? fallback defensive; MCP clients always send task */
|
|
312
320
|
const task = toolArgs.task ?? "";
|
|
@@ -314,19 +322,22 @@ function createMcpServer(options) {
|
|
|
314
322
|
const context = toolArgs.context;
|
|
315
323
|
const delegateMessage = context ? `[delegate] ${task}\n\ncontext: ${context}` : `[delegate] ${task}`;
|
|
316
324
|
try {
|
|
317
|
-
const
|
|
318
|
-
|
|
325
|
+
const response = await (0, socket_client_1.sendDaemonCommand)(socketPath, {
|
|
326
|
+
kind: "agent.senseTurn",
|
|
327
|
+
agent,
|
|
328
|
+
friendId,
|
|
319
329
|
channel: "mcp",
|
|
320
330
|
sessionKey: sessionId,
|
|
321
|
-
|
|
322
|
-
userMessage: delegateMessage,
|
|
331
|
+
message: delegateMessage,
|
|
323
332
|
});
|
|
333
|
+
/* v8 ignore next -- branch: ?? fallback for empty daemon response @preserve */
|
|
334
|
+
const text = response.message ?? "(empty response)";
|
|
324
335
|
writeResponse({
|
|
325
336
|
jsonrpc: "2.0",
|
|
326
337
|
id: request.id,
|
|
327
338
|
result: {
|
|
328
|
-
content: [{ type: "text", text
|
|
329
|
-
isError:
|
|
339
|
+
content: [{ type: "text", text }],
|
|
340
|
+
isError: !response.ok,
|
|
330
341
|
},
|
|
331
342
|
});
|
|
332
343
|
}
|
|
@@ -334,11 +345,17 @@ function createMcpServer(options) {
|
|
|
334
345
|
/* v8 ignore start — instanceof guard defensive; thrown errors are always Error */
|
|
335
346
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
336
347
|
/* v8 ignore stop */
|
|
348
|
+
/* v8 ignore start -- daemon-down detection: only triggers with real socket I/O @preserve */
|
|
349
|
+
const isDaemonDown = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("ENOENT");
|
|
350
|
+
const userMessage = isDaemonDown
|
|
351
|
+
? "The daemon is not running. Start it with `ouro up` (production) or `ouro dev` (development), then retry."
|
|
352
|
+
: `Error: ${errorMessage}`;
|
|
353
|
+
/* v8 ignore stop */
|
|
337
354
|
writeResponse({
|
|
338
355
|
jsonrpc: "2.0",
|
|
339
356
|
id: request.id,
|
|
340
357
|
result: {
|
|
341
|
-
content: [{ type: "text", text:
|
|
358
|
+
content: [{ type: "text", text: userMessage }],
|
|
342
359
|
isError: true,
|
|
343
360
|
},
|
|
344
361
|
});
|
|
@@ -42,8 +42,15 @@ exports.advanceObligation = advanceObligation;
|
|
|
42
42
|
exports.fulfillObligation = fulfillObligation;
|
|
43
43
|
exports.findPendingObligationForOrigin = findPendingObligationForOrigin;
|
|
44
44
|
exports.enrichObligation = enrichObligation;
|
|
45
|
+
exports.generateObligationId = generateObligationId;
|
|
46
|
+
exports.getReturnObligationsDir = getReturnObligationsDir;
|
|
47
|
+
exports.createReturnObligation = createReturnObligation;
|
|
48
|
+
exports.readReturnObligation = readReturnObligation;
|
|
49
|
+
exports.advanceReturnObligation = advanceReturnObligation;
|
|
50
|
+
exports.listActiveReturnObligations = listActiveReturnObligations;
|
|
45
51
|
const fs = __importStar(require("fs"));
|
|
46
52
|
const path = __importStar(require("path"));
|
|
53
|
+
const identity_1 = require("./identity");
|
|
47
54
|
const runtime_1 = require("../nerves/runtime");
|
|
48
55
|
const sync_1 = require("./sync");
|
|
49
56
|
function obligationsDir(agentRoot) {
|
|
@@ -223,3 +230,92 @@ function enrichObligation(agentRoot, id, meaning) {
|
|
|
223
230
|
});
|
|
224
231
|
return obligation;
|
|
225
232
|
}
|
|
233
|
+
function generateObligationId(timestamp) {
|
|
234
|
+
return `${timestamp}-${Math.random().toString(36).slice(2, 10)}`;
|
|
235
|
+
}
|
|
236
|
+
function getReturnObligationsDir(agentName) {
|
|
237
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "arc", "obligations", "inner");
|
|
238
|
+
}
|
|
239
|
+
function createReturnObligation(agentName, obligation) {
|
|
240
|
+
const dir = getReturnObligationsDir(agentName);
|
|
241
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
242
|
+
const filePath = path.join(dir, `${obligation.id}.json`);
|
|
243
|
+
fs.writeFileSync(filePath, JSON.stringify(obligation, null, 2), "utf8");
|
|
244
|
+
(0, sync_1.trackSyncWrite)(filePath);
|
|
245
|
+
(0, runtime_1.emitNervesEvent)({
|
|
246
|
+
event: "mind.obligation_created",
|
|
247
|
+
component: "mind",
|
|
248
|
+
message: "return obligation created",
|
|
249
|
+
meta: {
|
|
250
|
+
obligationId: obligation.id,
|
|
251
|
+
origin: `${obligation.origin.friendId}/${obligation.origin.channel}/${obligation.origin.key}`,
|
|
252
|
+
status: obligation.status,
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
return filePath;
|
|
256
|
+
}
|
|
257
|
+
function readReturnObligation(agentName, obligationId) {
|
|
258
|
+
const dir = getReturnObligationsDir(agentName);
|
|
259
|
+
try {
|
|
260
|
+
const raw = fs.readFileSync(path.join(dir, `${obligationId}.json`), "utf-8");
|
|
261
|
+
return JSON.parse(raw);
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function advanceReturnObligation(agentName, obligationId, update) {
|
|
268
|
+
const existing = readReturnObligation(agentName, obligationId);
|
|
269
|
+
if (!existing)
|
|
270
|
+
return null;
|
|
271
|
+
const updated = {
|
|
272
|
+
...existing,
|
|
273
|
+
status: update.status,
|
|
274
|
+
...(update.startedAt !== undefined ? { startedAt: update.startedAt } : {}),
|
|
275
|
+
...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
|
|
276
|
+
...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
|
|
277
|
+
};
|
|
278
|
+
const dir = getReturnObligationsDir(agentName);
|
|
279
|
+
const advancedFilePath = path.join(dir, `${obligationId}.json`);
|
|
280
|
+
fs.writeFileSync(advancedFilePath, JSON.stringify(updated, null, 2), "utf8");
|
|
281
|
+
(0, sync_1.trackSyncWrite)(advancedFilePath);
|
|
282
|
+
(0, runtime_1.emitNervesEvent)({
|
|
283
|
+
event: "mind.obligation_advanced",
|
|
284
|
+
component: "mind",
|
|
285
|
+
message: `obligation advanced to ${update.status}`,
|
|
286
|
+
meta: {
|
|
287
|
+
obligationId,
|
|
288
|
+
status: update.status,
|
|
289
|
+
...(update.returnTarget ? { returnTarget: update.returnTarget } : {}),
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
return updated;
|
|
293
|
+
}
|
|
294
|
+
function listActiveReturnObligations(agentName) {
|
|
295
|
+
const dir = getReturnObligationsDir(agentName);
|
|
296
|
+
if (!fs.existsSync(dir))
|
|
297
|
+
return [];
|
|
298
|
+
let entries;
|
|
299
|
+
try {
|
|
300
|
+
entries = fs.readdirSync(dir);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
const obligations = [];
|
|
306
|
+
for (const file of entries) {
|
|
307
|
+
if (!file.endsWith(".json"))
|
|
308
|
+
continue;
|
|
309
|
+
try {
|
|
310
|
+
const raw = fs.readFileSync(path.join(dir, file), "utf-8");
|
|
311
|
+
const parsed = JSON.parse(raw);
|
|
312
|
+
if (parsed.status === "queued" || parsed.status === "running") {
|
|
313
|
+
obligations.push(parsed);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
// skip unparseable
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return obligations.sort((a, b) => a.createdAt - b.createdAt);
|
|
321
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TurnContext: a single pre-read snapshot of all state sources needed
|
|
4
|
+
* by the inbound-turn pipeline and prompt assembly.
|
|
5
|
+
*
|
|
6
|
+
* Before this module existed, pipeline.ts read ~10 state sources inline
|
|
7
|
+
* and prompt.ts did several ad-hoc filesystem reads. This centralizes
|
|
8
|
+
* all reads into one place so the rest of the turn is pure derivation.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.buildTurnContext = buildTurnContext;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const runtime_1 = require("../nerves/runtime");
|
|
48
|
+
const manager_1 = require("./bridges/manager");
|
|
49
|
+
const identity_1 = require("./identity");
|
|
50
|
+
const tasks_1 = require("../repertoire/tasks");
|
|
51
|
+
const coding_1 = require("../repertoire/coding");
|
|
52
|
+
const session_activity_1 = require("./session-activity");
|
|
53
|
+
const thoughts_1 = require("./daemon/thoughts");
|
|
54
|
+
const pending_1 = require("../mind/pending");
|
|
55
|
+
const obligations_1 = require("./obligations");
|
|
56
|
+
const target_resolution_1 = require("./target-resolution");
|
|
57
|
+
const episodes_1 = require("../mind/episodes");
|
|
58
|
+
const cares_1 = require("./cares");
|
|
59
|
+
const config_1 = require("./config");
|
|
60
|
+
const daemon_health_1 = require("./daemon/daemon-health");
|
|
61
|
+
const prompt_1 = require("../mind/prompt");
|
|
62
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
63
|
+
const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
|
|
64
|
+
function isLiveCodingSessionStatus(status) {
|
|
65
|
+
return status === "spawning"
|
|
66
|
+
|| status === "running"
|
|
67
|
+
|| status === "waiting_input"
|
|
68
|
+
|| status === "stalled";
|
|
69
|
+
}
|
|
70
|
+
function emptyTaskBoard() {
|
|
71
|
+
return {
|
|
72
|
+
compact: "",
|
|
73
|
+
full: "",
|
|
74
|
+
byStatus: {
|
|
75
|
+
drafting: [],
|
|
76
|
+
processing: [],
|
|
77
|
+
validating: [],
|
|
78
|
+
collaborating: [],
|
|
79
|
+
paused: [],
|
|
80
|
+
blocked: [],
|
|
81
|
+
done: [],
|
|
82
|
+
cancelled: [],
|
|
83
|
+
},
|
|
84
|
+
issues: [],
|
|
85
|
+
actionRequired: [],
|
|
86
|
+
unresolvedDependencies: [],
|
|
87
|
+
activeSessions: [],
|
|
88
|
+
activeBridges: [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function readInnerWorkState() {
|
|
92
|
+
const defaultJob = {
|
|
93
|
+
status: "idle",
|
|
94
|
+
content: null,
|
|
95
|
+
origin: null,
|
|
96
|
+
mode: "reflect",
|
|
97
|
+
obligationStatus: null,
|
|
98
|
+
surfacedResult: null,
|
|
99
|
+
queuedAt: null,
|
|
100
|
+
startedAt: null,
|
|
101
|
+
surfacedAt: null,
|
|
102
|
+
};
|
|
103
|
+
try {
|
|
104
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
105
|
+
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
|
|
106
|
+
const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
|
|
107
|
+
const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
|
|
108
|
+
const dialogStatus = (0, thoughts_1.deriveInnerDialogStatus)(pendingMessages, turns, runtimeState);
|
|
109
|
+
const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
|
|
110
|
+
const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
|
|
111
|
+
return {
|
|
112
|
+
status: dialogStatus.processing === "started" ? "running" : "idle",
|
|
113
|
+
hasPending: dialogStatus.queue !== "clear",
|
|
114
|
+
origin: dialogStatus.origin,
|
|
115
|
+
contentSnippet: dialogStatus.contentSnippet,
|
|
116
|
+
obligationPending: dialogStatus.obligationPending || storeObligationPending,
|
|
117
|
+
job,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
121
|
+
return {
|
|
122
|
+
status: "idle",
|
|
123
|
+
hasPending: false,
|
|
124
|
+
job: defaultJob,
|
|
125
|
+
/* v8 ignore stop */
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function checkDaemonRunning() {
|
|
130
|
+
try {
|
|
131
|
+
return fs.existsSync(DAEMON_SOCKET_PATH);
|
|
132
|
+
}
|
|
133
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
134
|
+
return false;
|
|
135
|
+
/* v8 ignore stop */
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function hasTextField(record, key) {
|
|
139
|
+
return typeof record?.[key] === "string" && record[key].trim().length > 0;
|
|
140
|
+
}
|
|
141
|
+
function readSenseStatusLines() {
|
|
142
|
+
const config = (0, identity_1.loadAgentConfig)();
|
|
143
|
+
const senses = config.senses ?? {
|
|
144
|
+
cli: { enabled: true },
|
|
145
|
+
teams: { enabled: false },
|
|
146
|
+
bluebubbles: { enabled: false },
|
|
147
|
+
};
|
|
148
|
+
let payload = {};
|
|
149
|
+
try {
|
|
150
|
+
const raw = fs.readFileSync((0, identity_1.getAgentSecretsPath)(), "utf-8");
|
|
151
|
+
const parsed = JSON.parse(raw);
|
|
152
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
153
|
+
payload = parsed;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
157
|
+
payload = {};
|
|
158
|
+
/* v8 ignore stop */
|
|
159
|
+
}
|
|
160
|
+
const teams = payload.teams;
|
|
161
|
+
const bluebubbles = payload.bluebubbles;
|
|
162
|
+
const configured = {
|
|
163
|
+
cli: true,
|
|
164
|
+
teams: hasTextField(teams, "clientId") && hasTextField(teams, "clientSecret") && hasTextField(teams, "tenantId"),
|
|
165
|
+
bluebubbles: hasTextField(bluebubbles, "serverUrl") && hasTextField(bluebubbles, "password"),
|
|
166
|
+
};
|
|
167
|
+
const rows = [
|
|
168
|
+
{ label: "CLI", status: "interactive" },
|
|
169
|
+
{
|
|
170
|
+
label: "Teams",
|
|
171
|
+
status: !senses.teams.enabled ? "disabled" : configured.teams ? "ready" : "needs_config",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
label: "BlueBubbles",
|
|
175
|
+
status: !senses.bluebubbles.enabled ? "disabled" : configured.bluebubbles ? "ready" : "needs_config",
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
return rows.map((row) => `- ${row.label}: ${row.status}`);
|
|
179
|
+
}
|
|
180
|
+
function readBundleMetaFile() {
|
|
181
|
+
try {
|
|
182
|
+
const metaPath = path.join((0, identity_1.getAgentRoot)(), "bundle-meta.json");
|
|
183
|
+
const raw = fs.readFileSync(metaPath, "utf-8");
|
|
184
|
+
return JSON.parse(raw);
|
|
185
|
+
}
|
|
186
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
187
|
+
return null;
|
|
188
|
+
/* v8 ignore stop */
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// ── Builder ─────────────────────────────────────────────────────────
|
|
192
|
+
async function buildTurnContext(input) {
|
|
193
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
194
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
195
|
+
// Sync config
|
|
196
|
+
let syncConfig = { enabled: false, remote: "origin" };
|
|
197
|
+
try {
|
|
198
|
+
syncConfig = (0, config_1.getSyncConfig)();
|
|
199
|
+
}
|
|
200
|
+
catch { /* v8 ignore next -- defensive @preserve */ /* config not available */ }
|
|
201
|
+
// Bridges
|
|
202
|
+
const activeBridges = (0, manager_1.createBridgeManager)().findBridgesForSession({
|
|
203
|
+
friendId: input.currentSession.friendId,
|
|
204
|
+
channel: input.currentSession.channel,
|
|
205
|
+
key: input.currentSession.key,
|
|
206
|
+
});
|
|
207
|
+
// Session activity
|
|
208
|
+
let sessionActivity = [];
|
|
209
|
+
try {
|
|
210
|
+
sessionActivity = (0, session_activity_1.listSessionActivity)({
|
|
211
|
+
sessionsDir: `${agentRoot}/state/sessions`,
|
|
212
|
+
friendsDir: `${agentRoot}/friends`,
|
|
213
|
+
agentName,
|
|
214
|
+
currentSession: {
|
|
215
|
+
friendId: input.currentSession.friendId,
|
|
216
|
+
channel: input.currentSession.channel,
|
|
217
|
+
key: input.currentSession.key,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
222
|
+
sessionActivity = [];
|
|
223
|
+
/* v8 ignore stop */
|
|
224
|
+
}
|
|
225
|
+
// Target candidates
|
|
226
|
+
let targetCandidates = [];
|
|
227
|
+
try {
|
|
228
|
+
if (input.channel !== "inner") {
|
|
229
|
+
targetCandidates = await (0, target_resolution_1.listTargetSessionCandidates)({
|
|
230
|
+
sessionsDir: `${agentRoot}/state/sessions`,
|
|
231
|
+
friendsDir: `${agentRoot}/friends`,
|
|
232
|
+
agentName,
|
|
233
|
+
currentSession: {
|
|
234
|
+
friendId: input.currentSession.friendId,
|
|
235
|
+
channel: input.currentSession.channel,
|
|
236
|
+
key: input.currentSession.key,
|
|
237
|
+
},
|
|
238
|
+
friendStore: input.friendStore,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
243
|
+
targetCandidates = [];
|
|
244
|
+
/* v8 ignore stop */
|
|
245
|
+
}
|
|
246
|
+
// Pending obligations
|
|
247
|
+
let pendingObligations = [];
|
|
248
|
+
try {
|
|
249
|
+
pendingObligations = (0, obligations_1.readPendingObligations)(agentRoot);
|
|
250
|
+
}
|
|
251
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
252
|
+
pendingObligations = [];
|
|
253
|
+
/* v8 ignore stop */
|
|
254
|
+
}
|
|
255
|
+
// Coding sessions
|
|
256
|
+
let codingSessions = [];
|
|
257
|
+
let otherCodingSessions = [];
|
|
258
|
+
try {
|
|
259
|
+
const liveCodingSessions = (0, coding_1.getCodingSessionManager)()
|
|
260
|
+
.listSessions()
|
|
261
|
+
.filter((session) => isLiveCodingSessionStatus(session.status) && Boolean(session.originSession));
|
|
262
|
+
codingSessions = liveCodingSessions.filter((session) => session.originSession?.friendId === input.currentSession.friendId
|
|
263
|
+
&& session.originSession.channel === input.currentSession.channel
|
|
264
|
+
&& session.originSession.key === input.currentSession.key);
|
|
265
|
+
otherCodingSessions = liveCodingSessions.filter((session) => !(session.originSession?.friendId === input.currentSession.friendId
|
|
266
|
+
&& session.originSession.channel === input.currentSession.channel
|
|
267
|
+
&& session.originSession.key === input.currentSession.key));
|
|
268
|
+
}
|
|
269
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
270
|
+
codingSessions = [];
|
|
271
|
+
otherCodingSessions = [];
|
|
272
|
+
/* v8 ignore stop */
|
|
273
|
+
}
|
|
274
|
+
// Inner work state
|
|
275
|
+
const innerWorkState = readInnerWorkState();
|
|
276
|
+
// Task board
|
|
277
|
+
let taskBoard;
|
|
278
|
+
try {
|
|
279
|
+
taskBoard = (0, tasks_1.getTaskModule)().getBoard();
|
|
280
|
+
}
|
|
281
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
282
|
+
taskBoard = emptyTaskBoard();
|
|
283
|
+
/* v8 ignore stop */
|
|
284
|
+
}
|
|
285
|
+
// Return obligations
|
|
286
|
+
let returnObligations = [];
|
|
287
|
+
try {
|
|
288
|
+
returnObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
289
|
+
}
|
|
290
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
291
|
+
returnObligations = [];
|
|
292
|
+
/* v8 ignore stop */
|
|
293
|
+
}
|
|
294
|
+
// Recent episodes
|
|
295
|
+
const recentEpisodes = (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: 20 });
|
|
296
|
+
// Active cares
|
|
297
|
+
const activeCares = (0, cares_1.readActiveCares)(agentRoot);
|
|
298
|
+
// ── Prompt-assembly pre-reads ──────────────────────────────────────
|
|
299
|
+
const daemonRunning = checkDaemonRunning();
|
|
300
|
+
let senseStatusLines = [];
|
|
301
|
+
try {
|
|
302
|
+
senseStatusLines = readSenseStatusLines();
|
|
303
|
+
}
|
|
304
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
305
|
+
senseStatusLines = [];
|
|
306
|
+
/* v8 ignore stop */
|
|
307
|
+
}
|
|
308
|
+
const bundleMeta = readBundleMetaFile();
|
|
309
|
+
let daemonHealth = null;
|
|
310
|
+
try {
|
|
311
|
+
daemonHealth = (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
|
|
312
|
+
}
|
|
313
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
314
|
+
daemonHealth = null;
|
|
315
|
+
/* v8 ignore stop */
|
|
316
|
+
}
|
|
317
|
+
let journalFiles = [];
|
|
318
|
+
try {
|
|
319
|
+
const journalDir = path.join(agentRoot, "journal");
|
|
320
|
+
journalFiles = (0, prompt_1.readJournalFiles)(journalDir);
|
|
321
|
+
}
|
|
322
|
+
catch { /* v8 ignore start -- defensive: fallback on read failure @preserve */
|
|
323
|
+
journalFiles = [];
|
|
324
|
+
/* v8 ignore stop */
|
|
325
|
+
}
|
|
326
|
+
(0, runtime_1.emitNervesEvent)({
|
|
327
|
+
component: "senses",
|
|
328
|
+
event: "senses.turn_context_built",
|
|
329
|
+
message: "turn context snapshot assembled",
|
|
330
|
+
meta: {
|
|
331
|
+
channel: input.channel,
|
|
332
|
+
obligationCount: pendingObligations.length,
|
|
333
|
+
bridgeCount: activeBridges.length,
|
|
334
|
+
codingSessionCount: codingSessions.length,
|
|
335
|
+
episodeCount: recentEpisodes.length,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
activeBridges,
|
|
340
|
+
sessionActivity,
|
|
341
|
+
targetCandidates,
|
|
342
|
+
pendingObligations,
|
|
343
|
+
codingSessions,
|
|
344
|
+
otherCodingSessions,
|
|
345
|
+
innerWorkState,
|
|
346
|
+
taskBoard,
|
|
347
|
+
returnObligations,
|
|
348
|
+
recentEpisodes,
|
|
349
|
+
activeCares,
|
|
350
|
+
syncConfig,
|
|
351
|
+
syncFailure: undefined, // Set by pipeline after preTurnPull
|
|
352
|
+
daemonRunning,
|
|
353
|
+
senseStatusLines,
|
|
354
|
+
bundleMeta,
|
|
355
|
+
daemonHealth,
|
|
356
|
+
journalFiles,
|
|
357
|
+
};
|
|
358
|
+
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -257,7 +257,11 @@ function processTypeLabel(channel) {
|
|
|
257
257
|
return PROCESS_TYPE_LABELS[channel];
|
|
258
258
|
}
|
|
259
259
|
const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
|
|
260
|
-
function daemonStatus() {
|
|
260
|
+
function daemonStatus(preRead) {
|
|
261
|
+
/* v8 ignore next 2 -- pre-read branch: exercised via pipeline TurnContext path, not unit-testable in isolation @preserve */
|
|
262
|
+
if (preRead !== undefined) {
|
|
263
|
+
return preRead ? "running" : "not running";
|
|
264
|
+
}
|
|
261
265
|
try {
|
|
262
266
|
return fs.existsSync(DAEMON_SOCKET_PATH) ? "running" : "not running";
|
|
263
267
|
}
|
|
@@ -265,14 +269,15 @@ function daemonStatus() {
|
|
|
265
269
|
return "unknown";
|
|
266
270
|
}
|
|
267
271
|
}
|
|
268
|
-
function runtimeInfoSection(channel) {
|
|
272
|
+
function runtimeInfoSection(channel, options) {
|
|
269
273
|
const lines = [];
|
|
270
274
|
const agentName = (0, identity_1.getAgentName)();
|
|
271
275
|
const currentVersion = (0, bundle_manifest_1.getPackageVersion)();
|
|
272
276
|
lines.push(`## runtime`);
|
|
273
277
|
lines.push(`agent: ${agentName}`);
|
|
274
278
|
lines.push(`runtime version: ${currentVersion}`);
|
|
275
|
-
|
|
279
|
+
/* v8 ignore next -- branch: pre-read path exercised via pipeline TurnContext, not unit-testable in isolation @preserve */
|
|
280
|
+
const bundleMeta = options?.bundleMeta !== undefined ? options.bundleMeta : readBundleMeta();
|
|
276
281
|
if (bundleMeta?.previousRuntimeVersion && bundleMeta.previousRuntimeVersion !== currentVersion) {
|
|
277
282
|
lines.push(`previously: ${bundleMeta.previousRuntimeVersion}`);
|
|
278
283
|
const changelogCommand = (0, ouro_version_manager_1.buildChangelogCommand)(bundleMeta.previousRuntimeVersion, currentVersion);
|
|
@@ -289,7 +294,7 @@ function runtimeInfoSection(channel) {
|
|
|
289
294
|
lines.push(`channel: ${channel}`);
|
|
290
295
|
lines.push(`current sense: ${channel}`);
|
|
291
296
|
lines.push(`process type: ${processTypeLabel(channel)}`);
|
|
292
|
-
lines.push(`daemon: ${daemonStatus()}`);
|
|
297
|
+
lines.push(`daemon: ${daemonStatus(options?.daemonRunning)}`);
|
|
293
298
|
lines.push(`mcp serve: i can expose my tools to dev tools via \`ouro mcp-serve\`. see the configure-dev-tools skill for setup.`);
|
|
294
299
|
if (channel === "cli") {
|
|
295
300
|
lines.push("i introduce myself on boot with a fun random greeting.");
|
|
@@ -308,7 +313,7 @@ function runtimeInfoSection(channel) {
|
|
|
308
313
|
lines.push("i am responding in Microsoft Teams. i keep responses concise. i use markdown formatting. i do not introduce myself on boot.");
|
|
309
314
|
}
|
|
310
315
|
lines.push("");
|
|
311
|
-
lines.push(...senseRuntimeGuidance(channel));
|
|
316
|
+
lines.push(...senseRuntimeGuidance(channel, options?.senseStatusLines));
|
|
312
317
|
return lines.join("\n");
|
|
313
318
|
}
|
|
314
319
|
function hasTextField(record, key) {
|
|
@@ -356,9 +361,9 @@ function localSenseStatusLines() {
|
|
|
356
361
|
_senseStatusLinesCache = rows.map((row) => `- ${row.label}: ${row.status}`);
|
|
357
362
|
return [..._senseStatusLinesCache];
|
|
358
363
|
}
|
|
359
|
-
function senseRuntimeGuidance(channel) {
|
|
364
|
+
function senseRuntimeGuidance(channel, preReadStatusLines) {
|
|
360
365
|
const lines = ["available senses:"];
|
|
361
|
-
lines.push(...localSenseStatusLines());
|
|
366
|
+
lines.push(...(preReadStatusLines ?? localSenseStatusLines()));
|
|
362
367
|
lines.push("sense states:");
|
|
363
368
|
lines.push("- interactive = available when opened by the user instead of kept running by the daemon");
|
|
364
369
|
lines.push("- disabled = turned off in agent.json");
|
|
@@ -876,9 +881,8 @@ function formatRelativeTime(nowMs, mtimeMs) {
|
|
|
876
881
|
const days = Math.floor(hours / 24);
|
|
877
882
|
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
878
883
|
}
|
|
879
|
-
function journalSection(agentRoot, now) {
|
|
880
|
-
const
|
|
881
|
-
const files = readJournalFiles(journalDir);
|
|
884
|
+
function journalSection(agentRoot, now, preReadFiles) {
|
|
885
|
+
const files = preReadFiles ?? readJournalFiles(path.join(agentRoot, "journal"));
|
|
882
886
|
if (files.length === 0)
|
|
883
887
|
return "";
|
|
884
888
|
const nowMs = (now ?? new Date()).getTime();
|
|
@@ -977,9 +981,10 @@ function formatElapsedBrief(ms) {
|
|
|
977
981
|
const hours = Math.floor(minutes / 60);
|
|
978
982
|
return `${hours}h ago`;
|
|
979
983
|
}
|
|
980
|
-
function rhythmStatusSection() {
|
|
984
|
+
function rhythmStatusSection(preReadHealth) {
|
|
981
985
|
try {
|
|
982
|
-
|
|
986
|
+
/* v8 ignore next -- branch: pre-read path exercised via pipeline TurnContext @preserve */
|
|
987
|
+
const health = preReadHealth !== undefined ? preReadHealth : (0, daemon_health_1.readHealth)((0, daemon_health_1.getDefaultHealthPath)());
|
|
983
988
|
if (!health)
|
|
984
989
|
return "";
|
|
985
990
|
const habitNames = Object.keys(health.habits);
|
|
@@ -1032,8 +1037,8 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1032
1037
|
// Group 2: my body & environment
|
|
1033
1038
|
"# my body & environment",
|
|
1034
1039
|
bodyMapSection((0, identity_1.getAgentName)()),
|
|
1035
|
-
runtimeInfoSection(channel),
|
|
1036
|
-
rhythmStatusSection(),
|
|
1040
|
+
runtimeInfoSection(channel, options),
|
|
1041
|
+
rhythmStatusSection(options?.daemonHealth),
|
|
1037
1042
|
channelNatureSection((0, channel_1.getChannelCapabilities)(channel)),
|
|
1038
1043
|
providerSection(channel),
|
|
1039
1044
|
dateSection(),
|
|
@@ -1055,7 +1060,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
1055
1060
|
...(channel === "inner" ? [
|
|
1056
1061
|
"# my inner life",
|
|
1057
1062
|
metacognitiveFramingSection(channel),
|
|
1058
|
-
journalSection((0, identity_1.getAgentRoot)()),
|
|
1063
|
+
journalSection((0, identity_1.getAgentRoot)(), undefined, options?.journalFiles),
|
|
1059
1064
|
] : []),
|
|
1060
1065
|
// Group 6: social context (non-local, non-inner channels)
|
|
1061
1066
|
// Individual sections self-gate on isRemoteChannel/channel checks.
|
|
@@ -58,10 +58,9 @@ const coding_1 = require("./coding");
|
|
|
58
58
|
const diary_1 = require("../mind/diary");
|
|
59
59
|
const tasks_1 = require("./tasks");
|
|
60
60
|
const pending_1 = require("../mind/pending");
|
|
61
|
-
const obligations_1 = require("../
|
|
61
|
+
const obligations_1 = require("../heart/obligations");
|
|
62
62
|
const progress_story_1 = require("../heart/progress-story");
|
|
63
63
|
const cross_chat_delivery_1 = require("../heart/cross-chat-delivery");
|
|
64
|
-
const obligations_2 = require("../heart/obligations");
|
|
65
64
|
const episodes_1 = require("../mind/episodes");
|
|
66
65
|
const cares_1 = require("../heart/cares");
|
|
67
66
|
const presence_1 = require("../heart/presence");
|
|
@@ -220,7 +219,7 @@ function readActiveWorkInnerState() {
|
|
|
220
219
|
const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
|
|
221
220
|
const dialogStatus = (0, thoughts_1.deriveInnerDialogStatus)(pendingMessages, turns, runtimeState);
|
|
222
221
|
const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
|
|
223
|
-
const storeObligationPending = (0,
|
|
222
|
+
const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
|
|
224
223
|
return {
|
|
225
224
|
status: dialogStatus.processing === "started" ? "running" : "idle",
|
|
226
225
|
hasPending: dialogStatus.queue !== "clear",
|
|
@@ -269,7 +268,7 @@ async function buildToolActiveWorkFrame(ctx) {
|
|
|
269
268
|
}
|
|
270
269
|
const pendingObligations = (() => {
|
|
271
270
|
try {
|
|
272
|
-
return (0,
|
|
271
|
+
return (0, obligations_1.readPendingObligations)(agentRoot);
|
|
273
272
|
}
|
|
274
273
|
catch {
|
|
275
274
|
return [];
|
|
@@ -1296,7 +1295,7 @@ exports.baseToolDefinitions = [
|
|
|
1296
1295
|
writePendingEnvelope(pendingDir, envelope);
|
|
1297
1296
|
if (delegatedFrom) {
|
|
1298
1297
|
try {
|
|
1299
|
-
(0,
|
|
1298
|
+
(0, obligations_1.createObligation)((0, identity_1.getAgentRoot)(), {
|
|
1300
1299
|
origin: {
|
|
1301
1300
|
friendId: delegatedFrom.friendId,
|
|
1302
1301
|
channel: delegatedFrom.channel,
|
|
@@ -1311,7 +1310,7 @@ exports.baseToolDefinitions = [
|
|
|
1311
1310
|
}
|
|
1312
1311
|
/* v8 ignore next -- obligationId always set when delegatedFrom is set (see generateObligationId above) @preserve */
|
|
1313
1312
|
if (obligationId) {
|
|
1314
|
-
(0, obligations_1.
|
|
1313
|
+
(0, obligations_1.createReturnObligation)(agentName, {
|
|
1315
1314
|
id: obligationId,
|
|
1316
1315
|
origin: delegatedFrom,
|
|
1317
1316
|
status: "queued",
|
package/dist/repertoire/tools.js
CHANGED
|
@@ -48,8 +48,7 @@ const runtime_1 = require("../nerves/runtime");
|
|
|
48
48
|
const guardrails_1 = require("./guardrails");
|
|
49
49
|
const identity_1 = require("../heart/identity");
|
|
50
50
|
const surface_tool_1 = require("../senses/surface-tool");
|
|
51
|
-
const obligations_1 = require("../
|
|
52
|
-
const obligations_2 = require("../heart/obligations");
|
|
51
|
+
const obligations_1 = require("../heart/obligations");
|
|
53
52
|
const session_activity_1 = require("../heart/session-activity");
|
|
54
53
|
const path = __importStar(require("path"));
|
|
55
54
|
function safeGetAgentRoot() {
|
|
@@ -198,7 +197,7 @@ const surfaceToolDefinition = {
|
|
|
198
197
|
catch {
|
|
199
198
|
return "unknown";
|
|
200
199
|
} })();
|
|
201
|
-
(0, obligations_1.
|
|
200
|
+
(0, obligations_1.advanceReturnObligation)(name, obligationId, {
|
|
202
201
|
status: update.status,
|
|
203
202
|
...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
|
|
204
203
|
...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
|
|
@@ -213,9 +212,9 @@ const surfaceToolDefinition = {
|
|
|
213
212
|
/* v8 ignore start -- heart obligation fulfillment: tested via surface-tool.test.ts @preserve */
|
|
214
213
|
try {
|
|
215
214
|
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
216
|
-
const heartObligation = (0,
|
|
215
|
+
const heartObligation = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, origin);
|
|
217
216
|
if (heartObligation) {
|
|
218
|
-
(0,
|
|
217
|
+
(0, obligations_1.fulfillObligation)(agentRoot, heartObligation.id);
|
|
219
218
|
}
|
|
220
219
|
}
|
|
221
220
|
catch {
|
|
@@ -55,7 +55,7 @@ const prompt_1 = require("../mind/prompt");
|
|
|
55
55
|
const mcp_manager_1 = require("../repertoire/mcp-manager");
|
|
56
56
|
const bundle_manifest_1 = require("../mind/bundle-manifest");
|
|
57
57
|
const pending_1 = require("../mind/pending");
|
|
58
|
-
const obligations_1 = require("../
|
|
58
|
+
const obligations_1 = require("../heart/obligations");
|
|
59
59
|
const attention_queue_1 = require("./attention-queue");
|
|
60
60
|
const channel_1 = require("../mind/friends/channel");
|
|
61
61
|
const trust_gate_1 = require("./trust-gate");
|
|
@@ -66,7 +66,6 @@ const runtime_1 = require("../nerves/runtime");
|
|
|
66
66
|
const manager_1 = require("../heart/bridges/manager");
|
|
67
67
|
const session_activity_1 = require("../heart/session-activity");
|
|
68
68
|
const bluebubbles_1 = require("./bluebubbles");
|
|
69
|
-
const obligations_2 = require("../heart/obligations");
|
|
70
69
|
const habit_turn_message_1 = require("./habit-turn-message");
|
|
71
70
|
const journal_index_1 = require("../mind/journal-index");
|
|
72
71
|
const habit_parser_1 = require("../heart/daemon/habit-parser");
|
|
@@ -324,7 +323,7 @@ function advanceObligationQuietly(agentName, obligationId, update) {
|
|
|
324
323
|
if (!obligationId)
|
|
325
324
|
return;
|
|
326
325
|
try {
|
|
327
|
-
(0, obligations_1.
|
|
326
|
+
(0, obligations_1.advanceReturnObligation)(agentName, obligationId, update);
|
|
328
327
|
/* v8 ignore start -- best-effort: obligation fs errors must never block return routing @preserve */
|
|
329
328
|
}
|
|
330
329
|
catch {
|
|
@@ -352,14 +351,14 @@ async function routeDelegatedCompletion(agentRoot, agentName, completion, draine
|
|
|
352
351
|
if (delegated.obligationStatus === "pending") {
|
|
353
352
|
// Fulfill the persistent obligation in the store
|
|
354
353
|
try {
|
|
355
|
-
const pending = (0,
|
|
354
|
+
const pending = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, {
|
|
356
355
|
friendId: delegatedFrom.friendId,
|
|
357
356
|
channel: delegatedFrom.channel,
|
|
358
357
|
key: delegatedFrom.key,
|
|
359
358
|
});
|
|
360
359
|
/* v8 ignore next 2 -- obligation fulfillment tested via obligations.test.ts; integration requires real disk state @preserve */
|
|
361
360
|
if (pending) {
|
|
362
|
-
(0,
|
|
361
|
+
(0, obligations_1.fulfillObligation)(agentRoot, pending.id);
|
|
363
362
|
}
|
|
364
363
|
}
|
|
365
364
|
catch {
|
|
@@ -577,7 +576,7 @@ async function runInnerDialogTurn(options) {
|
|
|
577
576
|
}
|
|
578
577
|
else {
|
|
579
578
|
// Unified path: gather context for ALL habits (heartbeat included)
|
|
580
|
-
const obligations = (0, obligations_1.
|
|
579
|
+
const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
581
580
|
const nowMs = now().getTime();
|
|
582
581
|
const staleObligations = obligations.map((o) => ({
|
|
583
582
|
friendName: o.origin.friendId,
|
|
@@ -670,7 +669,7 @@ async function runInnerDialogTurn(options) {
|
|
|
670
669
|
signal: options?.signal,
|
|
671
670
|
/* v8 ignore start -- attention queue: callback invoked by pipeline during pending drain; tested via attention-queue unit tests @preserve */
|
|
672
671
|
onPendingDrained: (drained) => {
|
|
673
|
-
const outstandingObligations = (0, obligations_1.
|
|
672
|
+
const outstandingObligations = (0, obligations_1.listActiveReturnObligations)(agentName);
|
|
674
673
|
attentionQueue = (0, attention_queue_1.buildAttentionQueue)({
|
|
675
674
|
drainedPending: drained,
|
|
676
675
|
outstandingObligations,
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -47,17 +47,10 @@ const commands_1 = require("./commands");
|
|
|
47
47
|
const continuity_1 = require("./continuity");
|
|
48
48
|
const manager_1 = require("../heart/bridges/manager");
|
|
49
49
|
const identity_1 = require("../heart/identity");
|
|
50
|
-
const tasks_1 = require("../repertoire/tasks");
|
|
51
|
-
const coding_1 = require("../repertoire/coding");
|
|
52
|
-
const session_activity_1 = require("../heart/session-activity");
|
|
53
50
|
const socket_client_1 = require("../heart/daemon/socket-client");
|
|
54
51
|
const active_work_1 = require("../heart/active-work");
|
|
55
52
|
const delegation_1 = require("../heart/delegation");
|
|
56
|
-
const target_resolution_1 = require("../heart/target-resolution");
|
|
57
|
-
const thoughts_1 = require("../heart/daemon/thoughts");
|
|
58
|
-
const pending_1 = require("../mind/pending");
|
|
59
53
|
const obligations_1 = require("../heart/obligations");
|
|
60
|
-
const obligations_2 = require("../mind/obligations");
|
|
61
54
|
const provider_failover_1 = require("../heart/provider-failover");
|
|
62
55
|
const provider_ping_1 = require("../heart/provider-ping");
|
|
63
56
|
const auth_flow_1 = require("../heart/daemon/auth-flow");
|
|
@@ -68,7 +61,7 @@ const sync_1 = require("../heart/sync");
|
|
|
68
61
|
const config_1 = require("../heart/config");
|
|
69
62
|
const presence_1 = require("../heart/presence");
|
|
70
63
|
const episodes_1 = require("../mind/episodes");
|
|
71
|
-
const
|
|
64
|
+
const turn_context_1 = require("../heart/turn-context");
|
|
72
65
|
/**
|
|
73
66
|
* Emit episodes for obligation state transitions detected during a turn.
|
|
74
67
|
* Exported for direct testability (avoids v8 coverage merge issues in multi-file test suites).
|
|
@@ -89,33 +82,6 @@ function emitObligationTransitionEpisodes(agentRoot, preTurnObligationIds, postT
|
|
|
89
82
|
}
|
|
90
83
|
}
|
|
91
84
|
}
|
|
92
|
-
function emptyTaskBoard() {
|
|
93
|
-
return {
|
|
94
|
-
compact: "",
|
|
95
|
-
full: "",
|
|
96
|
-
byStatus: {
|
|
97
|
-
drafting: [],
|
|
98
|
-
processing: [],
|
|
99
|
-
validating: [],
|
|
100
|
-
collaborating: [],
|
|
101
|
-
paused: [],
|
|
102
|
-
blocked: [],
|
|
103
|
-
done: [],
|
|
104
|
-
cancelled: [],
|
|
105
|
-
},
|
|
106
|
-
issues: [],
|
|
107
|
-
actionRequired: [],
|
|
108
|
-
unresolvedDependencies: [],
|
|
109
|
-
activeSessions: [],
|
|
110
|
-
activeBridges: [],
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
function isLiveCodingSessionStatus(status) {
|
|
114
|
-
return status === "spawning"
|
|
115
|
-
|| status === "running"
|
|
116
|
-
|| status === "waiting_input"
|
|
117
|
-
|| status === "stalled";
|
|
118
|
-
}
|
|
119
85
|
function prependTurnSections(message, sections) {
|
|
120
86
|
/* v8 ignore next -- defensive: only user messages with non-empty sections reach here @preserve */
|
|
121
87
|
if (message.role !== "user" || sections.length === 0)
|
|
@@ -137,44 +103,6 @@ function prependTurnSections(message, sections) {
|
|
|
137
103
|
};
|
|
138
104
|
/* v8 ignore stop */
|
|
139
105
|
}
|
|
140
|
-
function readInnerWorkState() {
|
|
141
|
-
const defaultJob = {
|
|
142
|
-
status: "idle",
|
|
143
|
-
content: null,
|
|
144
|
-
origin: null,
|
|
145
|
-
mode: "reflect",
|
|
146
|
-
obligationStatus: null,
|
|
147
|
-
surfacedResult: null,
|
|
148
|
-
queuedAt: null,
|
|
149
|
-
startedAt: null,
|
|
150
|
-
surfacedAt: null,
|
|
151
|
-
};
|
|
152
|
-
try {
|
|
153
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
154
|
-
const pendingDir = (0, pending_1.getInnerDialogPendingDir)((0, identity_1.getAgentName)());
|
|
155
|
-
const sessionPath = (0, thoughts_1.getInnerDialogSessionPath)(agentRoot);
|
|
156
|
-
const { pendingMessages, turns, runtimeState } = (0, thoughts_1.readInnerDialogRawData)(sessionPath, pendingDir);
|
|
157
|
-
const dialogStatus = (0, thoughts_1.deriveInnerDialogStatus)(pendingMessages, turns, runtimeState);
|
|
158
|
-
const job = (0, thoughts_1.deriveInnerJob)(pendingMessages, turns, runtimeState);
|
|
159
|
-
// Derive obligationPending from both the pending message field and the obligation store
|
|
160
|
-
const storeObligationPending = (0, obligations_1.readPendingObligations)(agentRoot).length > 0;
|
|
161
|
-
return {
|
|
162
|
-
status: dialogStatus.processing === "started" ? "running" : "idle",
|
|
163
|
-
hasPending: dialogStatus.queue !== "clear",
|
|
164
|
-
origin: dialogStatus.origin,
|
|
165
|
-
contentSnippet: dialogStatus.contentSnippet,
|
|
166
|
-
obligationPending: dialogStatus.obligationPending || storeObligationPending,
|
|
167
|
-
job,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
return {
|
|
172
|
-
status: "idle",
|
|
173
|
-
hasPending: false,
|
|
174
|
-
job: defaultJob,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
106
|
// ── Pipeline ──────────────────────────────────────────────────────
|
|
179
107
|
let _lastSessionKey = null;
|
|
180
108
|
async function handleInboundTurn(input) {
|
|
@@ -378,100 +306,29 @@ async function handleInboundTurn(input) {
|
|
|
378
306
|
}
|
|
379
307
|
}
|
|
380
308
|
/* v8 ignore stop */
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
309
|
+
// Build the turn context snapshot — centralizes all state reads
|
|
310
|
+
const ctx = await (0, turn_context_1.buildTurnContext)({
|
|
311
|
+
currentSession,
|
|
312
|
+
channel: input.channel,
|
|
313
|
+
friendStore: input.friendStore,
|
|
385
314
|
});
|
|
315
|
+
// Propagate sync failure from pre-turn pull
|
|
316
|
+
ctx.syncFailure = syncFailure;
|
|
317
|
+
const { activeBridges, sessionActivity, pendingObligations, codingSessions, otherCodingSessions } = ctx;
|
|
386
318
|
const bridgeContext = (0, manager_1.formatBridgeContext)(activeBridges) || undefined;
|
|
387
|
-
let sessionActivity = [];
|
|
388
|
-
try {
|
|
389
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
390
|
-
sessionActivity = (0, session_activity_1.listSessionActivity)({
|
|
391
|
-
sessionsDir: `${agentRoot}/state/sessions`,
|
|
392
|
-
friendsDir: `${agentRoot}/friends`,
|
|
393
|
-
agentName: (0, identity_1.getAgentName)(),
|
|
394
|
-
currentSession: {
|
|
395
|
-
friendId: currentSession.friendId,
|
|
396
|
-
channel: currentSession.channel,
|
|
397
|
-
key: currentSession.key,
|
|
398
|
-
},
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
catch {
|
|
402
|
-
sessionActivity = [];
|
|
403
|
-
}
|
|
404
|
-
let targetCandidates = [];
|
|
405
|
-
try {
|
|
406
|
-
if (input.channel !== "inner") {
|
|
407
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
408
|
-
targetCandidates = await (0, target_resolution_1.listTargetSessionCandidates)({
|
|
409
|
-
sessionsDir: `${agentRoot}/state/sessions`,
|
|
410
|
-
friendsDir: `${agentRoot}/friends`,
|
|
411
|
-
agentName: (0, identity_1.getAgentName)(),
|
|
412
|
-
currentSession: {
|
|
413
|
-
friendId: currentSession.friendId,
|
|
414
|
-
channel: currentSession.channel,
|
|
415
|
-
key: currentSession.key,
|
|
416
|
-
},
|
|
417
|
-
friendStore: input.friendStore,
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
catch {
|
|
422
|
-
targetCandidates = [];
|
|
423
|
-
}
|
|
424
|
-
let pendingObligations = [];
|
|
425
|
-
try {
|
|
426
|
-
pendingObligations = (0, obligations_1.readPendingObligations)((0, identity_1.getAgentRoot)());
|
|
427
|
-
}
|
|
428
|
-
catch {
|
|
429
|
-
pendingObligations = [];
|
|
430
|
-
}
|
|
431
|
-
let codingSessions = [];
|
|
432
|
-
let otherCodingSessions = [];
|
|
433
|
-
try {
|
|
434
|
-
const liveCodingSessions = (0, coding_1.getCodingSessionManager)()
|
|
435
|
-
.listSessions()
|
|
436
|
-
.filter((session) => isLiveCodingSessionStatus(session.status) && Boolean(session.originSession));
|
|
437
|
-
codingSessions = liveCodingSessions.filter((session) => session.originSession?.friendId === currentSession.friendId
|
|
438
|
-
&& session.originSession.channel === currentSession.channel
|
|
439
|
-
&& session.originSession.key === currentSession.key);
|
|
440
|
-
otherCodingSessions = liveCodingSessions.filter((session) => !(session.originSession?.friendId === currentSession.friendId
|
|
441
|
-
&& session.originSession.channel === currentSession.channel
|
|
442
|
-
&& session.originSession.key === currentSession.key));
|
|
443
|
-
}
|
|
444
|
-
catch {
|
|
445
|
-
codingSessions = [];
|
|
446
|
-
otherCodingSessions = [];
|
|
447
|
-
}
|
|
448
319
|
const activeWorkFrame = (0, active_work_1.buildActiveWorkFrame)({
|
|
449
320
|
currentSession,
|
|
450
321
|
currentObligation,
|
|
451
322
|
mustResolveBeforeHandoff,
|
|
452
|
-
inner:
|
|
323
|
+
inner: ctx.innerWorkState,
|
|
453
324
|
bridges: activeBridges,
|
|
454
325
|
codingSessions,
|
|
455
326
|
otherCodingSessions,
|
|
456
327
|
pendingObligations,
|
|
457
|
-
taskBoard:
|
|
458
|
-
try {
|
|
459
|
-
return (0, tasks_1.getTaskModule)().getBoard();
|
|
460
|
-
}
|
|
461
|
-
catch {
|
|
462
|
-
return emptyTaskBoard();
|
|
463
|
-
}
|
|
464
|
-
})(),
|
|
328
|
+
taskBoard: ctx.taskBoard,
|
|
465
329
|
friendActivity: sessionActivity,
|
|
466
|
-
targetCandidates,
|
|
467
|
-
innerReturnObligations:
|
|
468
|
-
try {
|
|
469
|
-
return (0, obligations_2.listActiveObligations)((0, identity_1.getAgentName)());
|
|
470
|
-
}
|
|
471
|
-
catch {
|
|
472
|
-
return [];
|
|
473
|
-
}
|
|
474
|
-
})(),
|
|
330
|
+
targetCandidates: ctx.targetCandidates,
|
|
331
|
+
innerReturnObligations: ctx.returnObligations,
|
|
475
332
|
});
|
|
476
333
|
const delegationDecision = (0, delegation_1.decideDelegation)({
|
|
477
334
|
channel: input.channel,
|
|
@@ -502,8 +359,7 @@ async function handleInboundTurn(input) {
|
|
|
502
359
|
try {
|
|
503
360
|
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
504
361
|
const agentName = (0, identity_1.getAgentName)();
|
|
505
|
-
const recentEpisodes
|
|
506
|
-
const activeCares = (0, cares_1.readActiveCares)(agentRoot);
|
|
362
|
+
const { recentEpisodes, activeCares } = ctx;
|
|
507
363
|
const tempoState = (0, tempo_1.deriveTempo)({
|
|
508
364
|
activeSessions: sessionActivity.length + 1,
|
|
509
365
|
openObligations: pendingObligations.length,
|
|
@@ -571,6 +427,12 @@ async function handleInboundTurn(input) {
|
|
|
571
427
|
setMustResolveBeforeHandoff: (value) => {
|
|
572
428
|
mustResolveBeforeHandoff = value;
|
|
573
429
|
},
|
|
430
|
+
// Pre-read state from TurnContext for prompt assembly
|
|
431
|
+
daemonRunning: ctx.daemonRunning,
|
|
432
|
+
senseStatusLines: ctx.senseStatusLines,
|
|
433
|
+
bundleMeta: ctx.bundleMeta,
|
|
434
|
+
daemonHealth: ctx.daemonHealth,
|
|
435
|
+
journalFiles: ctx.journalFiles,
|
|
574
436
|
toolContext: {
|
|
575
437
|
/* v8 ignore next -- default no-op signin satisfies interface; real signin injected by sense adapter @preserve */
|
|
576
438
|
signin: async () => undefined,
|
package/package.json
CHANGED
package/dist/mind/obligations.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
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.getObligationsDir = getObligationsDir;
|
|
37
|
-
exports.generateObligationId = generateObligationId;
|
|
38
|
-
exports.createObligation = createObligation;
|
|
39
|
-
exports.readObligation = readObligation;
|
|
40
|
-
exports.advanceObligation = advanceObligation;
|
|
41
|
-
exports.listActiveObligations = listActiveObligations;
|
|
42
|
-
const fs = __importStar(require("fs"));
|
|
43
|
-
const path = __importStar(require("path"));
|
|
44
|
-
const identity_1 = require("../heart/identity");
|
|
45
|
-
const runtime_1 = require("../nerves/runtime");
|
|
46
|
-
const sync_1 = require("../heart/sync");
|
|
47
|
-
// ── Paths ────────────────────────────────────────────────────────
|
|
48
|
-
function getObligationsDir(agentName) {
|
|
49
|
-
return path.join((0, identity_1.getAgentRoot)(agentName), "arc", "obligations", "inner");
|
|
50
|
-
}
|
|
51
|
-
// ── ID generation ────────────────────────────────────────────────
|
|
52
|
-
function generateObligationId(timestamp) {
|
|
53
|
-
return `${timestamp}-${Math.random().toString(36).slice(2, 10)}`;
|
|
54
|
-
}
|
|
55
|
-
// ── Store operations ─────────────────────────────────────────────
|
|
56
|
-
function createObligation(agentName, obligation) {
|
|
57
|
-
const dir = getObligationsDir(agentName);
|
|
58
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
59
|
-
const filePath = path.join(dir, `${obligation.id}.json`);
|
|
60
|
-
fs.writeFileSync(filePath, JSON.stringify(obligation, null, 2), "utf8");
|
|
61
|
-
(0, sync_1.trackSyncWrite)(filePath);
|
|
62
|
-
(0, runtime_1.emitNervesEvent)({
|
|
63
|
-
event: "mind.obligation_created",
|
|
64
|
-
component: "mind",
|
|
65
|
-
message: "return obligation created",
|
|
66
|
-
meta: {
|
|
67
|
-
obligationId: obligation.id,
|
|
68
|
-
origin: `${obligation.origin.friendId}/${obligation.origin.channel}/${obligation.origin.key}`,
|
|
69
|
-
status: obligation.status,
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
return filePath;
|
|
73
|
-
}
|
|
74
|
-
function readObligation(agentName, obligationId) {
|
|
75
|
-
const dir = getObligationsDir(agentName);
|
|
76
|
-
try {
|
|
77
|
-
const raw = fs.readFileSync(path.join(dir, `${obligationId}.json`), "utf-8");
|
|
78
|
-
return JSON.parse(raw);
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function advanceObligation(agentName, obligationId, update) {
|
|
85
|
-
const existing = readObligation(agentName, obligationId);
|
|
86
|
-
if (!existing)
|
|
87
|
-
return null;
|
|
88
|
-
const updated = {
|
|
89
|
-
...existing,
|
|
90
|
-
status: update.status,
|
|
91
|
-
...(update.startedAt !== undefined ? { startedAt: update.startedAt } : {}),
|
|
92
|
-
...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
|
|
93
|
-
...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
|
|
94
|
-
};
|
|
95
|
-
const dir = getObligationsDir(agentName);
|
|
96
|
-
const advancedFilePath = path.join(dir, `${obligationId}.json`);
|
|
97
|
-
fs.writeFileSync(advancedFilePath, JSON.stringify(updated, null, 2), "utf8");
|
|
98
|
-
(0, sync_1.trackSyncWrite)(advancedFilePath);
|
|
99
|
-
(0, runtime_1.emitNervesEvent)({
|
|
100
|
-
event: "mind.obligation_advanced",
|
|
101
|
-
component: "mind",
|
|
102
|
-
message: `obligation advanced to ${update.status}`,
|
|
103
|
-
meta: {
|
|
104
|
-
obligationId,
|
|
105
|
-
status: update.status,
|
|
106
|
-
...(update.returnTarget ? { returnTarget: update.returnTarget } : {}),
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
return updated;
|
|
110
|
-
}
|
|
111
|
-
function listActiveObligations(agentName) {
|
|
112
|
-
const dir = getObligationsDir(agentName);
|
|
113
|
-
if (!fs.existsSync(dir))
|
|
114
|
-
return [];
|
|
115
|
-
let entries;
|
|
116
|
-
try {
|
|
117
|
-
entries = fs.readdirSync(dir);
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
|
-
const obligations = [];
|
|
123
|
-
for (const file of entries) {
|
|
124
|
-
if (!file.endsWith(".json"))
|
|
125
|
-
continue;
|
|
126
|
-
try {
|
|
127
|
-
const raw = fs.readFileSync(path.join(dir, file), "utf-8");
|
|
128
|
-
const parsed = JSON.parse(raw);
|
|
129
|
-
if (parsed.status === "queued" || parsed.status === "running") {
|
|
130
|
-
obligations.push(parsed);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
// skip unparseable
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return obligations.sort((a, b) => a.createdAt - b.createdAt);
|
|
138
|
-
}
|