@ouro.bot/cli 0.1.0-alpha.611 → 0.1.0-alpha.612
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 +10 -0
- package/dist/arc/cares.js +7 -3
- package/dist/arc/episodes.js +4 -3
- package/dist/arc/intentions.js +2 -1
- package/dist/arc/obligations.js +18 -6
- package/dist/arc/packets.js +9 -8
- package/dist/heart/awaiting/await-runtime-state.js +4 -1
- package/dist/heart/bridges/store.js +14 -2
- package/dist/heart/daemon/daemon.js +47 -0
- package/dist/heart/daemon/process-manager.js +13 -0
- package/dist/heart/daemon/sense-manager.js +12 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +107 -2
- package/dist/heart/mailbox/readers/sessions.js +2 -2
- package/dist/heart/session-events.js +73 -66
- package/dist/heart/session-transcript.js +6 -116
- package/dist/mailbox-ui/assets/{index-CtUWEo-S.js → index-9-AxCxuB.js} +3 -3
- package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -0
- package/dist/mailbox-ui/index.html +2 -2
- package/dist/mind/diary.js +6 -1
- package/dist/mind/friends/store-file.js +9 -1
- package/dist/mind/journal-index.js +2 -1
- package/dist/mind/pending.js +2 -1
- package/dist/mind/prompt.js +6 -5
- package/dist/repertoire/coding/context-pack.js +3 -2
- package/dist/repertoire/coding/manager.js +6 -2
- package/dist/repertoire/tools-awaiting.js +11 -6
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/repertoire/tools-bridge.js +0 -1
- package/dist/repertoire/tools-record.js +463 -0
- package/dist/repertoire/tools-runtime.js +87 -0
- package/dist/repertoire/tools-session.js +9 -37
- package/dist/senses/bluebubbles/index.js +1 -1
- package/package.json +1 -1
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +0 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
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.612",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Drop the session archive and route durable history lookup through notes.",
|
|
8
|
+
"`query_session` keeps `mode=search` parseable during the deprecation cycle, but now returns a structured deprecation stub pointing agents to `search_notes` or `consult_notes`; the search mode is targeted for removal in alpha.616.",
|
|
9
|
+
"Session `.archive.ndjson` files are no longer written or read. Existing files under `~/AgentBundles/<agent>.ouro/state/sessions/**/*.archive.ndjson` are operationally inert and safe to delete with `rm`; the harness deliberately does not provide a built-in delete command now that archive pressure is gone and pruning is unnecessary, though an optional `ouro session archive prune` follow-up may land later if user demand emerges.",
|
|
10
|
+
"Canonical notes now have self-trust-only `note` and `consult_notes` tools backed by a rebuildable `notes/.index.json` version 1 semantic index derived from markdown notes.",
|
|
11
|
+
"Wire `daemon.sense_revive` through the live sense manager so `revive_sense({ sense: \"bluebubbles\" })` can recover BlueBubbles in the actual daemon topology."
|
|
12
|
+
]
|
|
13
|
+
},
|
|
4
14
|
{
|
|
5
15
|
"version": "0.1.0-alpha.611",
|
|
6
16
|
"changes": [
|
package/dist/arc/cares.js
CHANGED
|
@@ -39,6 +39,7 @@ exports.readActiveCares = readActiveCares;
|
|
|
39
39
|
exports.updateCare = updateCare;
|
|
40
40
|
exports.resolveCare = resolveCare;
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
|
+
const session_events_1 = require("../heart/session-events");
|
|
42
43
|
const runtime_1 = require("../nerves/runtime");
|
|
43
44
|
const json_store_1 = require("./json-store");
|
|
44
45
|
function caresDir(agentRoot) {
|
|
@@ -49,8 +50,8 @@ function createCare(agentRoot, input) {
|
|
|
49
50
|
const id = (0, json_store_1.generateTimestampId)("care");
|
|
50
51
|
const care = {
|
|
51
52
|
id,
|
|
52
|
-
label: input.label,
|
|
53
|
-
why: input.why,
|
|
53
|
+
label: (0, session_events_1.capStructuredRecordString)(input.label),
|
|
54
|
+
why: (0, session_events_1.capStructuredRecordString)(input.why),
|
|
54
55
|
kind: input.kind,
|
|
55
56
|
status: input.status,
|
|
56
57
|
salience: input.salience,
|
|
@@ -59,7 +60,7 @@ function createCare(agentRoot, input) {
|
|
|
59
60
|
relatedAgentIds: input.relatedAgentIds,
|
|
60
61
|
relatedObligationIds: input.relatedObligationIds,
|
|
61
62
|
relatedEpisodeIds: input.relatedEpisodeIds,
|
|
62
|
-
currentRisk: input.currentRisk,
|
|
63
|
+
currentRisk: input.currentRisk === null ? null : (0, session_events_1.capStructuredRecordString)(input.currentRisk),
|
|
63
64
|
nextCheckAt: input.nextCheckAt,
|
|
64
65
|
createdAt: now,
|
|
65
66
|
updatedAt: now,
|
|
@@ -107,6 +108,9 @@ function updateCare(agentRoot, id, updates) {
|
|
|
107
108
|
const updated = {
|
|
108
109
|
...care,
|
|
109
110
|
...updates,
|
|
111
|
+
...(typeof updates.label === "string" ? { label: (0, session_events_1.capStructuredRecordString)(updates.label) } : {}),
|
|
112
|
+
...(typeof updates.why === "string" ? { why: (0, session_events_1.capStructuredRecordString)(updates.why) } : {}),
|
|
113
|
+
...(typeof updates.currentRisk === "string" ? { currentRisk: (0, session_events_1.capStructuredRecordString)(updates.currentRisk) } : {}),
|
|
110
114
|
id: care.id, // protect ID from overwrite
|
|
111
115
|
createdAt: care.createdAt, // protect createdAt
|
|
112
116
|
updatedAt: now,
|
package/dist/arc/episodes.js
CHANGED
|
@@ -37,6 +37,7 @@ exports.emitEpisode = emitEpisode;
|
|
|
37
37
|
exports.readRecentEpisodes = readRecentEpisodes;
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
|
+
const session_events_1 = require("../heart/session-events");
|
|
40
41
|
const runtime_1 = require("../nerves/runtime");
|
|
41
42
|
function episodesDir(agentRoot) {
|
|
42
43
|
return path.join(agentRoot, "arc", "episodes");
|
|
@@ -53,11 +54,11 @@ function emitEpisode(agentRoot, input) {
|
|
|
53
54
|
id,
|
|
54
55
|
timestamp: now,
|
|
55
56
|
kind: input.kind,
|
|
56
|
-
summary: input.summary,
|
|
57
|
-
whyItMattered: input.whyItMattered,
|
|
57
|
+
summary: (0, session_events_1.capStructuredRecordString)(input.summary),
|
|
58
|
+
whyItMattered: (0, session_events_1.capStructuredRecordString)(input.whyItMattered),
|
|
58
59
|
relatedEntities: input.relatedEntities,
|
|
59
60
|
salience: input.salience,
|
|
60
|
-
...(input.meta ? { meta: input.meta } : {}),
|
|
61
|
+
...(input.meta ? { meta: (0, session_events_1.capStructuredRecordStringLeaves)(input.meta) } : {}),
|
|
61
62
|
};
|
|
62
63
|
const dir = episodesDir(agentRoot);
|
|
63
64
|
fs.mkdirSync(dir, { recursive: true });
|
package/dist/arc/intentions.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.readOpenIntentions = readOpenIntentions;
|
|
|
38
38
|
exports.resolveIntention = resolveIntention;
|
|
39
39
|
exports.dismissIntention = dismissIntention;
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
|
+
const session_events_1 = require("../heart/session-events");
|
|
41
42
|
const runtime_1 = require("../nerves/runtime");
|
|
42
43
|
const json_store_1 = require("./json-store");
|
|
43
44
|
function intentionsDir(agentRoot) {
|
|
@@ -58,7 +59,7 @@ function captureIntention(agentRoot, input) {
|
|
|
58
59
|
const id = (0, json_store_1.generateTimestampId)("int");
|
|
59
60
|
const intention = {
|
|
60
61
|
id,
|
|
61
|
-
content: input.content,
|
|
62
|
+
content: (0, session_events_1.capStructuredRecordString)(input.content),
|
|
62
63
|
status: "open",
|
|
63
64
|
createdAt: now,
|
|
64
65
|
updatedAt: now,
|
package/dist/arc/obligations.js
CHANGED
|
@@ -50,6 +50,7 @@ exports.advanceReturnObligation = advanceReturnObligation;
|
|
|
50
50
|
exports.listActiveReturnObligations = listActiveReturnObligations;
|
|
51
51
|
const path = __importStar(require("path"));
|
|
52
52
|
const identity_1 = require("../heart/identity");
|
|
53
|
+
const session_events_1 = require("../heart/session-events");
|
|
53
54
|
const runtime_1 = require("../nerves/runtime");
|
|
54
55
|
const json_store_1 = require("./json-store");
|
|
55
56
|
function obligationsDir(agentRoot) {
|
|
@@ -68,7 +69,7 @@ function createObligation(agentRoot, input) {
|
|
|
68
69
|
id,
|
|
69
70
|
origin: input.origin,
|
|
70
71
|
...(input.bridgeId ? { bridgeId: input.bridgeId } : {}),
|
|
71
|
-
content: input.content,
|
|
72
|
+
content: (0, session_events_1.capStructuredRecordString)(input.content),
|
|
72
73
|
status: "pending",
|
|
73
74
|
createdAt: now,
|
|
74
75
|
updatedAt: now,
|
|
@@ -110,13 +111,13 @@ function advanceObligation(agentRoot, obligationId, update) {
|
|
|
110
111
|
obligation.currentSurface = update.currentSurface;
|
|
111
112
|
}
|
|
112
113
|
if (typeof update.currentArtifact === "string") {
|
|
113
|
-
obligation.currentArtifact = update.currentArtifact;
|
|
114
|
+
obligation.currentArtifact = (0, session_events_1.capStructuredRecordString)(update.currentArtifact);
|
|
114
115
|
}
|
|
115
116
|
if (typeof update.nextAction === "string") {
|
|
116
|
-
obligation.nextAction = update.nextAction;
|
|
117
|
+
obligation.nextAction = (0, session_events_1.capStructuredRecordString)(update.nextAction);
|
|
117
118
|
}
|
|
118
119
|
if (typeof update.latestNote === "string") {
|
|
119
|
-
obligation.latestNote = update.latestNote;
|
|
120
|
+
obligation.latestNote = (0, session_events_1.capStructuredRecordString)(update.latestNote);
|
|
120
121
|
}
|
|
121
122
|
obligation.updatedAt = new Date().toISOString();
|
|
122
123
|
(0, json_store_1.writeJsonFile)(dir, obligationId, obligation);
|
|
@@ -165,7 +166,14 @@ function enrichObligation(agentRoot, id, meaning) {
|
|
|
165
166
|
throw new Error(`Obligation not found: ${id}`);
|
|
166
167
|
}
|
|
167
168
|
const obligation = existing;
|
|
168
|
-
obligation.meaning =
|
|
169
|
+
obligation.meaning = {
|
|
170
|
+
...meaning,
|
|
171
|
+
...(typeof meaning.careReason === "string" ? { careReason: (0, session_events_1.capStructuredRecordString)(meaning.careReason) } : {}),
|
|
172
|
+
...(typeof meaning.resumeHint === "string" ? { resumeHint: (0, session_events_1.capStructuredRecordString)(meaning.resumeHint) } : {}),
|
|
173
|
+
...(meaning.waitingOn
|
|
174
|
+
? { waitingOn: { ...meaning.waitingOn, detail: (0, session_events_1.capStructuredRecordString)(meaning.waitingOn.detail) } }
|
|
175
|
+
: {}),
|
|
176
|
+
};
|
|
169
177
|
obligation.updatedAt = new Date().toISOString();
|
|
170
178
|
(0, json_store_1.writeJsonFile)(dir, id, obligation);
|
|
171
179
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -188,7 +196,11 @@ function getReturnObligationsDir(agentName) {
|
|
|
188
196
|
}
|
|
189
197
|
function createReturnObligation(agentName, obligation) {
|
|
190
198
|
const dir = getReturnObligationsDir(agentName);
|
|
191
|
-
|
|
199
|
+
const cappedObligation = {
|
|
200
|
+
...obligation,
|
|
201
|
+
delegatedContent: (0, session_events_1.capStructuredRecordString)(obligation.delegatedContent),
|
|
202
|
+
};
|
|
203
|
+
(0, json_store_1.writeJsonFile)(dir, obligation.id, cappedObligation);
|
|
192
204
|
const filePath = path.join(dir, `${obligation.id}.json`);
|
|
193
205
|
(0, runtime_1.emitNervesEvent)({
|
|
194
206
|
event: "mind.obligation_created",
|
package/dist/arc/packets.js
CHANGED
|
@@ -41,6 +41,7 @@ exports.revisePonderPacket = revisePonderPacket;
|
|
|
41
41
|
exports.advancePonderPacket = advancePonderPacket;
|
|
42
42
|
exports.findHarnessFrictionPacket = findHarnessFrictionPacket;
|
|
43
43
|
const path = __importStar(require("path"));
|
|
44
|
+
const session_events_1 = require("../heart/session-events");
|
|
44
45
|
const runtime_1 = require("../nerves/runtime");
|
|
45
46
|
const task_lifecycle_1 = require("./task-lifecycle");
|
|
46
47
|
const json_store_1 = require("./json-store");
|
|
@@ -92,14 +93,14 @@ function createPonderPacket(agentRoot, input) {
|
|
|
92
93
|
kind: input.kind,
|
|
93
94
|
sop: packetSop(input.kind),
|
|
94
95
|
status: "drafting",
|
|
95
|
-
objective: input.objective,
|
|
96
|
-
summary: input.summary,
|
|
97
|
-
successCriteria: input.successCriteria,
|
|
96
|
+
objective: (0, session_events_1.capStructuredRecordString)(input.objective),
|
|
97
|
+
summary: (0, session_events_1.capStructuredRecordString)(input.summary),
|
|
98
|
+
successCriteria: (0, session_events_1.capStructuredRecordStringArray)(input.successCriteria),
|
|
98
99
|
...(input.origin ? { origin: input.origin } : {}),
|
|
99
100
|
...(input.relatedObligationId ? { relatedObligationId: input.relatedObligationId } : {}),
|
|
100
101
|
...(input.relatedReturnObligationId ? { relatedReturnObligationId: input.relatedReturnObligationId } : {}),
|
|
101
102
|
...(input.followsPacketId ? { followsPacketId: input.followsPacketId } : {}),
|
|
102
|
-
payload: input.payload,
|
|
103
|
+
payload: (0, session_events_1.capStructuredRecordStringLeaves)(input.payload),
|
|
103
104
|
createdAt: now,
|
|
104
105
|
updatedAt: now,
|
|
105
106
|
};
|
|
@@ -124,10 +125,10 @@ function revisePonderPacket(agentRoot, packetId, input) {
|
|
|
124
125
|
...existing,
|
|
125
126
|
kind: input.kind,
|
|
126
127
|
sop: packetSop(input.kind),
|
|
127
|
-
objective: input.objective,
|
|
128
|
-
summary: input.summary,
|
|
129
|
-
successCriteria: input.successCriteria,
|
|
130
|
-
payload: input.payload,
|
|
128
|
+
objective: (0, session_events_1.capStructuredRecordString)(input.objective),
|
|
129
|
+
summary: (0, session_events_1.capStructuredRecordString)(input.summary),
|
|
130
|
+
successCriteria: (0, session_events_1.capStructuredRecordStringArray)(input.successCriteria),
|
|
131
|
+
payload: (0, session_events_1.capStructuredRecordStringLeaves)(input.payload),
|
|
131
132
|
updatedAt: Date.now(),
|
|
132
133
|
};
|
|
133
134
|
(0, json_store_1.writeJsonFile)(packetsDir(agentRoot), packetId, revised);
|
|
@@ -39,6 +39,7 @@ exports.writeAwaitRuntimeState = writeAwaitRuntimeState;
|
|
|
39
39
|
exports.recordAwaitCheck = recordAwaitCheck;
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
41
|
const json_store_1 = require("../../arc/json-store");
|
|
42
|
+
const session_events_1 = require("../session-events");
|
|
42
43
|
const runtime_1 = require("../../nerves/runtime");
|
|
43
44
|
function awaitRuntimeStateDir(agentRoot) {
|
|
44
45
|
return path.join(agentRoot, "state", "awaits");
|
|
@@ -67,7 +68,9 @@ function writeAwaitRuntimeState(agentRoot, name, partial) {
|
|
|
67
68
|
const existing = readAwaitRuntimeState(agentRoot, name);
|
|
68
69
|
const merged = {
|
|
69
70
|
last_checked: partial.last_checked ?? existing?.last_checked ?? null,
|
|
70
|
-
last_observation: partial.last_observation
|
|
71
|
+
last_observation: partial.last_observation != null
|
|
72
|
+
? (0, session_events_1.capStructuredRecordString)(partial.last_observation)
|
|
73
|
+
: existing?.last_observation ?? null,
|
|
71
74
|
checked_count: partial.checked_count ?? existing?.checked_count ?? 0,
|
|
72
75
|
};
|
|
73
76
|
const record = {
|
|
@@ -38,6 +38,7 @@ exports.createBridgeStore = createBridgeStore;
|
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const identity_1 = require("../identity");
|
|
41
|
+
const session_events_1 = require("../session-events");
|
|
41
42
|
const runtime_1 = require("../../nerves/runtime");
|
|
42
43
|
function sessionIdentityMatches(session, candidate) {
|
|
43
44
|
return (session.friendId === candidate.friendId
|
|
@@ -58,7 +59,18 @@ function createBridgeStore(options = {}) {
|
|
|
58
59
|
return {
|
|
59
60
|
save(bridge) {
|
|
60
61
|
ensureRoot();
|
|
61
|
-
|
|
62
|
+
const cappedBridge = {
|
|
63
|
+
...bridge,
|
|
64
|
+
objective: (0, session_events_1.capStructuredRecordString)(bridge.objective),
|
|
65
|
+
summary: (0, session_events_1.capStructuredRecordString)(bridge.summary),
|
|
66
|
+
attachedSessions: bridge.attachedSessions.map((session) => ({
|
|
67
|
+
...session,
|
|
68
|
+
snapshot: typeof session.snapshot === "string"
|
|
69
|
+
? (0, session_events_1.capStructuredRecordString)(session.snapshot)
|
|
70
|
+
: session.snapshot,
|
|
71
|
+
})),
|
|
72
|
+
};
|
|
73
|
+
fs.writeFileSync(bridgeFilePath(rootDir, bridge.id), JSON.stringify(cappedBridge, null, 2), "utf-8");
|
|
62
74
|
(0, runtime_1.emitNervesEvent)({
|
|
63
75
|
component: "engine",
|
|
64
76
|
event: "engine.bridge_store_save",
|
|
@@ -68,7 +80,7 @@ function createBridgeStore(options = {}) {
|
|
|
68
80
|
rootDir,
|
|
69
81
|
},
|
|
70
82
|
});
|
|
71
|
-
return
|
|
83
|
+
return cappedBridge;
|
|
72
84
|
},
|
|
73
85
|
get(id) {
|
|
74
86
|
const filePath = bridgeFilePath(rootDir, id);
|
|
@@ -449,6 +449,11 @@ function parseIncomingCommand(raw) {
|
|
|
449
449
|
}
|
|
450
450
|
return parsed;
|
|
451
451
|
}
|
|
452
|
+
function isValidSenseReviveCommand(command) {
|
|
453
|
+
return typeof command.agent === "string"
|
|
454
|
+
&& typeof command.sense === "string"
|
|
455
|
+
&& typeof command.reason === "string";
|
|
456
|
+
}
|
|
452
457
|
/**
|
|
453
458
|
* Handle agent.senseTurn command: runs a full agent turn via the daemon process.
|
|
454
459
|
* Dynamic import lazy-loads shared-turn. Hot-reload works because ouro dev
|
|
@@ -1114,6 +1119,48 @@ class OuroDaemon {
|
|
|
1114
1119
|
message: "log streaming available via ouro logs",
|
|
1115
1120
|
data: { logDir: "~/AgentBundles/<agent>.ouro/state/daemon/logs" },
|
|
1116
1121
|
};
|
|
1122
|
+
case "daemon.sense_revive": {
|
|
1123
|
+
if (!isValidSenseReviveCommand(command)) {
|
|
1124
|
+
return {
|
|
1125
|
+
ok: false,
|
|
1126
|
+
error: "Invalid daemon.sense_revive payload: expected string fields 'agent', 'sense', and 'reason'.",
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
const revivedSenseRow = await this.senseManager?.reviveSense?.(command.agent, command.sense);
|
|
1130
|
+
if (revivedSenseRow) {
|
|
1131
|
+
return {
|
|
1132
|
+
ok: true,
|
|
1133
|
+
message: `revived ${command.agent}/${command.sense}`,
|
|
1134
|
+
data: revivedSenseRow,
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
const managedSenseSnapshots = this.processManager.listAgentSnapshots()
|
|
1138
|
+
.filter((snapshot) => snapshot.name.startsWith(`${command.agent}:`));
|
|
1139
|
+
if (managedSenseSnapshots.length === 0) {
|
|
1140
|
+
return {
|
|
1141
|
+
ok: false,
|
|
1142
|
+
error: `No managed agent '${command.agent}' is registered with daemon-managed senses.`,
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
const exactTargetName = `${command.agent}:${command.sense}`;
|
|
1146
|
+
const target = managedSenseSnapshots.find((snapshot) => snapshot.name === exactTargetName)
|
|
1147
|
+
?? managedSenseSnapshots.find((snapshot) => snapshot.channel === command.sense);
|
|
1148
|
+
if (!target) {
|
|
1149
|
+
return {
|
|
1150
|
+
ok: false,
|
|
1151
|
+
error: `No managed sense '${command.sense}' is registered for agent '${command.agent}'.`,
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
this.processManager.resetAgentFailureState(target.name);
|
|
1155
|
+
await this.processManager.startAgent(target.name);
|
|
1156
|
+
const freshSnapshot = this.processManager.listAgentSnapshots()
|
|
1157
|
+
.find((snapshot) => snapshot.name === target.name) ?? target;
|
|
1158
|
+
return {
|
|
1159
|
+
ok: true,
|
|
1160
|
+
message: `revived ${command.agent}/${command.sense}`,
|
|
1161
|
+
data: freshSnapshot,
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1117
1164
|
case "agent.start":
|
|
1118
1165
|
await this.processManager.startAgent(command.agent);
|
|
1119
1166
|
return { ok: true, message: `started ${command.agent}` };
|
|
@@ -502,6 +502,19 @@ class DaemonProcessManager {
|
|
|
502
502
|
await this.stopAgent(state.config.name);
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
|
+
resetAgentFailureState(agent) {
|
|
506
|
+
const state = this.requireAgent(agent);
|
|
507
|
+
this.clearRestartTimer(state);
|
|
508
|
+
this.clearCooldownTimer(state);
|
|
509
|
+
state.cooldownRetryCount = 0;
|
|
510
|
+
state.crashTimestamps = [];
|
|
511
|
+
state.fastCrashCount = 0;
|
|
512
|
+
state.respawnLoopTripped = false;
|
|
513
|
+
state.orchestratedRestartTimestamps = [];
|
|
514
|
+
state.snapshot.errorReason = null;
|
|
515
|
+
state.snapshot.fixHint = null;
|
|
516
|
+
this.notifySnapshotChange(state.snapshot);
|
|
517
|
+
}
|
|
505
518
|
sendToAgent(agent, message) {
|
|
506
519
|
const state = this.requireAgent(agent);
|
|
507
520
|
if (!state.process)
|
|
@@ -667,6 +667,18 @@ class DaemonSenseManager {
|
|
|
667
667
|
}
|
|
668
668
|
await this.processManager.startAgent?.(managedName);
|
|
669
669
|
}
|
|
670
|
+
async reviveSense(agent, sense) {
|
|
671
|
+
const parsed = parseSenseSnapshotName(`${agent}:${sense}`);
|
|
672
|
+
if (!parsed)
|
|
673
|
+
return null;
|
|
674
|
+
const context = this.contexts.get(parsed.agent);
|
|
675
|
+
if (!context || !context.senses[parsed.sense].enabled)
|
|
676
|
+
return null;
|
|
677
|
+
const managedName = `${parsed.agent}:${parsed.sense}`;
|
|
678
|
+
this.processManager.resetAgentFailureState?.(managedName);
|
|
679
|
+
await this.processManager.startAgent?.(managedName);
|
|
680
|
+
return this.listSenseRows().find((row) => row.agent === parsed.agent && row.sense === parsed.sense) ?? null;
|
|
681
|
+
}
|
|
670
682
|
listSenseRows() {
|
|
671
683
|
const runtime = new Map();
|
|
672
684
|
for (const snapshot of this.processManager.listAgentSnapshots()) {
|
|
@@ -53,6 +53,7 @@ const daemon_health_1 = require("../../daemon/daemon-health");
|
|
|
53
53
|
const shared_1 = require("./shared");
|
|
54
54
|
const agent_machine_1 = require("./agent-machine");
|
|
55
55
|
const sessions_1 = require("./sessions");
|
|
56
|
+
const NOTES_VIEW_LIMIT = 20;
|
|
56
57
|
/* v8 ignore start — defensive parsing of on-disk JSON, fallback branches are safety nets */
|
|
57
58
|
function readCodingDeep(agentRoot) {
|
|
58
59
|
const stateFilePath = path.join(agentRoot, "state", "coding", "sessions.json");
|
|
@@ -376,13 +377,117 @@ function readNotesView(agentRoot) {
|
|
|
376
377
|
// no journal index
|
|
377
378
|
}
|
|
378
379
|
journalEntries.sort((a, b) => b.mtime - a.mtime);
|
|
380
|
+
const canonicalNotes = readCanonicalNotes(agentRoot);
|
|
379
381
|
return {
|
|
380
382
|
diaryEntryCount: diaryEntries.length,
|
|
381
|
-
recentDiaryEntries: diaryEntries.slice(0,
|
|
383
|
+
recentDiaryEntries: diaryEntries.slice(0, NOTES_VIEW_LIMIT),
|
|
382
384
|
journalEntryCount: journalEntries.length,
|
|
383
|
-
recentJournalEntries: journalEntries.slice(0,
|
|
385
|
+
recentJournalEntries: journalEntries.slice(0, NOTES_VIEW_LIMIT),
|
|
386
|
+
canonicalNoteCount: canonicalNotes.length,
|
|
387
|
+
recentCanonicalNotes: canonicalNotes.slice(0, NOTES_VIEW_LIMIT),
|
|
384
388
|
};
|
|
385
389
|
}
|
|
390
|
+
function readCanonicalNotes(agentRoot) {
|
|
391
|
+
const notesRoot = path.join(agentRoot, "notes");
|
|
392
|
+
const notes = [];
|
|
393
|
+
for (const filename of (0, shared_1.safeReaddir)(notesRoot)) {
|
|
394
|
+
if (!filename.endsWith(".md"))
|
|
395
|
+
continue;
|
|
396
|
+
const filePath = path.join(notesRoot, filename);
|
|
397
|
+
if ((0, shared_1.safeIsDirectory)(filePath))
|
|
398
|
+
continue;
|
|
399
|
+
try {
|
|
400
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
401
|
+
const { frontmatter, body } = parseMarkdownFrontmatter(raw);
|
|
402
|
+
const writtenAt = safeCanonicalNoteTimestamp(frontmatter.created_at, filePath);
|
|
403
|
+
notes.push({
|
|
404
|
+
filename,
|
|
405
|
+
title: firstMarkdownHeading(body) ?? titleFromFilename(filename),
|
|
406
|
+
tags: Array.isArray(frontmatter.tags) ? frontmatter.tags : [],
|
|
407
|
+
preview: body.slice(0, 200),
|
|
408
|
+
writtenAt,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
// skip unreadable notes
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
notes.sort((a, b) => b.writtenAt.localeCompare(a.writtenAt) || b.filename.localeCompare(a.filename));
|
|
416
|
+
return notes;
|
|
417
|
+
}
|
|
418
|
+
function safeCanonicalNoteTimestamp(value, filePath) {
|
|
419
|
+
const fallback = (0, shared_1.safeFileMtime)(filePath);
|
|
420
|
+
if (typeof value !== "string")
|
|
421
|
+
return fallback;
|
|
422
|
+
const trimmed = value.trim();
|
|
423
|
+
if (!trimmed)
|
|
424
|
+
return fallback;
|
|
425
|
+
return Number.isNaN(new Date(trimmed).getTime()) ? fallback : trimmed;
|
|
426
|
+
}
|
|
427
|
+
function parseMarkdownFrontmatter(raw) {
|
|
428
|
+
const lines = raw.split(/\r?\n/);
|
|
429
|
+
if (lines[0] !== "---")
|
|
430
|
+
return { frontmatter: {}, body: raw };
|
|
431
|
+
const endIndex = lines.findIndex((line, index) => index > 0 && line === "---");
|
|
432
|
+
if (endIndex === -1)
|
|
433
|
+
return { frontmatter: {}, body: raw };
|
|
434
|
+
return {
|
|
435
|
+
frontmatter: parseMinimalFrontmatter(lines.slice(1, endIndex)),
|
|
436
|
+
body: lines.slice(endIndex + 1).join("\n").replace(/^\n/, ""),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function parseMinimalFrontmatter(lines) {
|
|
440
|
+
const frontmatter = {};
|
|
441
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
442
|
+
const line = lines[index];
|
|
443
|
+
const match = line?.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
444
|
+
if (!match)
|
|
445
|
+
continue;
|
|
446
|
+
const key = match[1];
|
|
447
|
+
const rawValue = match[2];
|
|
448
|
+
if (key === "tags") {
|
|
449
|
+
frontmatter.tags = parseFrontmatterTags(rawValue, lines, index + 1);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
frontmatter[key] = rawValue.trim();
|
|
453
|
+
}
|
|
454
|
+
return frontmatter;
|
|
455
|
+
}
|
|
456
|
+
function parseFrontmatterTags(rawValue, lines, startIndex) {
|
|
457
|
+
const trimmed = rawValue.trim();
|
|
458
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
459
|
+
try {
|
|
460
|
+
const parsed = JSON.parse(trimmed);
|
|
461
|
+
return parsed.filter((item) => typeof item === "string");
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
return trimmed.slice(1, -1).split(",").map((tag) => tag.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (trimmed.length > 0)
|
|
468
|
+
return [trimmed];
|
|
469
|
+
const tags = [];
|
|
470
|
+
for (let index = startIndex; index < lines.length; index += 1) {
|
|
471
|
+
const itemMatch = lines[index]?.match(/^\s*-\s*(.+)$/);
|
|
472
|
+
if (!itemMatch)
|
|
473
|
+
break;
|
|
474
|
+
const tag = itemMatch[1].trim().replace(/^['"]|['"]$/g, "");
|
|
475
|
+
if (tag)
|
|
476
|
+
tags.push(tag);
|
|
477
|
+
}
|
|
478
|
+
return tags;
|
|
479
|
+
}
|
|
480
|
+
function firstMarkdownHeading(body) {
|
|
481
|
+
const heading = body
|
|
482
|
+
.split(/\r?\n/)
|
|
483
|
+
.map((line) => line.match(/^#\s+(.+)$/)?.[1]?.trim())
|
|
484
|
+
.find((title) => title && title.length > 0);
|
|
485
|
+
return heading ?? null;
|
|
486
|
+
}
|
|
487
|
+
function titleFromFilename(filename) {
|
|
488
|
+
const stem = filename.replace(/\.md$/i, "").replace(/^\d{4}-\d{2}-\d{2}-/, "");
|
|
489
|
+
return stem.replace(/[-_]+/g, " ").trim() || filename;
|
|
490
|
+
}
|
|
386
491
|
function readFriendView(agentName, options = {}) {
|
|
387
492
|
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
388
493
|
const agentRoot = path.join(bundlesRoot, `${agentName}.ouro`);
|
|
@@ -213,8 +213,7 @@ function readSessionTranscript(agentName, friendId, channel, key, options = {})
|
|
|
213
213
|
const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
|
|
214
214
|
if (!envelope)
|
|
215
215
|
return null;
|
|
216
|
-
|
|
217
|
-
const rawMessages = (0, session_events_1.loadFullEventHistory)(sessionPath);
|
|
216
|
+
const rawMessages = envelope.events;
|
|
218
217
|
const friendsDir = path.join(agentRoot, "friends");
|
|
219
218
|
const friendName = (0, shared_1.resolveFriendName)(friendsDir, friendId);
|
|
220
219
|
const messages = rawMessages;
|
|
@@ -225,6 +224,7 @@ function readSessionTranscript(agentName, friendId, channel, key, options = {})
|
|
|
225
224
|
key,
|
|
226
225
|
sessionPath,
|
|
227
226
|
messageCount: messages.length,
|
|
227
|
+
truncatedHistory: envelope.projection.trimmed,
|
|
228
228
|
lastUsage: parseSessionUsage(envelope.lastUsage),
|
|
229
229
|
continuity: parseSessionContinuity(envelope.state),
|
|
230
230
|
messages,
|