@ouro.bot/cli 0.1.0-alpha.364 → 0.1.0-alpha.366
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/README.md +15 -6
- package/changelog.json +17 -0
- package/dist/heart/auth/auth-flow.js +25 -110
- package/dist/heart/config.js +69 -55
- package/dist/heart/core.js +83 -33
- package/dist/heart/daemon/agent-config-check.js +60 -239
- package/dist/heart/daemon/agentic-repair.js +2 -1
- package/dist/heart/daemon/cli-defaults.js +15 -68
- package/dist/heart/daemon/cli-exec.js +249 -89
- package/dist/heart/daemon/cli-parse.js +71 -0
- package/dist/heart/daemon/daemon-cli.js +1 -2
- package/dist/heart/daemon/daemon-entry.js +1 -3
- package/dist/heart/daemon/doctor.js +9 -29
- package/dist/heart/daemon/interactive-repair.js +37 -2
- package/dist/heart/daemon/provider-discovery.js +32 -59
- package/dist/heart/hatch/hatch-flow.js +9 -12
- package/dist/heart/hatch/specialist-prompt.js +1 -1
- package/dist/heart/hatch/specialist-tools.js +21 -1
- package/dist/heart/migrate-config.js +15 -42
- package/dist/heart/provider-binding-resolver.js +6 -7
- package/dist/heart/provider-credentials.js +379 -0
- package/dist/heart/provider-failover.js +3 -11
- package/dist/heart/provider-ping.js +13 -3
- package/dist/heart/provider-state.js +8 -0
- package/dist/heart/provider-visibility.js +3 -6
- package/dist/heart/providers/anthropic-token.js +15 -47
- package/dist/heart/providers/anthropic.js +4 -9
- package/dist/heart/providers/azure.js +3 -3
- package/dist/heart/providers/github-copilot.js +2 -2
- package/dist/heart/providers/minimax-vlm.js +2 -2
- package/dist/heart/providers/minimax.js +1 -1
- package/dist/heart/providers/openai-codex.js +4 -9
- package/dist/repertoire/bitwarden-store.js +63 -17
- package/dist/repertoire/bundle-templates.js +2 -2
- package/dist/repertoire/credential-access.js +47 -467
- package/dist/repertoire/tools-attachments.js +5 -4
- package/dist/repertoire/tools-vault.js +10 -80
- package/dist/repertoire/vault-unlock.js +359 -0
- package/dist/senses/bluebubbles/client.js +39 -4
- package/dist/senses/pipeline.js +0 -1
- package/package.json +1 -1
- package/dist/heart/provider-credential-pool.js +0 -395
|
@@ -1,44 +1,7 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.vaultToolDefinitions = void 0;
|
|
37
|
-
const crypto = __importStar(require("node:crypto"));
|
|
38
|
-
const fs = __importStar(require("node:fs"));
|
|
39
|
-
const path = __importStar(require("node:path"));
|
|
40
4
|
const identity_1 = require("../heart/identity");
|
|
41
|
-
const vault_setup_1 = require("./vault-setup");
|
|
42
5
|
const runtime_1 = require("../nerves/runtime");
|
|
43
6
|
exports.vaultToolDefinitions = [
|
|
44
7
|
{
|
|
@@ -61,49 +24,16 @@ exports.vaultToolDefinitions = [
|
|
|
61
24
|
message: "vault_setup invoked",
|
|
62
25
|
meta: { tool: "vault_setup", agentName },
|
|
63
26
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
fs.mkdirSync(secretsDir, { recursive: true, mode: 0o700 });
|
|
75
|
-
}
|
|
76
|
-
let secrets = {};
|
|
77
|
-
if (fs.existsSync(secretsPath)) {
|
|
78
|
-
try {
|
|
79
|
-
secrets = JSON.parse(fs.readFileSync(secretsPath, "utf-8"));
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
// If secrets.json is corrupt, start fresh but don't lose the file
|
|
83
|
-
secrets = {};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
secrets.vault = {
|
|
87
|
-
...(typeof secrets.vault === "object" && secrets.vault !== null ? secrets.vault : {}),
|
|
88
|
-
masterPassword,
|
|
89
|
-
email,
|
|
90
|
-
serverUrl,
|
|
91
|
-
};
|
|
92
|
-
fs.writeFileSync(secretsPath, JSON.stringify(secrets, null, 2) + "\n", {
|
|
93
|
-
mode: 0o600,
|
|
94
|
-
});
|
|
95
|
-
// Create the vault account
|
|
96
|
-
const result = await (0, vault_setup_1.createVaultAccount)(agentName, serverUrl, email, masterPassword);
|
|
97
|
-
if (!result.success) {
|
|
98
|
-
return `Vault setup failed: ${result.error}`;
|
|
99
|
-
}
|
|
100
|
-
return `Vault created at ${serverUrl} for ${email}. Master password stored in secrets.json.`;
|
|
101
|
-
}
|
|
102
|
-
catch (err) {
|
|
103
|
-
/* v8 ignore next -- defensive: error handling @preserve */
|
|
104
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
105
|
-
return `Vault setup error: ${reason}`;
|
|
106
|
-
}
|
|
27
|
+
return [
|
|
28
|
+
"Vault setup is human-required.",
|
|
29
|
+
"",
|
|
30
|
+
"Why I cannot do it here:",
|
|
31
|
+
" Creating or unlocking a vault requires secret entry that must stay out of agent context.",
|
|
32
|
+
"",
|
|
33
|
+
"Do this in a terminal:",
|
|
34
|
+
` ouro vault create --agent ${agentName}`,
|
|
35
|
+
` ouro vault unlock --agent ${agentName}`,
|
|
36
|
+
].join("\n");
|
|
107
37
|
},
|
|
108
38
|
summaryKeys: [],
|
|
109
39
|
},
|
|
@@ -0,0 +1,359 @@
|
|
|
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.resolveVaultUnlockStore = resolveVaultUnlockStore;
|
|
37
|
+
exports.readVaultUnlockSecret = readVaultUnlockSecret;
|
|
38
|
+
exports.storeVaultUnlockSecret = storeVaultUnlockSecret;
|
|
39
|
+
exports.getVaultUnlockStatus = getVaultUnlockStatus;
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const crypto = __importStar(require("node:crypto"));
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const os = __importStar(require("node:os"));
|
|
44
|
+
const path = __importStar(require("node:path"));
|
|
45
|
+
const runtime_1 = require("../nerves/runtime");
|
|
46
|
+
const VAULT_UNLOCK_SERVICE = "ouro.vault";
|
|
47
|
+
const PLAINTEXT_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock");
|
|
48
|
+
const WINDOWS_DPAPI_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock-dpapi");
|
|
49
|
+
const SUPPORTED_STORES = ["auto", "macos-keychain", "windows-dpapi", "linux-secret-service", "plaintext-file"];
|
|
50
|
+
function platform(deps) {
|
|
51
|
+
return deps.platform ?? process.platform;
|
|
52
|
+
}
|
|
53
|
+
function spawnSync(deps) {
|
|
54
|
+
return deps.spawnSync ?? node_child_process_1.spawnSync;
|
|
55
|
+
}
|
|
56
|
+
function homeDir(deps) {
|
|
57
|
+
return deps.homeDir ?? os.homedir();
|
|
58
|
+
}
|
|
59
|
+
function vaultKey(config) {
|
|
60
|
+
return `${config.serverUrl}:${config.email}`;
|
|
61
|
+
}
|
|
62
|
+
function vaultLabel(config) {
|
|
63
|
+
return `${config.email} at ${config.serverUrl}`;
|
|
64
|
+
}
|
|
65
|
+
function plaintextUnlockPath(config, deps) {
|
|
66
|
+
const digest = crypto.createHash("sha256").update(vaultKey(config)).digest("hex").slice(0, 24);
|
|
67
|
+
return path.join(homeDir(deps), PLAINTEXT_UNLOCK_DIR, `${digest}.secret`);
|
|
68
|
+
}
|
|
69
|
+
function windowsDpapiUnlockPath(config, deps) {
|
|
70
|
+
const digest = crypto.createHash("sha256").update(vaultKey(config)).digest("hex").slice(0, 24);
|
|
71
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
72
|
+
const baseDir = localAppData && platform(deps) === "win32"
|
|
73
|
+
? path.join(localAppData, "Ouro")
|
|
74
|
+
: path.join(homeDir(deps), WINDOWS_DPAPI_UNLOCK_DIR);
|
|
75
|
+
return path.join(baseDir, "vault-unlock", `${digest}.dpapi`);
|
|
76
|
+
}
|
|
77
|
+
function commandExists(command, deps) {
|
|
78
|
+
const result = spawnSync(deps)(command, ["--version"], { encoding: "utf8" });
|
|
79
|
+
const code = result.error?.code;
|
|
80
|
+
return code !== "ENOENT";
|
|
81
|
+
}
|
|
82
|
+
function missingSecureStoreMessage(config) {
|
|
83
|
+
const agentPart = config.agentName ? ` for ${config.agentName}` : "";
|
|
84
|
+
return [
|
|
85
|
+
`No supported secure local secret store was found on this machine${agentPart}.`,
|
|
86
|
+
"",
|
|
87
|
+
`Ouro knows the credential vault is ${vaultLabel(config)}, but it cannot cache the vault unlock secret here yet.`,
|
|
88
|
+
"",
|
|
89
|
+
"On macOS, Ouro uses Keychain automatically.",
|
|
90
|
+
"On Windows, Ouro uses a CurrentUser DPAPI-encrypted local file automatically.",
|
|
91
|
+
"On Linux/WSL, install and configure Secret Service/libsecret, or choose the explicit plaintext fallback on a trusted machine.",
|
|
92
|
+
"",
|
|
93
|
+
config.agentName
|
|
94
|
+
? `Run \`ouro vault unlock --agent ${config.agentName} --store plaintext-file\` to store the vault unlock secret in a chmod 0600 local file.`
|
|
95
|
+
: "Run `ouro vault unlock --store plaintext-file` to store the vault unlock secret in a chmod 0600 local file.",
|
|
96
|
+
].join("\n");
|
|
97
|
+
}
|
|
98
|
+
function lockedMessage(config, store) {
|
|
99
|
+
const agentPart = config.agentName ? ` for ${config.agentName}` : "";
|
|
100
|
+
const command = config.agentName
|
|
101
|
+
? `ouro vault unlock --agent ${config.agentName}${store.kind === "plaintext-file" ? " --store plaintext-file" : ""}`
|
|
102
|
+
: `ouro vault unlock${store.kind === "plaintext-file" ? " --store plaintext-file" : ""}`;
|
|
103
|
+
return [
|
|
104
|
+
`Ouro credential vault is locked on this machine${agentPart}.`,
|
|
105
|
+
"",
|
|
106
|
+
`Vault: ${vaultLabel(config)}`,
|
|
107
|
+
`Local unlock store: ${store.kind} (${store.location})`,
|
|
108
|
+
"",
|
|
109
|
+
`Run \`${command}\` and enter the vault unlock secret from the operator password manager.`,
|
|
110
|
+
].join("\n");
|
|
111
|
+
}
|
|
112
|
+
function validateStoreKind(store) {
|
|
113
|
+
const requested = store ?? "auto";
|
|
114
|
+
if (!SUPPORTED_STORES.includes(requested)) {
|
|
115
|
+
throw new Error(`unknown vault unlock store '${requested}'. Use auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file.`);
|
|
116
|
+
}
|
|
117
|
+
return requested;
|
|
118
|
+
}
|
|
119
|
+
function resolveVaultUnlockStore(config, deps = {}) {
|
|
120
|
+
const requested = validateStoreKind(deps.store);
|
|
121
|
+
const currentPlatform = platform(deps);
|
|
122
|
+
if (requested === "macos-keychain") {
|
|
123
|
+
if (currentPlatform !== "darwin") {
|
|
124
|
+
throw new Error(`macos-keychain unlock store is only available on macOS; this machine is ${currentPlatform}.`);
|
|
125
|
+
}
|
|
126
|
+
return { kind: "macos-keychain", secure: true, location: "macOS Keychain" };
|
|
127
|
+
}
|
|
128
|
+
if (requested === "linux-secret-service") {
|
|
129
|
+
if (currentPlatform !== "linux") {
|
|
130
|
+
throw new Error(`linux-secret-service unlock store is only available on Linux/WSL; this machine is ${currentPlatform}.`);
|
|
131
|
+
}
|
|
132
|
+
if (!commandExists("secret-tool", deps)) {
|
|
133
|
+
throw new Error("linux-secret-service unlock store requires the `secret-tool` command from libsecret.");
|
|
134
|
+
}
|
|
135
|
+
return { kind: "linux-secret-service", secure: true, location: "Secret Service via secret-tool" };
|
|
136
|
+
}
|
|
137
|
+
if (requested === "windows-dpapi") {
|
|
138
|
+
if (currentPlatform !== "win32") {
|
|
139
|
+
throw new Error(`windows-dpapi unlock store is only available on Windows; this machine is ${currentPlatform}.`);
|
|
140
|
+
}
|
|
141
|
+
return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(config, deps) };
|
|
142
|
+
}
|
|
143
|
+
if (requested === "plaintext-file") {
|
|
144
|
+
return { kind: "plaintext-file", secure: false, location: plaintextUnlockPath(config, deps) };
|
|
145
|
+
}
|
|
146
|
+
if (currentPlatform === "darwin") {
|
|
147
|
+
return { kind: "macos-keychain", secure: true, location: "macOS Keychain" };
|
|
148
|
+
}
|
|
149
|
+
if (currentPlatform === "win32") {
|
|
150
|
+
return { kind: "windows-dpapi", secure: true, location: windowsDpapiUnlockPath(config, deps) };
|
|
151
|
+
}
|
|
152
|
+
if (currentPlatform === "linux" && commandExists("secret-tool", deps)) {
|
|
153
|
+
return { kind: "linux-secret-service", secure: true, location: "Secret Service via secret-tool" };
|
|
154
|
+
}
|
|
155
|
+
throw new Error(missingSecureStoreMessage(config));
|
|
156
|
+
}
|
|
157
|
+
function readFromMacosKeychain(config, deps) {
|
|
158
|
+
const result = spawnSync(deps)("security", [
|
|
159
|
+
"find-generic-password",
|
|
160
|
+
"-s",
|
|
161
|
+
VAULT_UNLOCK_SERVICE,
|
|
162
|
+
"-a",
|
|
163
|
+
vaultKey(config),
|
|
164
|
+
"-w",
|
|
165
|
+
], { encoding: "utf8" });
|
|
166
|
+
const secret = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
167
|
+
return result.status === 0 && secret ? secret : null;
|
|
168
|
+
}
|
|
169
|
+
function writeToMacosKeychain(config, secret, deps) {
|
|
170
|
+
const result = spawnSync(deps)("security", [
|
|
171
|
+
"add-generic-password",
|
|
172
|
+
"-U",
|
|
173
|
+
"-s",
|
|
174
|
+
VAULT_UNLOCK_SERVICE,
|
|
175
|
+
"-a",
|
|
176
|
+
vaultKey(config),
|
|
177
|
+
"-w",
|
|
178
|
+
secret,
|
|
179
|
+
], { encoding: "utf8" });
|
|
180
|
+
if (result.status !== 0) {
|
|
181
|
+
const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
|
|
182
|
+
throw new Error(`failed to store vault unlock secret in macOS Keychain${stderr ? `: ${stderr}` : ""}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function readFromLinuxSecretService(config, deps) {
|
|
186
|
+
const result = spawnSync(deps)("secret-tool", [
|
|
187
|
+
"lookup",
|
|
188
|
+
"service",
|
|
189
|
+
VAULT_UNLOCK_SERVICE,
|
|
190
|
+
"account",
|
|
191
|
+
vaultKey(config),
|
|
192
|
+
], { encoding: "utf8" });
|
|
193
|
+
const secret = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
194
|
+
return result.status === 0 && secret ? secret : null;
|
|
195
|
+
}
|
|
196
|
+
function writeToLinuxSecretService(config, secret, deps) {
|
|
197
|
+
const result = spawnSync(deps)("secret-tool", [
|
|
198
|
+
"store",
|
|
199
|
+
"--label",
|
|
200
|
+
`Ouro credential vault ${vaultLabel(config)}`,
|
|
201
|
+
"service",
|
|
202
|
+
VAULT_UNLOCK_SERVICE,
|
|
203
|
+
"account",
|
|
204
|
+
vaultKey(config),
|
|
205
|
+
], { encoding: "utf8", input: secret });
|
|
206
|
+
if (result.status !== 0) {
|
|
207
|
+
const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
|
|
208
|
+
throw new Error(`failed to store vault unlock secret in Linux Secret Service${stderr ? `: ${stderr}` : ""}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function runWindowsDpapi(mode, payload, deps) {
|
|
212
|
+
const script = `
|
|
213
|
+
$ErrorActionPreference = "Stop"
|
|
214
|
+
$inputJson = [Console]::In.ReadToEnd()
|
|
215
|
+
$payload = $inputJson | ConvertFrom-Json
|
|
216
|
+
Add-Type -AssemblyName System.Security
|
|
217
|
+
if ($payload.mode -eq "protect") {
|
|
218
|
+
$bytes = [Text.Encoding]::UTF8.GetBytes([string]$payload.secret)
|
|
219
|
+
$protected = [Security.Cryptography.ProtectedData]::Protect($bytes, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
|
|
220
|
+
[Console]::Out.Write([Convert]::ToBase64String($protected))
|
|
221
|
+
} elseif ($payload.mode -eq "unprotect") {
|
|
222
|
+
$protected = [Convert]::FromBase64String([string]$payload.ciphertext)
|
|
223
|
+
$bytes = [Security.Cryptography.ProtectedData]::Unprotect($protected, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
|
|
224
|
+
[Console]::Out.Write([Text.Encoding]::UTF8.GetString($bytes))
|
|
225
|
+
} else {
|
|
226
|
+
throw "unknown DPAPI mode"
|
|
227
|
+
}
|
|
228
|
+
`;
|
|
229
|
+
const result = spawnSync(deps)("powershell.exe", [
|
|
230
|
+
"-NoProfile",
|
|
231
|
+
"-NonInteractive",
|
|
232
|
+
"-ExecutionPolicy",
|
|
233
|
+
"Bypass",
|
|
234
|
+
"-Command",
|
|
235
|
+
script,
|
|
236
|
+
], {
|
|
237
|
+
encoding: "utf8",
|
|
238
|
+
input: JSON.stringify({ mode, ...payload }),
|
|
239
|
+
});
|
|
240
|
+
if (result.status !== 0) {
|
|
241
|
+
const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
|
|
242
|
+
const error = result.error instanceof Error ? result.error.message : stderr;
|
|
243
|
+
throw new Error(`Windows DPAPI ${mode} failed${error ? `: ${error}` : ""}`);
|
|
244
|
+
}
|
|
245
|
+
return typeof result.stdout === "string" ? result.stdout : "";
|
|
246
|
+
}
|
|
247
|
+
function readFromWindowsDpapi(config, deps) {
|
|
248
|
+
const filePath = windowsDpapiUnlockPath(config, deps);
|
|
249
|
+
if (!fs.existsSync(filePath))
|
|
250
|
+
return null;
|
|
251
|
+
const ciphertext = fs.readFileSync(filePath, "utf8").trim();
|
|
252
|
+
if (!ciphertext)
|
|
253
|
+
return null;
|
|
254
|
+
const secret = runWindowsDpapi("unprotect", { ciphertext }, deps).trim();
|
|
255
|
+
return secret || null;
|
|
256
|
+
}
|
|
257
|
+
function writeToWindowsDpapi(config, secret, deps) {
|
|
258
|
+
const filePath = windowsDpapiUnlockPath(config, deps);
|
|
259
|
+
const ciphertext = runWindowsDpapi("protect", { secret }, deps).trim();
|
|
260
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
261
|
+
fs.writeFileSync(filePath, `${ciphertext}\n`, "utf8");
|
|
262
|
+
}
|
|
263
|
+
function readFromPlaintextFile(config, deps) {
|
|
264
|
+
const filePath = plaintextUnlockPath(config, deps);
|
|
265
|
+
if (!fs.existsSync(filePath))
|
|
266
|
+
return null;
|
|
267
|
+
if (platform(deps) !== "win32") {
|
|
268
|
+
const mode = fs.statSync(filePath).mode & 0o777;
|
|
269
|
+
if ((mode & 0o077) !== 0) {
|
|
270
|
+
throw new Error(`refusing to read plaintext vault unlock file at ${filePath} because permissions are too broad; run chmod 600 ${filePath}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const secret = fs.readFileSync(filePath, "utf8").trim();
|
|
274
|
+
return secret || null;
|
|
275
|
+
}
|
|
276
|
+
function writeToPlaintextFile(config, secret, deps) {
|
|
277
|
+
const filePath = plaintextUnlockPath(config, deps);
|
|
278
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
|
|
279
|
+
fs.writeFileSync(filePath, secret, { encoding: "utf8", mode: 0o600 });
|
|
280
|
+
if (platform(deps) !== "win32") {
|
|
281
|
+
fs.chmodSync(path.dirname(filePath), 0o700);
|
|
282
|
+
fs.chmodSync(filePath, 0o600);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function readFromStore(config, store, deps) {
|
|
286
|
+
if (store.kind === "macos-keychain")
|
|
287
|
+
return readFromMacosKeychain(config, deps);
|
|
288
|
+
if (store.kind === "windows-dpapi")
|
|
289
|
+
return readFromWindowsDpapi(config, deps);
|
|
290
|
+
if (store.kind === "linux-secret-service")
|
|
291
|
+
return readFromLinuxSecretService(config, deps);
|
|
292
|
+
return readFromPlaintextFile(config, deps);
|
|
293
|
+
}
|
|
294
|
+
function writeToStore(config, store, secret, deps) {
|
|
295
|
+
if (store.kind === "macos-keychain") {
|
|
296
|
+
writeToMacosKeychain(config, secret, deps);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (store.kind === "linux-secret-service") {
|
|
300
|
+
writeToLinuxSecretService(config, secret, deps);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (store.kind === "windows-dpapi") {
|
|
304
|
+
writeToWindowsDpapi(config, secret, deps);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
writeToPlaintextFile(config, secret, deps);
|
|
308
|
+
}
|
|
309
|
+
function readVaultUnlockSecret(config, deps = {}) {
|
|
310
|
+
const store = resolveVaultUnlockStore(config, deps);
|
|
311
|
+
const secret = readFromStore(config, store, deps);
|
|
312
|
+
if (!secret) {
|
|
313
|
+
throw new Error(lockedMessage(config, store));
|
|
314
|
+
}
|
|
315
|
+
(0, runtime_1.emitNervesEvent)({
|
|
316
|
+
component: "repertoire",
|
|
317
|
+
event: "repertoire.vault_unlock_loaded",
|
|
318
|
+
message: "loaded vault unlock material from local store",
|
|
319
|
+
meta: { store: store.kind, secure: store.secure, hasAgentName: !!config.agentName },
|
|
320
|
+
});
|
|
321
|
+
return { secret, store };
|
|
322
|
+
}
|
|
323
|
+
function storeVaultUnlockSecret(config, secret, deps = {}) {
|
|
324
|
+
const trimmed = secret.trim();
|
|
325
|
+
if (!trimmed) {
|
|
326
|
+
throw new Error("vault unlock secret is required");
|
|
327
|
+
}
|
|
328
|
+
const store = resolveVaultUnlockStore(config, deps);
|
|
329
|
+
writeToStore(config, store, trimmed, deps);
|
|
330
|
+
(0, runtime_1.emitNervesEvent)({
|
|
331
|
+
component: "repertoire",
|
|
332
|
+
event: "repertoire.vault_unlock_stored",
|
|
333
|
+
message: "stored vault unlock material in local store",
|
|
334
|
+
meta: { store: store.kind, secure: store.secure, hasAgentName: !!config.agentName },
|
|
335
|
+
});
|
|
336
|
+
return store;
|
|
337
|
+
}
|
|
338
|
+
function getVaultUnlockStatus(config, deps = {}) {
|
|
339
|
+
try {
|
|
340
|
+
const store = resolveVaultUnlockStore(config, deps);
|
|
341
|
+
const stored = !!readFromStore(config, store, deps);
|
|
342
|
+
return {
|
|
343
|
+
configured: true,
|
|
344
|
+
stored,
|
|
345
|
+
store,
|
|
346
|
+
fix: stored
|
|
347
|
+
? "Vault unlock secret is available on this machine."
|
|
348
|
+
: lockedMessage(config, store),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
return {
|
|
353
|
+
configured: false,
|
|
354
|
+
stored: false,
|
|
355
|
+
error: error instanceof Error ? error.message : String(error),
|
|
356
|
+
fix: error instanceof Error ? error.message : String(error),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.createBlueBubblesClient = createBlueBubblesClient;
|
|
4
37
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -533,13 +566,15 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
|
|
|
533
566
|
throw new Error("VLM fallback requires a minimax credential for this agent — " +
|
|
534
567
|
"configure one or switch to a vision-capable chat model");
|
|
535
568
|
}
|
|
536
|
-
const {
|
|
569
|
+
const { readProviderCredentialRecord } = await Promise.resolve().then(() => __importStar(require("../../heart/provider-credentials")));
|
|
570
|
+
const credential = await readProviderCredentialRecord((0, identity_1.getAgentName)(), "minimax");
|
|
571
|
+
const apiKey = credential.ok ? credential.record.credentials.apiKey : undefined;
|
|
537
572
|
if (!apiKey) {
|
|
538
|
-
throw new Error("VLM fallback: minimax API key not found in
|
|
539
|
-
"
|
|
573
|
+
throw new Error("VLM fallback: minimax API key not found in the agent vault — " +
|
|
574
|
+
"run `ouro auth --agent <agent> --provider minimax`");
|
|
540
575
|
}
|
|
541
576
|
return (0, minimax_vlm_1.minimaxVlmDescribe)({
|
|
542
|
-
apiKey,
|
|
577
|
+
apiKey: String(apiKey),
|
|
543
578
|
prompt: params.prompt,
|
|
544
579
|
imageDataUrl: params.imageDataUrl,
|
|
545
580
|
baseURL: minimax_1.MINIMAX_PROVIDER_BASE_URL,
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -205,7 +205,6 @@ async function handleInboundTurn(input) {
|
|
|
205
205
|
model: failoverAction.model,
|
|
206
206
|
credentialRevision: failoverAction.credentialRevision,
|
|
207
207
|
source: failoverAction.source,
|
|
208
|
-
contributedByAgent: failoverAction.contributedByAgent,
|
|
209
208
|
},
|
|
210
209
|
});
|
|
211
210
|
// Replace "switch to <provider>" with a context message for the agent.
|