@ouro.bot/cli 0.1.0-alpha.14 → 0.1.0-alpha.141
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/AdoptionSpecialist.ouro/psyche/SOUL.md +2 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +151 -205
- package/changelog.json +913 -0
- package/dist/heart/active-work.js +633 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/commitments.js +105 -0
- package/dist/heart/config.js +66 -21
- package/dist/heart/core.js +645 -112
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/agent-service.js +467 -0
- package/dist/heart/daemon/auth-flow.js +457 -0
- package/dist/heart/daemon/daemon-cli.js +1840 -196
- package/dist/heart/daemon/daemon-entry.js +80 -3
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon.js +301 -1
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +15 -80
- package/dist/heart/daemon/heartbeat-timer.js +131 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/launchd.js +159 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/mcp-server.js +464 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-path-installer.js +67 -34
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/process-manager.js +13 -0
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +219 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/sense-manager.js +50 -2
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-orchestrator.js +2 -2
- package/dist/heart/daemon/specialist-prompt.js +10 -7
- package/dist/heart/daemon/specialist-tools.js +52 -3
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/daemon/update-checker.js +111 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/identity.js +64 -21
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +197 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +159 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +195 -34
- package/dist/heart/providers/azure.js +115 -9
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +49 -14
- package/dist/heart/session-activity.js +173 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/streaming.js +117 -33
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +122 -32
- package/dist/mind/bundle-manifest.js +14 -0
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +70 -56
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +35 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +19 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/obligations.js +134 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +554 -88
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/index.js +12 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/ado-semantic.js +6 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +254 -0
- package/dist/repertoire/coding/feedback.js +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +210 -4
- package/dist/repertoire/coding/spawner.js +59 -12
- package/dist/repertoire/coding/tools.js +176 -4
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/guardrails.js +290 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +198 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +12 -0
- package/dist/repertoire/tasks/index.js +23 -9
- package/dist/repertoire/tasks/transitions.js +1 -2
- package/dist/repertoire/tools-base.js +980 -271
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-teams.js +65 -59
- package/dist/repertoire/tools.js +266 -91
- package/dist/senses/attention-queue.js +97 -0
- package/dist/senses/bluebubbles-client.js +210 -5
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +12 -4
- package/dist/senses/bluebubbles-mutation-log.js +45 -5
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +944 -45
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +374 -131
- package/dist/senses/contextual-heartbeat.js +102 -0
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/debug-activity.js +154 -0
- package/dist/senses/inner-dialog-worker.js +47 -18
- package/dist/senses/inner-dialog.js +500 -84
- package/dist/senses/pipeline.js +454 -0
- package/dist/senses/surface-tool.js +82 -0
- package/dist/senses/teams.js +607 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +12 -4
- package/skills/configure-dev-tools.md +109 -0
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deliverCrossChatMessage = deliverCrossChatMessage;
|
|
4
|
+
const types_1 = require("../mind/friends/types");
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
function buildPendingEnvelope(request, agentName, now) {
|
|
7
|
+
return {
|
|
8
|
+
from: agentName,
|
|
9
|
+
friendId: request.friendId,
|
|
10
|
+
channel: request.channel,
|
|
11
|
+
key: request.key,
|
|
12
|
+
content: request.content,
|
|
13
|
+
timestamp: now,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function queueForLater(request, deps, detail) {
|
|
17
|
+
deps.queuePending(buildPendingEnvelope(request, deps.agentName, (deps.now ?? Date.now)()));
|
|
18
|
+
return {
|
|
19
|
+
status: "queued_for_later",
|
|
20
|
+
detail,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function isExplicitlyAuthorized(request) {
|
|
24
|
+
return request.intent === "explicit_cross_chat"
|
|
25
|
+
&& Boolean(request.authorizingSession)
|
|
26
|
+
&& (0, types_1.isTrustedLevel)(request.authorizingSession?.trustLevel);
|
|
27
|
+
}
|
|
28
|
+
async function deliverCrossChatMessage(request, deps) {
|
|
29
|
+
(0, runtime_1.emitNervesEvent)({
|
|
30
|
+
component: "engine",
|
|
31
|
+
event: "engine.cross_chat_delivery_start",
|
|
32
|
+
message: "resolving cross-chat delivery",
|
|
33
|
+
meta: {
|
|
34
|
+
friendId: request.friendId,
|
|
35
|
+
channel: request.channel,
|
|
36
|
+
key: request.key,
|
|
37
|
+
intent: request.intent,
|
|
38
|
+
authorizingTrustLevel: request.authorizingSession?.trustLevel ?? null,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (request.intent === "generic_outreach") {
|
|
42
|
+
const result = queueForLater(request, deps, "generic outreach stays queued until the target session is next active");
|
|
43
|
+
(0, runtime_1.emitNervesEvent)({
|
|
44
|
+
component: "engine",
|
|
45
|
+
event: "engine.cross_chat_delivery_end",
|
|
46
|
+
message: "queued generic outreach for later delivery",
|
|
47
|
+
meta: {
|
|
48
|
+
friendId: request.friendId,
|
|
49
|
+
channel: request.channel,
|
|
50
|
+
key: request.key,
|
|
51
|
+
status: result.status,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
if (!isExplicitlyAuthorized(request)) {
|
|
57
|
+
const result = {
|
|
58
|
+
status: "blocked",
|
|
59
|
+
detail: "explicit cross-chat delivery requires a trusted asking session",
|
|
60
|
+
};
|
|
61
|
+
(0, runtime_1.emitNervesEvent)({
|
|
62
|
+
level: "warn",
|
|
63
|
+
component: "engine",
|
|
64
|
+
event: "engine.cross_chat_delivery_end",
|
|
65
|
+
message: "blocked explicit cross-chat delivery",
|
|
66
|
+
meta: {
|
|
67
|
+
friendId: request.friendId,
|
|
68
|
+
channel: request.channel,
|
|
69
|
+
key: request.key,
|
|
70
|
+
status: result.status,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
const deliverer = deps.deliverers?.[request.channel];
|
|
76
|
+
if (!deliverer) {
|
|
77
|
+
const result = queueForLater(request, deps, "live delivery unavailable right now; queued for the next active turn");
|
|
78
|
+
(0, runtime_1.emitNervesEvent)({
|
|
79
|
+
component: "engine",
|
|
80
|
+
event: "engine.cross_chat_delivery_end",
|
|
81
|
+
message: "queued explicit cross-chat delivery because no live deliverer was available",
|
|
82
|
+
meta: {
|
|
83
|
+
friendId: request.friendId,
|
|
84
|
+
channel: request.channel,
|
|
85
|
+
key: request.key,
|
|
86
|
+
status: result.status,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const direct = await deliverer(request);
|
|
93
|
+
if (direct.status === "delivered_now" || direct.status === "blocked" || direct.status === "failed") {
|
|
94
|
+
const result = {
|
|
95
|
+
status: direct.status,
|
|
96
|
+
detail: direct.detail,
|
|
97
|
+
};
|
|
98
|
+
(0, runtime_1.emitNervesEvent)({
|
|
99
|
+
level: result.status === "failed" ? "error" : result.status === "blocked" ? "warn" : "info",
|
|
100
|
+
component: "engine",
|
|
101
|
+
event: "engine.cross_chat_delivery_end",
|
|
102
|
+
message: "completed direct cross-chat delivery resolution",
|
|
103
|
+
meta: {
|
|
104
|
+
friendId: request.friendId,
|
|
105
|
+
channel: request.channel,
|
|
106
|
+
key: request.key,
|
|
107
|
+
status: result.status,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
const result = queueForLater(request, deps, direct.detail.trim() || "live delivery unavailable right now; queued for the next active turn");
|
|
113
|
+
(0, runtime_1.emitNervesEvent)({
|
|
114
|
+
component: "engine",
|
|
115
|
+
event: "engine.cross_chat_delivery_end",
|
|
116
|
+
message: "queued explicit cross-chat delivery after adapter reported unavailability",
|
|
117
|
+
meta: {
|
|
118
|
+
friendId: request.friendId,
|
|
119
|
+
channel: request.channel,
|
|
120
|
+
key: request.key,
|
|
121
|
+
status: result.status,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const result = {
|
|
128
|
+
status: "failed",
|
|
129
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
130
|
+
};
|
|
131
|
+
(0, runtime_1.emitNervesEvent)({
|
|
132
|
+
level: "error",
|
|
133
|
+
component: "engine",
|
|
134
|
+
event: "engine.cross_chat_delivery_end",
|
|
135
|
+
message: "cross-chat delivery threw unexpectedly",
|
|
136
|
+
meta: {
|
|
137
|
+
friendId: request.friendId,
|
|
138
|
+
channel: request.channel,
|
|
139
|
+
key: request.key,
|
|
140
|
+
status: result.status,
|
|
141
|
+
reason: result.detail,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
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.listEnabledBundleAgents = listEnabledBundleAgents;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const identity_1 = require("../identity");
|
|
40
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
+
function listEnabledBundleAgents(options = {}) {
|
|
42
|
+
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
43
|
+
const readdirSync = options.readdirSync ?? fs.readdirSync;
|
|
44
|
+
const readFileSync = options.readFileSync ?? fs.readFileSync;
|
|
45
|
+
let entries;
|
|
46
|
+
try {
|
|
47
|
+
entries = readdirSync(bundlesRoot, { withFileTypes: true });
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
(0, runtime_1.emitNervesEvent)({
|
|
51
|
+
level: "warn",
|
|
52
|
+
component: "daemon",
|
|
53
|
+
event: "daemon.agent_discovery_failed",
|
|
54
|
+
message: "failed to read bundle root for daemon agent discovery",
|
|
55
|
+
meta: { bundlesRoot },
|
|
56
|
+
});
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const discovered = [];
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
if (!entry.isDirectory() || !entry.name.endsWith(".ouro"))
|
|
62
|
+
continue;
|
|
63
|
+
const agentName = entry.name.slice(0, -5);
|
|
64
|
+
const configPath = path.join(bundlesRoot, entry.name, "agent.json");
|
|
65
|
+
let enabled = true;
|
|
66
|
+
try {
|
|
67
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
68
|
+
const parsed = JSON.parse(raw);
|
|
69
|
+
if (typeof parsed.enabled === "boolean") {
|
|
70
|
+
enabled = parsed.enabled;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (enabled) {
|
|
77
|
+
discovered.push(agentName);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return discovered.sort((left, right) => left.localeCompare(right));
|
|
81
|
+
}
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent service layer — handles MCP-facing daemon commands.
|
|
4
|
+
* Each handler receives { agent, friendId, ...params } and returns DaemonResponse.
|
|
5
|
+
* For MVP, these read from agent state on the filesystem.
|
|
6
|
+
* Full inference support can come later.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.handleAgentStatus = handleAgentStatus;
|
|
43
|
+
exports.handleAgentAsk = handleAgentAsk;
|
|
44
|
+
exports.handleAgentCatchup = handleAgentCatchup;
|
|
45
|
+
exports.handleAgentDelegate = handleAgentDelegate;
|
|
46
|
+
exports.handleAgentGetContext = handleAgentGetContext;
|
|
47
|
+
exports.handleAgentSearchMemory = handleAgentSearchMemory;
|
|
48
|
+
exports.handleAgentGetTask = handleAgentGetTask;
|
|
49
|
+
exports.handleAgentCheckScope = handleAgentCheckScope;
|
|
50
|
+
exports.handleAgentRequestDecision = handleAgentRequestDecision;
|
|
51
|
+
exports.handleAgentCheckGuidance = handleAgentCheckGuidance;
|
|
52
|
+
exports.handleAgentReportProgress = handleAgentReportProgress;
|
|
53
|
+
exports.handleAgentReportBlocker = handleAgentReportBlocker;
|
|
54
|
+
exports.handleAgentReportComplete = handleAgentReportComplete;
|
|
55
|
+
const fs = __importStar(require("fs"));
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const identity_1 = require("../identity");
|
|
58
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
59
|
+
function readAgentFile(agent, ...segments) {
|
|
60
|
+
const filePath = path.join((0, identity_1.getAgentRoot)(agent), ...segments);
|
|
61
|
+
if (!fs.existsSync(filePath))
|
|
62
|
+
return null;
|
|
63
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
64
|
+
}
|
|
65
|
+
/** Read agent memory from multiple possible locations. */
|
|
66
|
+
function readAgentMemory(agent) {
|
|
67
|
+
// Try memory/MEMORY.md first, then psyche/memory/facts.jsonl
|
|
68
|
+
return readAgentFile(agent, "memory", "MEMORY.md")
|
|
69
|
+
?? readAgentFile(agent, "psyche", "memory", "facts.jsonl");
|
|
70
|
+
}
|
|
71
|
+
function listStateFiles(agent, ...segments) {
|
|
72
|
+
const dirPath = path.join((0, identity_1.getAgentStateRoot)(agent), ...segments);
|
|
73
|
+
if (!fs.existsSync(dirPath))
|
|
74
|
+
return [];
|
|
75
|
+
return fs.readdirSync(dirPath).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl") || f.endsWith(".md"));
|
|
76
|
+
}
|
|
77
|
+
async function handleAgentStatus(params) {
|
|
78
|
+
(0, runtime_1.emitNervesEvent)({
|
|
79
|
+
component: "daemon",
|
|
80
|
+
event: "daemon.agent_service_start",
|
|
81
|
+
message: "handling agent.status",
|
|
82
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
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
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
ok: true,
|
|
94
|
+
message: `Agent ${params.agent} status`,
|
|
95
|
+
data: {
|
|
96
|
+
agent: params.agent,
|
|
97
|
+
status: "active",
|
|
98
|
+
sessionCount: sessionFiles.length,
|
|
99
|
+
hasMemory: memoryContent !== null,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function handleAgentAsk(params) {
|
|
104
|
+
(0, runtime_1.emitNervesEvent)({
|
|
105
|
+
component: "daemon",
|
|
106
|
+
event: "daemon.agent_service_start",
|
|
107
|
+
message: "handling agent.ask",
|
|
108
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
109
|
+
});
|
|
110
|
+
const question = params.question;
|
|
111
|
+
if (!question) {
|
|
112
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
119
|
+
return { ok: false, error: "Missing required parameter: question" };
|
|
120
|
+
}
|
|
121
|
+
// MVP: return memory + recent session context without running inference
|
|
122
|
+
const memoryContent = readAgentMemory(params.agent);
|
|
123
|
+
const context = memoryContent
|
|
124
|
+
? `Based on agent memory:\n${memoryContent.slice(0, 2000)}`
|
|
125
|
+
: `Agent ${params.agent} has no memory file. Question was: ${question}`;
|
|
126
|
+
(0, runtime_1.emitNervesEvent)({
|
|
127
|
+
component: "daemon",
|
|
128
|
+
event: "daemon.agent_service_end",
|
|
129
|
+
message: "completed agent.ask",
|
|
130
|
+
meta: { agent: params.agent },
|
|
131
|
+
});
|
|
132
|
+
return { ok: true, message: context };
|
|
133
|
+
}
|
|
134
|
+
async function handleAgentCatchup(params) {
|
|
135
|
+
(0, runtime_1.emitNervesEvent)({
|
|
136
|
+
component: "daemon",
|
|
137
|
+
event: "daemon.agent_service_start",
|
|
138
|
+
message: "handling agent.catchup",
|
|
139
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
140
|
+
});
|
|
141
|
+
const sessionFiles = listStateFiles(params.agent, "sessions");
|
|
142
|
+
const recentSessions = sessionFiles.slice(-5);
|
|
143
|
+
(0, runtime_1.emitNervesEvent)({
|
|
144
|
+
component: "daemon",
|
|
145
|
+
event: "daemon.agent_service_end",
|
|
146
|
+
message: "completed agent.catchup",
|
|
147
|
+
meta: { agent: params.agent },
|
|
148
|
+
});
|
|
149
|
+
return {
|
|
150
|
+
ok: true,
|
|
151
|
+
message: recentSessions.length > 0
|
|
152
|
+
? `Recent activity: ${recentSessions.length} recent sessions found`
|
|
153
|
+
: `No recent activity for ${params.agent}`,
|
|
154
|
+
data: { recentSessions },
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
async function handleAgentDelegate(params) {
|
|
158
|
+
(0, runtime_1.emitNervesEvent)({
|
|
159
|
+
component: "daemon",
|
|
160
|
+
event: "daemon.agent_service_start",
|
|
161
|
+
message: "handling agent.delegate",
|
|
162
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
163
|
+
});
|
|
164
|
+
const task = params.task;
|
|
165
|
+
if (!task) {
|
|
166
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
173
|
+
return { ok: false, error: "Missing required parameter: task" };
|
|
174
|
+
}
|
|
175
|
+
(0, runtime_1.emitNervesEvent)({
|
|
176
|
+
component: "daemon",
|
|
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
|
+
};
|
|
186
|
+
}
|
|
187
|
+
async function handleAgentGetContext(params) {
|
|
188
|
+
(0, runtime_1.emitNervesEvent)({
|
|
189
|
+
component: "daemon",
|
|
190
|
+
event: "daemon.agent_service_start",
|
|
191
|
+
message: "handling agent.getContext",
|
|
192
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
193
|
+
});
|
|
194
|
+
const memoryContent = readAgentMemory(params.agent);
|
|
195
|
+
const taskFiles = listStateFiles(params.agent, "tasks");
|
|
196
|
+
(0, runtime_1.emitNervesEvent)({
|
|
197
|
+
component: "daemon",
|
|
198
|
+
event: "daemon.agent_service_end",
|
|
199
|
+
message: "completed agent.getContext",
|
|
200
|
+
meta: { agent: params.agent },
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
ok: true,
|
|
204
|
+
data: {
|
|
205
|
+
agent: params.agent,
|
|
206
|
+
hasMemory: memoryContent !== null,
|
|
207
|
+
memorySummary: memoryContent ? memoryContent.slice(0, 500) : null,
|
|
208
|
+
taskCount: taskFiles.length,
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
async function handleAgentSearchMemory(params) {
|
|
213
|
+
(0, runtime_1.emitNervesEvent)({
|
|
214
|
+
component: "daemon",
|
|
215
|
+
event: "daemon.agent_service_start",
|
|
216
|
+
message: "handling agent.searchMemory",
|
|
217
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
218
|
+
});
|
|
219
|
+
const query = params.query;
|
|
220
|
+
if (!query) {
|
|
221
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
228
|
+
return { ok: false, error: "Missing required parameter: query" };
|
|
229
|
+
}
|
|
230
|
+
// MVP: simple substring search in memory file
|
|
231
|
+
const memoryContent = readAgentMemory(params.agent);
|
|
232
|
+
const matches = [];
|
|
233
|
+
if (memoryContent) {
|
|
234
|
+
const lines = memoryContent.split("\n");
|
|
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
|
+
});
|
|
248
|
+
return {
|
|
249
|
+
ok: true,
|
|
250
|
+
message: matches.length > 0 ? `Found ${matches.length} matches` : "No matches found",
|
|
251
|
+
data: { query, matches: matches.slice(0, 20) },
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
async function handleAgentGetTask(params) {
|
|
255
|
+
(0, runtime_1.emitNervesEvent)({
|
|
256
|
+
component: "daemon",
|
|
257
|
+
event: "daemon.agent_service_start",
|
|
258
|
+
message: "handling agent.getTask",
|
|
259
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
260
|
+
});
|
|
261
|
+
const taskFiles = listStateFiles(params.agent, "tasks");
|
|
262
|
+
(0, runtime_1.emitNervesEvent)({
|
|
263
|
+
component: "daemon",
|
|
264
|
+
event: "daemon.agent_service_end",
|
|
265
|
+
message: "completed agent.getTask",
|
|
266
|
+
meta: { agent: params.agent },
|
|
267
|
+
});
|
|
268
|
+
return {
|
|
269
|
+
ok: true,
|
|
270
|
+
message: taskFiles.length > 0
|
|
271
|
+
? `Current tasks: ${taskFiles.join(", ")}`
|
|
272
|
+
: `No active tasks for ${params.agent}`,
|
|
273
|
+
data: { tasks: taskFiles },
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
async function handleAgentCheckScope(params) {
|
|
277
|
+
(0, runtime_1.emitNervesEvent)({
|
|
278
|
+
component: "daemon",
|
|
279
|
+
event: "daemon.agent_service_start",
|
|
280
|
+
message: "handling agent.checkScope",
|
|
281
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
282
|
+
});
|
|
283
|
+
const item = params.item;
|
|
284
|
+
if (!item) {
|
|
285
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
292
|
+
return { ok: false, error: "Missing required parameter: item" };
|
|
293
|
+
}
|
|
294
|
+
(0, runtime_1.emitNervesEvent)({
|
|
295
|
+
component: "daemon",
|
|
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
|
+
};
|
|
305
|
+
}
|
|
306
|
+
async function handleAgentRequestDecision(params) {
|
|
307
|
+
(0, runtime_1.emitNervesEvent)({
|
|
308
|
+
component: "daemon",
|
|
309
|
+
event: "daemon.agent_service_start",
|
|
310
|
+
message: "handling agent.requestDecision",
|
|
311
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
312
|
+
});
|
|
313
|
+
const topic = params.topic;
|
|
314
|
+
if (!topic) {
|
|
315
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
322
|
+
return { ok: false, error: "Missing required parameter: topic" };
|
|
323
|
+
}
|
|
324
|
+
(0, runtime_1.emitNervesEvent)({
|
|
325
|
+
component: "daemon",
|
|
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
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async function handleAgentCheckGuidance(params) {
|
|
342
|
+
(0, runtime_1.emitNervesEvent)({
|
|
343
|
+
component: "daemon",
|
|
344
|
+
event: "daemon.agent_service_start",
|
|
345
|
+
message: "handling agent.checkGuidance",
|
|
346
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
347
|
+
});
|
|
348
|
+
const topic = params.topic;
|
|
349
|
+
if (!topic) {
|
|
350
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
357
|
+
return { ok: false, error: "Missing required parameter: topic" };
|
|
358
|
+
}
|
|
359
|
+
// MVP: check memory for relevant guidance
|
|
360
|
+
const memoryContent = readAgentMemory(params.agent);
|
|
361
|
+
let guidance = `No specific guidance found for: ${topic}`;
|
|
362
|
+
if (memoryContent) {
|
|
363
|
+
const lines = memoryContent.split("\n");
|
|
364
|
+
const topicLower = topic.toLowerCase();
|
|
365
|
+
const relevant = lines.filter((line) => line.toLowerCase().includes(topicLower));
|
|
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
|
+
});
|
|
376
|
+
return { ok: true, message: guidance };
|
|
377
|
+
}
|
|
378
|
+
async function handleAgentReportProgress(params) {
|
|
379
|
+
(0, runtime_1.emitNervesEvent)({
|
|
380
|
+
component: "daemon",
|
|
381
|
+
event: "daemon.agent_service_start",
|
|
382
|
+
message: "handling agent.reportProgress",
|
|
383
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
384
|
+
});
|
|
385
|
+
const summary = params.summary;
|
|
386
|
+
if (!summary) {
|
|
387
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
394
|
+
return { ok: false, error: "Missing required parameter: summary" };
|
|
395
|
+
}
|
|
396
|
+
(0, runtime_1.emitNervesEvent)({
|
|
397
|
+
component: "daemon",
|
|
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
|
+
};
|
|
407
|
+
}
|
|
408
|
+
async function handleAgentReportBlocker(params) {
|
|
409
|
+
(0, runtime_1.emitNervesEvent)({
|
|
410
|
+
component: "daemon",
|
|
411
|
+
event: "daemon.agent_service_start",
|
|
412
|
+
message: "handling agent.reportBlocker",
|
|
413
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
414
|
+
});
|
|
415
|
+
const blocker = params.blocker;
|
|
416
|
+
if (!blocker) {
|
|
417
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
424
|
+
return { ok: false, error: "Missing required parameter: blocker" };
|
|
425
|
+
}
|
|
426
|
+
(0, runtime_1.emitNervesEvent)({
|
|
427
|
+
component: "daemon",
|
|
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
|
+
};
|
|
437
|
+
}
|
|
438
|
+
async function handleAgentReportComplete(params) {
|
|
439
|
+
(0, runtime_1.emitNervesEvent)({
|
|
440
|
+
component: "daemon",
|
|
441
|
+
event: "daemon.agent_service_start",
|
|
442
|
+
message: "handling agent.reportComplete",
|
|
443
|
+
meta: { agent: params.agent, friendId: params.friendId },
|
|
444
|
+
});
|
|
445
|
+
const summary = params.summary;
|
|
446
|
+
if (!summary) {
|
|
447
|
+
(0, runtime_1.emitNervesEvent)({
|
|
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
|
+
});
|
|
454
|
+
return { ok: false, error: "Missing required parameter: summary" };
|
|
455
|
+
}
|
|
456
|
+
(0, runtime_1.emitNervesEvent)({
|
|
457
|
+
component: "daemon",
|
|
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
|
+
};
|
|
467
|
+
}
|