@ouro.bot/cli 0.1.0-alpha.119 → 0.1.0-alpha.120
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
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
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.120",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Daemon startup now kills ALL orphaned ouro processes (daemons AND agents) from previous instances \u2014 fixes stale-version processes handling requests after every update.",
|
|
8
|
+
"Failover error messages no longer contain raw JSON API response bodies. Error messages are sanitized at the source and the failover summary uses clean classification labels only."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.119",
|
|
6
13
|
"changes": [
|
|
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.OuroDaemon = void 0;
|
|
37
|
-
exports.
|
|
37
|
+
exports.killOrphanProcesses = killOrphanProcesses;
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const net = __importStar(require("net"));
|
|
40
40
|
const path = __importStar(require("path"));
|
|
@@ -52,18 +52,21 @@ const pending_1 = require("../../mind/pending");
|
|
|
52
52
|
const channel_1 = require("../../mind/friends/channel");
|
|
53
53
|
const mcp_manager_1 = require("../../repertoire/mcp-manager");
|
|
54
54
|
/**
|
|
55
|
-
* Kill orphaned
|
|
56
|
-
*
|
|
57
|
-
*
|
|
55
|
+
* Kill ALL orphaned ouro processes from previous daemon instances.
|
|
56
|
+
* On each `ouro up`, old daemon AND agent processes persist because:
|
|
57
|
+
* - Daemons are spawned detached and never killed on restart
|
|
58
|
+
* - Each old daemon keeps respawning agents from its own (stale) code
|
|
59
|
+
* This scans for both daemon-entry.js and agent-entry.js processes
|
|
60
|
+
* and kills everything except the current process.
|
|
58
61
|
*/
|
|
59
|
-
/* v8 ignore start -- orphan cleanup: uses ps/kill
|
|
60
|
-
function
|
|
62
|
+
/* v8 ignore start -- orphan cleanup: uses ps/kill, tested via deployment @preserve */
|
|
63
|
+
function killOrphanProcesses() {
|
|
61
64
|
try {
|
|
62
65
|
const myPid = process.pid;
|
|
63
66
|
const result = (0, child_process_1.execSync)("ps -eo pid,command", { encoding: "utf-8", timeout: 5000 });
|
|
64
67
|
const pidsToKill = [];
|
|
65
68
|
for (const line of result.split("\n")) {
|
|
66
|
-
if (!line.includes("agent-entry.js"))
|
|
69
|
+
if (!line.includes("agent-entry.js") && !line.includes("daemon-entry.js"))
|
|
67
70
|
continue;
|
|
68
71
|
const trimmed = line.trim();
|
|
69
72
|
const pid = parseInt(trimmed, 10);
|
|
@@ -81,7 +84,7 @@ function killOrphanAgentProcesses() {
|
|
|
81
84
|
(0, runtime_1.emitNervesEvent)({
|
|
82
85
|
component: "daemon",
|
|
83
86
|
event: "daemon.orphan_cleanup",
|
|
84
|
-
message: `killed ${pidsToKill.length} orphaned
|
|
87
|
+
message: `killed ${pidsToKill.length} orphaned ouro processes`,
|
|
85
88
|
meta: { pids: pidsToKill },
|
|
86
89
|
});
|
|
87
90
|
}
|
|
@@ -91,7 +94,7 @@ function killOrphanAgentProcesses() {
|
|
|
91
94
|
level: "warn",
|
|
92
95
|
component: "daemon",
|
|
93
96
|
event: "daemon.orphan_cleanup_error",
|
|
94
|
-
message: "failed to clean up orphaned
|
|
97
|
+
message: "failed to clean up orphaned ouro processes",
|
|
95
98
|
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
96
99
|
});
|
|
97
100
|
}
|
|
@@ -204,7 +207,7 @@ class OuroDaemon {
|
|
|
204
207
|
// Pre-initialize MCP connections so they're ready for the first command (non-blocking)
|
|
205
208
|
/* v8 ignore next -- catch callback: getSharedMcpManager logs errors internally @preserve */
|
|
206
209
|
(0, mcp_manager_1.getSharedMcpManager)().catch(() => { });
|
|
207
|
-
|
|
210
|
+
killOrphanProcesses();
|
|
208
211
|
await this.processManager.startAutoStartAgents();
|
|
209
212
|
await this.senseManager?.startAutoStartSenses();
|
|
210
213
|
this.scheduler.start?.();
|
|
@@ -19,12 +19,10 @@ const CLASSIFICATION_LABELS = {
|
|
|
19
19
|
"network-error": "is unreachable (network error)",
|
|
20
20
|
"unknown": "encountered an error",
|
|
21
21
|
};
|
|
22
|
-
function buildFailoverContext(
|
|
22
|
+
function buildFailoverContext(_errorMessage, classification, currentProvider, currentModel, agentName, inventory, providerModels) {
|
|
23
23
|
const label = CLASSIFICATION_LABELS[classification];
|
|
24
24
|
const providerWithModel = currentModel ? `${currentProvider} (${currentModel})` : currentProvider;
|
|
25
|
-
const errorSummary =
|
|
26
|
-
? `${providerWithModel} ${label} (${errorMessage})`
|
|
27
|
-
: `${providerWithModel} ${label}`;
|
|
25
|
+
const errorSummary = `${providerWithModel} ${label}`;
|
|
28
26
|
const workingProviders = [];
|
|
29
27
|
const unconfiguredProviders = [];
|
|
30
28
|
const failingProviders = [];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeErrorMessage = sanitizeErrorMessage;
|
|
3
4
|
exports.pingProvider = pingProvider;
|
|
4
5
|
exports.runHealthInventory = runHealthInventory;
|
|
5
6
|
const anthropic_1 = require("./providers/anthropic");
|
|
@@ -10,6 +11,28 @@ const github_copilot_1 = require("./providers/github-copilot");
|
|
|
10
11
|
const auth_flow_1 = require("./daemon/auth-flow");
|
|
11
12
|
const runtime_1 = require("../nerves/runtime");
|
|
12
13
|
const PING_TIMEOUT_MS = 10_000;
|
|
14
|
+
/**
|
|
15
|
+
* Strip raw JSON API response bodies from error messages.
|
|
16
|
+
* SDK errors often include the full response body: "400 {"type":"error","error":...}".
|
|
17
|
+
* Extract just the HTTP status prefix or a short summary.
|
|
18
|
+
*/
|
|
19
|
+
function sanitizeErrorMessage(message) {
|
|
20
|
+
// Match "NNN {json...}" pattern — keep the status code, drop the JSON
|
|
21
|
+
const match = message.match(/^(\d{3})\s*\{/);
|
|
22
|
+
if (match) {
|
|
23
|
+
// Try to extract the inner message from the JSON
|
|
24
|
+
try {
|
|
25
|
+
const json = JSON.parse(message.slice(match[1].length).trim());
|
|
26
|
+
const inner = json?.error?.message;
|
|
27
|
+
if (typeof inner === "string" && inner && inner !== "Error") {
|
|
28
|
+
return `${match[1]} ${inner}`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch { /* not valid JSON, fall through */ }
|
|
32
|
+
return `HTTP ${match[1]}`;
|
|
33
|
+
}
|
|
34
|
+
return message;
|
|
35
|
+
}
|
|
13
36
|
function hasEmptyCredentials(provider, config) {
|
|
14
37
|
switch (provider) {
|
|
15
38
|
case "anthropic":
|
|
@@ -106,7 +129,7 @@ async function pingProvider(provider, config) {
|
|
|
106
129
|
message: `provider ping failed: ${provider}`,
|
|
107
130
|
meta: { provider, classification, error: err.message },
|
|
108
131
|
});
|
|
109
|
-
return { ok: false, classification, message: err.message };
|
|
132
|
+
return { ok: false, classification, message: sanitizeErrorMessage(err.message) };
|
|
110
133
|
}
|
|
111
134
|
}
|
|
112
135
|
const PINGABLE_PROVIDERS = ["anthropic", "openai-codex", "azure", "minimax", "github-copilot"];
|