@inetafrica/open-claudia 3.5.70 → 3.5.71

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.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.5.71
4
+
5
+ 3.5.70 plus a fix to its one-time effort reset, found during the 3.5.70 fleet roll on 20 Oct.
6
+
7
+ - **Effort reset now sticks** (`core/state.js`, `bot.js`): the reset ran when the state module loaded. On the pods the switchboard (the front process that holds calls) loads it first, so it used the file up; the bot then loaded the old max/xhigh levels from disk and saved them back (maya-cloud: "4 stored level(s) back to the default", yet all four still set). The bot now applies the reset itself at boot, saves the cleared levels at once, and only then retires the file. A plain module load (switchboard, CLI) leaves it alone.
8
+
9
+ Tests: `test-effort-reset.js` now checks the levels on disk and that a plain load leaves the file.
10
+
3
11
  ## 3.5.70
4
12
 
5
13
  3.5.69 plus three things Sumeet asked for on 20 Oct: a card answer ("Hidden text and thread hand-offs") and a message after seeing the Opus 5.5 cost chart.
package/bot.js CHANGED
@@ -62,6 +62,9 @@ require("./core/provider-migration").completeProviderMigration({
62
62
  sources: migrationSources,
63
63
  snapshot: migrationSnapshot,
64
64
  });
65
+ // One-shot effort reset (core/state.js): here, in the bot, so the switchboard
66
+ // or a CLI that loads the state module first cannot use it up.
67
+ require("./core/state").applyEffortResetFile();
65
68
  const { readRuntimeMode, sideChatCoordinator } = require("./core/side-chat");
66
69
  const runtimeMode = readRuntimeMode(CONFIG_DIR);
67
70
  const { vault } = require("./core/vault-store");
package/core/state.js CHANGED
@@ -380,8 +380,11 @@ const savedState = (() => {
380
380
  // One-shot "every chat back to the default effort" request, dropped into the
381
381
  // config dir by whoever runs the bot (Sumeet, 20 Oct 2026: high on every bot;
382
382
  // chats pinned to xhigh or max would otherwise keep beating the new default).
383
- // Applied once at boot, before anyone's settings load, so the next save writes
384
- // it; the file is then renamed so a level someone picks later is never undone.
383
+ // Applied by the bot itself at boot (bot.js), never on module load: under a
384
+ // switchboard the front process loads this module first, and on 20 Oct it used
385
+ // the file up while the bot loaded the old levels from disk and saved them
386
+ // back. The cleared levels are saved at once; only then is the file renamed,
387
+ // so a level someone picks later is never undone.
385
388
  // Format: {"providers": ["claude"]}.
386
389
  const EFFORT_RESET_FILE = path.join(CONFIG_DIR, "effort-reset.json");
387
390
 
@@ -404,10 +407,16 @@ function applyEffortReset(state, request) {
404
407
  return cleared;
405
408
  }
406
409
 
407
- function applyEffortResetFile(state, file = EFFORT_RESET_FILE) {
410
+ function applyEffortResetFile(file = EFFORT_RESET_FILE) {
408
411
  if (!fs.existsSync(file)) return null;
409
412
  try {
410
- const cleared = applyEffortReset(state, JSON.parse(fs.readFileSync(file, "utf8")));
413
+ const request = JSON.parse(fs.readFileSync(file, "utf8"));
414
+ const cleared = applyEffortReset(savedState, request)
415
+ + applyEffortReset({ users: Object.fromEntries(userStates) }, request);
416
+ if (cleared > 0 && !saveState()) {
417
+ console.error(`Effort reset: ${cleared} level(s) cleared for now, but the save failed; trying again next boot`);
418
+ return cleared;
419
+ }
411
420
  fs.renameSync(file, `${file}.done-${Date.now()}`);
412
421
  console.error(`Effort reset: ${cleared} stored level(s) back to the default`);
413
422
  return cleared;
@@ -417,8 +426,6 @@ function applyEffortResetFile(state, file = EFFORT_RESET_FILE) {
417
426
  }
418
427
  }
419
428
 
420
- applyEffortResetFile(savedState);
421
-
422
429
  const userStates = new Map();
423
430
 
424
431
  let cachedFreshDefaultProvider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "3.5.70",
3
+ "version": "3.5.71",
4
4
  "description": "An always-on, provider-agnostic coding-agent harness for Claude Code and OpenAI Codex via chat",
5
5
  "main": "bot.js",
6
6
  "bin": {
@@ -18,23 +18,48 @@ fs.writeFileSync(stateFile, JSON.stringify({
18
18
  },
19
19
  }));
20
20
 
21
- // Without a request file nothing changes.
22
21
  const env = { ...process.env, OPEN_CLAUDIA_TEST: "1", OPEN_CLAUDIA_CONFIG_DIR: dir, HOME: dir };
23
- const probe = `
24
- require(${JSON.stringify(path.join(__dirname, "core/state.js"))});
25
- process.stdout.write("loaded");
26
- `;
27
- let run = spawnSync(process.execPath, ["-e", probe], { env, encoding: "utf8" });
28
- assert.strictEqual(run.status, 0, run.stderr);
29
- assert.doesNotMatch(run.stderr, /Effort reset:/);
30
-
31
- // With one: Claude levels cleared at boot, Codex untouched, file retired.
22
+ const statePath = JSON.stringify(path.join(__dirname, "core/state.js"));
23
+ const run = (code) => {
24
+ const result = spawnSync(process.execPath, ["-e", code], { env, encoding: "utf8" });
25
+ assert.strictEqual(result.status, 0, result.stderr);
26
+ return result;
27
+ };
28
+ const boot = `require(${statePath}).applyEffortResetFile(); process.stdout.write("booted");`;
29
+ const levelsOnDisk = () => {
30
+ const disk = JSON.parse(fs.readFileSync(stateFile, "utf8"));
31
+ return [
32
+ disk.users["kazee:owner"].providerSettings.claude.effort,
33
+ disk.rooms["kazee:room-a"].providerSettings.claude.effort,
34
+ disk.users["kazee:owner"].providerSettings.codex.effort,
35
+ disk.rooms["kazee:room-a"].providerSettings.codex.effort,
36
+ ];
37
+ };
38
+
39
+ // Without a request file nothing changes.
40
+ let result = run(boot);
41
+ assert.doesNotMatch(result.stderr, /Effort reset:/);
42
+ assert.deepStrictEqual(levelsOnDisk(), ["max", "xhigh", "max", "xhigh"]);
43
+
44
+ // Loading the module alone (the switchboard, a CLI) must not use the file up:
45
+ // on 20 Oct the switchboard did, and the bot then saved the old levels back.
32
46
  fs.writeFileSync(resetFile, JSON.stringify({ providers: ["claude"] }));
33
- run = spawnSync(process.execPath, ["-e", probe], { env, encoding: "utf8" });
34
- assert.strictEqual(run.status, 0, run.stderr);
35
- assert.match(run.stderr, /Effort reset: 2 stored level\(s\) back to the default/);
47
+ result = run(`require(${statePath}); process.stdout.write("loaded");`);
48
+ assert.doesNotMatch(result.stderr, /Effort reset:/);
49
+ assert.ok(fs.existsSync(resetFile), "a plain module load leaves the request for the bot");
50
+
51
+ // The bot applies it: Claude levels cleared ON DISK, Codex untouched, file retired.
52
+ result = run(boot);
53
+ assert.match(result.stderr, /Effort reset: 2 stored level\(s\) back to the default/);
36
54
  assert.ok(!fs.existsSync(resetFile), "request file is retired after use");
37
55
  assert.ok(fs.readdirSync(dir).some((name) => name.startsWith("effort-reset.json.done-")));
56
+ assert.deepStrictEqual(levelsOnDisk(), [null, null, "max", "xhigh"]);
57
+
58
+ // A fresh process (the next boot) reads the cleared levels, and nothing runs twice.
59
+ result = run(`const s = require(${statePath}); s.applyEffortResetFile();
60
+ process.stdout.write(String(s.savedState.rooms["kazee:room-a"].providerSettings.claude.effort));`);
61
+ assert.strictEqual(result.stdout, "null");
62
+ assert.doesNotMatch(result.stderr, /Effort reset:/);
38
63
 
39
64
  // The pure function: users and rooms, only the named providers.
40
65
  const { applyEffortReset } = require("./core/state");
@@ -660,7 +660,10 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
660
660
  // of saved login details removed ("Nothing: remove it completely"), thread
661
661
  // hand-off ("Yes, build it"), and high effort as the default on every bot
662
662
  // ("let's set high on all the bots instead and make it the default").
663
- assert.strictEqual(pkg.version, "3.5.70", "release version must remain unchanged without explicit approval");
663
+ // 3.5.71 = 3.5.70 + the effort-reset fix: on the pods the switchboard used the
664
+ // reset file up and the bot saved the old max/xhigh back. Same approved
665
+ // rollout (Sumeet, 20 Oct: "set high on all the bots"), now working.
666
+ assert.strictEqual(pkg.version, "3.5.71", "release version must remain unchanged without explicit approval");
664
667
  for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
665
668
  assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
666
669
  }