@ouro.bot/cli 0.1.0-alpha.2 → 0.1.0-alpha.200
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/README.md +187 -191
- package/SerpentGuide.ouro/agent.json +82 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +6 -3
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
- package/assets/ouroboros.png +0 -0
- package/changelog.json +1248 -0
- package/dist/heart/active-work.js +832 -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/cares.js +179 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config.js +114 -28
- package/dist/heart/core.js +689 -120
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-config-check.js +149 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/auth-flow.js +477 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/daemon-cli.js +2897 -193
- package/dist/heart/daemon/daemon-entry.js +194 -8
- package/dist/heart/daemon/daemon-health.js +136 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
- package/dist/heart/daemon/daemon-tombstone.js +123 -0
- package/dist/heart/daemon/daemon.js +488 -13
- package/dist/heart/daemon/habit-migration.js +181 -0
- package/dist/heart/daemon/habit-parser.js +119 -0
- package/dist/heart/daemon/habit-scheduler.js +369 -0
- package/dist/heart/daemon/hatch-animation.js +35 -0
- package/dist/heart/daemon/hatch-flow.js +32 -122
- package/dist/heart/daemon/hatch-specialist.js +7 -2
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/launchd.js +165 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/mcp-server.js +591 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +4 -3
- package/dist/heart/daemon/ouro-path-installer.js +221 -0
- package/dist/heart/daemon/ouro-uti.js +11 -2
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/outlook-http.js +439 -0
- package/dist/heart/daemon/outlook-read.js +1618 -0
- package/dist/heart/daemon/outlook-render.js +1032 -0
- package/dist/heart/daemon/outlook-types.js +7 -0
- package/dist/heart/daemon/outlook-view.js +194 -0
- package/dist/heart/daemon/process-manager.js +94 -1
- package/dist/heart/daemon/run-hooks.js +39 -0
- package/dist/heart/daemon/runtime-logging.js +61 -14
- package/dist/heart/daemon/runtime-metadata.js +219 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +314 -0
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- 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 +129 -0
- package/dist/heart/daemon/specialist-prompt.js +101 -0
- package/dist/heart/daemon/specialist-tools.js +283 -0
- package/dist/heart/daemon/staged-restart.js +138 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- 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 +220 -52
- package/dist/heart/intentions.js +173 -0
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +225 -0
- package/dist/heart/presence.js +185 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +178 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +199 -36
- package/dist/heart/providers/azure.js +116 -10
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +51 -16
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +172 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/start-of-turn-packet.js +232 -0
- package/dist/heart/streaming.js +120 -33
- package/dist/heart/sync.js +217 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -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 +77 -1
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +69 -56
- package/dist/mind/episodes.js +119 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +64 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +36 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +9 -1
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/obligations.js +138 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +861 -105
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/audit.js +1 -1
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +63 -3
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
- package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/ado-semantic.js +11 -5
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -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 +58 -12
- package/dist/repertoire/coding/tools.js +209 -7
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/guardrails.js +291 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +251 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +28 -10
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +11 -28
- package/dist/repertoire/tools-base.js +1360 -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 +318 -91
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +97 -0
- package/dist/senses/bluebubbles-client.js +532 -0
- package/dist/senses/bluebubbles-entry.js +13 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +261 -0
- package/dist/senses/bluebubbles-mutation-log.js +116 -0
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +1327 -0
- package/dist/senses/cli/adapter.js +274 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +349 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +198 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +687 -262
- package/dist/senses/commands.js +65 -1
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +592 -84
- package/dist/senses/pipeline.js +693 -0
- package/dist/senses/shared-turn.js +196 -0
- package/dist/senses/surface-tool.js +95 -0
- package/dist/senses/teams.js +817 -151
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +24 -7
- package/skills/configure-dev-tools.md +81 -0
- package/subagents/README.md +4 -70
- package/AdoptionSpecialist.ouro/agent.json +0 -20
- package/dist/heart/daemon/subagent-installer.js +0 -125
- package/dist/inner-worker-entry.js +0 -4
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.playHatchAnimation = playHatchAnimation;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
const EGG = "\uD83E\uDD5A";
|
|
6
|
+
const SNAKE = "\uD83D\uDC0D";
|
|
7
|
+
const DOTS = " . . . ";
|
|
8
|
+
function wait(ms) {
|
|
9
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Play the hatch animation: egg -> dots -> snake + name.
|
|
13
|
+
* The writer function receives each chunk. Default writer is process.stderr.write.
|
|
14
|
+
*/
|
|
15
|
+
async function playHatchAnimation(hatchlingName, writer) {
|
|
16
|
+
(0, runtime_1.emitNervesEvent)({
|
|
17
|
+
component: "daemon",
|
|
18
|
+
event: "daemon.hatch_animation_start",
|
|
19
|
+
message: "playing hatch animation",
|
|
20
|
+
meta: { hatchlingName },
|
|
21
|
+
});
|
|
22
|
+
const write = writer ?? ((text) => process.stderr.write(text));
|
|
23
|
+
// Total animation time randomized between 3–5 seconds
|
|
24
|
+
const totalMs = 3000 + Math.floor(Math.random() * 2000);
|
|
25
|
+
const eggPhase = Math.floor(totalMs * 0.4);
|
|
26
|
+
const dotsPhase = Math.floor(totalMs * 0.4);
|
|
27
|
+
const revealPause = totalMs - eggPhase - dotsPhase;
|
|
28
|
+
write(`\n ${EGG}`);
|
|
29
|
+
await wait(eggPhase);
|
|
30
|
+
write(DOTS);
|
|
31
|
+
await wait(dotsPhase);
|
|
32
|
+
write(`${SNAKE} \x1b[1m${hatchlingName}\x1b[0m`);
|
|
33
|
+
await wait(revealPause);
|
|
34
|
+
write("\n\n");
|
|
35
|
+
}
|
|
@@ -33,18 +33,25 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.writeSecretsFile = writeSecretsFile;
|
|
36
37
|
exports.runHatchFlow = runHatchFlow;
|
|
37
38
|
const fs = __importStar(require("fs"));
|
|
38
39
|
const os = __importStar(require("os"));
|
|
39
40
|
const path = __importStar(require("path"));
|
|
40
41
|
const identity_1 = require("../identity");
|
|
42
|
+
const config_1 = require("../config");
|
|
41
43
|
const runtime_1 = require("../../nerves/runtime");
|
|
44
|
+
const auth_flow_1 = require("./auth-flow");
|
|
45
|
+
const habit_parser_1 = require("./habit-parser");
|
|
42
46
|
const hatch_specialist_1 = require("./hatch-specialist");
|
|
43
47
|
function requiredCredentialKeys(provider) {
|
|
44
48
|
if (provider === "anthropic")
|
|
45
49
|
return ["setupToken"];
|
|
46
50
|
if (provider === "openai-codex")
|
|
47
51
|
return ["oauthAccessToken"];
|
|
52
|
+
/* v8 ignore next -- branch tested via requiredCredentialKeys unit test @preserve */
|
|
53
|
+
if (provider === "github-copilot")
|
|
54
|
+
return ["githubToken"];
|
|
48
55
|
if (provider === "minimax")
|
|
49
56
|
return ["apiKey"];
|
|
50
57
|
return ["apiKey", "endpoint", "deployment"];
|
|
@@ -65,70 +72,8 @@ function validateCredentials(provider, credentials) {
|
|
|
65
72
|
throw new Error(`Missing required credentials for ${provider}: ${missing.join(", ")}`);
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
|
-
function buildSecretsTemplate() {
|
|
69
|
-
return {
|
|
70
|
-
providers: {
|
|
71
|
-
azure: {
|
|
72
|
-
modelName: "gpt-4o-mini",
|
|
73
|
-
apiKey: "",
|
|
74
|
-
endpoint: "",
|
|
75
|
-
deployment: "",
|
|
76
|
-
apiVersion: "2025-04-01-preview",
|
|
77
|
-
},
|
|
78
|
-
minimax: {
|
|
79
|
-
model: "minimax-text-01",
|
|
80
|
-
apiKey: "",
|
|
81
|
-
},
|
|
82
|
-
anthropic: {
|
|
83
|
-
model: "claude-opus-4-6",
|
|
84
|
-
setupToken: "",
|
|
85
|
-
},
|
|
86
|
-
"openai-codex": {
|
|
87
|
-
model: "gpt-5.2",
|
|
88
|
-
oauthAccessToken: "",
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
teams: {
|
|
92
|
-
clientId: "",
|
|
93
|
-
clientSecret: "",
|
|
94
|
-
tenantId: "",
|
|
95
|
-
},
|
|
96
|
-
oauth: {
|
|
97
|
-
graphConnectionName: "graph",
|
|
98
|
-
adoConnectionName: "ado",
|
|
99
|
-
githubConnectionName: "",
|
|
100
|
-
},
|
|
101
|
-
teamsChannel: {
|
|
102
|
-
skipConfirmation: true,
|
|
103
|
-
port: 3978,
|
|
104
|
-
},
|
|
105
|
-
integrations: {
|
|
106
|
-
perplexityApiKey: "",
|
|
107
|
-
openaiEmbeddingsApiKey: "",
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
75
|
function writeSecretsFile(agentName, provider, credentials, secretsRoot) {
|
|
112
|
-
|
|
113
|
-
if (provider === "anthropic") {
|
|
114
|
-
secrets.providers.anthropic.setupToken = credentials.setupToken.trim();
|
|
115
|
-
}
|
|
116
|
-
else if (provider === "openai-codex") {
|
|
117
|
-
secrets.providers["openai-codex"].oauthAccessToken = credentials.oauthAccessToken.trim();
|
|
118
|
-
}
|
|
119
|
-
else if (provider === "minimax") {
|
|
120
|
-
secrets.providers.minimax.apiKey = credentials.apiKey.trim();
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
secrets.providers.azure.apiKey = credentials.apiKey.trim();
|
|
124
|
-
secrets.providers.azure.endpoint = credentials.endpoint.trim();
|
|
125
|
-
secrets.providers.azure.deployment = credentials.deployment.trim();
|
|
126
|
-
}
|
|
127
|
-
const secretsDir = path.join(secretsRoot, agentName);
|
|
128
|
-
fs.mkdirSync(secretsDir, { recursive: true });
|
|
129
|
-
const secretsPath = path.join(secretsDir, "secrets.json");
|
|
130
|
-
fs.writeFileSync(secretsPath, `${JSON.stringify(secrets, null, 2)}\n`, "utf-8");
|
|
131
|
-
return secretsPath;
|
|
76
|
+
return (0, auth_flow_1.writeProviderCredentials)(agentName, provider, credentials, { secretsRoot }).secretsPath;
|
|
132
77
|
}
|
|
133
78
|
function writeReadme(dir, purpose) {
|
|
134
79
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -137,51 +82,24 @@ function writeReadme(dir, purpose) {
|
|
|
137
82
|
fs.writeFileSync(readmePath, `# ${path.basename(dir)}\n\n${purpose}\n`, "utf-8");
|
|
138
83
|
}
|
|
139
84
|
}
|
|
140
|
-
function
|
|
141
|
-
const
|
|
142
|
-
const slug = trimmed
|
|
143
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
144
|
-
.replace(/^-+/, "")
|
|
145
|
-
.replace(/-+$/, "");
|
|
146
|
-
return slug || "friend";
|
|
147
|
-
}
|
|
148
|
-
function pad(value) {
|
|
149
|
-
return String(value).padStart(2, "0");
|
|
150
|
-
}
|
|
151
|
-
function formatTaskStem(now) {
|
|
152
|
-
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;
|
|
153
|
-
}
|
|
154
|
-
function writeHeartbeatTask(bundleRoot, now) {
|
|
155
|
-
const habitsDir = path.join(bundleRoot, "tasks", "habits");
|
|
85
|
+
function writeHeartbeatHabit(bundleRoot, now) {
|
|
86
|
+
const habitsDir = path.join(bundleRoot, "habits");
|
|
156
87
|
fs.mkdirSync(habitsDir, { recursive: true });
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
"
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"status: processing",
|
|
166
|
-
`created: ${iso}`,
|
|
167
|
-
`updated: ${iso}`,
|
|
168
|
-
"requester: system",
|
|
169
|
-
"validator: null",
|
|
170
|
-
"cadence: \"30m\"",
|
|
171
|
-
"scheduledAt: null",
|
|
172
|
-
"lastRun: null",
|
|
173
|
-
"---",
|
|
174
|
-
"",
|
|
175
|
-
"Run a lightweight heartbeat cycle. Review task board and inbox.",
|
|
176
|
-
"",
|
|
177
|
-
].join("\n");
|
|
88
|
+
const filePath = path.join(habitsDir, "heartbeat.md");
|
|
89
|
+
const content = (0, habit_parser_1.renderHabitFile)({
|
|
90
|
+
title: "Heartbeat check-in",
|
|
91
|
+
cadence: "30m",
|
|
92
|
+
status: "active",
|
|
93
|
+
lastRun: "null",
|
|
94
|
+
created: now.toISOString(),
|
|
95
|
+
}, "Run a lightweight heartbeat cycle. Review task board and inbox.\nCheck on pending obligations. Journal anything important.");
|
|
178
96
|
fs.writeFileSync(filePath, content, "utf-8");
|
|
179
97
|
}
|
|
180
98
|
function writeFriendImprint(bundleRoot, humanName, now) {
|
|
181
99
|
const friendsDir = path.join(bundleRoot, "friends");
|
|
182
100
|
fs.mkdirSync(friendsDir, { recursive: true });
|
|
183
101
|
const nowIso = now.toISOString();
|
|
184
|
-
const id = `friend-${slugify(humanName)}`;
|
|
102
|
+
const id = `friend-${(0, config_1.slugify)(humanName) || "friend"}`;
|
|
185
103
|
const localExternalId = `${os.userInfo().username}@${os.hostname()}`;
|
|
186
104
|
const record = {
|
|
187
105
|
id,
|
|
@@ -206,25 +124,18 @@ function writeFriendImprint(bundleRoot, humanName, now) {
|
|
|
206
124
|
};
|
|
207
125
|
fs.writeFileSync(path.join(friendsDir, `${id}.json`), `${JSON.stringify(record, null, 2)}\n`, "utf-8");
|
|
208
126
|
}
|
|
209
|
-
function
|
|
210
|
-
const
|
|
211
|
-
fs.mkdirSync(
|
|
212
|
-
fs.
|
|
213
|
-
fs.writeFileSync(path.join(
|
|
214
|
-
fs.writeFileSync(path.join(
|
|
215
|
-
fs.writeFileSync(path.join(psycheDir, "TACIT.md"), "# TACIT\n\n- Save what I learn.\n- Keep tasks current.\n", "utf-8");
|
|
216
|
-
fs.writeFileSync(path.join(psycheDir, "ASPIRATIONS.md"), "# ASPIRATIONS\n\n- Become a reliable partner for my primary friend.\n", "utf-8");
|
|
217
|
-
}
|
|
218
|
-
function writeMemoryScaffold(bundleRoot) {
|
|
219
|
-
const memoryRoot = path.join(bundleRoot, "psyche", "memory");
|
|
220
|
-
fs.mkdirSync(path.join(memoryRoot, "daily"), { recursive: true });
|
|
221
|
-
fs.mkdirSync(path.join(memoryRoot, "archive"), { recursive: true });
|
|
222
|
-
fs.writeFileSync(path.join(memoryRoot, "facts.jsonl"), "", "utf-8");
|
|
223
|
-
fs.writeFileSync(path.join(memoryRoot, "entities.json"), "{}\n", "utf-8");
|
|
127
|
+
function writeDiaryScaffold(bundleRoot) {
|
|
128
|
+
const diaryRoot = path.join(bundleRoot, "diary");
|
|
129
|
+
fs.mkdirSync(path.join(diaryRoot, "daily"), { recursive: true });
|
|
130
|
+
fs.mkdirSync(path.join(diaryRoot, "archive"), { recursive: true });
|
|
131
|
+
fs.writeFileSync(path.join(diaryRoot, "facts.jsonl"), "", "utf-8");
|
|
132
|
+
fs.writeFileSync(path.join(diaryRoot, "entities.json"), "{}\n", "utf-8");
|
|
224
133
|
}
|
|
225
134
|
function writeHatchlingAgentConfig(bundleRoot, input) {
|
|
226
135
|
const template = (0, identity_1.buildDefaultAgentTemplate)(input.agentName);
|
|
227
136
|
template.provider = input.provider;
|
|
137
|
+
template.humanFacing = { provider: input.provider, model: template.humanFacing.model };
|
|
138
|
+
template.agentFacing = { provider: input.provider, model: template.agentFacing.model };
|
|
228
139
|
template.enabled = true;
|
|
229
140
|
fs.writeFileSync(path.join(bundleRoot, "agent.json"), `${JSON.stringify(template, null, 2)}\n`, "utf-8");
|
|
230
141
|
}
|
|
@@ -250,26 +161,25 @@ async function runHatchFlow(input, deps = {}) {
|
|
|
250
161
|
identitiesDir: targetIdentities,
|
|
251
162
|
random,
|
|
252
163
|
});
|
|
253
|
-
const specialistSecretsPath = writeSecretsFile("
|
|
164
|
+
const specialistSecretsPath = writeSecretsFile("SerpentGuide", input.provider, input.credentials, secretsRoot);
|
|
254
165
|
const hatchlingSecretsPath = writeSecretsFile(input.agentName, input.provider, input.credentials, secretsRoot);
|
|
255
166
|
const bundleRoot = path.join(bundlesRoot, `${input.agentName}.ouro`);
|
|
256
167
|
fs.mkdirSync(bundleRoot, { recursive: true });
|
|
257
168
|
writeReadme(bundleRoot, "Root of this agent bundle.");
|
|
258
169
|
writeReadme(path.join(bundleRoot, "psyche"), "Identity and behavior files.");
|
|
259
|
-
writeReadme(path.join(bundleRoot, "
|
|
170
|
+
writeReadme(path.join(bundleRoot, "diary"), "Persistent diary — things I've learned and remember.");
|
|
260
171
|
writeReadme(path.join(bundleRoot, "friends"), "Known friend records.");
|
|
261
172
|
writeReadme(path.join(bundleRoot, "tasks"), "Task files.");
|
|
262
|
-
writeReadme(path.join(bundleRoot, "tasks", "habits"), "Recurring tasks.");
|
|
263
173
|
writeReadme(path.join(bundleRoot, "tasks", "one-shots"), "One-shot tasks.");
|
|
264
174
|
writeReadme(path.join(bundleRoot, "tasks", "ongoing"), "Ongoing tasks.");
|
|
175
|
+
writeReadme(path.join(bundleRoot, "habits"), "Recurring habits and autonomous rhythms.");
|
|
265
176
|
writeReadme(path.join(bundleRoot, "skills"), "Local skill files.");
|
|
266
177
|
writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
|
|
267
178
|
writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
|
|
268
179
|
writeHatchlingAgentConfig(bundleRoot, input);
|
|
269
|
-
|
|
270
|
-
writeMemoryScaffold(bundleRoot);
|
|
180
|
+
writeDiaryScaffold(bundleRoot);
|
|
271
181
|
writeFriendImprint(bundleRoot, input.humanName, now);
|
|
272
|
-
|
|
182
|
+
writeHeartbeatHabit(bundleRoot, now);
|
|
273
183
|
(0, runtime_1.emitNervesEvent)({
|
|
274
184
|
component: "daemon",
|
|
275
185
|
event: "daemon.hatch_flow_end",
|
|
@@ -42,10 +42,15 @@ const os = __importStar(require("os"));
|
|
|
42
42
|
const path = __importStar(require("path"));
|
|
43
43
|
const runtime_1 = require("../../nerves/runtime");
|
|
44
44
|
function getSpecialistIdentitySourceDir() {
|
|
45
|
-
|
|
45
|
+
// Prefer ~/AgentBundles/ if it exists (user may have customized identities)
|
|
46
|
+
const userSource = path.join(os.homedir(), "AgentBundles", "SerpentGuide.ouro", "psyche", "identities");
|
|
47
|
+
if (fs.existsSync(userSource))
|
|
48
|
+
return userSource;
|
|
49
|
+
// Fall back to the bundled copy shipped with the npm package
|
|
50
|
+
return path.join(__dirname, "..", "..", "..", "SerpentGuide.ouro", "psyche", "identities");
|
|
46
51
|
}
|
|
47
52
|
function getRepoSpecialistIdentitiesDir() {
|
|
48
|
-
return path.join(process.cwd(), "
|
|
53
|
+
return path.join(process.cwd(), "SerpentGuide.ouro", "psyche", "identities");
|
|
49
54
|
}
|
|
50
55
|
function listMarkdownIdentityFiles(dir) {
|
|
51
56
|
let entries;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agentConfigV2Hook = agentConfigV2Hook;
|
|
4
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
5
|
+
const migrate_config_1 = require("../../migrate-config");
|
|
6
|
+
async function agentConfigV2Hook(ctx) {
|
|
7
|
+
(0, runtime_1.emitNervesEvent)({
|
|
8
|
+
component: "daemon",
|
|
9
|
+
event: "daemon.agent_config_v2_hook_start",
|
|
10
|
+
message: "running agent-config-v2 update hook",
|
|
11
|
+
meta: { agentRoot: ctx.agentRoot, currentVersion: ctx.currentVersion },
|
|
12
|
+
});
|
|
13
|
+
try {
|
|
14
|
+
(0, migrate_config_1.migrateAgentConfigV1ToV2)(ctx.agentRoot);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
|
|
18
|
+
(0, runtime_1.emitNervesEvent)({
|
|
19
|
+
component: "daemon",
|
|
20
|
+
event: "daemon.agent_config_v2_hook_error",
|
|
21
|
+
message: "agent-config-v2 hook migration failed",
|
|
22
|
+
meta: { agentRoot: ctx.agentRoot, error: errorMessage },
|
|
23
|
+
});
|
|
24
|
+
return { ok: false, error: errorMessage };
|
|
25
|
+
}
|
|
26
|
+
(0, runtime_1.emitNervesEvent)({
|
|
27
|
+
component: "daemon",
|
|
28
|
+
event: "daemon.agent_config_v2_hook_end",
|
|
29
|
+
message: "agent-config-v2 hook completed",
|
|
30
|
+
meta: { agentRoot: ctx.agentRoot },
|
|
31
|
+
});
|
|
32
|
+
return { ok: true };
|
|
33
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
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.bundleMetaHook = bundleMetaHook;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
40
|
+
/**
|
|
41
|
+
* Migrate bundle from schema 1 to schema 2:
|
|
42
|
+
* - Move state/{episodes,obligations,cares,intentions}/* to arc/{name}/*
|
|
43
|
+
* - Move psyche/memory/* to diary/
|
|
44
|
+
* Idempotent: skips missing sources; on collision, newer mtime wins.
|
|
45
|
+
*/
|
|
46
|
+
function migrateToSchema2(agentRoot) {
|
|
47
|
+
(0, runtime_1.emitNervesEvent)({
|
|
48
|
+
component: "daemon",
|
|
49
|
+
event: "daemon.bundle_migration_start",
|
|
50
|
+
message: "migrating bundle to schema 2",
|
|
51
|
+
meta: { agentRoot },
|
|
52
|
+
});
|
|
53
|
+
// Migrate arc entities
|
|
54
|
+
for (const name of ["episodes", "obligations", "cares", "intentions"]) {
|
|
55
|
+
const src = path.join(agentRoot, "state", name);
|
|
56
|
+
const dest = path.join(agentRoot, "arc", name);
|
|
57
|
+
migrateDirectory(src, dest);
|
|
58
|
+
}
|
|
59
|
+
// Migrate diary
|
|
60
|
+
const memorySrc = path.join(agentRoot, "psyche", "memory");
|
|
61
|
+
const diaryDest = path.join(agentRoot, "diary");
|
|
62
|
+
migrateDirectory(memorySrc, diaryDest);
|
|
63
|
+
// Update bundle .gitignore
|
|
64
|
+
updateBundleGitignore(agentRoot);
|
|
65
|
+
(0, runtime_1.emitNervesEvent)({
|
|
66
|
+
component: "daemon",
|
|
67
|
+
event: "daemon.bundle_migration_end",
|
|
68
|
+
message: "bundle migration to schema 2 complete",
|
|
69
|
+
meta: { agentRoot },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Ensure bundle .gitignore has state/ ignored and does NOT ignore arc/, diary/, journal/.
|
|
74
|
+
*/
|
|
75
|
+
function updateBundleGitignore(agentRoot) {
|
|
76
|
+
const gitignorePath = path.join(agentRoot, ".gitignore");
|
|
77
|
+
let lines = [];
|
|
78
|
+
try {
|
|
79
|
+
if (fs.existsSync(gitignorePath)) {
|
|
80
|
+
lines = fs.readFileSync(gitignorePath, "utf-8").split("\n");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// If we can't read, start fresh
|
|
85
|
+
}
|
|
86
|
+
// Remove arc/, diary/, journal/ from ignore (they should be tracked)
|
|
87
|
+
const toRemove = new Set(["arc/", "diary/", "journal/"]);
|
|
88
|
+
lines = lines.filter((line) => !toRemove.has(line.trim()));
|
|
89
|
+
// Ensure state/ is in the ignore list
|
|
90
|
+
const hasState = lines.some((line) => line.trim() === "state/");
|
|
91
|
+
if (!hasState) {
|
|
92
|
+
lines.push("state/");
|
|
93
|
+
}
|
|
94
|
+
// Write back, trimming trailing empty lines and ensuring trailing newline
|
|
95
|
+
const content = lines.join("\n").replace(/\n+$/, "") + "\n";
|
|
96
|
+
try {
|
|
97
|
+
fs.writeFileSync(gitignorePath, content, "utf-8");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Non-blocking: if we can't write .gitignore, migration still succeeds
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Recursively copy files from src to dest.
|
|
105
|
+
* Creates destination directories as needed. Skips if source doesn't exist.
|
|
106
|
+
* When both source and destination exist, compares mtimes: newer file wins.
|
|
107
|
+
* Logs a warning either way when a collision is detected.
|
|
108
|
+
*/
|
|
109
|
+
function migrateDirectory(src, dest) {
|
|
110
|
+
if (!fs.existsSync(src))
|
|
111
|
+
return;
|
|
112
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
113
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
const srcPath = path.join(src, entry.name);
|
|
116
|
+
const destPath = path.join(dest, entry.name);
|
|
117
|
+
if (entry.isDirectory()) {
|
|
118
|
+
migrateDirectory(srcPath, destPath);
|
|
119
|
+
}
|
|
120
|
+
else if (!fs.existsSync(destPath)) {
|
|
121
|
+
fs.copyFileSync(srcPath, destPath);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Collision: both source and destination exist — compare mtimes
|
|
125
|
+
const srcMtime = fs.statSync(srcPath).mtimeMs;
|
|
126
|
+
const destMtime = fs.statSync(destPath).mtimeMs;
|
|
127
|
+
if (srcMtime > destMtime) {
|
|
128
|
+
fs.copyFileSync(srcPath, destPath);
|
|
129
|
+
(0, runtime_1.emitNervesEvent)({
|
|
130
|
+
level: "warn",
|
|
131
|
+
component: "daemon",
|
|
132
|
+
event: "daemon.bundle_migration_collision",
|
|
133
|
+
message: `migration collision: source newer, overwriting destination`,
|
|
134
|
+
meta: { srcPath, destPath, srcMtime, destMtime },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
(0, runtime_1.emitNervesEvent)({
|
|
139
|
+
level: "warn",
|
|
140
|
+
component: "daemon",
|
|
141
|
+
event: "daemon.bundle_migration_collision",
|
|
142
|
+
message: `migration collision: destination newer or equal, keeping destination`,
|
|
143
|
+
meta: { srcPath, destPath, srcMtime, destMtime },
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function bundleMetaHook(ctx) {
|
|
150
|
+
(0, runtime_1.emitNervesEvent)({
|
|
151
|
+
component: "daemon",
|
|
152
|
+
event: "daemon.bundle_meta_hook_start",
|
|
153
|
+
message: "running bundle-meta update hook",
|
|
154
|
+
meta: { agentRoot: ctx.agentRoot, currentVersion: ctx.currentVersion },
|
|
155
|
+
});
|
|
156
|
+
const metaPath = path.join(ctx.agentRoot, "bundle-meta.json");
|
|
157
|
+
let existing;
|
|
158
|
+
try {
|
|
159
|
+
if (fs.existsSync(metaPath)) {
|
|
160
|
+
const raw = fs.readFileSync(metaPath, "utf-8");
|
|
161
|
+
existing = JSON.parse(raw);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Malformed JSON -- treat as missing, will overwrite with fresh
|
|
166
|
+
existing = undefined;
|
|
167
|
+
}
|
|
168
|
+
// Run schema-2 migration if needed
|
|
169
|
+
const currentSchema = existing?.bundleSchemaVersion ?? 1;
|
|
170
|
+
if (currentSchema < 2) {
|
|
171
|
+
migrateToSchema2(ctx.agentRoot);
|
|
172
|
+
}
|
|
173
|
+
const updated = {
|
|
174
|
+
runtimeVersion: ctx.currentVersion,
|
|
175
|
+
bundleSchemaVersion: currentSchema < 2 ? 2 : currentSchema,
|
|
176
|
+
lastUpdated: new Date().toISOString(),
|
|
177
|
+
};
|
|
178
|
+
// Save old runtimeVersion as previousRuntimeVersion (if there was one)
|
|
179
|
+
if (existing?.runtimeVersion) {
|
|
180
|
+
updated.previousRuntimeVersion = existing.runtimeVersion;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
fs.writeFileSync(metaPath, JSON.stringify(updated, null, 2) + "\n", "utf-8");
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
|
|
187
|
+
(0, runtime_1.emitNervesEvent)({
|
|
188
|
+
component: "daemon",
|
|
189
|
+
event: "daemon.bundle_meta_hook_error",
|
|
190
|
+
message: "bundle-meta hook write failed",
|
|
191
|
+
meta: { agentRoot: ctx.agentRoot, error: errorMessage },
|
|
192
|
+
});
|
|
193
|
+
return { ok: false, error: errorMessage };
|
|
194
|
+
}
|
|
195
|
+
(0, runtime_1.emitNervesEvent)({
|
|
196
|
+
component: "daemon",
|
|
197
|
+
event: "daemon.bundle_meta_hook_end",
|
|
198
|
+
message: "bundle-meta updated",
|
|
199
|
+
meta: {
|
|
200
|
+
agentRoot: ctx.agentRoot,
|
|
201
|
+
runtimeVersion: updated.runtimeVersion,
|
|
202
|
+
previousRuntimeVersion: updated.previousRuntimeVersion,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
return { ok: true };
|
|
206
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildInnerStatusOutput = buildInnerStatusOutput;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
function formatRelativeTime(elapsedMs) {
|
|
6
|
+
const minutes = Math.floor(elapsedMs / (60 * 1000));
|
|
7
|
+
if (minutes < 1)
|
|
8
|
+
return "just now";
|
|
9
|
+
if (minutes === 1)
|
|
10
|
+
return "1 minute ago";
|
|
11
|
+
if (minutes < 60)
|
|
12
|
+
return `${minutes} minutes ago`;
|
|
13
|
+
const hours = Math.floor(minutes / 60);
|
|
14
|
+
if (hours === 1)
|
|
15
|
+
return "1 hour ago";
|
|
16
|
+
return `${hours} hours ago`;
|
|
17
|
+
}
|
|
18
|
+
function formatCadence(cadenceMs) {
|
|
19
|
+
const minutes = Math.round(cadenceMs / (60 * 1000));
|
|
20
|
+
if (minutes >= 60) {
|
|
21
|
+
const hours = Math.round(minutes / 60);
|
|
22
|
+
return `${hours}h`;
|
|
23
|
+
}
|
|
24
|
+
return `${minutes}m`;
|
|
25
|
+
}
|
|
26
|
+
function buildInnerStatusOutput(input) {
|
|
27
|
+
const { agentName, runtimeState, journalFiles, heartbeat, attentionCount, now } = input;
|
|
28
|
+
const lines = [];
|
|
29
|
+
lines.push(`inner dialog status: ${agentName}`);
|
|
30
|
+
// Last turn
|
|
31
|
+
if (runtimeState?.lastCompletedAt) {
|
|
32
|
+
const lastMs = new Date(runtimeState.lastCompletedAt).getTime();
|
|
33
|
+
const elapsed = now - lastMs;
|
|
34
|
+
const relativeTime = formatRelativeTime(elapsed);
|
|
35
|
+
const reasonSuffix = runtimeState.reason ? ` (${runtimeState.reason})` : "";
|
|
36
|
+
lines.push(` last turn: ${relativeTime}${reasonSuffix}`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
lines.push(" last turn: unknown");
|
|
40
|
+
}
|
|
41
|
+
// Status
|
|
42
|
+
if (runtimeState) {
|
|
43
|
+
const reasonSuffix = runtimeState.status === "running" && runtimeState.reason ? ` (${runtimeState.reason})` : "";
|
|
44
|
+
lines.push(` status: ${runtimeState.status}${reasonSuffix}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
lines.push(" status: unknown");
|
|
48
|
+
}
|
|
49
|
+
// Heartbeat health
|
|
50
|
+
if (heartbeat && heartbeat.lastCompletedAt !== null) {
|
|
51
|
+
const elapsed = now - heartbeat.lastCompletedAt;
|
|
52
|
+
const threshold = heartbeat.cadenceMs * 1.5;
|
|
53
|
+
const health = elapsed < threshold ? "healthy" : "overdue";
|
|
54
|
+
const cadenceStr = formatCadence(heartbeat.cadenceMs);
|
|
55
|
+
const sinceStr = formatRelativeTime(elapsed);
|
|
56
|
+
lines.push(` heartbeat: ${health} (cadence ${cadenceStr}, ${sinceStr})`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
lines.push(" heartbeat: unknown");
|
|
60
|
+
}
|
|
61
|
+
// Journal
|
|
62
|
+
if (journalFiles.length === 0) {
|
|
63
|
+
lines.push(" journal: (empty)");
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
lines.push(" journal:");
|
|
67
|
+
const sorted = [...journalFiles].sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
68
|
+
for (const file of sorted) {
|
|
69
|
+
const elapsed = now - file.mtimeMs;
|
|
70
|
+
const relativeTime = formatRelativeTime(elapsed);
|
|
71
|
+
lines.push(` - ${file.name} (${relativeTime})`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Attention
|
|
75
|
+
const thoughtWord = attentionCount === 1 ? "thought" : "thoughts";
|
|
76
|
+
lines.push(` attention: ${attentionCount} held ${thoughtWord}`);
|
|
77
|
+
(0, runtime_1.emitNervesEvent)({
|
|
78
|
+
component: "daemon",
|
|
79
|
+
event: "daemon.inner_status_read",
|
|
80
|
+
message: "inner dialog status read",
|
|
81
|
+
meta: {
|
|
82
|
+
agentName,
|
|
83
|
+
status: runtimeState?.status ?? "unknown",
|
|
84
|
+
journalCount: journalFiles.length,
|
|
85
|
+
attentionCount,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|