@bongos/core 1.24.76 → 1.24.77

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.
@@ -265,6 +265,10 @@ const WORKER_ENV_ALLOW = [
265
265
  // missing here would be set on the host and silently absent in the worker.
266
266
  ...claudeBinEnvNames(),
267
267
  'XDG_CONFIG_HOME',
268
+ // The runner's own config root (task 1005095): its login, heartbeat and run log
269
+ // sit apart from the builder's own CLI session on the same device, and a worker
270
+ // that did not inherit this would claim and ship as the wrong session.
271
+ 'BONGOS_CONFIG_ROOT',
268
272
  // THE WORKER'S OWN CREDENTIAL, and it has to be here (task 1003907, found by
269
273
  // running it). On a desktop, the claude CLI authenticates from the credential
270
274
  // store under USERPROFILE/HOME, which are already allowed - so this list looked
@@ -545,7 +549,9 @@ function queueGatedRow(queueGate, now) {
545
549
  async function iteration(opts, deps = {}) {
546
550
  const runCmd = deps.run || run;
547
551
  const spawnWork = deps.spawnWorker || spawnWorker;
548
- const readGauge = deps.gauge || (() => gauge.evaluate());
552
+ // absentMeansGo: a device with no gauge file at all works until the usage limit
553
+ // stops it (task 1005095) — see decideCapacity in modules/autonomy/gauge.js.
554
+ const readGauge = deps.gauge || (() => gauge.evaluate(undefined, { absentMeansGo: true }));
549
555
  const pick = deps.pickTask || pickTask;
550
556
  const log = deps.record || record;
551
557
 
@@ -26,9 +26,14 @@ function gaugePath() {
26
26
  catch (_) { return null; }
27
27
  }
28
28
 
29
+ // null means there is NO file. A file that exists but cannot be read or parsed
30
+ // comes back as the string 'unreadable', which the decision treats as a bad
31
+ // reading (unknown) and never as "this device has no gauge" (task 1005095).
29
32
  function loadGauge(p) {
30
33
  if (!p) return null;
31
- try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (_) { return null; }
34
+ let text;
35
+ try { text = fs.readFileSync(p, 'utf8'); } catch (e) { return e && e.code === 'ENOENT' ? null : 'unreadable'; }
36
+ try { return JSON.parse(text); } catch (_) { return 'unreadable'; }
32
37
  }
33
38
 
34
39
  function readConfig() {
@@ -47,9 +52,12 @@ function readConfig() {
47
52
  return c;
48
53
  }
49
54
 
50
- function evaluate(nowEpochS = Math.floor(Date.now() / 1000)) {
55
+ // `overrides` is merged over the env config. The supervisor passes
56
+ // { absentMeansGo: true } (task 1005095); this CLI passes nothing, so a missing
57
+ // file is still UNKNOWN here.
58
+ function evaluate(nowEpochS = Math.floor(Date.now() / 1000), overrides = {}) {
51
59
  const p = gaugePath();
52
- return { path: p, decision: decideCapacity({ gauge: loadGauge(p), now: nowEpochS, config: readConfig() }) };
60
+ return { path: p, decision: decideCapacity({ gauge: loadGauge(p), now: nowEpochS, config: { ...readConfig(), ...overrides } }) };
53
61
  }
54
62
 
55
63
  async function main(argv) {
@@ -333,7 +333,11 @@ function sessionStoreDir() {
333
333
  // Directory name deliberately NOT 'sessions': that is a live module key, and ADR 0083
334
334
  // §Decision #4 forbids naming one in shared machinery. 'instances' is the truer name anyway —
335
335
  // one file per instance is exactly what this holds.
336
- return path.join(os.homedir(), '.config', ic.FALLBACK_DIR, 'instances');
336
+ // Under the config ROOT, which is ~/.config unless BONGOS_CONFIG_ROOT moves it
337
+ // (task 1005095) — so an Autobongos runner's login is never filed into, or read
338
+ // out of, the builder's own store. The root is not the brand: the anchor is
339
+ // still the same fixed dir name for every checkout that shares a root.
340
+ return path.join(ic.configRoot(), ic.FALLBACK_DIR, 'instances');
337
341
  }
338
342
 
339
343
  // The store's filename for an instance, derived from its api_base host. Returns null when the base
@@ -0,0 +1,8 @@
1
+ # scripts/gds/autobongos-bootstrap.ps1 -- @bongos-forwarder (task 1004848). Generated by
2
+ # scripts/bongos/codemod-rename-scripts-gds.js; do not edit.
3
+ # The real script is scripts/bongos/autobongos-bootstrap.ps1. This forwarder keeps callers that still name
4
+ # the old path working, and warns once so they get repointed. Task 1003706 removes it.
5
+ if (-not $env:BONGOS_FORWARDER_WARNED) { Write-Warning '[bongos] scripts/gds/autobongos-bootstrap.ps1 has moved to scripts/bongos/autobongos-bootstrap.ps1. This old path still works for now, but update whatever called it. The forwarders in scripts/gds/ are removed in a later release.' }
6
+ $env:BONGOS_FORWARDER_WARNED = '1'
7
+ & (Join-Path $PSScriptRoot '..\bongos\autobongos-bootstrap.ps1') @args
8
+ exit $LASTEXITCODE
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ # scripts/gds/autobongos-bootstrap.sh — @bongos-forwarder (task 1004848). Generated by
3
+ # scripts/bongos/codemod-rename-scripts-gds.js; do not edit.
4
+ # The real script is scripts/bongos/autobongos-bootstrap.sh. This forwarder keeps callers that still name
5
+ # the old path working, and warns once so they get repointed. Task 1003706 removes it.
6
+ if [ -z "${BONGOS_FORWARDER_WARNED:-}" ]; then echo "[bongos] scripts/gds/autobongos-bootstrap.sh has moved to scripts/bongos/autobongos-bootstrap.sh. This old path still works for now, but update whatever called it. The forwarders in scripts/gds/ are removed in a later release." >&2; fi
7
+ export BONGOS_FORWARDER_WARNED=1
8
+ exec bash "$(dirname "$0")/../bongos/autobongos-bootstrap.sh" "$@"
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ // scripts/gds/autobongos-host.js — @bongos-forwarder (task 1004848). Generated by
3
+ // scripts/bongos/codemod-rename-scripts-gds.js; do not edit.
4
+ // The real script is scripts/bongos/autobongos-host.js. This forwarder keeps callers that still name
5
+ // the old path working, and warns once so they get repointed. Task 1003706 removes it.
6
+ 'use strict';
7
+ require('../bongos/forwarder.js').forward(module, 'autobongos-host.js');
@@ -112,17 +112,35 @@ function resolveApiBase({ session, env = process.env, b = safeBrand() } = {}) {
112
112
  return fromSession || defaultApiBase(b);
113
113
  }
114
114
 
115
+ // The folder every config dir lives under: ~/.config, unless BONGOS_CONFIG_ROOT
116
+ // names another one (task 1005095).
117
+ //
118
+ // WHY AN OVERRIDE. An Autobongos runner on a builder's own laptop holds a login
119
+ // of its own (src/bongos/runner-login.js), and it must not share a session file
120
+ // with the builder's CLI: one slot means adding the laptop as a runner signs the
121
+ // builder's own tools out, and removing the runner signs them out again. The
122
+ // runner's device program (scripts/bongos/autobongos-host.js) sets this for the
123
+ // supervisor and every worker it starts, so their session, heartbeat and run log
124
+ // sit apart — and with a root of its own the LEGACY dirs below are not found
125
+ // either, so the runner can never fall back to the builder's own session.
126
+ // One fixed name, read directly: the branded-prefix lookup needs the brand, and
127
+ // this decides where the brand's own dir goes.
128
+ function configRoot(env = process.env) {
129
+ const over = typeof env.BONGOS_CONFIG_ROOT === 'string' ? env.BONGOS_CONFIG_ROOT.trim() : '';
130
+ return over ? path.resolve(over) : path.join(os.homedir(), '.config');
131
+ }
132
+
115
133
  // Absolute path to the instance config dir — the WRITE target and first read.
116
134
  function configHome(b = safeBrand()) {
117
- return path.join(os.homedir(), '.config', configDirName(b));
135
+ return path.join(configRoot(), configDirName(b));
118
136
  }
119
137
 
120
138
  // All config dirs to try on READ, configured first then legacy, de-duped.
121
139
  function configReadDirs(b = safeBrand()) {
122
- const home = os.homedir();
140
+ const root = configRoot();
123
141
  const dirs = [configHome(b)];
124
142
  for (const d of LEGACY_DIRS) {
125
- const p = path.join(home, '.config', d);
143
+ const p = path.join(root, d);
126
144
  if (!dirs.includes(p)) dirs.push(p);
127
145
  }
128
146
  return dirs;
@@ -367,6 +385,7 @@ module.exports = {
367
385
  envPrefix,
368
386
  defaultApiBase,
369
387
  resolveApiBase,
388
+ configRoot,
370
389
  configHome,
371
390
  configReadDirs,
372
391
  configPath,
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.24.76'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.24.77'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');