@ouro.bot/cli 0.1.0-alpha.343 → 0.1.0-alpha.344

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.json CHANGED
@@ -1,6 +1,13 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.344",
6
+ "changes": [
7
+ "Provider readiness groundwork now has stable machine identity stored at `~/.ouro-cli/machine.json`, preserving random machine IDs across hostname changes while recording aliases for diagnostics.",
8
+ "Per-agent provider bindings and readiness can now be read, validated, written, and bootstrapped in `<agent>.ouro/state/providers.json` using explicit `outward` and `inner` lanes without storing credentials in bundle state."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.343",
6
13
  "changes": [
@@ -0,0 +1,161 @@
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.getMachineIdentityPath = getMachineIdentityPath;
37
+ exports.loadOrCreateMachineIdentity = loadOrCreateMachineIdentity;
38
+ const crypto = __importStar(require("crypto"));
39
+ const fs = __importStar(require("fs"));
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ const runtime_1 = require("../nerves/runtime");
43
+ function nowIso(deps) {
44
+ return (deps.now?.() ?? new Date()).toISOString();
45
+ }
46
+ function currentHostname(deps) {
47
+ return (deps.hostname?.() ?? os.hostname()).trim();
48
+ }
49
+ function defaultRandomId() {
50
+ return `machine_${crypto.randomUUID()}`;
51
+ }
52
+ function normalizeAliases(value) {
53
+ if (!Array.isArray(value))
54
+ return [];
55
+ const aliases = [];
56
+ for (const alias of value) {
57
+ if (typeof alias !== "string")
58
+ continue;
59
+ const trimmed = alias.trim();
60
+ if (trimmed && !aliases.includes(trimmed))
61
+ aliases.push(trimmed);
62
+ }
63
+ return aliases;
64
+ }
65
+ function parseMachineIdentity(value) {
66
+ if (!value || typeof value !== "object" || Array.isArray(value))
67
+ return null;
68
+ const record = value;
69
+ const aliases = normalizeAliases(record.hostnameAliases);
70
+ if (record.schemaVersion !== 1 ||
71
+ typeof record.machineId !== "string" ||
72
+ record.machineId.trim().length === 0 ||
73
+ typeof record.createdAt !== "string" ||
74
+ record.createdAt.trim().length === 0 ||
75
+ typeof record.updatedAt !== "string" ||
76
+ record.updatedAt.trim().length === 0) {
77
+ return null;
78
+ }
79
+ return {
80
+ schemaVersion: 1,
81
+ machineId: record.machineId,
82
+ createdAt: record.createdAt,
83
+ updatedAt: record.updatedAt,
84
+ hostnameAliases: aliases,
85
+ };
86
+ }
87
+ function writeMachineIdentity(machinePath, identity) {
88
+ fs.mkdirSync(path.dirname(machinePath), { recursive: true, mode: 0o700 });
89
+ fs.writeFileSync(machinePath, `${JSON.stringify(identity, null, 2)}\n`, { encoding: "utf-8", mode: 0o600 });
90
+ }
91
+ function getMachineIdentityPath(homeDir = os.homedir()) {
92
+ return path.join(homeDir, ".ouro-cli", "machine.json");
93
+ }
94
+ function loadOrCreateMachineIdentity(deps = {}) {
95
+ const homeDir = deps.homeDir ?? os.homedir();
96
+ const machinePath = getMachineIdentityPath(homeDir);
97
+ const hostname = currentHostname(deps);
98
+ let existing = null;
99
+ let hadInvalidFile = false;
100
+ try {
101
+ existing = parseMachineIdentity(JSON.parse(fs.readFileSync(machinePath, "utf-8")));
102
+ if (!existing)
103
+ hadInvalidFile = true;
104
+ }
105
+ catch (error) {
106
+ const code = error && typeof error === "object" && "code" in error
107
+ ? error.code
108
+ : undefined;
109
+ if (code !== "ENOENT")
110
+ hadInvalidFile = true;
111
+ }
112
+ if (hadInvalidFile) {
113
+ (0, runtime_1.emitNervesEvent)({
114
+ level: "warn",
115
+ component: "config/identity",
116
+ event: "config.machine_identity_invalid",
117
+ message: "machine identity file is invalid; replacing it",
118
+ meta: { path: machinePath },
119
+ });
120
+ }
121
+ if (existing) {
122
+ if (hostname && !existing.hostnameAliases.includes(hostname)) {
123
+ const updated = {
124
+ ...existing,
125
+ updatedAt: nowIso(deps),
126
+ hostnameAliases: [...existing.hostnameAliases, hostname],
127
+ };
128
+ writeMachineIdentity(machinePath, updated);
129
+ (0, runtime_1.emitNervesEvent)({
130
+ component: "config/identity",
131
+ event: "config.machine_identity_alias_added",
132
+ message: "recorded hostname alias for stable machine identity",
133
+ meta: { machineId: updated.machineId, hostname },
134
+ });
135
+ return updated;
136
+ }
137
+ (0, runtime_1.emitNervesEvent)({
138
+ component: "config/identity",
139
+ event: "config.machine_identity_loaded",
140
+ message: "loaded stable machine identity",
141
+ meta: { machineId: existing.machineId },
142
+ });
143
+ return existing;
144
+ }
145
+ const timestamp = nowIso(deps);
146
+ const identity = {
147
+ schemaVersion: 1,
148
+ machineId: (deps.randomId?.() ?? defaultRandomId()).trim() || defaultRandomId(),
149
+ createdAt: timestamp,
150
+ updatedAt: timestamp,
151
+ hostnameAliases: hostname ? [hostname] : [],
152
+ };
153
+ writeMachineIdentity(machinePath, identity);
154
+ (0, runtime_1.emitNervesEvent)({
155
+ component: "config/identity",
156
+ event: "config.machine_identity_created",
157
+ message: "created stable machine identity",
158
+ meta: { machineId: identity.machineId },
159
+ });
160
+ return identity;
161
+ }
@@ -0,0 +1,208 @@
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.validateProviderState = validateProviderState;
37
+ exports.getProviderStatePath = getProviderStatePath;
38
+ exports.readProviderState = readProviderState;
39
+ exports.writeProviderState = writeProviderState;
40
+ exports.bootstrapProviderStateFromAgentConfig = bootstrapProviderStateFromAgentConfig;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const runtime_1 = require("../nerves/runtime");
44
+ const identity_1 = require("./identity");
45
+ const LANES = ["outward", "inner"];
46
+ const VALID_SOURCES = new Set(["bootstrap", "local"]);
47
+ const VALID_READINESS = new Set(["ready", "failed", "stale", "unknown"]);
48
+ function isProvider(value) {
49
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(identity_1.PROVIDER_CREDENTIALS, value);
50
+ }
51
+ function isNonEmptyString(value) {
52
+ return typeof value === "string" && value.trim().length > 0;
53
+ }
54
+ function validateBinding(value, label) {
55
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
56
+ throw new Error(`${label} must be an object`);
57
+ }
58
+ const record = value;
59
+ if (!isProvider(record.provider))
60
+ throw new Error(`${label}.provider must be a valid provider`);
61
+ if (!isNonEmptyString(record.model))
62
+ throw new Error(`${label}.model must be a non-empty string`);
63
+ if (!VALID_SOURCES.has(record.source)) {
64
+ throw new Error(`${label}.source must be bootstrap or local`);
65
+ }
66
+ if (!isNonEmptyString(record.updatedAt))
67
+ throw new Error(`${label}.updatedAt must be a non-empty string`);
68
+ return {
69
+ provider: record.provider,
70
+ model: record.model,
71
+ source: record.source,
72
+ updatedAt: record.updatedAt,
73
+ };
74
+ }
75
+ function validateReadiness(value, label) {
76
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
77
+ throw new Error(`${label} must be an object`);
78
+ }
79
+ const record = value;
80
+ if (!VALID_READINESS.has(record.status)) {
81
+ throw new Error(`${label}.status must be ready, failed, stale, or unknown`);
82
+ }
83
+ if (!isProvider(record.provider))
84
+ throw new Error(`${label}.provider must be a valid provider`);
85
+ if (!isNonEmptyString(record.model))
86
+ throw new Error(`${label}.model must be a non-empty string`);
87
+ if (record.checkedAt !== undefined && typeof record.checkedAt !== "string") {
88
+ throw new Error(`${label}.checkedAt must be a string when present`);
89
+ }
90
+ if (record.credentialRevision !== undefined && typeof record.credentialRevision !== "string") {
91
+ throw new Error(`${label}.credentialRevision must be a string when present`);
92
+ }
93
+ if (record.error !== undefined && typeof record.error !== "string") {
94
+ throw new Error(`${label}.error must be a string when present`);
95
+ }
96
+ if (record.attempts !== undefined && typeof record.attempts !== "number") {
97
+ throw new Error(`${label}.attempts must be a number when present`);
98
+ }
99
+ return {
100
+ status: record.status,
101
+ provider: record.provider,
102
+ model: record.model,
103
+ ...(record.checkedAt !== undefined ? { checkedAt: record.checkedAt } : {}),
104
+ ...(record.credentialRevision !== undefined ? { credentialRevision: record.credentialRevision } : {}),
105
+ ...(record.error !== undefined ? { error: record.error } : {}),
106
+ ...(record.attempts !== undefined ? { attempts: record.attempts } : {}),
107
+ };
108
+ }
109
+ function validateProviderState(value) {
110
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
111
+ throw new Error("provider state must be an object");
112
+ }
113
+ const record = value;
114
+ if (record.schemaVersion !== 1)
115
+ throw new Error("schemaVersion must be 1");
116
+ if (!isNonEmptyString(record.machineId))
117
+ throw new Error("machineId must be a non-empty string");
118
+ if (!isNonEmptyString(record.updatedAt))
119
+ throw new Error("updatedAt must be a non-empty string");
120
+ if (!record.lanes || typeof record.lanes !== "object" || Array.isArray(record.lanes)) {
121
+ throw new Error("lanes must be an object");
122
+ }
123
+ const rawLanes = record.lanes;
124
+ const lanes = {
125
+ outward: validateBinding(rawLanes.outward, "outward"),
126
+ inner: validateBinding(rawLanes.inner, "inner"),
127
+ };
128
+ if (!record.readiness || typeof record.readiness !== "object" || Array.isArray(record.readiness)) {
129
+ throw new Error("readiness must be an object");
130
+ }
131
+ const rawReadiness = record.readiness;
132
+ const readiness = {};
133
+ for (const lane of LANES) {
134
+ if (rawReadiness[lane] !== undefined) {
135
+ readiness[lane] = validateReadiness(rawReadiness[lane], `${lane}.readiness`);
136
+ }
137
+ }
138
+ return {
139
+ schemaVersion: 1,
140
+ machineId: record.machineId,
141
+ updatedAt: record.updatedAt,
142
+ lanes,
143
+ readiness,
144
+ };
145
+ }
146
+ function getProviderStatePath(agentRoot) {
147
+ return path.join(agentRoot, "state", "providers.json");
148
+ }
149
+ function readProviderState(agentRoot) {
150
+ const statePath = getProviderStatePath(agentRoot);
151
+ let raw;
152
+ try {
153
+ raw = fs.readFileSync(statePath, "utf-8");
154
+ }
155
+ catch (error) {
156
+ const code = error.code;
157
+ if (code === "ENOENT") {
158
+ return { ok: false, reason: "missing", statePath, error: "provider state not found" };
159
+ }
160
+ return { ok: false, reason: "invalid", statePath, error: String(error) };
161
+ }
162
+ try {
163
+ const state = validateProviderState(JSON.parse(raw));
164
+ (0, runtime_1.emitNervesEvent)({
165
+ component: "config/identity",
166
+ event: "config.provider_state_read",
167
+ message: "read provider state",
168
+ meta: { statePath, machineId: state.machineId },
169
+ });
170
+ return { ok: true, statePath, state };
171
+ }
172
+ catch (error) {
173
+ return { ok: false, reason: "invalid", statePath, error: String(error) };
174
+ }
175
+ }
176
+ function writeProviderState(agentRoot, state) {
177
+ const statePath = getProviderStatePath(agentRoot);
178
+ const validated = validateProviderState(state);
179
+ fs.mkdirSync(path.dirname(statePath), { recursive: true });
180
+ fs.writeFileSync(statePath, `${JSON.stringify(validated, null, 2)}\n`, "utf-8");
181
+ (0, runtime_1.emitNervesEvent)({
182
+ component: "config/identity",
183
+ event: "config.provider_state_written",
184
+ message: "wrote provider state",
185
+ meta: { statePath, machineId: validated.machineId },
186
+ });
187
+ }
188
+ function binding(provider, model, updatedAt) {
189
+ return {
190
+ provider,
191
+ model,
192
+ source: "bootstrap",
193
+ updatedAt,
194
+ };
195
+ }
196
+ function bootstrapProviderStateFromAgentConfig(input) {
197
+ const updatedAt = input.now.toISOString();
198
+ return {
199
+ schemaVersion: 1,
200
+ machineId: input.machineId,
201
+ updatedAt,
202
+ lanes: {
203
+ outward: binding(input.agentConfig.humanFacing.provider, input.agentConfig.humanFacing.model, updatedAt),
204
+ inner: binding(input.agentConfig.agentFacing.provider, input.agentConfig.agentFacing.model, updatedAt),
205
+ },
206
+ readiness: {},
207
+ };
208
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.343",
3
+ "version": "0.1.0-alpha.344",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",