@ouro.bot/cli 0.1.0-alpha.9 → 0.1.0-alpha.90
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/agent.json +70 -9
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +147 -205
- package/assets/ouroboros.png +0 -0
- package/changelog.json +529 -0
- package/dist/heart/active-work.js +251 -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 +109 -0
- package/dist/heart/config.js +68 -23
- package/dist/heart/core.js +452 -93
- 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 +1737 -269
- 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 +260 -0
- 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 +53 -84
- package/dist/heart/daemon/specialist-prompt.js +63 -11
- 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 +191 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/providers/anthropic.js +74 -9
- package/dist/heart/providers/azure.js +86 -7
- package/dist/heart/providers/github-copilot.js +149 -0
- package/dist/heart/providers/minimax.js +4 -0
- package/dist/heart/providers/openai-codex.js +12 -3
- package/dist/heart/safe-workspace.js +362 -0
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +169 -0
- package/dist/heart/session-recall.js +116 -0
- package/dist/heart/streaming.js +100 -22
- package/dist/heart/target-resolution.js +123 -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 +57 -11
- 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 +31 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +467 -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/feedback.js +180 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +69 -4
- package/dist/repertoire/coding/spawner.js +21 -3
- package/dist/repertoire/coding/tools.js +105 -2
- 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 +714 -249
- 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 +894 -45
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +400 -164
- 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 +377 -83
- package/dist/senses/pipeline.js +307 -0
- package/dist/senses/teams.js +573 -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 -142
- 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
|
@@ -0,0 +1,260 @@
|
|
|
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.installOuroCommand = installOuroCommand;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
+
const WRAPPER_SCRIPT = `#!/bin/sh
|
|
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" "$@"
|
|
48
|
+
`;
|
|
49
|
+
function detectShellProfile(homeDir, shell) {
|
|
50
|
+
if (!shell)
|
|
51
|
+
return null;
|
|
52
|
+
const base = path.basename(shell);
|
|
53
|
+
if (base === "zsh")
|
|
54
|
+
return path.join(homeDir, ".zshrc");
|
|
55
|
+
if (base === "bash") {
|
|
56
|
+
// macOS uses .bash_profile, Linux uses .bashrc
|
|
57
|
+
const profilePath = path.join(homeDir, ".bash_profile");
|
|
58
|
+
return profilePath;
|
|
59
|
+
}
|
|
60
|
+
if (base === "fish")
|
|
61
|
+
return path.join(homeDir, ".config", "fish", "config.fish");
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function isBinDirInPath(binDir, envPath) {
|
|
65
|
+
return envPath.split(path.delimiter).some((p) => p === binDir);
|
|
66
|
+
}
|
|
67
|
+
function buildPathExportLine(binDir, shell) {
|
|
68
|
+
const base = shell ? path.basename(shell) : /* v8 ignore next -- unreachable: only called when detectShellProfile returns non-null, which requires shell @preserve */ "";
|
|
69
|
+
if (base === "fish") {
|
|
70
|
+
return `\n# Added by ouro\nset -gx PATH ${binDir} $PATH\n`;
|
|
71
|
+
}
|
|
72
|
+
return `\n# Added by ouro\nexport PATH="${binDir}:$PATH"\n`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Remove lines matching the old ouro PATH block from shell profile content.
|
|
76
|
+
* Returns the cleaned content.
|
|
77
|
+
*/
|
|
78
|
+
function removeOldPathBlock(content, oldBinDir) {
|
|
79
|
+
const lines = content.split("\n");
|
|
80
|
+
const result = [];
|
|
81
|
+
let i = 0;
|
|
82
|
+
while (i < lines.length) {
|
|
83
|
+
// Detect "# Added by ouro" followed by a PATH export containing the old binDir
|
|
84
|
+
if (lines[i].trim() === "# Added by ouro" && i + 1 < lines.length && lines[i + 1].includes(oldBinDir)) {
|
|
85
|
+
// Skip both lines (comment + export)
|
|
86
|
+
i += 2;
|
|
87
|
+
// Also skip trailing blank line if present
|
|
88
|
+
/* v8 ignore next -- edge: trailing blank line presence varies @preserve */
|
|
89
|
+
if (i < lines.length && lines[i].trim() === "")
|
|
90
|
+
i++;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
result.push(lines[i]);
|
|
94
|
+
i++;
|
|
95
|
+
}
|
|
96
|
+
return result.join("\n");
|
|
97
|
+
}
|
|
98
|
+
function installOuroCommand(deps = {}) {
|
|
99
|
+
/* v8 ignore start -- dep defaults: only used in real runtime, tests always inject @preserve */
|
|
100
|
+
const platform = deps.platform ?? process.platform;
|
|
101
|
+
const homeDir = deps.homeDir ?? os.homedir();
|
|
102
|
+
const existsSync = deps.existsSync ?? fs.existsSync;
|
|
103
|
+
const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
|
|
104
|
+
const writeFileSync = deps.writeFileSync ?? fs.writeFileSync;
|
|
105
|
+
const readFileSync = deps.readFileSync ?? ((p, enc) => fs.readFileSync(p, enc));
|
|
106
|
+
const appendFileSync = deps.appendFileSync ?? fs.appendFileSync;
|
|
107
|
+
const chmodSync = deps.chmodSync ?? fs.chmodSync;
|
|
108
|
+
const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
|
|
109
|
+
const rmdirSync = deps.rmdirSync ?? fs.rmdirSync;
|
|
110
|
+
const readdirSync = deps.readdirSync ?? ((p) => fs.readdirSync(p).map(String));
|
|
111
|
+
const envPath = deps.envPath ?? process.env.PATH ?? "";
|
|
112
|
+
const shell = deps.shell ?? process.env.SHELL;
|
|
113
|
+
/* v8 ignore stop */
|
|
114
|
+
if (platform === "win32") {
|
|
115
|
+
(0, runtime_1.emitNervesEvent)({
|
|
116
|
+
component: "daemon",
|
|
117
|
+
event: "daemon.ouro_path_install_skip",
|
|
118
|
+
message: "skipped ouro PATH install on Windows",
|
|
119
|
+
meta: { platform },
|
|
120
|
+
});
|
|
121
|
+
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: "windows", migratedFromOldPath: false };
|
|
122
|
+
}
|
|
123
|
+
// Ensure ~/.ouro-cli/ directory layout exists
|
|
124
|
+
if (deps.ensureCliLayout) {
|
|
125
|
+
deps.ensureCliLayout();
|
|
126
|
+
}
|
|
127
|
+
const binDir = path.join(homeDir, ".ouro-cli", "bin");
|
|
128
|
+
const scriptPath = path.join(binDir, "ouro");
|
|
129
|
+
// ── Migration from old ~/.local/bin/ouro ──
|
|
130
|
+
const oldBinDir = path.join(homeDir, ".local", "bin");
|
|
131
|
+
const oldScriptPath = path.join(oldBinDir, "ouro");
|
|
132
|
+
let migratedFromOldPath = false;
|
|
133
|
+
if (existsSync(oldScriptPath)) {
|
|
134
|
+
(0, runtime_1.emitNervesEvent)({
|
|
135
|
+
component: "daemon",
|
|
136
|
+
event: "daemon.ouro_path_migrate_start",
|
|
137
|
+
message: "migrating ouro from old PATH location",
|
|
138
|
+
meta: { oldScriptPath },
|
|
139
|
+
});
|
|
140
|
+
try {
|
|
141
|
+
unlinkSync(oldScriptPath);
|
|
142
|
+
migratedFromOldPath = true;
|
|
143
|
+
// Remove empty ~/.local/bin/ directory
|
|
144
|
+
if (existsSync(oldBinDir)) {
|
|
145
|
+
try {
|
|
146
|
+
const remaining = readdirSync(oldBinDir);
|
|
147
|
+
if (remaining.length === 0) {
|
|
148
|
+
rmdirSync(oldBinDir);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Best effort cleanup
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Best effort migration — continue with new install
|
|
158
|
+
}
|
|
159
|
+
// Remove old PATH entry from shell profile
|
|
160
|
+
const profilePath = detectShellProfile(homeDir, shell);
|
|
161
|
+
/* v8 ignore start -- profile cleanup: only fires during migration from old layout @preserve */
|
|
162
|
+
if (profilePath) {
|
|
163
|
+
try {
|
|
164
|
+
const profileContent = readFileSync(profilePath, "utf-8");
|
|
165
|
+
if (profileContent.includes(oldBinDir)) {
|
|
166
|
+
const cleaned = removeOldPathBlock(profileContent, oldBinDir);
|
|
167
|
+
writeFileSync(profilePath, cleaned);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// Best effort profile cleanup
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/* v8 ignore stop */
|
|
175
|
+
}
|
|
176
|
+
(0, runtime_1.emitNervesEvent)({
|
|
177
|
+
component: "daemon",
|
|
178
|
+
event: "daemon.ouro_path_install_start",
|
|
179
|
+
message: "installing ouro command to PATH",
|
|
180
|
+
meta: { scriptPath, binDir },
|
|
181
|
+
});
|
|
182
|
+
// If ouro already exists, check content and repair if stale
|
|
183
|
+
if (existsSync(scriptPath)) {
|
|
184
|
+
let existingContent = "";
|
|
185
|
+
try {
|
|
186
|
+
existingContent = readFileSync(scriptPath, "utf-8");
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// Can't read — treat as stale, will overwrite below
|
|
190
|
+
}
|
|
191
|
+
if (existingContent === WRAPPER_SCRIPT) {
|
|
192
|
+
(0, runtime_1.emitNervesEvent)({
|
|
193
|
+
component: "daemon",
|
|
194
|
+
event: "daemon.ouro_path_install_skip",
|
|
195
|
+
message: "ouro command already installed",
|
|
196
|
+
meta: { scriptPath },
|
|
197
|
+
});
|
|
198
|
+
return { installed: false, scriptPath, pathReady: isBinDirInPath(binDir, envPath), shellProfileUpdated: null, skippedReason: "already-installed", migratedFromOldPath };
|
|
199
|
+
}
|
|
200
|
+
// Content is stale — repair by overwriting
|
|
201
|
+
(0, runtime_1.emitNervesEvent)({
|
|
202
|
+
component: "daemon",
|
|
203
|
+
event: "daemon.ouro_path_install_repair",
|
|
204
|
+
message: "repairing stale ouro wrapper script",
|
|
205
|
+
meta: { scriptPath },
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
mkdirSync(binDir, { recursive: true });
|
|
210
|
+
writeFileSync(scriptPath, WRAPPER_SCRIPT, { mode: 0o755 });
|
|
211
|
+
chmodSync(scriptPath, 0o755);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
(0, runtime_1.emitNervesEvent)({
|
|
215
|
+
level: "warn",
|
|
216
|
+
component: "daemon",
|
|
217
|
+
event: "daemon.ouro_path_install_error",
|
|
218
|
+
message: "failed to install ouro command",
|
|
219
|
+
meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
|
|
220
|
+
});
|
|
221
|
+
return { installed: false, scriptPath: null, pathReady: false, shellProfileUpdated: null, skippedReason: error instanceof Error ? error.message : /* v8 ignore next -- defensive @preserve */ String(error), migratedFromOldPath };
|
|
222
|
+
}
|
|
223
|
+
// Check if ~/.ouro-cli/bin is already in PATH
|
|
224
|
+
let shellProfileUpdated = null;
|
|
225
|
+
const pathReady = isBinDirInPath(binDir, envPath);
|
|
226
|
+
if (!pathReady) {
|
|
227
|
+
const profilePath = detectShellProfile(homeDir, shell);
|
|
228
|
+
if (profilePath) {
|
|
229
|
+
try {
|
|
230
|
+
let existing = "";
|
|
231
|
+
try {
|
|
232
|
+
existing = readFileSync(profilePath, "utf-8");
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Profile doesn't exist yet — that's fine, we'll create it
|
|
236
|
+
}
|
|
237
|
+
if (!existing.includes(binDir)) {
|
|
238
|
+
appendFileSync(profilePath, buildPathExportLine(binDir, shell));
|
|
239
|
+
shellProfileUpdated = profilePath;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
(0, runtime_1.emitNervesEvent)({
|
|
244
|
+
level: "warn",
|
|
245
|
+
component: "daemon",
|
|
246
|
+
event: "daemon.ouro_path_profile_error",
|
|
247
|
+
message: "failed to update shell profile for PATH",
|
|
248
|
+
meta: { profilePath, error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
(0, runtime_1.emitNervesEvent)({
|
|
254
|
+
component: "daemon",
|
|
255
|
+
event: "daemon.ouro_path_install_end",
|
|
256
|
+
message: "ouro command installed",
|
|
257
|
+
meta: { scriptPath, pathReady, shellProfileUpdated },
|
|
258
|
+
});
|
|
259
|
+
return { installed: true, scriptPath, pathReady, shellProfileUpdated, migratedFromOldPath };
|
|
260
|
+
}
|
|
@@ -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)({
|