@ouro.bot/cli 0.1.0-alpha.143 → 0.1.0-alpha.146
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 +21 -8
- package/dist/heart/daemon/agent-service.js +207 -314
- package/dist/heart/daemon/daemon-cli.js +245 -5
- package/dist/heart/daemon/heartbeat-timer.js +3 -2
- package/dist/heart/daemon/mcp-server.js +128 -1
- package/dist/heart/daemon/ouro-path-installer.js +11 -0
- package/dist/heart/daemon/process-manager.js +11 -0
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/target-resolution.js +4 -0
- package/dist/mind/friends/channel.js +9 -0
- package/dist/mind/prompt.js +4 -0
- package/dist/repertoire/coding/spawner.js +8 -9
- package/dist/repertoire/tools-base.js +11 -3
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/bluebubbles-client.js +48 -0
- package/dist/senses/bluebubbles.js +22 -6
- package/dist/senses/inner-dialog.js +15 -0
- package/dist/senses/pipeline.js +9 -0
- package/dist/senses/shared-turn.js +196 -0
- package/package.json +1 -1
- package/skills/configure-dev-tools.md +41 -69
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Agent service layer — handles MCP-facing daemon commands.
|
|
4
4
|
* Each handler receives { agent, friendId, ...params } and returns DaemonResponse.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* DRY: uses the same shared functions the agent's own tools use (diary, session-recall).
|
|
7
|
+
* This file is a thin adapter — no reimplemented search, parsing, or state reading.
|
|
7
8
|
*/
|
|
8
9
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
10
|
if (k2 === undefined) k2 = k;
|
|
@@ -55,413 +56,305 @@ exports.handleAgentReportComplete = handleAgentReportComplete;
|
|
|
55
56
|
const fs = __importStar(require("fs"));
|
|
56
57
|
const path = __importStar(require("path"));
|
|
57
58
|
const identity_1 = require("../identity");
|
|
59
|
+
const diary_1 = require("../../mind/diary");
|
|
58
60
|
const runtime_1 = require("../../nerves/runtime");
|
|
61
|
+
/** Format diary hits the same way the recall tool does. */
|
|
62
|
+
function formatDiaryHits(hits) {
|
|
63
|
+
return hits.map((f) => `[diary] ${f.text} (source=${f.source}, createdAt=${f.createdAt})`);
|
|
64
|
+
}
|
|
65
|
+
/** Read a file from the agent root, returning null if it doesn't exist. */
|
|
59
66
|
function readAgentFile(agent, ...segments) {
|
|
60
67
|
const filePath = path.join((0, identity_1.getAgentRoot)(agent), ...segments);
|
|
61
68
|
if (!fs.existsSync(filePath))
|
|
62
69
|
return null;
|
|
63
70
|
return fs.readFileSync(filePath, "utf-8");
|
|
64
71
|
}
|
|
65
|
-
/**
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
/** Resolve the diary root for a specific agent. */
|
|
73
|
+
function agentDiaryRoot(agent) {
|
|
74
|
+
return (0, diary_1.resolveDiaryRoot)(path.join((0, identity_1.getAgentRoot)(agent), "psyche", "memory"));
|
|
75
|
+
}
|
|
76
|
+
/** Read inner dialog runtime status. */
|
|
77
|
+
function readInnerDialogStatus(agent) {
|
|
78
|
+
const content = readAgentFile(agent, "state", "sessions", "self", "inner", "runtime.json");
|
|
79
|
+
if (!content)
|
|
80
|
+
return null;
|
|
81
|
+
try {
|
|
82
|
+
const data = JSON.parse(content);
|
|
83
|
+
return { status: data.status ?? "unknown", lastCompletedAt: data.lastCompletedAt ?? "" };
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function safeReaddir(dirPath) {
|
|
90
|
+
try {
|
|
91
|
+
return fs.readdirSync(dirPath).map(String);
|
|
92
|
+
/* v8 ignore start — catch is defensive; tested paths don't trigger fs errors */
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
/* v8 ignore stop */
|
|
98
|
+
}
|
|
99
|
+
function safeIsDir(dirPath) {
|
|
100
|
+
try {
|
|
101
|
+
return fs.statSync(dirPath).isDirectory();
|
|
102
|
+
/* v8 ignore start — catch is defensive; tested paths don't trigger fs errors */
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/* v8 ignore stop */
|
|
70
108
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
109
|
+
/** Enumerate sessions from state/sessions/, reading session.json files. */
|
|
110
|
+
function enumerateSessions(agent) {
|
|
111
|
+
const sessionsDir = path.join((0, identity_1.getAgentRoot)(agent), "state", "sessions");
|
|
112
|
+
if (!fs.existsSync(sessionsDir))
|
|
74
113
|
return [];
|
|
75
|
-
|
|
114
|
+
const sessions = [];
|
|
115
|
+
for (const friendId of safeReaddir(sessionsDir)) {
|
|
116
|
+
const friendPath = path.join(sessionsDir, friendId);
|
|
117
|
+
if (!safeIsDir(friendPath))
|
|
118
|
+
continue;
|
|
119
|
+
for (const channel of safeReaddir(friendPath)) {
|
|
120
|
+
const channelPath = path.join(friendPath, channel);
|
|
121
|
+
if (!safeIsDir(channelPath))
|
|
122
|
+
continue;
|
|
123
|
+
for (const key of safeReaddir(channelPath)) {
|
|
124
|
+
const sessionFile = path.join(channelPath, key, "session.json");
|
|
125
|
+
if (!fs.existsSync(sessionFile))
|
|
126
|
+
continue;
|
|
127
|
+
try {
|
|
128
|
+
const data = JSON.parse(fs.readFileSync(sessionFile, "utf-8"));
|
|
129
|
+
sessions.push({ friendId, channel, key, lastUsage: data.lastUsage ?? "" });
|
|
130
|
+
}
|
|
131
|
+
catch { /* skip malformed */ }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return sessions;
|
|
76
136
|
}
|
|
137
|
+
/** List markdown files in {agentRoot}/tasks/. */
|
|
138
|
+
function listTaskFiles(agent) {
|
|
139
|
+
const tasksDir = path.join((0, identity_1.getAgentRoot)(agent), "tasks");
|
|
140
|
+
if (!fs.existsSync(tasksDir))
|
|
141
|
+
return [];
|
|
142
|
+
try {
|
|
143
|
+
return fs.readdirSync(tasksDir).map(String).filter((f) => f.endsWith(".md"));
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function emit(event, message, meta) {
|
|
150
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event, message, meta });
|
|
151
|
+
}
|
|
152
|
+
// ─── Handlers ────────────────────────────────────────────────────────────────
|
|
77
153
|
async function handleAgentStatus(params) {
|
|
78
|
-
(0, runtime_1.emitNervesEvent)({
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
});
|
|
84
|
-
const sessionFiles = listStateFiles(params.agent, "sessions");
|
|
85
|
-
const memoryContent = readAgentMemory(params.agent);
|
|
86
|
-
(0, runtime_1.emitNervesEvent)({
|
|
87
|
-
component: "daemon",
|
|
88
|
-
event: "daemon.agent_service_end",
|
|
89
|
-
message: "completed agent.status",
|
|
90
|
-
meta: { agent: params.agent },
|
|
91
|
-
});
|
|
154
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.agent_service_start", message: "handling agent.status", meta: { agent: params.agent } });
|
|
155
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
156
|
+
const facts = (0, diary_1.readDiaryEntries)(diaryRoot);
|
|
157
|
+
const innerStatus = readInnerDialogStatus(params.agent);
|
|
158
|
+
const sessions = enumerateSessions(params.agent);
|
|
159
|
+
emit("daemon.agent_service_end", "completed agent.status", { agent: params.agent });
|
|
92
160
|
return {
|
|
93
161
|
ok: true,
|
|
94
162
|
message: `Agent ${params.agent} status`,
|
|
95
163
|
data: {
|
|
96
164
|
agent: params.agent,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
165
|
+
innerStatus: innerStatus?.status ?? "unknown",
|
|
166
|
+
lastThoughtAt: innerStatus?.lastCompletedAt ?? null,
|
|
167
|
+
sessionCount: sessions.length,
|
|
168
|
+
hasMemory: facts.length > 0,
|
|
169
|
+
factCount: facts.length,
|
|
100
170
|
},
|
|
101
171
|
};
|
|
102
172
|
}
|
|
103
173
|
async function handleAgentAsk(params) {
|
|
104
|
-
(
|
|
105
|
-
component: "daemon",
|
|
106
|
-
event: "daemon.agent_service_start",
|
|
107
|
-
message: "handling agent.ask",
|
|
108
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
109
|
-
});
|
|
174
|
+
emit("daemon.agent_service_start", "handling agent.ask", { agent: params.agent });
|
|
110
175
|
const question = params.question;
|
|
111
176
|
if (!question) {
|
|
112
|
-
(
|
|
113
|
-
level: "error",
|
|
114
|
-
component: "daemon",
|
|
115
|
-
event: "daemon.agent_service_error",
|
|
116
|
-
message: "agent.ask missing question parameter",
|
|
117
|
-
meta: { agent: params.agent },
|
|
118
|
-
});
|
|
177
|
+
emit("daemon.agent_service_error", "agent.ask missing question", { agent: params.agent });
|
|
119
178
|
return { ok: false, error: "Missing required parameter: question" };
|
|
120
179
|
}
|
|
121
|
-
//
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
event: "daemon.agent_service_end",
|
|
129
|
-
message: "completed agent.ask",
|
|
130
|
-
meta: { agent: params.agent },
|
|
131
|
-
});
|
|
180
|
+
// Use the same searchDiaryEntries the recall tool uses (substring fallback — no embedding provider in shim)
|
|
181
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
182
|
+
const hits = await (0, diary_1.searchDiaryEntries)(question, (0, diary_1.readDiaryEntries)(diaryRoot));
|
|
183
|
+
const context = hits.length > 0
|
|
184
|
+
? hits.slice(0, 10).map((f) => f.text).join("\n")
|
|
185
|
+
: `No relevant memories found for: ${question}`;
|
|
186
|
+
emit("daemon.agent_service_end", "completed agent.ask", { agent: params.agent });
|
|
132
187
|
return { ok: true, message: context };
|
|
133
188
|
}
|
|
134
189
|
async function handleAgentCatchup(params) {
|
|
135
|
-
(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
190
|
+
emit("daemon.agent_service_start", "handling agent.catchup", { agent: params.agent });
|
|
191
|
+
const sessions = enumerateSessions(params.agent);
|
|
192
|
+
const sorted = sessions.sort((a, b) => (b.lastUsage || "").localeCompare(a.lastUsage || ""));
|
|
193
|
+
const recentSessions = sorted.slice(0, 5);
|
|
194
|
+
const innerStatus = readInnerDialogStatus(params.agent);
|
|
195
|
+
const parts = [];
|
|
196
|
+
if (innerStatus) {
|
|
197
|
+
parts.push(`Inner dialog: ${innerStatus.status} (last completed: ${innerStatus.lastCompletedAt || "never"})`);
|
|
198
|
+
}
|
|
199
|
+
if (recentSessions.length > 0) {
|
|
200
|
+
parts.push(`Recent sessions (${recentSessions.length}):`);
|
|
201
|
+
for (const s of recentSessions) {
|
|
202
|
+
parts.push(` - ${s.friendId}/${s.channel}/${s.key} (${s.lastUsage || "unknown"})`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
parts.push("No recent sessions");
|
|
207
|
+
}
|
|
208
|
+
emit("daemon.agent_service_end", "completed agent.catchup", { agent: params.agent });
|
|
149
209
|
return {
|
|
150
210
|
ok: true,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
data: { recentSessions },
|
|
211
|
+
/* v8 ignore next — parts always has at least one element (either sessions or "No recent sessions") */
|
|
212
|
+
message: parts.length > 0 ? parts.join("\n") : `No recent activity for ${params.agent}`,
|
|
213
|
+
data: { recentSessions, innerStatus },
|
|
155
214
|
};
|
|
156
215
|
}
|
|
157
216
|
async function handleAgentDelegate(params) {
|
|
158
|
-
(
|
|
159
|
-
component: "daemon",
|
|
160
|
-
event: "daemon.agent_service_start",
|
|
161
|
-
message: "handling agent.delegate",
|
|
162
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
163
|
-
});
|
|
217
|
+
emit("daemon.agent_service_start", "handling agent.delegate", { agent: params.agent });
|
|
164
218
|
const task = params.task;
|
|
165
219
|
if (!task) {
|
|
166
|
-
(
|
|
167
|
-
level: "error",
|
|
168
|
-
component: "daemon",
|
|
169
|
-
event: "daemon.agent_service_error",
|
|
170
|
-
message: "agent.delegate missing task parameter",
|
|
171
|
-
meta: { agent: params.agent },
|
|
172
|
-
});
|
|
220
|
+
emit("daemon.agent_service_error", "agent.delegate missing task", { agent: params.agent });
|
|
173
221
|
return { ok: false, error: "Missing required parameter: task" };
|
|
174
222
|
}
|
|
175
|
-
(
|
|
176
|
-
|
|
177
|
-
event: "daemon.agent_service_end",
|
|
178
|
-
message: "completed agent.delegate",
|
|
179
|
-
meta: { agent: params.agent },
|
|
180
|
-
});
|
|
181
|
-
return {
|
|
182
|
-
ok: true,
|
|
183
|
-
message: `Task queued for delegate to ${params.agent}: ${task}`,
|
|
184
|
-
data: { task, context: params.context ?? null, queuedAt: new Date().toISOString() },
|
|
185
|
-
};
|
|
223
|
+
emit("daemon.agent_service_end", "completed agent.delegate", { agent: params.agent });
|
|
224
|
+
return { ok: true, message: `Task queued: ${task}`, data: { task, context: params.context ?? null, queuedAt: new Date().toISOString() } };
|
|
186
225
|
}
|
|
187
226
|
async function handleAgentGetContext(params) {
|
|
188
|
-
(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
227
|
+
emit("daemon.agent_service_start", "handling agent.getContext", { agent: params.agent });
|
|
228
|
+
const query = (params.question ?? params.query ?? params.topic);
|
|
229
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
230
|
+
const facts = (0, diary_1.readDiaryEntries)(diaryRoot);
|
|
231
|
+
const innerStatus = readInnerDialogStatus(params.agent);
|
|
232
|
+
const sessions = enumerateSessions(params.agent);
|
|
233
|
+
const taskFiles = listTaskFiles(params.agent);
|
|
234
|
+
let memorySummary = null;
|
|
235
|
+
if (query) {
|
|
236
|
+
const hits = await (0, diary_1.searchDiaryEntries)(query, facts);
|
|
237
|
+
memorySummary = hits.length > 0
|
|
238
|
+
? hits.slice(0, 10).map((f) => f.text).join("\n")
|
|
239
|
+
: `No relevant memories for: ${query}`;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const recent = facts.slice(-10);
|
|
243
|
+
if (recent.length > 0)
|
|
244
|
+
memorySummary = recent.map((f) => f.text).join("\n");
|
|
245
|
+
}
|
|
246
|
+
emit("daemon.agent_service_end", "completed agent.getContext", { agent: params.agent });
|
|
202
247
|
return {
|
|
203
248
|
ok: true,
|
|
204
249
|
data: {
|
|
205
250
|
agent: params.agent,
|
|
206
|
-
hasMemory:
|
|
207
|
-
|
|
251
|
+
hasMemory: facts.length > 0,
|
|
252
|
+
factCount: facts.length,
|
|
253
|
+
memorySummary,
|
|
208
254
|
taskCount: taskFiles.length,
|
|
255
|
+
sessionCount: sessions.length,
|
|
256
|
+
innerStatus: innerStatus?.status ?? null,
|
|
209
257
|
},
|
|
210
258
|
};
|
|
211
259
|
}
|
|
212
260
|
async function handleAgentSearchMemory(params) {
|
|
213
|
-
(
|
|
214
|
-
component: "daemon",
|
|
215
|
-
event: "daemon.agent_service_start",
|
|
216
|
-
message: "handling agent.searchMemory",
|
|
217
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
218
|
-
});
|
|
261
|
+
emit("daemon.agent_service_start", "handling agent.searchMemory", { agent: params.agent });
|
|
219
262
|
const query = params.query;
|
|
220
263
|
if (!query) {
|
|
221
|
-
(
|
|
222
|
-
level: "error",
|
|
223
|
-
component: "daemon",
|
|
224
|
-
event: "daemon.agent_service_error",
|
|
225
|
-
message: "agent.searchMemory missing query parameter",
|
|
226
|
-
meta: { agent: params.agent },
|
|
227
|
-
});
|
|
264
|
+
emit("daemon.agent_service_error", "agent.searchMemory missing query", { agent: params.agent });
|
|
228
265
|
return { ok: false, error: "Missing required parameter: query" };
|
|
229
266
|
}
|
|
230
|
-
//
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const queryLower = query.toLowerCase();
|
|
236
|
-
for (const line of lines) {
|
|
237
|
-
if (line.toLowerCase().includes(queryLower)) {
|
|
238
|
-
matches.push(line.trim());
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
(0, runtime_1.emitNervesEvent)({
|
|
243
|
-
component: "daemon",
|
|
244
|
-
event: "daemon.agent_service_end",
|
|
245
|
-
message: "completed agent.searchMemory",
|
|
246
|
-
meta: { agent: params.agent, matchCount: matches.length },
|
|
247
|
-
});
|
|
267
|
+
// Same searchDiaryEntries as the recall tool
|
|
268
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
269
|
+
const hits = await (0, diary_1.searchDiaryEntries)(query, (0, diary_1.readDiaryEntries)(diaryRoot));
|
|
270
|
+
const formatted = formatDiaryHits(hits.slice(0, 20));
|
|
271
|
+
emit("daemon.agent_service_end", "completed agent.searchMemory", { agent: params.agent, matchCount: hits.length });
|
|
248
272
|
return {
|
|
249
273
|
ok: true,
|
|
250
|
-
message:
|
|
251
|
-
data: { query, matches:
|
|
274
|
+
message: hits.length > 0 ? `Found ${hits.length} matches` : "No matches found",
|
|
275
|
+
data: { query, matches: formatted },
|
|
252
276
|
};
|
|
253
277
|
}
|
|
254
278
|
async function handleAgentGetTask(params) {
|
|
255
|
-
(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
component: "daemon",
|
|
264
|
-
event: "daemon.agent_service_end",
|
|
265
|
-
message: "completed agent.getTask",
|
|
266
|
-
meta: { agent: params.agent },
|
|
279
|
+
emit("daemon.agent_service_start", "handling agent.getTask", { agent: params.agent });
|
|
280
|
+
const taskFiles = listTaskFiles(params.agent);
|
|
281
|
+
const activeTasks = taskFiles.filter((f) => f.toLowerCase().includes("doing") && !f.toLowerCase().includes("done"));
|
|
282
|
+
const taskNames = activeTasks.length > 0 ? activeTasks : taskFiles;
|
|
283
|
+
const tasks = taskNames.map((name) => {
|
|
284
|
+
const content = readAgentFile(params.agent, "tasks", name);
|
|
285
|
+
const firstLine = content?.split("\n").find((l) => l.trim().length > 0)?.trim() ?? "";
|
|
286
|
+
return { name, statusLine: firstLine };
|
|
267
287
|
});
|
|
288
|
+
emit("daemon.agent_service_end", "completed agent.getTask", { agent: params.agent });
|
|
268
289
|
return {
|
|
269
290
|
ok: true,
|
|
270
|
-
message:
|
|
271
|
-
|
|
272
|
-
: `No active tasks for ${params.agent}`,
|
|
273
|
-
data: { tasks: taskFiles },
|
|
291
|
+
message: tasks.length > 0 ? `Tasks (${tasks.length}): ${tasks.map((t) => t.name).join(", ")}` : `No active tasks for ${params.agent}`,
|
|
292
|
+
data: { tasks, activeCount: activeTasks.length, totalCount: taskFiles.length },
|
|
274
293
|
};
|
|
275
294
|
}
|
|
276
295
|
async function handleAgentCheckScope(params) {
|
|
277
|
-
(
|
|
278
|
-
component: "daemon",
|
|
279
|
-
event: "daemon.agent_service_start",
|
|
280
|
-
message: "handling agent.checkScope",
|
|
281
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
282
|
-
});
|
|
296
|
+
emit("daemon.agent_service_start", "handling agent.checkScope", { agent: params.agent });
|
|
283
297
|
const item = params.item;
|
|
284
298
|
if (!item) {
|
|
285
|
-
(
|
|
286
|
-
level: "error",
|
|
287
|
-
component: "daemon",
|
|
288
|
-
event: "daemon.agent_service_error",
|
|
289
|
-
message: "agent.checkScope missing item parameter",
|
|
290
|
-
meta: { agent: params.agent },
|
|
291
|
-
});
|
|
299
|
+
emit("daemon.agent_service_error", "agent.checkScope missing item", { agent: params.agent });
|
|
292
300
|
return { ok: false, error: "Missing required parameter: item" };
|
|
293
301
|
}
|
|
294
|
-
(
|
|
295
|
-
|
|
296
|
-
event: "daemon.agent_service_end",
|
|
297
|
-
message: "completed agent.checkScope",
|
|
298
|
-
meta: { agent: params.agent },
|
|
299
|
-
});
|
|
300
|
-
return {
|
|
301
|
-
ok: true,
|
|
302
|
-
message: `Scope check for: ${item}`,
|
|
303
|
-
data: { item, inScope: true, reason: "MVP: scope check requires inference — defaulting to in-scope" },
|
|
304
|
-
};
|
|
302
|
+
emit("daemon.agent_service_end", "completed agent.checkScope", { agent: params.agent });
|
|
303
|
+
return { ok: true, message: `Scope check for: ${item}`, data: { item, inScope: true, reason: "MVP: scope check requires inference — defaulting to in-scope" } };
|
|
305
304
|
}
|
|
306
305
|
async function handleAgentRequestDecision(params) {
|
|
307
|
-
(
|
|
308
|
-
component: "daemon",
|
|
309
|
-
event: "daemon.agent_service_start",
|
|
310
|
-
message: "handling agent.requestDecision",
|
|
311
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
312
|
-
});
|
|
306
|
+
emit("daemon.agent_service_start", "handling agent.requestDecision", { agent: params.agent });
|
|
313
307
|
const topic = params.topic;
|
|
314
308
|
if (!topic) {
|
|
315
|
-
(
|
|
316
|
-
level: "error",
|
|
317
|
-
component: "daemon",
|
|
318
|
-
event: "daemon.agent_service_error",
|
|
319
|
-
message: "agent.requestDecision missing topic parameter",
|
|
320
|
-
meta: { agent: params.agent },
|
|
321
|
-
});
|
|
309
|
+
emit("daemon.agent_service_error", "agent.requestDecision missing topic", { agent: params.agent });
|
|
322
310
|
return { ok: false, error: "Missing required parameter: topic" };
|
|
323
311
|
}
|
|
324
|
-
(
|
|
325
|
-
|
|
326
|
-
event: "daemon.agent_service_end",
|
|
327
|
-
message: "completed agent.requestDecision",
|
|
328
|
-
meta: { agent: params.agent },
|
|
329
|
-
});
|
|
330
|
-
return {
|
|
331
|
-
ok: true,
|
|
332
|
-
message: `Decision request queued: ${topic}`,
|
|
333
|
-
data: {
|
|
334
|
-
topic,
|
|
335
|
-
options: params.options ?? null,
|
|
336
|
-
status: "pending",
|
|
337
|
-
note: "MVP: decision requires inference — queued for agent review",
|
|
338
|
-
},
|
|
339
|
-
};
|
|
312
|
+
emit("daemon.agent_service_end", "completed agent.requestDecision", { agent: params.agent });
|
|
313
|
+
return { ok: true, message: `Decision request queued: ${topic}`, data: { topic, options: params.options ?? null, status: "pending" } };
|
|
340
314
|
}
|
|
341
315
|
async function handleAgentCheckGuidance(params) {
|
|
342
|
-
(
|
|
343
|
-
component: "daemon",
|
|
344
|
-
event: "daemon.agent_service_start",
|
|
345
|
-
message: "handling agent.checkGuidance",
|
|
346
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
347
|
-
});
|
|
316
|
+
emit("daemon.agent_service_start", "handling agent.checkGuidance", { agent: params.agent });
|
|
348
317
|
const topic = params.topic;
|
|
349
318
|
if (!topic) {
|
|
350
|
-
(
|
|
351
|
-
level: "error",
|
|
352
|
-
component: "daemon",
|
|
353
|
-
event: "daemon.agent_service_error",
|
|
354
|
-
message: "agent.checkGuidance missing topic parameter",
|
|
355
|
-
meta: { agent: params.agent },
|
|
356
|
-
});
|
|
319
|
+
emit("daemon.agent_service_error", "agent.checkGuidance missing topic", { agent: params.agent });
|
|
357
320
|
return { ok: false, error: "Missing required parameter: topic" };
|
|
358
321
|
}
|
|
359
|
-
//
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (relevant.length > 0) {
|
|
367
|
-
guidance = `Relevant guidance:\n${relevant.slice(0, 10).join("\n")}`;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
(0, runtime_1.emitNervesEvent)({
|
|
371
|
-
component: "daemon",
|
|
372
|
-
event: "daemon.agent_service_end",
|
|
373
|
-
message: "completed agent.checkGuidance",
|
|
374
|
-
meta: { agent: params.agent },
|
|
375
|
-
});
|
|
322
|
+
// Same searchDiaryEntries as the recall tool
|
|
323
|
+
const diaryRoot = agentDiaryRoot(params.agent);
|
|
324
|
+
const hits = await (0, diary_1.searchDiaryEntries)(topic, (0, diary_1.readDiaryEntries)(diaryRoot));
|
|
325
|
+
const guidance = hits.length > 0
|
|
326
|
+
? `Relevant guidance:\n${hits.slice(0, 10).map((f) => f.text).join("\n")}`
|
|
327
|
+
: `No specific guidance found for: ${topic}`;
|
|
328
|
+
emit("daemon.agent_service_end", "completed agent.checkGuidance", { agent: params.agent });
|
|
376
329
|
return { ok: true, message: guidance };
|
|
377
330
|
}
|
|
378
331
|
async function handleAgentReportProgress(params) {
|
|
379
|
-
(
|
|
380
|
-
component: "daemon",
|
|
381
|
-
event: "daemon.agent_service_start",
|
|
382
|
-
message: "handling agent.reportProgress",
|
|
383
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
384
|
-
});
|
|
332
|
+
emit("daemon.agent_service_start", "handling agent.reportProgress", { agent: params.agent });
|
|
385
333
|
const summary = params.summary;
|
|
386
334
|
if (!summary) {
|
|
387
|
-
(
|
|
388
|
-
level: "error",
|
|
389
|
-
component: "daemon",
|
|
390
|
-
event: "daemon.agent_service_error",
|
|
391
|
-
message: "agent.reportProgress missing summary parameter",
|
|
392
|
-
meta: { agent: params.agent },
|
|
393
|
-
});
|
|
335
|
+
emit("daemon.agent_service_error", "agent.reportProgress missing summary", { agent: params.agent });
|
|
394
336
|
return { ok: false, error: "Missing required parameter: summary" };
|
|
395
337
|
}
|
|
396
|
-
(
|
|
397
|
-
|
|
398
|
-
event: "daemon.agent_service_end",
|
|
399
|
-
message: "completed agent.reportProgress",
|
|
400
|
-
meta: { agent: params.agent },
|
|
401
|
-
});
|
|
402
|
-
return {
|
|
403
|
-
ok: true,
|
|
404
|
-
message: `Progress noted: ${summary}`,
|
|
405
|
-
data: { summary, receivedAt: new Date().toISOString() },
|
|
406
|
-
};
|
|
338
|
+
emit("daemon.agent_service_end", "completed agent.reportProgress", { agent: params.agent });
|
|
339
|
+
return { ok: true, message: `Progress noted: ${summary}`, data: { summary, receivedAt: new Date().toISOString() } };
|
|
407
340
|
}
|
|
408
341
|
async function handleAgentReportBlocker(params) {
|
|
409
|
-
(
|
|
410
|
-
component: "daemon",
|
|
411
|
-
event: "daemon.agent_service_start",
|
|
412
|
-
message: "handling agent.reportBlocker",
|
|
413
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
414
|
-
});
|
|
342
|
+
emit("daemon.agent_service_start", "handling agent.reportBlocker", { agent: params.agent });
|
|
415
343
|
const blocker = params.blocker;
|
|
416
344
|
if (!blocker) {
|
|
417
|
-
(
|
|
418
|
-
level: "error",
|
|
419
|
-
component: "daemon",
|
|
420
|
-
event: "daemon.agent_service_error",
|
|
421
|
-
message: "agent.reportBlocker missing blocker parameter",
|
|
422
|
-
meta: { agent: params.agent },
|
|
423
|
-
});
|
|
345
|
+
emit("daemon.agent_service_error", "agent.reportBlocker missing blocker", { agent: params.agent });
|
|
424
346
|
return { ok: false, error: "Missing required parameter: blocker" };
|
|
425
347
|
}
|
|
426
|
-
(
|
|
427
|
-
|
|
428
|
-
event: "daemon.agent_service_end",
|
|
429
|
-
message: "completed agent.reportBlocker",
|
|
430
|
-
meta: { agent: params.agent },
|
|
431
|
-
});
|
|
432
|
-
return {
|
|
433
|
-
ok: true,
|
|
434
|
-
message: `Blocker reported: ${blocker}`,
|
|
435
|
-
data: { blocker, receivedAt: new Date().toISOString() },
|
|
436
|
-
};
|
|
348
|
+
emit("daemon.agent_service_end", "completed agent.reportBlocker", { agent: params.agent });
|
|
349
|
+
return { ok: true, message: `Blocker reported: ${blocker}`, data: { blocker, receivedAt: new Date().toISOString() } };
|
|
437
350
|
}
|
|
438
351
|
async function handleAgentReportComplete(params) {
|
|
439
|
-
(
|
|
440
|
-
component: "daemon",
|
|
441
|
-
event: "daemon.agent_service_start",
|
|
442
|
-
message: "handling agent.reportComplete",
|
|
443
|
-
meta: { agent: params.agent, friendId: params.friendId },
|
|
444
|
-
});
|
|
352
|
+
emit("daemon.agent_service_start", "handling agent.reportComplete", { agent: params.agent });
|
|
445
353
|
const summary = params.summary;
|
|
446
354
|
if (!summary) {
|
|
447
|
-
(
|
|
448
|
-
level: "error",
|
|
449
|
-
component: "daemon",
|
|
450
|
-
event: "daemon.agent_service_error",
|
|
451
|
-
message: "agent.reportComplete missing summary parameter",
|
|
452
|
-
meta: { agent: params.agent },
|
|
453
|
-
});
|
|
355
|
+
emit("daemon.agent_service_error", "agent.reportComplete missing summary", { agent: params.agent });
|
|
454
356
|
return { ok: false, error: "Missing required parameter: summary" };
|
|
455
357
|
}
|
|
456
|
-
(
|
|
457
|
-
|
|
458
|
-
event: "daemon.agent_service_end",
|
|
459
|
-
message: "completed agent.reportComplete",
|
|
460
|
-
meta: { agent: params.agent },
|
|
461
|
-
});
|
|
462
|
-
return {
|
|
463
|
-
ok: true,
|
|
464
|
-
message: `Completion reported: ${summary}`,
|
|
465
|
-
data: { summary, receivedAt: new Date().toISOString() },
|
|
466
|
-
};
|
|
358
|
+
emit("daemon.agent_service_end", "completed agent.reportComplete", { agent: params.agent });
|
|
359
|
+
return { ok: true, message: `Completion reported: ${summary}`, data: { summary, receivedAt: new Date().toISOString() } };
|
|
467
360
|
}
|