@ouro.bot/cli 0.1.0-alpha.680 → 0.1.0-alpha.682
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.json +12 -0
- package/dist/heart/agent-entry.js +57 -1
- package/dist/heart/context-loss-sentinel.js +6 -0
- package/dist/heart/daemon/cli-exec.js +3 -0
- package/dist/heart/daemon/daemon.js +6 -3
- package/dist/heart/daemon/process-manager.js +7 -0
- package/dist/heart/start-of-turn-packet.js +4 -1
- package/dist/senses/private-runtime-worker.js +12 -6
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.682",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Buffer private-runtime IPC messages during credential bootstrap so external event wakes are not lost, with coverage for filters and child-process-only disconnect behavior."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.681",
|
|
12
|
+
"changes": [
|
|
13
|
+
"Prevent parked private runtimes from waking during reloads, preserve Whisper machine config, and render temporal recovery context at turn start."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
4
16
|
{
|
|
5
17
|
"version": "0.1.0-alpha.680",
|
|
6
18
|
"changes": [
|
|
@@ -45,6 +45,51 @@ if (!agentName) {
|
|
|
45
45
|
const cli_logging_1 = require("../nerves/cli-logging");
|
|
46
46
|
const runtime_1 = require("../nerves/runtime");
|
|
47
47
|
(0, cli_logging_1.configureCliRuntimeLogger)("self");
|
|
48
|
+
const ipcStateKey = Symbol.for("ouro.agentEntry.ipcState");
|
|
49
|
+
const ipcState = (globalThis[ipcStateKey] ??= {
|
|
50
|
+
bufferedMessages: [],
|
|
51
|
+
installed: false,
|
|
52
|
+
workerMessageHandler: null,
|
|
53
|
+
});
|
|
54
|
+
ipcState.bufferedMessages = [];
|
|
55
|
+
ipcState.workerMessageHandler = null;
|
|
56
|
+
function isRuntimeCredentialBootstrapMessage(message) {
|
|
57
|
+
return !!message
|
|
58
|
+
&& typeof message === "object"
|
|
59
|
+
&& !Array.isArray(message)
|
|
60
|
+
&& message.type === "ouro.runtimeCredentialBootstrap";
|
|
61
|
+
}
|
|
62
|
+
function isPrivateRuntimeWorkMessage(message) {
|
|
63
|
+
if (!message || typeof message !== "object" || Array.isArray(message))
|
|
64
|
+
return false;
|
|
65
|
+
const type = message.type;
|
|
66
|
+
return type === "heartbeat"
|
|
67
|
+
|| type === "habit"
|
|
68
|
+
|| type === "await"
|
|
69
|
+
|| type === "shutdown"
|
|
70
|
+
|| type === "poke"
|
|
71
|
+
|| type === "chat"
|
|
72
|
+
|| type === "message";
|
|
73
|
+
}
|
|
74
|
+
function forwardOrBufferRuntimeMessage(message) {
|
|
75
|
+
if (isRuntimeCredentialBootstrapMessage(message))
|
|
76
|
+
return;
|
|
77
|
+
if (!isPrivateRuntimeWorkMessage(message))
|
|
78
|
+
return;
|
|
79
|
+
if (ipcState.workerMessageHandler) {
|
|
80
|
+
ipcState.workerMessageHandler(message);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
ipcState.bufferedMessages.push(message);
|
|
84
|
+
}
|
|
85
|
+
if (!ipcState.installed) {
|
|
86
|
+
process.on("message", forwardOrBufferRuntimeMessage);
|
|
87
|
+
/* v8 ignore next 3 -- child-process disconnect exits the live worker; default worker listener covers this behavior in process-listener tests @preserve */
|
|
88
|
+
process.on("disconnect", () => {
|
|
89
|
+
process.exit(0);
|
|
90
|
+
});
|
|
91
|
+
ipcState.installed = true;
|
|
92
|
+
}
|
|
48
93
|
(0, runtime_1.emitNervesEvent)({
|
|
49
94
|
component: "senses",
|
|
50
95
|
event: "senses.entry_boot",
|
|
@@ -67,7 +112,18 @@ Promise.resolve().then(() => __importStar(require("./runtime-credentials"))).the
|
|
|
67
112
|
.catch(() => undefined);
|
|
68
113
|
}
|
|
69
114
|
const { startPrivateRuntimeWorker } = await Promise.resolve().then(() => __importStar(require("../senses/private-runtime-worker")));
|
|
70
|
-
|
|
115
|
+
const bufferedMessages = ipcState.bufferedMessages.splice(0);
|
|
116
|
+
const worker = await startPrivateRuntimeWorker({
|
|
117
|
+
attachProcessListeners: false,
|
|
118
|
+
bufferedMessages,
|
|
119
|
+
});
|
|
120
|
+
ipcState.workerMessageHandler = (message) => {
|
|
121
|
+
void worker.handleMessage(message);
|
|
122
|
+
};
|
|
123
|
+
const messagesBufferedDuringStart = ipcState.bufferedMessages.splice(0);
|
|
124
|
+
for (const message of messagesBufferedDuringStart) {
|
|
125
|
+
ipcState.workerMessageHandler(message);
|
|
126
|
+
}
|
|
71
127
|
})
|
|
72
128
|
.catch((error) => {
|
|
73
129
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -864,6 +864,11 @@ function renderSignal(signalEntry) {
|
|
|
864
864
|
return ` - ${signalEntry.status.toUpperCase()} ${signalEntry.id}: ${signalEntry.summary}${repairText}`;
|
|
865
865
|
}
|
|
866
866
|
function formatReceipt(receipt) {
|
|
867
|
+
const blockedGuidance = receipt.verdict === "blocked"
|
|
868
|
+
? receipt.latestReadyLocator
|
|
869
|
+
? "guidance: current latest is blocked; repair blocked signals or use latest-ready before continuing."
|
|
870
|
+
: "guidance: current latest is blocked; repair blocked signals before continuing."
|
|
871
|
+
: null;
|
|
867
872
|
return [
|
|
868
873
|
`Recovery Sentinel - ${receipt.agent}`,
|
|
869
874
|
`generated: ${receipt.generatedAt}`,
|
|
@@ -872,6 +877,7 @@ function formatReceipt(receipt) {
|
|
|
872
877
|
`verdict: ${receipt.verdict}`,
|
|
873
878
|
`latest-ready: ${receipt.latestReadyLocator ?? "unavailable"}`,
|
|
874
879
|
`summary: ${receipt.summary}`,
|
|
880
|
+
...(blockedGuidance ? [blockedGuidance] : []),
|
|
875
881
|
"",
|
|
876
882
|
"Recovery anchor",
|
|
877
883
|
` kind: ${receipt.recoveryAnchor.kind}`,
|
|
@@ -2167,6 +2167,9 @@ async function applyRuntimeChangeToRunningAgent(agent, deps, onProgress, options
|
|
|
2167
2167
|
: { kind: "agent.restart", agent }));
|
|
2168
2168
|
if (!response.ok)
|
|
2169
2169
|
return `daemon restart skipped: ${response.error ?? response.message ?? "unknown daemon error"}`;
|
|
2170
|
+
if (typeof response.message === "string" && response.message.startsWith("restart skipped")) {
|
|
2171
|
+
return response.message;
|
|
2172
|
+
}
|
|
2170
2173
|
const deadline = cliNowMs(deps) + DEFAULT_RUNTIME_APPLY_TIMEOUT_MS;
|
|
2171
2174
|
onProgress?.(`waiting for ${agent} to come back\n- reload request accepted`);
|
|
2172
2175
|
while (cliNowMs(deps) < deadline) {
|
|
@@ -1349,11 +1349,14 @@ class OuroDaemon {
|
|
|
1349
1349
|
if (!this.processManager.restartAgent) {
|
|
1350
1350
|
return { ok: false, error: "Managed agent restart is not available." };
|
|
1351
1351
|
}
|
|
1352
|
-
const
|
|
1353
|
-
.
|
|
1354
|
-
if (!
|
|
1352
|
+
const managedSnapshot = this.processManager.listAgentSnapshots()
|
|
1353
|
+
.find((snapshot) => snapshot.name === command.agent);
|
|
1354
|
+
if (!managedSnapshot) {
|
|
1355
1355
|
return { ok: false, error: `Unknown managed agent '${command.agent}'.` };
|
|
1356
1356
|
}
|
|
1357
|
+
if (managedSnapshot.autoStart === false && managedSnapshot.status === "stopped") {
|
|
1358
|
+
return { ok: true, message: `restart skipped for parked non-autostart agent '${command.agent}'` };
|
|
1359
|
+
}
|
|
1357
1360
|
const restartWork = command.skipConfigCheck === true
|
|
1358
1361
|
? this.processManager.restartAgent(command.agent, { skipConfigCheck: true })
|
|
1359
1362
|
: this.processManager.restartAgent(command.agent);
|
|
@@ -610,6 +610,13 @@ class DaemonProcessManager {
|
|
|
610
610
|
return;
|
|
611
611
|
}
|
|
612
612
|
state.snapshot.lastCrashAt = new Date(now).toISOString();
|
|
613
|
+
if (state.config.autoStart === false) {
|
|
614
|
+
state.snapshot.status = "stopped";
|
|
615
|
+
state.snapshot.errorReason = "non-autostart worker exited unexpectedly; not respawning";
|
|
616
|
+
state.snapshot.fixHint = "Start it explicitly after checking the exit cause.";
|
|
617
|
+
this.notifySnapshotChange(state.snapshot);
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
613
620
|
// Fast-crash detection: if the agent dies within 5 seconds of starting, it's likely
|
|
614
621
|
// a configuration issue (missing credentials, bad provider, etc.) not a transient failure.
|
|
615
622
|
// After 3 consecutive fast crashes, stop retrying and mark as config-failed.
|
|
@@ -263,7 +263,7 @@ function renderStartOfTurnPacket(packet) {
|
|
|
263
263
|
if (tokens <= budget.max)
|
|
264
264
|
break;
|
|
265
265
|
// Skip continuity sections — they are protected.
|
|
266
|
-
if (section.label === "resume" || section.label === "arc" || section.label === "recoverySentinel")
|
|
266
|
+
if (section.label === "resume" || section.label === "arc" || section.label === "recoverySentinel" || section.label === "sessionTiming")
|
|
267
267
|
continue;
|
|
268
268
|
// Remove this section entirely
|
|
269
269
|
const idx = sections.findIndex((s) => s.label === section.label);
|
|
@@ -297,6 +297,9 @@ function formatSections(sections) {
|
|
|
297
297
|
case "recoverySentinel":
|
|
298
298
|
parts.push(`**Recovery Sentinel:**\n${section.content}`);
|
|
299
299
|
break;
|
|
300
|
+
case "sessionTiming":
|
|
301
|
+
parts.push(`**Thread timing:** ${section.content}`);
|
|
302
|
+
break;
|
|
300
303
|
case "obligations":
|
|
301
304
|
parts.push(`**Owed:**\n${section.content}`);
|
|
302
305
|
break;
|
|
@@ -567,12 +567,18 @@ function createPrivateRuntimeWorker(runTurn = (options) => (0, private_runtime_1
|
|
|
567
567
|
}
|
|
568
568
|
return { run, handleMessage };
|
|
569
569
|
}
|
|
570
|
-
async function startPrivateRuntimeWorker() {
|
|
570
|
+
async function startPrivateRuntimeWorker(options = {}) {
|
|
571
571
|
const worker = createPrivateRuntimeWorker();
|
|
572
|
-
|
|
572
|
+
if (options.attachProcessListeners ?? true) {
|
|
573
|
+
process.on("message", (message) => {
|
|
574
|
+
void worker.handleMessage(message);
|
|
575
|
+
});
|
|
576
|
+
process.on("disconnect", () => {
|
|
577
|
+
process.exit(0);
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
for (const message of options.bufferedMessages ?? []) {
|
|
573
581
|
void worker.handleMessage(message);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
process.exit(0);
|
|
577
|
-
});
|
|
582
|
+
}
|
|
583
|
+
return worker;
|
|
578
584
|
}
|