@ouro.bot/cli 0.1.0-alpha.11 → 0.1.0-alpha.111
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 +147 -205
- package/assets/ouroboros.png +0 -0
- package/changelog.json +672 -0
- package/dist/heart/active-work.js +622 -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 +68 -23
- package/dist/heart/core.js +492 -96
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/auth-flow.js +430 -0
- package/dist/heart/daemon/daemon-cli.js +1711 -208
- package/dist/heart/daemon/daemon-entry.js +55 -6
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon.js +216 -10
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +7 -82
- 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/message-router.js +17 -8
- package/dist/heart/daemon/ouro-bot-entry.js +0 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-entry.js +0 -0
- package/dist/heart/daemon/ouro-path-installer.js +59 -15
- package/dist/heart/daemon/ouro-uti.js +11 -2
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/process-manager.js +14 -1
- 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 +307 -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 +37 -94
- package/dist/heart/daemon/specialist-prompt.js +50 -12
- package/dist/heart/daemon/specialist-tools.js +211 -60
- 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 +126 -21
- package/dist/heart/kicks.js +1 -19
- 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/providers/anthropic.js +74 -9
- package/dist/heart/providers/azure.js +87 -8
- package/dist/heart/providers/github-copilot.js +149 -0
- package/dist/heart/providers/minimax.js +5 -1
- package/dist/heart/providers/openai-codex.js +13 -4
- package/dist/heart/safe-workspace.js +381 -0
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +169 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/streaming.js +108 -24
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/tool-loop.js +194 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +14 -2
- package/dist/mind/bundle-manifest.js +70 -0
- package/dist/mind/context.js +60 -14
- 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/memory.js +27 -26
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +527 -77
- 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/repertoire/ado-client.js +4 -2
- 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 +39 -9
- package/dist/repertoire/coding/tools.js +171 -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 +195 -0
- package/dist/repertoire/skills.js +3 -26
- 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 +925 -250
- package/dist/repertoire/tools-bluebubbles.js +93 -0
- package/dist/repertoire/tools-teams.js +58 -25
- package/dist/repertoire/tools.js +106 -53
- 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 +900 -45
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +448 -170
- 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 +388 -83
- package/dist/senses/pipeline.js +334 -0
- package/dist/senses/teams.js +577 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +14 -3
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/specialist-session.js +0 -177
- 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
|
@@ -39,7 +39,12 @@ const os = __importStar(require("os"));
|
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
41
|
const WRAPPER_SCRIPT = `#!/bin/sh
|
|
42
|
-
|
|
42
|
+
ENTRY="$HOME/.ouro-cli/CurrentVersion/node_modules/@ouro.bot/cli/dist/heart/daemon/ouro-entry.js"
|
|
43
|
+
if [ ! -e "$ENTRY" ]; then
|
|
44
|
+
echo "ouro not installed. Run: npx ouro.bot" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
exec node "$ENTRY" "$@"
|
|
43
48
|
`;
|
|
44
49
|
function detectShellProfile(homeDir, shell) {
|
|
45
50
|
if (!shell)
|
|
@@ -66,6 +71,16 @@ function buildPathExportLine(binDir, shell) {
|
|
|
66
71
|
}
|
|
67
72
|
return `\n# Added by ouro\nexport PATH="${binDir}:$PATH"\n`;
|
|
68
73
|
}
|
|
74
|
+
function isWrapperCurrent(scriptPath, existsSync, readFileSync) {
|
|
75
|
+
if (!existsSync(scriptPath))
|
|
76
|
+
return false;
|
|
77
|
+
try {
|
|
78
|
+
return readFileSync(scriptPath, "utf-8") === WRAPPER_SCRIPT;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
69
84
|
function installOuroCommand(deps = {}) {
|
|
70
85
|
/* v8 ignore start -- dep defaults: only used in real runtime, tests always inject @preserve */
|
|
71
86
|
const platform = deps.platform ?? process.platform;
|
|
@@ -86,26 +101,55 @@ function installOuroCommand(deps = {}) {
|
|
|
86
101
|
message: "skipped ouro PATH install on Windows",
|
|
87
102
|
meta: { platform },
|
|
88
103
|
});
|
|
89
|
-
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows" };
|
|
104
|
+
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows", repairedOldLauncher: false };
|
|
105
|
+
}
|
|
106
|
+
// Ensure ~/.ouro-cli/ directory layout exists
|
|
107
|
+
if (deps.ensureCliLayout) {
|
|
108
|
+
deps.ensureCliLayout();
|
|
90
109
|
}
|
|
91
|
-
const binDir = path.join(homeDir, ".
|
|
110
|
+
const binDir = path.join(homeDir, ".ouro-cli", "bin");
|
|
92
111
|
const scriptPath = path.join(binDir, "ouro");
|
|
93
|
-
(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
//
|
|
100
|
-
|
|
112
|
+
const oldScriptPath = path.join(homeDir, ".local", "bin", "ouro");
|
|
113
|
+
const modernCurrent = isWrapperCurrent(scriptPath, existsSync, readFileSync);
|
|
114
|
+
const oldExists = existsSync(oldScriptPath);
|
|
115
|
+
const oldCurrent = oldExists && isWrapperCurrent(oldScriptPath, existsSync, readFileSync);
|
|
116
|
+
// ── Repair old ~/.local/bin/ouro launcher ──
|
|
117
|
+
// If the old launcher exists with stale content it can shadow the modern
|
|
118
|
+
// path and cause the wrong CLI version to run. Overwrite it with the
|
|
119
|
+
// current wrapper so both paths resolve to ~/.ouro-cli/CurrentVersion.
|
|
120
|
+
let repairedOldLauncher = false;
|
|
121
|
+
if (oldExists && !oldCurrent) {
|
|
122
|
+
(0, runtime_1.emitNervesEvent)({
|
|
123
|
+
component: "daemon",
|
|
124
|
+
event: "daemon.ouro_path_repair_old",
|
|
125
|
+
message: "repairing stale old launcher at ~/.local/bin/ouro",
|
|
126
|
+
meta: { oldScriptPath },
|
|
127
|
+
});
|
|
128
|
+
try {
|
|
129
|
+
writeFileSync(oldScriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
130
|
+
chmodSync(oldScriptPath, 0o755);
|
|
131
|
+
repairedOldLauncher = true;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Best effort — old launcher repair failure must not block modern install
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// ── Fast-path: modern wrapper already current ──
|
|
138
|
+
if (modernCurrent) {
|
|
101
139
|
(0, runtime_1.emitNervesEvent)({
|
|
102
140
|
component: "daemon",
|
|
103
141
|
event: "daemon.ouro_path_install_skip",
|
|
104
142
|
message: "ouro command already installed",
|
|
105
143
|
meta: { scriptPath },
|
|
106
144
|
});
|
|
107
|
-
return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed" };
|
|
145
|
+
return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed", repairedOldLauncher };
|
|
108
146
|
}
|
|
147
|
+
(0, runtime_1.emitNervesEvent)({
|
|
148
|
+
component: "daemon",
|
|
149
|
+
event: "daemon.ouro_path_install_start",
|
|
150
|
+
message: existsSync(scriptPath) ? "repairing stale ouro wrapper script" : "installing ouro command to PATH",
|
|
151
|
+
meta: { scriptPath, binDir },
|
|
152
|
+
});
|
|
109
153
|
try {
|
|
110
154
|
mkdirSync(binDir, { recursive: true });
|
|
111
155
|
writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
@@ -119,9 +163,9 @@ function installOuroCommand(deps = {}) {
|
|
|
119
163
|
message: "failed to install ouro command",
|
|
120
164
|
meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
|
|
121
165
|
});
|
|
122
|
-
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error) };
|
|
166
|
+
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error), repairedOldLauncher };
|
|
123
167
|
}
|
|
124
|
-
// Check if ~/.
|
|
168
|
+
// Check if ~/.ouro-cli/bin is already in PATH
|
|
125
169
|
let shellProfileUpdated = null;
|
|
126
170
|
const pathReady = isBinDirInPath(binDir, envPath);
|
|
127
171
|
if (!pathReady) {
|
|
@@ -157,5 +201,5 @@ function installOuroCommand(deps = {}) {
|
|
|
157
201
|
message: "ouro command installed",
|
|
158
202
|
meta: { scriptPath, pathReady, shellProfileUpdated },
|
|
159
203
|
});
|
|
160
|
-
return { installed: true, scriptPath, pathReady, shellProfileUpdated };
|
|
204
|
+
return { installed: true, scriptPath, pathReady, shellProfileUpdated, repairedOldLauncher };
|
|
161
205
|
}
|
|
@@ -42,7 +42,13 @@ const identity_1 = require("../identity");
|
|
|
42
42
|
const runtime_1 = require("../../nerves/runtime");
|
|
43
43
|
const LSREGISTER_PATH = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister";
|
|
44
44
|
const ICON_SIZES = [16, 32, 128, 256, 512];
|
|
45
|
-
function resolveIconSourcePath(repoRoot) {
|
|
45
|
+
function resolveIconSourcePath(repoRoot, existsSync) {
|
|
46
|
+
// Prefer bundled asset (shipped with npm package)
|
|
47
|
+
const bundledPath = path.resolve(repoRoot, "assets", "ouroboros.png");
|
|
48
|
+
if (existsSync(bundledPath)) {
|
|
49
|
+
return bundledPath;
|
|
50
|
+
}
|
|
51
|
+
// Fall back to adjacent repo path (dev environment)
|
|
46
52
|
return path.resolve(repoRoot, "..", "ouroboros-website", "public", "images", "ouroboros.png");
|
|
47
53
|
}
|
|
48
54
|
function buildIconAsset(iconSourcePath, icnsPath, iconsetDir, deps) {
|
|
@@ -91,6 +97,7 @@ function buildInfoPlist(iconInstalled) {
|
|
|
91
97
|
" <key>UTTypeConformsTo</key>",
|
|
92
98
|
" <array>",
|
|
93
99
|
" <string>public.folder</string>",
|
|
100
|
+
" <string>com.apple.package</string>",
|
|
94
101
|
" </array>",
|
|
95
102
|
" <key>UTTypeTagSpecification</key>",
|
|
96
103
|
" <dict>",
|
|
@@ -112,6 +119,8 @@ function buildInfoPlist(iconInstalled) {
|
|
|
112
119
|
" </array>",
|
|
113
120
|
" <key>CFBundleTypeRole</key>",
|
|
114
121
|
" <string>Editor</string>",
|
|
122
|
+
" <key>LSTypeIsPackage</key>",
|
|
123
|
+
" <true/>",
|
|
115
124
|
` ${iconTag.trim()}`,
|
|
116
125
|
" </dict>",
|
|
117
126
|
" </array>",
|
|
@@ -152,7 +161,7 @@ function registerOuroBundleUti(deps = {}) {
|
|
|
152
161
|
const plistPath = path.join(contentsDir, "Info.plist");
|
|
153
162
|
const icnsPath = path.join(resourcesDir, "ouro.icns");
|
|
154
163
|
const iconsetDir = path.join(supportRoot, "ouro.iconset");
|
|
155
|
-
const iconSourcePath = resolveIconSourcePath(repoRoot);
|
|
164
|
+
const iconSourcePath = resolveIconSourcePath(repoRoot, existsSync);
|
|
156
165
|
(0, runtime_1.emitNervesEvent)({
|
|
157
166
|
component: "daemon",
|
|
158
167
|
event: "daemon.ouro_uti_register_start",
|
|
@@ -0,0 +1,171 @@
|
|
|
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.getOuroCliHome = getOuroCliHome;
|
|
37
|
+
exports.getCurrentVersion = getCurrentVersion;
|
|
38
|
+
exports.getPreviousVersion = getPreviousVersion;
|
|
39
|
+
exports.buildChangelogCommand = buildChangelogCommand;
|
|
40
|
+
exports.listInstalledVersions = listInstalledVersions;
|
|
41
|
+
exports.installVersion = installVersion;
|
|
42
|
+
exports.activateVersion = activateVersion;
|
|
43
|
+
exports.ensureLayout = ensureLayout;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
48
|
+
function getOuroCliHome(homeDir) {
|
|
49
|
+
/* v8 ignore next -- dep default: tests always inject @preserve */
|
|
50
|
+
const home = homeDir ?? os.homedir();
|
|
51
|
+
return path.join(home, ".ouro-cli");
|
|
52
|
+
}
|
|
53
|
+
function getCurrentVersion(deps) {
|
|
54
|
+
const cliHome = getOuroCliHome(deps.homeDir);
|
|
55
|
+
/* v8 ignore next -- dep default: tests always inject @preserve */
|
|
56
|
+
const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
|
|
57
|
+
try {
|
|
58
|
+
const target = readlinkSync(path.join(cliHome, "CurrentVersion"));
|
|
59
|
+
return path.basename(target);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function getPreviousVersion(deps) {
|
|
66
|
+
const cliHome = getOuroCliHome(deps.homeDir);
|
|
67
|
+
/* v8 ignore next -- dep default: tests always inject @preserve */
|
|
68
|
+
const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
|
|
69
|
+
try {
|
|
70
|
+
const target = readlinkSync(path.join(cliHome, "previous"));
|
|
71
|
+
return path.basename(target);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function buildChangelogCommand(previousVersion, currentVersion) {
|
|
78
|
+
if (!previousVersion || !currentVersion || previousVersion === currentVersion) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return `ouro changelog --from ${previousVersion}`;
|
|
82
|
+
}
|
|
83
|
+
function listInstalledVersions(deps) {
|
|
84
|
+
const cliHome = getOuroCliHome(deps.homeDir);
|
|
85
|
+
/* v8 ignore next -- dep default: tests always inject @preserve */
|
|
86
|
+
const readdirSync = deps.readdirSync ?? ((p, opts) => fs.readdirSync(p, opts));
|
|
87
|
+
try {
|
|
88
|
+
const entries = readdirSync(path.join(cliHome, "versions"), { withFileTypes: true });
|
|
89
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function installVersion(version, deps) {
|
|
96
|
+
const cliHome = getOuroCliHome(deps.homeDir);
|
|
97
|
+
/* v8 ignore start -- dep defaults: tests always inject @preserve */
|
|
98
|
+
const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
|
|
99
|
+
const execSync = deps.execSync ?? ((cmd, opts) => require("child_process").execSync(cmd, opts));
|
|
100
|
+
/* v8 ignore stop */
|
|
101
|
+
const versionDir = path.join(cliHome, "versions", version);
|
|
102
|
+
(0, runtime_1.emitNervesEvent)({
|
|
103
|
+
component: "daemon",
|
|
104
|
+
event: "daemon.cli_version_install_start",
|
|
105
|
+
message: "installing CLI version",
|
|
106
|
+
meta: { version, versionDir },
|
|
107
|
+
});
|
|
108
|
+
mkdirSync(versionDir, { recursive: true });
|
|
109
|
+
execSync(`npm install --prefix ${versionDir} @ouro.bot/cli@${version}`, { stdio: "pipe" });
|
|
110
|
+
(0, runtime_1.emitNervesEvent)({
|
|
111
|
+
component: "daemon",
|
|
112
|
+
event: "daemon.cli_version_install_end",
|
|
113
|
+
message: "CLI version installed",
|
|
114
|
+
meta: { version, versionDir },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function activateVersion(version, deps) {
|
|
118
|
+
const cliHome = getOuroCliHome(deps.homeDir);
|
|
119
|
+
/* v8 ignore start -- dep defaults: tests always inject @preserve */
|
|
120
|
+
const readlinkSync = deps.readlinkSync ?? fs.readlinkSync;
|
|
121
|
+
const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
|
|
122
|
+
const symlinkSync = deps.symlinkSync ?? fs.symlinkSync;
|
|
123
|
+
const existsSync = deps.existsSync ?? fs.existsSync;
|
|
124
|
+
/* v8 ignore stop */
|
|
125
|
+
const currentVersionPath = path.join(cliHome, "CurrentVersion");
|
|
126
|
+
const previousPath = path.join(cliHome, "previous");
|
|
127
|
+
const newTarget = path.join(cliHome, "versions", version);
|
|
128
|
+
(0, runtime_1.emitNervesEvent)({
|
|
129
|
+
component: "daemon",
|
|
130
|
+
event: "daemon.cli_version_activate",
|
|
131
|
+
message: "activating CLI version",
|
|
132
|
+
meta: { version },
|
|
133
|
+
});
|
|
134
|
+
// Read old CurrentVersion target (may not exist)
|
|
135
|
+
let oldTarget = null;
|
|
136
|
+
try {
|
|
137
|
+
oldTarget = readlinkSync(currentVersionPath);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// No current version — first install
|
|
141
|
+
}
|
|
142
|
+
// Update previous symlink to point to old current
|
|
143
|
+
if (oldTarget) {
|
|
144
|
+
try {
|
|
145
|
+
unlinkSync(previousPath);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// previous symlink may not exist yet
|
|
149
|
+
}
|
|
150
|
+
symlinkSync(oldTarget, previousPath);
|
|
151
|
+
}
|
|
152
|
+
// Update CurrentVersion symlink
|
|
153
|
+
if (existsSync(currentVersionPath)) {
|
|
154
|
+
unlinkSync(currentVersionPath);
|
|
155
|
+
}
|
|
156
|
+
symlinkSync(newTarget, currentVersionPath);
|
|
157
|
+
}
|
|
158
|
+
function ensureLayout(deps) {
|
|
159
|
+
const cliHome = getOuroCliHome(deps.homeDir);
|
|
160
|
+
/* v8 ignore next -- dep default: tests always inject @preserve */
|
|
161
|
+
const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
|
|
162
|
+
mkdirSync(cliHome, { recursive: true });
|
|
163
|
+
mkdirSync(path.join(cliHome, "bin"), { recursive: true });
|
|
164
|
+
mkdirSync(path.join(cliHome, "versions"), { recursive: true });
|
|
165
|
+
(0, runtime_1.emitNervesEvent)({
|
|
166
|
+
component: "daemon",
|
|
167
|
+
event: "daemon.cli_layout_ensured",
|
|
168
|
+
message: "CLI directory layout ensured",
|
|
169
|
+
meta: { cliHome },
|
|
170
|
+
});
|
|
171
|
+
}
|
|
@@ -51,6 +51,7 @@ class DaemonProcessManager {
|
|
|
51
51
|
now;
|
|
52
52
|
setTimeoutFn;
|
|
53
53
|
clearTimeoutFn;
|
|
54
|
+
existsSyncFn;
|
|
54
55
|
constructor(options) {
|
|
55
56
|
this.maxRestartsPerHour = options.maxRestartsPerHour ?? 10;
|
|
56
57
|
this.stabilityThresholdMs = options.stabilityThresholdMs ?? 60_000;
|
|
@@ -60,6 +61,7 @@ class DaemonProcessManager {
|
|
|
60
61
|
this.now = options.now ?? (() => Date.now());
|
|
61
62
|
this.setTimeoutFn = options.setTimeoutFn ?? ((cb, delay) => setTimeout(cb, delay));
|
|
62
63
|
this.clearTimeoutFn = options.clearTimeoutFn ?? ((timer) => clearTimeout(timer));
|
|
64
|
+
this.existsSyncFn = options.existsSync ?? null;
|
|
63
65
|
for (const agent of options.agents) {
|
|
64
66
|
this.agents.set(agent.name, {
|
|
65
67
|
config: agent,
|
|
@@ -96,7 +98,18 @@ class DaemonProcessManager {
|
|
|
96
98
|
state.snapshot.status = "starting";
|
|
97
99
|
const runCwd = (0, identity_1.getRepoRoot)();
|
|
98
100
|
const entryScript = path.join((0, identity_1.getRepoRoot)(), "dist", state.config.entry);
|
|
99
|
-
|
|
101
|
+
if (this.existsSyncFn && !this.existsSyncFn(entryScript)) {
|
|
102
|
+
state.snapshot.status = "crashed";
|
|
103
|
+
(0, runtime_1.emitNervesEvent)({
|
|
104
|
+
level: "error",
|
|
105
|
+
component: "daemon",
|
|
106
|
+
event: "daemon.agent_entry_missing",
|
|
107
|
+
message: "agent entry script does not exist — cannot spawn. Run 'ouro daemon install' from the correct location.",
|
|
108
|
+
meta: { agent, entryScript },
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const args = [entryScript, "--agent", state.config.agentArg ?? agent, ...(state.config.args ?? [])];
|
|
100
113
|
const child = this.spawnFn("node", args, {
|
|
101
114
|
cwd: runCwd,
|
|
102
115
|
env: state.config.env ? { ...process.env, ...state.config.env } : process.env,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runHooks = runHooks;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
const bundle_meta_1 = require("./hooks/bundle-meta");
|
|
6
|
+
async function runHooks(deps) {
|
|
7
|
+
(0, runtime_1.emitNervesEvent)({
|
|
8
|
+
component: "daemon",
|
|
9
|
+
event: "daemon.run_hooks_start",
|
|
10
|
+
message: "running update hooks",
|
|
11
|
+
meta: { bundlesRoot: deps.bundlesRoot },
|
|
12
|
+
});
|
|
13
|
+
try {
|
|
14
|
+
deps.registerUpdateHook(bundle_meta_1.bundleMetaHook);
|
|
15
|
+
const currentVersion = deps.getPackageVersion();
|
|
16
|
+
await deps.applyPendingUpdates(deps.bundlesRoot, currentVersion);
|
|
17
|
+
(0, runtime_1.emitNervesEvent)({
|
|
18
|
+
component: "daemon",
|
|
19
|
+
event: "daemon.run_hooks_success",
|
|
20
|
+
message: "update hooks completed successfully",
|
|
21
|
+
meta: { bundlesRoot: deps.bundlesRoot },
|
|
22
|
+
});
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
(0, runtime_1.emitNervesEvent)({
|
|
27
|
+
component: "daemon",
|
|
28
|
+
event: "daemon.run_hooks_error",
|
|
29
|
+
message: "update hooks failed",
|
|
30
|
+
meta: {
|
|
31
|
+
bundlesRoot: deps.bundlesRoot,
|
|
32
|
+
error: err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -35,52 +35,95 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.configureDaemonRuntimeLogger = configureDaemonRuntimeLogger;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
|
-
const os = __importStar(require("os"));
|
|
39
38
|
const path = __importStar(require("path"));
|
|
40
39
|
const nerves_1 = require("../../nerves");
|
|
41
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
42
|
-
const
|
|
41
|
+
const identity_1 = require("../identity");
|
|
42
|
+
const LEGACY_SHARED_RUNTIME_LOGGING = {
|
|
43
43
|
level: "info",
|
|
44
44
|
sinks: ["terminal", "ndjson"],
|
|
45
45
|
};
|
|
46
|
-
function
|
|
47
|
-
|
|
46
|
+
function defaultLoggingForProcess(processName) {
|
|
47
|
+
if (processName === "ouro" || processName === "ouro-bot") {
|
|
48
|
+
return {
|
|
49
|
+
level: "info",
|
|
50
|
+
sinks: ["ndjson"],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (processName === "bluebubbles") {
|
|
54
|
+
return {
|
|
55
|
+
level: "warn",
|
|
56
|
+
sinks: ["terminal", "ndjson"],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return { ...LEGACY_SHARED_RUNTIME_LOGGING };
|
|
48
60
|
}
|
|
49
61
|
function isLogLevel(value) {
|
|
50
62
|
return value === "debug" || value === "info" || value === "warn" || value === "error";
|
|
51
63
|
}
|
|
64
|
+
function normalizeSinks(value, fallback) {
|
|
65
|
+
if (!Array.isArray(value)) {
|
|
66
|
+
return [...fallback];
|
|
67
|
+
}
|
|
68
|
+
const sinks = value.filter((entry) => entry === "terminal" || entry === "ndjson");
|
|
69
|
+
return sinks.length > 0 ? [...new Set(sinks)] : [...fallback];
|
|
70
|
+
}
|
|
71
|
+
function isLegacySharedDefaultConfig(candidate, normalizedLevel, normalizedSinks) {
|
|
72
|
+
return normalizedLevel === LEGACY_SHARED_RUNTIME_LOGGING.level
|
|
73
|
+
&& normalizedSinks.length === LEGACY_SHARED_RUNTIME_LOGGING.sinks.length
|
|
74
|
+
&& LEGACY_SHARED_RUNTIME_LOGGING.sinks.every((sink) => normalizedSinks.includes(sink))
|
|
75
|
+
&& Object.keys(candidate).every((key) => key === "level" || key === "sinks");
|
|
76
|
+
}
|
|
52
77
|
function resolveRuntimeLoggingConfig(configPath, processName) {
|
|
53
|
-
const
|
|
78
|
+
const processDefault = defaultLoggingForProcess(processName);
|
|
54
79
|
let parsed = null;
|
|
55
80
|
try {
|
|
56
81
|
const raw = fs.readFileSync(configPath, "utf-8");
|
|
57
82
|
parsed = JSON.parse(raw);
|
|
58
83
|
}
|
|
59
84
|
catch {
|
|
60
|
-
return { ...
|
|
85
|
+
return { ...processDefault };
|
|
61
86
|
}
|
|
62
87
|
if (!parsed || typeof parsed !== "object") {
|
|
63
|
-
return { ...
|
|
88
|
+
return { ...processDefault };
|
|
64
89
|
}
|
|
65
90
|
const candidate = parsed;
|
|
66
|
-
const level = isLogLevel(candidate.level) ? candidate.level :
|
|
67
|
-
const sinks =
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
const level = isLogLevel(candidate.level) ? candidate.level : processDefault.level;
|
|
92
|
+
const sinks = normalizeSinks(candidate.sinks, processDefault.sinks);
|
|
93
|
+
if ((processName === "ouro" || processName === "ouro-bot")
|
|
94
|
+
&& isLegacySharedDefaultConfig(candidate, level, sinks)) {
|
|
95
|
+
return { ...processDefault };
|
|
96
|
+
}
|
|
70
97
|
return {
|
|
71
98
|
level,
|
|
72
|
-
sinks
|
|
99
|
+
sinks,
|
|
73
100
|
};
|
|
74
101
|
}
|
|
102
|
+
function resolveAgentNameForPaths(explicit) {
|
|
103
|
+
if (explicit && explicit.trim().length > 0)
|
|
104
|
+
return explicit.trim();
|
|
105
|
+
try {
|
|
106
|
+
return (0, identity_1.getAgentName)();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return "slugger";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
75
112
|
function configureDaemonRuntimeLogger(processName, options = {}) {
|
|
76
|
-
const
|
|
77
|
-
const configPath = options.configPath
|
|
113
|
+
const agentName = resolveAgentNameForPaths(options.agentName);
|
|
114
|
+
const configPath = options.configPath
|
|
115
|
+
?? (options.homeDir
|
|
116
|
+
? path.join(options.homeDir, "AgentBundles", `${agentName}.ouro`, "state", "daemon", "logging.json")
|
|
117
|
+
: (0, identity_1.getAgentDaemonLoggingConfigPath)(agentName));
|
|
78
118
|
const config = resolveRuntimeLoggingConfig(configPath, processName);
|
|
119
|
+
const logsDir = options.homeDir
|
|
120
|
+
? path.join(options.homeDir, "AgentBundles", `${agentName}.ouro`, "state", "daemon", "logs")
|
|
121
|
+
: (0, identity_1.getAgentDaemonLogsDir)(agentName);
|
|
79
122
|
const sinks = config.sinks.map((sinkName) => {
|
|
80
123
|
if (sinkName === "terminal") {
|
|
81
124
|
return (0, nerves_1.createTerminalSink)();
|
|
82
125
|
}
|
|
83
|
-
const ndjsonPath = path.join(
|
|
126
|
+
const ndjsonPath = path.join(logsDir, `${processName}.ndjson`);
|
|
84
127
|
return (0, nerves_1.createNdjsonFileSink)(ndjsonPath);
|
|
85
128
|
});
|
|
86
129
|
const logger = (0, nerves_1.createLogger)({
|