@ouro.bot/cli 0.1.0-alpha.646 → 0.1.0-alpha.648

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.648",
6
+ "changes": [
7
+ "Daemon restart state truth: stale exits from a child intentionally replaced during restart are ignored, preventing provider refresh from reporting success while a later SIGTERM from the old worker clears the replacement pid and leaves status stuck at `starting`."
8
+ ]
9
+ },
10
+ {
11
+ "version": "0.1.0-alpha.647",
12
+ "changes": [
13
+ "Provider refresh restart hardening: provider-refresh restarts now skip redundant vault config checks after credentials are already refreshed, and the Bitwarden cross-process lock wait outlasts a single `bw` child timeout so concurrent vault users survive normal holder cleanup instead of failing at the same 30s boundary."
14
+ ]
15
+ },
4
16
  {
5
17
  "version": "0.1.0-alpha.646",
6
18
  "changes": [
@@ -2001,14 +2001,16 @@ async function storeRuntimeConfigKey(input) {
2001
2001
  function readRuntimeApplyWorker(payload, agent) {
2002
2002
  return payload.workers.find((worker) => worker.agent === agent) ?? null;
2003
2003
  }
2004
- async function applyRuntimeChangeToRunningAgent(agent, deps, onProgress) {
2004
+ async function applyRuntimeChangeToRunningAgent(agent, deps, onProgress, options = {}) {
2005
2005
  try {
2006
2006
  onProgress?.("checking whether Ouro is already running");
2007
2007
  const alive = await deps.checkSocketAlive(deps.socketPath);
2008
2008
  if (!alive)
2009
2009
  return "daemon is not running; next `ouro up` will load the change";
2010
2010
  onProgress?.(`asking Ouro to reload ${agent}`);
2011
- const response = await withCliTimeout(DEFAULT_AGENT_RESTART_TIMEOUT_MS, "daemon restart request timed out", () => deps.sendCommand(deps.socketPath, { kind: "agent.restart", agent }));
2011
+ const response = await withCliTimeout(DEFAULT_AGENT_RESTART_TIMEOUT_MS, "daemon restart request timed out", () => deps.sendCommand(deps.socketPath, options.skipRestartConfigCheck
2012
+ ? { kind: "agent.restart", agent, skipConfigCheck: true }
2013
+ : { kind: "agent.restart", agent }));
2012
2014
  if (!response.ok)
2013
2015
  return `daemon restart skipped: ${response.error ?? response.message ?? "unknown daemon error"}`;
2014
2016
  const deadline = cliNowMs(deps) + DEFAULT_RUNTIME_APPLY_TIMEOUT_MS;
@@ -4716,7 +4718,7 @@ async function executeProviderRefresh(command, deps) {
4716
4718
  deps.writeStdout(message);
4717
4719
  return message;
4718
4720
  }
4719
- const reload = await runCommandProgressPhase(progress, `applying change to running ${command.agent}`, () => applyRuntimeChangeToRunningAgent(command.agent, deps, (message) => progress.updateDetail(message)), (result) => result);
4721
+ const reload = await runCommandProgressPhase(progress, `applying change to running ${command.agent}`, () => applyRuntimeChangeToRunningAgent(command.agent, deps, (message) => progress.updateDetail(message), { skipRestartConfigCheck: true }), (result) => result);
4720
4722
  progress.end();
4721
4723
  lines.push(`running agent: ${reload}`);
4722
4724
  const message = lines.join("\n");
@@ -1177,7 +1177,10 @@ class OuroDaemon {
1177
1177
  if (!managed) {
1178
1178
  return { ok: false, error: `Unknown managed agent '${command.agent}'.` };
1179
1179
  }
1180
- void this.processManager.restartAgent(command.agent).catch((error) => {
1180
+ const restartWork = command.skipConfigCheck === true
1181
+ ? this.processManager.restartAgent(command.agent, { skipConfigCheck: true })
1182
+ : this.processManager.restartAgent(command.agent);
1183
+ void restartWork.catch((error) => {
1181
1184
  (0, runtime_1.emitNervesEvent)({
1182
1185
  level: "error",
1183
1186
  component: "daemon",
@@ -203,7 +203,7 @@ class DaemonProcessManager {
203
203
  });
204
204
  }
205
205
  }
206
- async startAgent(agent) {
206
+ async startAgent(agent, options = {}) {
207
207
  const state = this.requireAgent(agent);
208
208
  if (state.process || state.startInFlight)
209
209
  return;
@@ -215,7 +215,7 @@ class DaemonProcessManager {
215
215
  this.clearRestartTimer(state);
216
216
  state.stopRequested = false;
217
217
  state.snapshot.status = "starting";
218
- if (this.configCheckFn) {
218
+ if (this.configCheckFn && options.skipConfigCheck !== true) {
219
219
  let result;
220
220
  try {
221
221
  result = await this.configCheckFn(agent);
@@ -260,6 +260,10 @@ class DaemonProcessManager {
260
260
  state.snapshot.errorReason = null;
261
261
  state.snapshot.fixHint = null;
262
262
  }
263
+ if (options.skipConfigCheck === true) {
264
+ state.snapshot.errorReason = null;
265
+ state.snapshot.fixHint = null;
266
+ }
263
267
  const runCwd = (0, identity_1.getRepoRoot)();
264
268
  const entryScript = path.join((0, identity_1.getRepoRoot)(), "dist", state.config.entry);
265
269
  if (this.existsSyncFn && !this.existsSyncFn(entryScript)) {
@@ -392,7 +396,7 @@ class DaemonProcessManager {
392
396
  });
393
397
  /* v8 ignore stop */
394
398
  child.once("exit", (code, signal) => {
395
- this.onExit(state, code, signal);
399
+ this.onExit(state, child, code, signal);
396
400
  });
397
401
  }
398
402
  finally {
@@ -437,7 +441,7 @@ class DaemonProcessManager {
437
441
  }
438
442
  this.notifySnapshotChange(state.snapshot);
439
443
  }
440
- async restartAgent(agent) {
444
+ async restartAgent(agent, options = {}) {
441
445
  const state = this.requireAgent(agent);
442
446
  // Respawn-loop guard: prune timestamps outside the window, then check
443
447
  // whether we've already restarted this agent too many times in it.
@@ -519,7 +523,7 @@ class DaemonProcessManager {
519
523
  state.startAttemptedAtMs = null;
520
524
  }
521
525
  await this.stopAgent(agent);
522
- await this.startAgent(agent);
526
+ await this.startAgent(agent, options);
523
527
  }
524
528
  async stopAll() {
525
529
  for (const state of this.agents.values()) {
@@ -575,8 +579,8 @@ class DaemonProcessManager {
575
579
  listAgentSnapshots() {
576
580
  return [...this.agents.values()].map((state) => state.snapshot);
577
581
  }
578
- onExit(state, code, signal) {
579
- if (!state.process)
582
+ onExit(state, child, code, signal) {
583
+ if (state.process !== child)
580
584
  return;
581
585
  state.process = null;
582
586
  state.startInFlight = false;
@@ -168,7 +168,8 @@ function isBwItemNotFoundError(error) {
168
168
  // detection serializes across processes.
169
169
  // ---------------------------------------------------------------------------
170
170
  const BW_LOCK_FILENAME = ".ouro-bw.lock";
171
- const BW_LOCK_TIMEOUT_MS = 30_000;
171
+ const BW_COMMAND_TIMEOUT_MS = 30_000;
172
+ const BW_LOCK_TIMEOUT_MS = 75_000;
172
173
  const BW_LOCK_POLL_MS = 100;
173
174
  const BW_LOCK_DEAD_CHILD_GRACE_MS = 2_000;
174
175
  const BW_LOCK_STALE_MS = BW_LOCK_TIMEOUT_MS * 2;
@@ -344,7 +345,7 @@ function execBw(args, sessionToken, appDataDir, stdin, bwBinaryPath = "bw", extr
344
345
  ...extraEnv,
345
346
  };
346
347
  const runCommand = (lock) => new Promise((resolve, reject) => {
347
- const child = (0, node_child_process_1.execFile)(bwBinaryPath, args, { timeout: 30_000, env }, (err, stdout, stderr) => {
348
+ const child = (0, node_child_process_1.execFile)(bwBinaryPath, args, { timeout: BW_COMMAND_TIMEOUT_MS, env }, (err, stdout, stderr) => {
348
349
  if (err) {
349
350
  if (isBwNotInstalled(err)) {
350
351
  reject(new Error("bw CLI not found. Install from https://bitwarden.com/help/cli/"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.646",
3
+ "version": "0.1.0-alpha.648",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",