@ouro.bot/cli 0.1.0-alpha.1 → 0.1.0-alpha.100
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 +596 -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 +102 -23
- package/dist/heart/core.js +512 -94
- 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 +1935 -185
- 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 +218 -9
- package/dist/heart/daemon/hatch-animation.js +35 -0
- package/dist/heart/daemon/hatch-flow.js +10 -83
- package/dist/heart/daemon/hatch-specialist.js +6 -1
- 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 +147 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron.js +260 -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 +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 +32 -2
- package/dist/heart/daemon/run-hooks.js +37 -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/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 +129 -0
- package/dist/heart/daemon/specialist-prompt.js +99 -0
- package/dist/heart/daemon/specialist-tools.js +283 -0
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/task-scheduler.js +4 -1
- 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 +153 -23
- 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 +77 -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 +381 -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 +103 -22
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +37 -4
- package/dist/mind/bundle-manifest.js +70 -0
- package/dist/mind/context.js +141 -11
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +43 -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 +9 -1
- package/dist/mind/memory.js +89 -26
- package/dist/mind/obligation-steering.js +31 -0
- package/dist/mind/pending.js +160 -0
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt-refresh.js +20 -0
- package/dist/mind/prompt.js +499 -8
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/file-completeness.js +14 -4
- 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 +210 -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 +770 -213
- 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 +484 -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 +1181 -0
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +452 -99
- 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 +387 -70
- package/dist/senses/pipeline.js +307 -0
- package/dist/senses/session-lock.js +119 -0
- package/dist/senses/teams.js +574 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +16 -4
- package/subagents/README.md +4 -68
- 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 -593
- 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.CrontabCronManager = exports.LaunchdCronManager = void 0;
|
|
37
|
+
exports.createOsCronManager = createOsCronManager;
|
|
38
|
+
exports.cadenceToSeconds = cadenceToSeconds;
|
|
39
|
+
exports.scheduleToCalendarInterval = scheduleToCalendarInterval;
|
|
40
|
+
exports.generatePlistXml = generatePlistXml;
|
|
41
|
+
exports.plistLabel = plistLabel;
|
|
42
|
+
exports.crontabLine = crontabLine;
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
45
|
+
const PLIST_PREFIX = "bot.ouro.";
|
|
46
|
+
function plistLabel(job) {
|
|
47
|
+
return `${PLIST_PREFIX}${job.agent}.${job.taskId}`;
|
|
48
|
+
}
|
|
49
|
+
function cadenceToSeconds(schedule) {
|
|
50
|
+
const parts = schedule.trim().split(/\s+/);
|
|
51
|
+
if (parts.length !== 5)
|
|
52
|
+
return null;
|
|
53
|
+
const [minute, hour, day, month, weekday] = parts;
|
|
54
|
+
// Simple interval patterns only
|
|
55
|
+
if (month !== "*" || weekday !== "*" || day !== "*")
|
|
56
|
+
return null;
|
|
57
|
+
const everyNMinutes = /^\*\/(\d+)$/.exec(minute);
|
|
58
|
+
if (everyNMinutes && hour === "*") {
|
|
59
|
+
return parseInt(everyNMinutes[1], 10) * 60;
|
|
60
|
+
}
|
|
61
|
+
const everyNHours = /^\*\/(\d+)$/.exec(hour);
|
|
62
|
+
if (everyNHours && minute === "0") {
|
|
63
|
+
return parseInt(everyNHours[1], 10) * 3600;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function scheduleToCalendarInterval(schedule) {
|
|
68
|
+
const parts = schedule.trim().split(/\s+/);
|
|
69
|
+
if (parts.length !== 5)
|
|
70
|
+
return null;
|
|
71
|
+
const [minute, hour, day, month] = parts;
|
|
72
|
+
const result = {};
|
|
73
|
+
if (minute !== "*" && !/^\*\//.test(minute))
|
|
74
|
+
result.Minute = parseInt(minute, 10);
|
|
75
|
+
if (hour !== "*" && !/^\*\//.test(hour))
|
|
76
|
+
result.Hour = parseInt(hour, 10);
|
|
77
|
+
if (day !== "*")
|
|
78
|
+
result.Day = parseInt(day, 10);
|
|
79
|
+
if (month !== "*")
|
|
80
|
+
result.Month = parseInt(month, 10);
|
|
81
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
82
|
+
}
|
|
83
|
+
function generatePlistXml(job) {
|
|
84
|
+
const label = plistLabel(job);
|
|
85
|
+
const seconds = cadenceToSeconds(job.schedule);
|
|
86
|
+
const calendar = seconds === null ? scheduleToCalendarInterval(job.schedule) : null;
|
|
87
|
+
let triggerXml;
|
|
88
|
+
if (seconds !== null) {
|
|
89
|
+
triggerXml = ` <key>StartInterval</key>\n <integer>${seconds}</integer>`;
|
|
90
|
+
}
|
|
91
|
+
else if (calendar !== null) {
|
|
92
|
+
const entries = Object.entries(calendar)
|
|
93
|
+
.map(([k, v]) => ` <key>${k}</key>\n <integer>${v}</integer>`)
|
|
94
|
+
.join("\n");
|
|
95
|
+
triggerXml = ` <key>StartCalendarInterval</key>\n <dict>\n${entries}\n </dict>`;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
triggerXml = ` <key>StartInterval</key>\n <integer>1800</integer>`;
|
|
99
|
+
}
|
|
100
|
+
return [
|
|
101
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
102
|
+
`<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">`,
|
|
103
|
+
`<plist version="1.0">`,
|
|
104
|
+
`<dict>`,
|
|
105
|
+
` <key>Label</key>`,
|
|
106
|
+
` <string>${label}</string>`,
|
|
107
|
+
` <key>ProgramArguments</key>`,
|
|
108
|
+
` <array>`,
|
|
109
|
+
` <string>${job.command.split(" ")[0]}</string>`,
|
|
110
|
+
...job.command.split(" ").slice(1).map((arg) => ` <string>${arg}</string>`),
|
|
111
|
+
` </array>`,
|
|
112
|
+
triggerXml,
|
|
113
|
+
` <key>StandardOutPath</key>`,
|
|
114
|
+
` <string>/tmp/${label}.stdout.log</string>`,
|
|
115
|
+
` <key>StandardErrorPath</key>`,
|
|
116
|
+
` <string>/tmp/${label}.stderr.log</string>`,
|
|
117
|
+
`</dict>`,
|
|
118
|
+
`</plist>`,
|
|
119
|
+
``,
|
|
120
|
+
].join("\n");
|
|
121
|
+
}
|
|
122
|
+
class LaunchdCronManager {
|
|
123
|
+
deps;
|
|
124
|
+
constructor(deps) {
|
|
125
|
+
this.deps = deps;
|
|
126
|
+
}
|
|
127
|
+
get launchAgentsDir() {
|
|
128
|
+
return `${this.deps.homeDir}/Library/LaunchAgents`;
|
|
129
|
+
}
|
|
130
|
+
sync(jobs) {
|
|
131
|
+
this.deps.mkdirp(this.launchAgentsDir);
|
|
132
|
+
const desiredLabels = new Set(jobs.map(plistLabel));
|
|
133
|
+
// Remove stale plists
|
|
134
|
+
const existing = this.listPlistFiles();
|
|
135
|
+
for (const filename of existing) {
|
|
136
|
+
const label = filename.replace(".plist", "");
|
|
137
|
+
if (!desiredLabels.has(label)) {
|
|
138
|
+
const fullPath = `${this.launchAgentsDir}/${filename}`;
|
|
139
|
+
try {
|
|
140
|
+
this.deps.exec(`launchctl unload "${fullPath}"`);
|
|
141
|
+
}
|
|
142
|
+
catch { /* best effort */ }
|
|
143
|
+
this.deps.removeFile(fullPath);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Write current plists
|
|
147
|
+
for (const job of jobs) {
|
|
148
|
+
const label = plistLabel(job);
|
|
149
|
+
const filename = `${label}.plist`;
|
|
150
|
+
const fullPath = `${this.launchAgentsDir}/${filename}`;
|
|
151
|
+
const xml = generatePlistXml(job);
|
|
152
|
+
try {
|
|
153
|
+
this.deps.exec(`launchctl unload "${fullPath}"`);
|
|
154
|
+
}
|
|
155
|
+
catch { /* best effort */ }
|
|
156
|
+
this.deps.writeFile(fullPath, xml);
|
|
157
|
+
try {
|
|
158
|
+
this.deps.exec(`launchctl load "${fullPath}"`);
|
|
159
|
+
}
|
|
160
|
+
catch { /* best effort */ }
|
|
161
|
+
}
|
|
162
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.os_cron_synced", message: "synced OS cron entries", meta: { platform: "darwin", jobCount: jobs.length } });
|
|
163
|
+
}
|
|
164
|
+
removeAll() {
|
|
165
|
+
const existing = this.listPlistFiles();
|
|
166
|
+
for (const filename of existing) {
|
|
167
|
+
const fullPath = `${this.launchAgentsDir}/${filename}`;
|
|
168
|
+
try {
|
|
169
|
+
this.deps.exec(`launchctl unload "${fullPath}"`);
|
|
170
|
+
}
|
|
171
|
+
catch { /* best effort */ }
|
|
172
|
+
this.deps.removeFile(fullPath);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
list() {
|
|
176
|
+
return this.listPlistFiles().map((f) => f.replace(".plist", ""));
|
|
177
|
+
}
|
|
178
|
+
listPlistFiles() {
|
|
179
|
+
if (!this.deps.existsFile(this.launchAgentsDir))
|
|
180
|
+
return [];
|
|
181
|
+
return this.deps.listDir(this.launchAgentsDir).filter((f) => f.startsWith(PLIST_PREFIX) && f.endsWith(".plist"));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.LaunchdCronManager = LaunchdCronManager;
|
|
185
|
+
const CRONTAB_MARKER_PREFIX = "# ouro:";
|
|
186
|
+
function crontabLine(job) {
|
|
187
|
+
return `${CRONTAB_MARKER_PREFIX}${job.id}\n${job.schedule} ${job.command}`;
|
|
188
|
+
}
|
|
189
|
+
class CrontabCronManager {
|
|
190
|
+
deps;
|
|
191
|
+
constructor(deps) {
|
|
192
|
+
this.deps = deps;
|
|
193
|
+
}
|
|
194
|
+
sync(jobs) {
|
|
195
|
+
const currentLines = this.readCrontab();
|
|
196
|
+
const cleaned = this.removeOuroLines(currentLines);
|
|
197
|
+
const newLines = jobs.map(crontabLine);
|
|
198
|
+
const combined = [...cleaned, ...newLines].join("\n").trim();
|
|
199
|
+
this.deps.execWrite("crontab -", combined ? `${combined}\n` : "");
|
|
200
|
+
}
|
|
201
|
+
removeAll() {
|
|
202
|
+
const currentLines = this.readCrontab();
|
|
203
|
+
const cleaned = this.removeOuroLines(currentLines);
|
|
204
|
+
const combined = cleaned.join("\n").trim();
|
|
205
|
+
this.deps.execWrite("crontab -", combined ? `${combined}\n` : "");
|
|
206
|
+
}
|
|
207
|
+
list() {
|
|
208
|
+
const lines = this.readCrontab();
|
|
209
|
+
return lines
|
|
210
|
+
.filter((l) => l.startsWith(CRONTAB_MARKER_PREFIX))
|
|
211
|
+
.map((l) => l.slice(CRONTAB_MARKER_PREFIX.length));
|
|
212
|
+
}
|
|
213
|
+
readCrontab() {
|
|
214
|
+
try {
|
|
215
|
+
return this.deps.execOutput("crontab -l").split("\n");
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
removeOuroLines(lines) {
|
|
222
|
+
const result = [];
|
|
223
|
+
let skipNext = false;
|
|
224
|
+
for (const line of lines) {
|
|
225
|
+
if (line.startsWith(CRONTAB_MARKER_PREFIX)) {
|
|
226
|
+
skipNext = true;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (skipNext) {
|
|
230
|
+
skipNext = false;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
result.push(line);
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.CrontabCronManager = CrontabCronManager;
|
|
239
|
+
function createOsCronManager(options = {}) {
|
|
240
|
+
const platform = options.platform ?? process.platform;
|
|
241
|
+
if (platform === "darwin") {
|
|
242
|
+
/* v8 ignore start -- integration: default stubs for real OS operations @preserve */
|
|
243
|
+
const deps = options.launchdDeps ?? {
|
|
244
|
+
exec: () => { },
|
|
245
|
+
writeFile: () => { },
|
|
246
|
+
removeFile: () => { },
|
|
247
|
+
existsFile: () => false,
|
|
248
|
+
listDir: () => [],
|
|
249
|
+
mkdirp: () => { },
|
|
250
|
+
homeDir: os.homedir(),
|
|
251
|
+
};
|
|
252
|
+
/* v8 ignore stop */
|
|
253
|
+
return new LaunchdCronManager(deps);
|
|
254
|
+
}
|
|
255
|
+
const deps = options.crontabDeps ?? {
|
|
256
|
+
execOutput: () => "",
|
|
257
|
+
execWrite: () => { },
|
|
258
|
+
};
|
|
259
|
+
return new CrontabCronManager(deps);
|
|
260
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
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.syncGlobalOuroBotWrapper = syncGlobalOuroBotWrapper;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
41
|
+
const runtime_metadata_1 = require("./runtime-metadata");
|
|
42
|
+
function normalizeOutput(output) {
|
|
43
|
+
return (typeof output === "string" ? output : output.toString("utf-8")).trim();
|
|
44
|
+
}
|
|
45
|
+
function resolveGlobalPrefix(execFileSyncImpl) {
|
|
46
|
+
return normalizeOutput(execFileSyncImpl("npm", ["prefix", "-g"], { encoding: "utf-8" }));
|
|
47
|
+
}
|
|
48
|
+
function resolveGlobalRoot(execFileSyncImpl) {
|
|
49
|
+
return normalizeOutput(execFileSyncImpl("npm", ["root", "-g"], { encoding: "utf-8" }));
|
|
50
|
+
}
|
|
51
|
+
function readInstalledWrapperVersion(globalRoot, existsSyncImpl, readFileSyncImpl) {
|
|
52
|
+
const packageJsonPath = path.join(globalRoot, "ouro.bot", "package.json");
|
|
53
|
+
if (!existsSyncImpl(packageJsonPath))
|
|
54
|
+
return null;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(readFileSyncImpl(packageJsonPath, "utf-8"));
|
|
57
|
+
return typeof parsed.version === "string" && parsed.version.trim().length > 0 ? parsed.version.trim() : null;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function resolveExecutableOwner(globalPrefix, platform, existsSyncImpl, realpathSyncImpl) {
|
|
64
|
+
const binName = platform === "win32" ? "ouro.bot.cmd" : "ouro.bot";
|
|
65
|
+
const binPath = platform === "win32"
|
|
66
|
+
? path.join(globalPrefix, binName)
|
|
67
|
+
: path.join(globalPrefix, "bin", binName);
|
|
68
|
+
if (!existsSyncImpl(binPath))
|
|
69
|
+
return null;
|
|
70
|
+
try {
|
|
71
|
+
const resolved = realpathSyncImpl(binPath);
|
|
72
|
+
if (resolved.includes(`${path.sep}node_modules${path.sep}ouro.bot${path.sep}`))
|
|
73
|
+
return "wrapper";
|
|
74
|
+
if (resolved.includes(`${path.sep}node_modules${path.sep}@ouro.bot${path.sep}cli${path.sep}`))
|
|
75
|
+
return "cli";
|
|
76
|
+
return "other";
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return "unknown";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function syncGlobalOuroBotWrapper(deps = {}) {
|
|
83
|
+
/* v8 ignore start -- dependency-injection defaults are only exercised in the live runtime */
|
|
84
|
+
const execFileSyncImpl = deps.execFileSync ?? child_process_1.execFileSync;
|
|
85
|
+
const existsSyncImpl = deps.existsSync ?? fs.existsSync;
|
|
86
|
+
const readFileSyncImpl = deps.readFileSync ?? fs.readFileSync;
|
|
87
|
+
const realpathSyncImpl = deps.realpathSync ?? fs.realpathSync;
|
|
88
|
+
const runtimeVersion = deps.runtimeVersion ?? (0, runtime_metadata_1.getRuntimeMetadata)().version;
|
|
89
|
+
const platform = deps.platform ?? process.platform;
|
|
90
|
+
/* v8 ignore stop */
|
|
91
|
+
(0, runtime_1.emitNervesEvent)({
|
|
92
|
+
component: "daemon",
|
|
93
|
+
event: "daemon.ouro_bot_global_sync_start",
|
|
94
|
+
message: "checking global ouro.bot wrapper",
|
|
95
|
+
meta: { version: runtimeVersion },
|
|
96
|
+
});
|
|
97
|
+
const globalPrefix = resolveGlobalPrefix(execFileSyncImpl);
|
|
98
|
+
const globalRoot = resolveGlobalRoot(execFileSyncImpl);
|
|
99
|
+
const installedVersion = readInstalledWrapperVersion(globalRoot, existsSyncImpl, readFileSyncImpl);
|
|
100
|
+
const executableOwner = resolveExecutableOwner(globalPrefix, platform, existsSyncImpl, realpathSyncImpl);
|
|
101
|
+
if (executableOwner === "wrapper") {
|
|
102
|
+
(0, runtime_1.emitNervesEvent)({
|
|
103
|
+
component: "daemon",
|
|
104
|
+
event: "daemon.ouro_bot_global_sync_end",
|
|
105
|
+
message: "global ouro.bot wrapper already current",
|
|
106
|
+
meta: { version: runtimeVersion, installedVersion, executableOwner, installed: false },
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
installed: false,
|
|
110
|
+
version: runtimeVersion,
|
|
111
|
+
installedVersion,
|
|
112
|
+
executableOwner,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
execFileSyncImpl("npm", ["install", "-g", "--force", "ouro.bot@latest"], { stdio: "pipe", encoding: "utf-8" });
|
|
116
|
+
(0, runtime_1.emitNervesEvent)({
|
|
117
|
+
component: "daemon",
|
|
118
|
+
event: "daemon.ouro_bot_global_sync_end",
|
|
119
|
+
message: "global ouro.bot wrapper synced",
|
|
120
|
+
meta: { version: runtimeVersion, installedVersion, executableOwner, installed: true },
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
installed: true,
|
|
124
|
+
version: runtimeVersion,
|
|
125
|
+
installedVersion,
|
|
126
|
+
executableOwner,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -37,8 +37,9 @@ exports.runOuroBotWrapper = runOuroBotWrapper;
|
|
|
37
37
|
const runtime_1 = require("../../nerves/runtime");
|
|
38
38
|
const daemon_cli_1 = require("./daemon-cli");
|
|
39
39
|
async function defaultLoadCanonicalRunner() {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
// Use the subpath export so we get the daemon-cli module directly,
|
|
41
|
+
// NOT the root entry point which has side-effects (immediately runs the CLI).
|
|
42
|
+
const specifier = "@ouro.bot/cli/runOuroCli";
|
|
42
43
|
const loaded = await Promise.resolve(`${specifier}`).then(s => __importStar(require(s)));
|
|
43
44
|
const candidate = Object.prototype.hasOwnProperty.call(loaded, "runOuroCli")
|
|
44
45
|
? loaded["runOuroCli"]
|
|
@@ -46,7 +47,7 @@ async function defaultLoadCanonicalRunner() {
|
|
|
46
47
|
if (typeof candidate === "function") {
|
|
47
48
|
return candidate;
|
|
48
49
|
}
|
|
49
|
-
throw new Error("@ouro.bot/cli does not export runOuroCli");
|
|
50
|
+
throw new Error("@ouro.bot/cli/runOuroCli does not export runOuroCli");
|
|
50
51
|
}
|
|
51
52
|
function defaultWriteStdout(_text) {
|
|
52
53
|
// Wrapper is intentionally silent by default to avoid duplicate terminal output.
|
|
@@ -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
|
+
}
|