@ouro.bot/cli 0.1.0-alpha.677 → 0.1.0-alpha.679

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,18 @@
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.679",
6
+ "changes": [
7
+ "Preserve machine runtime config during A2A identity writes and report BlueBubbles attachment gaps before stale proof facts."
8
+ ]
9
+ },
10
+ {
11
+ "version": "0.1.0-alpha.678",
12
+ "changes": [
13
+ "Register dev-tool MCP clients through the installed ouro command instead of repo dist, preventing Codex and Claude setup from pinning long-lived clients to stale ignored build artifacts."
14
+ ]
15
+ },
4
16
  {
5
17
  "version": "0.1.0-alpha.677",
6
18
  "changes": [
@@ -143,21 +143,28 @@ async function loadOrMintA2AIdentity(input) {
143
143
  * Load (or mint-on-first-use) THIS agent's own A2A identity from the machine-local
144
144
  * runtime config — the convenience entry the main-process tools use to obtain the
145
145
  * self identity that signs outbound sealed envelopes. Mirrors the a2a sense
146
- * entrypoint's load (read machine config → `loadOrMintA2AIdentity` → persist a fresh
147
- * seed under the right machine id). Reads the in-memory machine-config cache (no
148
- * remote vault round-trip per call). `sodium` is optional (defaults to `ready()`).
146
+ * entrypoint's load (use a cached seed when present, otherwise refresh machine
147
+ * config → `loadOrMintA2AIdentity` → merge a fresh seed under the right machine
148
+ * id). `sodium` is optional (defaults to `ready()`).
149
149
  */
150
150
  async function loadSelfA2AIdentity(input) {
151
151
  const sodium = input.sodium ?? await (0, a2a_client_1.ready)();
152
152
  const machineId = (0, machine_identity_1.loadOrCreateMachineIdentity)({ homeDir: os.homedir() }).machineId;
153
- const read = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(input.agentName);
153
+ const cached = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(input.agentName);
154
+ const read = cached.ok && readStoredA2ASeed(cached.config)
155
+ ? cached
156
+ : await (0, runtime_credentials_1.refreshMachineRuntimeCredentialConfig)(input.agentName, machineId);
157
+ if (!read.ok && read.reason !== "missing") {
158
+ throw new Error(`A2A identity requires readable machine runtime config at ${read.itemPath}: ${read.error}`);
159
+ }
154
160
  const config = read.ok ? read.config : {};
155
161
  return loadOrMintA2AIdentity({
156
162
  agentName: input.agentName,
157
163
  sodium,
158
164
  config,
159
165
  upsert: async (next) => {
160
- await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(input.agentName, machineId, next);
166
+ const seed = readStoredA2ASeed(next);
167
+ await (0, runtime_credentials_1.mergeMachineRuntimeCredentialConfig)(input.agentName, machineId, { a2a: { identity: { ed25519Seed: seed } } });
161
168
  },
162
169
  });
163
170
  }
@@ -1865,7 +1865,7 @@ async function executeVaultRecover(command, deps) {
1865
1865
  await (0, runtime_credentials_1.upsertRuntimeCredentialConfig)(command.agent, splitRuntimeConfig.agentConfig, now);
1866
1866
  }
1867
1867
  if (machineRuntimeFields.length > 0) {
1868
- await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(command.agent, currentMachineId(deps), splitRuntimeConfig.machineConfig, now);
1868
+ await (0, runtime_credentials_1.mergeMachineRuntimeCredentialConfig)(command.agent, currentMachineId(deps), splitRuntimeConfig.machineConfig, now);
1869
1869
  }
1870
1870
  return {
1871
1871
  providerCount: importedProviders.size,
@@ -2125,19 +2125,20 @@ function runtimeScopeLabel(scope) {
2125
2125
  async function storeRuntimeConfigKeys(input) {
2126
2126
  const machineId = input.scope === "machine" ? currentMachineId(input.deps) : undefined;
2127
2127
  input.onProgress?.("checking existing runtime config");
2128
- const current = input.scope === "machine"
2129
- ? await (0, runtime_credentials_1.refreshMachineRuntimeCredentialConfig)(input.agent, machineId, { preserveCachedOnFailure: true })
2130
- : await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(input.agent, { preserveCachedOnFailure: true });
2131
- if (!current.ok && current.reason !== "missing") {
2132
- throw new Error(`cannot read existing runtime credentials from ${current.itemPath}: ${current.error}`);
2128
+ let nextConfig = {};
2129
+ if (input.scope !== "machine") {
2130
+ const current = await (0, runtime_credentials_1.refreshRuntimeCredentialConfig)(input.agent, { preserveCachedOnFailure: true });
2131
+ if (!current.ok && current.reason !== "missing") {
2132
+ throw new Error(`cannot read existing runtime credentials from ${current.itemPath}: ${current.error}`);
2133
+ }
2134
+ nextConfig = current.ok ? current.config : {};
2133
2135
  }
2134
- let nextConfig = current.ok ? current.config : {};
2135
2136
  for (const entry of input.entries) {
2136
- input.onProgress?.(`storing ${entry.key} in ${current.itemPath}`);
2137
+ input.onProgress?.(`storing ${entry.key} in ${runtimeScopeLabel(input.scope)}`);
2137
2138
  nextConfig = setRuntimeConfigValue(nextConfig, entry.key, entry.value);
2138
2139
  }
2139
2140
  const stored = input.scope === "machine"
2140
- ? await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(input.agent, machineId, nextConfig, providerCliNow(input.deps))
2141
+ ? await (0, runtime_credentials_1.mergeMachineRuntimeCredentialConfig)(input.agent, machineId, nextConfig, providerCliNow(input.deps))
2141
2142
  : await (0, runtime_credentials_1.upsertRuntimeCredentialConfig)(input.agent, nextConfig, providerCliNow(input.deps));
2142
2143
  input.onProgress?.(`stored ${input.entries.map((entry) => entry.key).join(", ")}; credential values were not printed`);
2143
2144
  return { revision: stored.revision, itemPath: stored.itemPath, ...(machineId ? { machineId } : {}) };
@@ -3470,8 +3471,7 @@ async function executeConnectBlueBubbles(agent, deps) {
3470
3471
  progress.end();
3471
3472
  throw new Error(`cannot read existing machine runtime credentials from ${current.itemPath}: ${current.error}`);
3472
3473
  }
3473
- const nextConfig = {
3474
- ...(current.ok ? current.config : {}),
3474
+ const blueBubblesPatch = {
3475
3475
  bluebubbles: {
3476
3476
  serverUrl,
3477
3477
  password,
@@ -3485,7 +3485,7 @@ async function executeConnectBlueBubbles(agent, deps) {
3485
3485
  },
3486
3486
  };
3487
3487
  progress.updateDetail("storing local machine config");
3488
- stored = await (0, runtime_credentials_1.upsertMachineRuntimeCredentialConfig)(agent, machineId, nextConfig, providerCliNow(deps));
3488
+ stored = await (0, runtime_credentials_1.mergeMachineRuntimeCredentialConfig)(agent, machineId, blueBubblesPatch, providerCliNow(deps));
3489
3489
  progress.updateDetail("enabling BlueBubbles in agent.json");
3490
3490
  enableAgentSense(agent, "bluebubbles", deps);
3491
3491
  progress.completePhase("saving BlueBubbles attachment", "secret stored");
@@ -6809,9 +6809,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
6809
6809
  }
6810
6810
  const sourceRoot = (0, identity_1.getRepoRoot)();
6811
6811
  const runtimeMode = (0, runtime_mode_1.detectRuntimeMode)(sourceRoot);
6812
- const baseMcpServeCommand = runtimeMode === "dev"
6813
- ? `node ${path.join(sourceRoot, "dist", "heart", "daemon", "ouro-bot-entry.js")} mcp-serve --agent ${setupAgent}`
6814
- : `ouro mcp-serve --agent ${setupAgent}`;
6812
+ const baseMcpServeCommand = `ouro mcp-serve --agent ${setupAgent}`;
6815
6813
  const mcpServeCommand = `${mcpServePrefix}${baseMcpServeCommand}`;
6816
6814
  if (tool === "claude-code") {
6817
6815
  // 1. Register MCP server with Claude Code
@@ -756,17 +756,23 @@ class DaemonSenseManager {
756
756
  const rows = [...this.contexts.entries()].flatMap(([agent, context]) => {
757
757
  context.facts = senseFactsFromRuntimeConfig(agent, context.senses, (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent), (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent));
758
758
  const blueBubblesRuntimeFacts = readBlueBubblesRuntimeFacts(agent, this.bundlesRoot, runtime.get(agent)?.bluebubbles);
759
+ const blueBubblesConfigured = context.facts.bluebubbles.configured;
759
760
  const runtimeInfo = {
760
761
  cli: { configured: true },
761
762
  teams: {
762
763
  configured: context.facts.teams.configured,
763
764
  ...(runtime.get(agent)?.teams ?? {}),
764
765
  },
765
- bluebubbles: {
766
- configured: context.facts.bluebubbles.configured,
767
- optional: context.facts.bluebubbles.optional,
768
- ...blueBubblesRuntimeFacts,
769
- },
766
+ bluebubbles: blueBubblesConfigured
767
+ ? {
768
+ configured: true,
769
+ optional: context.facts.bluebubbles.optional,
770
+ ...blueBubblesRuntimeFacts,
771
+ }
772
+ : {
773
+ configured: false,
774
+ optional: context.facts.bluebubbles.optional,
775
+ },
770
776
  mail: {
771
777
  configured: context.facts.mail.configured,
772
778
  ...(runtime.get(agent)?.mail ?? {}),
@@ -793,11 +799,13 @@ class DaemonSenseManager {
793
799
  status: entry.status,
794
800
  detail: entry.enabled
795
801
  ? entry.sense === "bluebubbles"
796
- ? blueBubblesRuntimeFacts.detail
797
- ?? context.facts[entry.sense].detail
802
+ ? blueBubblesConfigured
803
+ ? blueBubblesRuntimeFacts.detail
804
+ ?? context.facts[entry.sense].detail
805
+ : context.facts[entry.sense].detail
798
806
  : context.facts[entry.sense].detail
799
807
  : "not enabled in agent.json",
800
- ...(entry.sense === "bluebubbles" ? {
808
+ ...(entry.sense === "bluebubbles" && blueBubblesConfigured ? {
801
809
  proofMethod: blueBubblesRuntimeFacts.proofMethod,
802
810
  lastProofAt: blueBubblesRuntimeFacts.lastProofAt,
803
811
  proofAgeMs: blueBubblesRuntimeFacts.proofAgeMs,
@@ -45,6 +45,7 @@ exports.refreshRuntimeCredentialConfig = refreshRuntimeCredentialConfig;
45
45
  exports.refreshMachineRuntimeCredentialConfig = refreshMachineRuntimeCredentialConfig;
46
46
  exports.upsertRuntimeCredentialConfig = upsertRuntimeCredentialConfig;
47
47
  exports.upsertMachineRuntimeCredentialConfig = upsertMachineRuntimeCredentialConfig;
48
+ exports.mergeMachineRuntimeCredentialConfig = mergeMachineRuntimeCredentialConfig;
48
49
  exports.resetRuntimeCredentialConfigCache = resetRuntimeCredentialConfigCache;
49
50
  const crypto = __importStar(require("node:crypto"));
50
51
  const runtime_1 = require("../nerves/runtime");
@@ -314,6 +315,17 @@ async function refreshRuntimeCredentialConfig(agentName, options = {}) {
314
315
  async function refreshMachineRuntimeCredentialConfig(agentName, machineId, options = {}) {
315
316
  return refreshRuntimeCredentialConfigItem(agentName, machineRuntimeConfigItemName(machineId), cacheMachineResult, options);
316
317
  }
318
+ function mergeRuntimeCredentialConfig(base, patch) {
319
+ const next = { ...base };
320
+ for (const key of Object.keys(patch)) {
321
+ const baseValue = next[key];
322
+ const patchValue = patch[key];
323
+ next[key] = isRecord(baseValue) && isRecord(patchValue)
324
+ ? mergeRuntimeCredentialConfig(baseValue, patchValue)
325
+ : patchValue;
326
+ }
327
+ return next;
328
+ }
317
329
  async function upsertRuntimeCredentialConfig(agentName, config, now = new Date()) {
318
330
  const payload = {
319
331
  schemaVersion: 1,
@@ -361,6 +373,16 @@ async function upsertMachineRuntimeCredentialConfig(agentName, machineId, config
361
373
  cacheMachineResult(agentName, result);
362
374
  return result;
363
375
  }
376
+ // Partial machine-runtime writers must use this helper, not raw upsert: one
377
+ // machine item carries multiple local attachments such as A2A, BlueBubbles, and Voice.
378
+ async function mergeMachineRuntimeCredentialConfig(agentName, machineId, patch, now = new Date()) {
379
+ const current = await refreshMachineRuntimeCredentialConfig(agentName, machineId);
380
+ if (!current.ok && current.reason !== "missing") {
381
+ throw new Error(`cannot merge machine runtime config at ${current.itemPath}: ${current.error}`);
382
+ }
383
+ const base = current.ok ? current.config : {};
384
+ return upsertMachineRuntimeCredentialConfig(agentName, machineId, mergeRuntimeCredentialConfig(base, patch), now);
385
+ }
364
386
  function resetRuntimeCredentialConfigCache() {
365
387
  cachedRuntimeConfigs = new Map();
366
388
  cachedMachineRuntimeConfigs = new Map();
@@ -60,7 +60,7 @@ Promise.all([
60
60
  Promise.resolve().then(() => __importStar(require("../heart/machine-identity"))),
61
61
  Promise.resolve().then(() => __importStar(require("@ouro.bot/friends/a2a-client"))),
62
62
  ])
63
- .then(async ([{ startA2AServer }, { loadOrMintA2AIdentity }, { waitForRuntimeCredentialBootstrap, readMachineRuntimeCredentialConfig, upsertMachineRuntimeCredentialConfig }, { loadOrCreateMachineIdentity }, { ready },]) => {
63
+ .then(async ([{ startA2AServer }, { loadOrMintA2AIdentity, readStoredA2ASeed }, { waitForRuntimeCredentialBootstrap, readMachineRuntimeCredentialConfig, refreshMachineRuntimeCredentialConfig, mergeMachineRuntimeCredentialConfig }, { loadOrCreateMachineIdentity }, { ready },]) => {
64
64
  const os = await Promise.resolve().then(() => __importStar(require("node:os")));
65
65
  // Wait for the daemon to deliver the machine-local runtime config (carrying the
66
66
  // a2a identity seed) into the in-memory cache before we read or mint identity.
@@ -73,14 +73,21 @@ Promise.all([
73
73
  });
74
74
  const sodium = await ready();
75
75
  const machineId = loadOrCreateMachineIdentity({ homeDir: os.homedir() }).machineId;
76
- const machineConfigRead = readMachineRuntimeCredentialConfig(agentName);
76
+ const cachedMachineConfigRead = readMachineRuntimeCredentialConfig(agentName);
77
+ const machineConfigRead = cachedMachineConfigRead.ok && readStoredA2ASeed(cachedMachineConfigRead.config)
78
+ ? cachedMachineConfigRead
79
+ : await refreshMachineRuntimeCredentialConfig(agentName, machineId);
80
+ if (!machineConfigRead.ok && machineConfigRead.reason !== "missing") {
81
+ throw new Error(`A2A identity requires readable machine runtime config at ${machineConfigRead.itemPath}: ${machineConfigRead.error}`);
82
+ }
77
83
  const machineConfig = machineConfigRead.ok ? machineConfigRead.config : {};
78
84
  const identity = await loadOrMintA2AIdentity({
79
85
  agentName,
80
86
  sodium,
81
87
  config: machineConfig,
82
88
  upsert: async (next) => {
83
- await upsertMachineRuntimeCredentialConfig(agentName, machineId, next);
89
+ const seed = readStoredA2ASeed(next);
90
+ await mergeMachineRuntimeCredentialConfig(agentName, machineId, { a2a: { identity: { ed25519Seed: seed } } });
84
91
  },
85
92
  });
86
93
  const rawPort = argValue("--port");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.677",
3
+ "version": "0.1.0-alpha.679",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",