@atomic-chat/core 0.20.6 → 0.21.0

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.
Files changed (226) hide show
  1. package/dist/audio/jobs.js +4 -0
  2. package/dist/audio/jobs.js.map +1 -1
  3. package/dist/audio/service.d.ts +1 -1
  4. package/dist/audio/service.js +3 -1
  5. package/dist/audio/service.js.map +1 -1
  6. package/dist/audio/session.js +28 -16
  7. package/dist/audio/session.js.map +1 -1
  8. package/dist/audio/state.d.ts +3 -1
  9. package/dist/audio/state.js +3 -1
  10. package/dist/audio/state.js.map +1 -1
  11. package/dist/cli/launch.d.ts +23 -3
  12. package/dist/cli/launch.js +59 -8
  13. package/dist/cli/launch.js.map +1 -1
  14. package/dist/cli/main.d.ts +1 -1
  15. package/dist/contracts/events.d.ts +8 -0
  16. package/dist/contracts/settings.d.ts +5 -0
  17. package/dist/contracts/settings.js.map +1 -1
  18. package/dist/core/atomic-core.d.ts +3 -1
  19. package/dist/core/atomic-core.js +4 -1
  20. package/dist/core/atomic-core.js.map +1 -1
  21. package/dist/core/create.js +4 -1
  22. package/dist/core/create.js.map +1 -1
  23. package/dist/core/sessions.js +1 -0
  24. package/dist/core/sessions.js.map +1 -1
  25. package/dist/integrations/catalog.d.ts +25 -8
  26. package/dist/integrations/catalog.js +105 -38
  27. package/dist/integrations/catalog.js.map +1 -1
  28. package/dist/integrations/configure/atomic-agent.d.ts +9 -1
  29. package/dist/integrations/configure/atomic-agent.js +42 -3
  30. package/dist/integrations/configure/atomic-agent.js.map +1 -1
  31. package/dist/integrations/configure/backup.d.ts +21 -0
  32. package/dist/integrations/configure/backup.js +52 -0
  33. package/dist/integrations/configure/backup.js.map +1 -0
  34. package/dist/integrations/configure/claude-code.d.ts +11 -4
  35. package/dist/integrations/configure/claude-code.js +73 -24
  36. package/dist/integrations/configure/claude-code.js.map +1 -1
  37. package/dist/integrations/configure/cline.d.ts +14 -4
  38. package/dist/integrations/configure/cline.js +78 -6
  39. package/dist/integrations/configure/cline.js.map +1 -1
  40. package/dist/integrations/configure/codex.d.ts +5 -3
  41. package/dist/integrations/configure/codex.js +12 -5
  42. package/dist/integrations/configure/codex.js.map +1 -1
  43. package/dist/integrations/configure/copilot.d.ts +28 -5
  44. package/dist/integrations/configure/copilot.js +124 -8
  45. package/dist/integrations/configure/copilot.js.map +1 -1
  46. package/dist/integrations/configure/droid.d.ts +13 -7
  47. package/dist/integrations/configure/droid.js +48 -17
  48. package/dist/integrations/configure/droid.js.map +1 -1
  49. package/dist/integrations/configure/dsh.d.ts +36 -20
  50. package/dist/integrations/configure/dsh.js +250 -48
  51. package/dist/integrations/configure/dsh.js.map +1 -1
  52. package/dist/integrations/configure/goose.d.ts +21 -7
  53. package/dist/integrations/configure/goose.js +141 -10
  54. package/dist/integrations/configure/goose.js.map +1 -1
  55. package/dist/integrations/configure/hermes.d.ts +63 -10
  56. package/dist/integrations/configure/hermes.js +360 -75
  57. package/dist/integrations/configure/hermes.js.map +1 -1
  58. package/dist/integrations/configure/json-backup.d.ts +73 -0
  59. package/dist/integrations/configure/json-backup.js +292 -0
  60. package/dist/integrations/configure/json-backup.js.map +1 -0
  61. package/dist/integrations/configure/json-key-backup.d.ts +43 -0
  62. package/dist/integrations/configure/json-key-backup.js +113 -0
  63. package/dist/integrations/configure/json-key-backup.js.map +1 -0
  64. package/dist/integrations/configure/kilo.d.ts +4 -4
  65. package/dist/integrations/configure/kilo.js +6 -9
  66. package/dist/integrations/configure/kilo.js.map +1 -1
  67. package/dist/integrations/configure/legacy-env-block.d.ts +18 -0
  68. package/dist/integrations/configure/legacy-env-block.js +47 -0
  69. package/dist/integrations/configure/legacy-env-block.js.map +1 -0
  70. package/dist/integrations/configure/mimo.d.ts +3 -2
  71. package/dist/integrations/configure/mimo.js +8 -9
  72. package/dist/integrations/configure/mimo.js.map +1 -1
  73. package/dist/integrations/configure/muse.d.ts +3 -3
  74. package/dist/integrations/configure/muse.js +5 -6
  75. package/dist/integrations/configure/muse.js.map +1 -1
  76. package/dist/integrations/configure/openclaude.d.ts +22 -7
  77. package/dist/integrations/configure/openclaude.js +132 -39
  78. package/dist/integrations/configure/openclaude.js.map +1 -1
  79. package/dist/integrations/configure/openclaw.d.ts +19 -5
  80. package/dist/integrations/configure/openclaw.js +79 -23
  81. package/dist/integrations/configure/openclaw.js.map +1 -1
  82. package/dist/integrations/configure/opencode-style.d.ts +53 -11
  83. package/dist/integrations/configure/opencode-style.js +218 -23
  84. package/dist/integrations/configure/opencode-style.js.map +1 -1
  85. package/dist/integrations/configure/opencode.d.ts +5 -4
  86. package/dist/integrations/configure/opencode.js +8 -10
  87. package/dist/integrations/configure/opencode.js.map +1 -1
  88. package/dist/integrations/configure/openhands.d.ts +5 -4
  89. package/dist/integrations/configure/openhands.js +7 -7
  90. package/dist/integrations/configure/openhands.js.map +1 -1
  91. package/dist/integrations/configure/pi.d.ts +6 -5
  92. package/dist/integrations/configure/pi.js +79 -30
  93. package/dist/integrations/configure/pi.js.map +1 -1
  94. package/dist/integrations/configure/poolside.d.ts +5 -4
  95. package/dist/integrations/configure/poolside.js +7 -7
  96. package/dist/integrations/configure/poolside.js.map +1 -1
  97. package/dist/integrations/configure/registry.d.ts +6 -0
  98. package/dist/integrations/configure/registry.js +1 -0
  99. package/dist/integrations/configure/registry.js.map +1 -1
  100. package/dist/integrations/configure/zcode.d.ts +6 -7
  101. package/dist/integrations/configure/zcode.js +26 -11
  102. package/dist/integrations/configure/zcode.js.map +1 -1
  103. package/dist/integrations/configure/zed.d.ts +16 -4
  104. package/dist/integrations/configure/zed.js +61 -13
  105. package/dist/integrations/configure/zed.js.map +1 -1
  106. package/dist/models/gguf/kv-cache.d.ts +20 -1
  107. package/dist/models/gguf/kv-cache.js +97 -7
  108. package/dist/models/gguf/kv-cache.js.map +1 -1
  109. package/dist/models/gguf/reader.d.ts +5 -3
  110. package/dist/models/gguf/reader.js +10 -6
  111. package/dist/models/gguf/reader.js.map +1 -1
  112. package/dist/runtime/llamacpp/args.d.ts +14 -0
  113. package/dist/runtime/llamacpp/args.js +48 -4
  114. package/dist/runtime/llamacpp/args.js.map +1 -1
  115. package/dist/runtime/llamacpp/ctx-ladder.d.ts +6 -3
  116. package/dist/runtime/llamacpp/ctx-ladder.js +6 -3
  117. package/dist/runtime/llamacpp/ctx-ladder.js.map +1 -1
  118. package/dist/runtime/llamacpp/fit-margin.d.ts +24 -0
  119. package/dist/runtime/llamacpp/fit-margin.js +31 -0
  120. package/dist/runtime/llamacpp/fit-margin.js.map +1 -1
  121. package/dist/runtime/llamacpp/generation-limits.d.ts +45 -0
  122. package/dist/runtime/llamacpp/generation-limits.js +61 -0
  123. package/dist/runtime/llamacpp/generation-limits.js.map +1 -0
  124. package/dist/runtime/llamacpp/load-plan.d.ts +14 -2
  125. package/dist/runtime/llamacpp/load-plan.js +64 -13
  126. package/dist/runtime/llamacpp/load-plan.js.map +1 -1
  127. package/dist/runtime/llamacpp/runtime.d.ts +1 -0
  128. package/dist/runtime/llamacpp/runtime.js +2 -0
  129. package/dist/runtime/llamacpp/runtime.js.map +1 -1
  130. package/dist/runtime/managed-engines/runtime.js +13 -2
  131. package/dist/runtime/managed-engines/runtime.js.map +1 -1
  132. package/dist/runtime/managed-engines/spec.d.ts +6 -0
  133. package/dist/runtime/managed-engines/spec.js.map +1 -1
  134. package/dist/runtime/managed-models/auto-limits.d.ts +47 -0
  135. package/dist/runtime/managed-models/auto-limits.js +60 -0
  136. package/dist/runtime/managed-models/auto-limits.js.map +1 -0
  137. package/dist/runtime/managed-models/index.d.ts +1 -0
  138. package/dist/runtime/managed-models/index.js +1 -0
  139. package/dist/runtime/managed-models/index.js.map +1 -1
  140. package/dist/runtime/mlx/config.d.ts +9 -5
  141. package/dist/runtime/mlx/config.js +12 -6
  142. package/dist/runtime/mlx/config.js.map +1 -1
  143. package/dist/runtime/mlx/model-files.d.ts +9 -0
  144. package/dist/runtime/mlx/model-files.js +26 -0
  145. package/dist/runtime/mlx/model-files.js.map +1 -1
  146. package/dist/runtime/mlx/runtime.d.ts +7 -0
  147. package/dist/runtime/mlx/runtime.js +24 -2
  148. package/dist/runtime/mlx/runtime.js.map +1 -1
  149. package/dist/runtime/sglang/adapter.d.ts +4 -0
  150. package/dist/runtime/sglang/adapter.js +9 -6
  151. package/dist/runtime/sglang/adapter.js.map +1 -1
  152. package/dist/runtime/sglang/engine.js +2 -1
  153. package/dist/runtime/sglang/engine.js.map +1 -1
  154. package/dist/runtime/sglang/memory.d.ts +11 -1
  155. package/dist/runtime/sglang/memory.js +34 -3
  156. package/dist/runtime/sglang/memory.js.map +1 -1
  157. package/dist/runtime/sglang/settings.d.ts +2 -1
  158. package/dist/runtime/sglang/settings.js +11 -7
  159. package/dist/runtime/sglang/settings.js.map +1 -1
  160. package/dist/runtime/vllm/adapter.d.ts +4 -0
  161. package/dist/runtime/vllm/adapter.js +9 -6
  162. package/dist/runtime/vllm/adapter.js.map +1 -1
  163. package/dist/runtime/vllm/engine.js +1 -0
  164. package/dist/runtime/vllm/engine.js.map +1 -1
  165. package/dist/runtime/vllm/memory.d.ts +12 -1
  166. package/dist/runtime/vllm/memory.js +44 -2
  167. package/dist/runtime/vllm/memory.js.map +1 -1
  168. package/dist/runtime/vllm/settings.d.ts +2 -1
  169. package/dist/runtime/vllm/settings.js +12 -7
  170. package/dist/runtime/vllm/settings.js.map +1 -1
  171. package/dist/server/public/context-window.d.ts +29 -0
  172. package/dist/server/public/context-window.js +77 -0
  173. package/dist/server/public/context-window.js.map +1 -0
  174. package/dist/server/public/decision-preview.js +1 -0
  175. package/dist/server/public/decision-preview.js.map +1 -1
  176. package/dist/server/public/errors.d.ts +15 -4
  177. package/dist/server/public/errors.js +53 -7
  178. package/dist/server/public/errors.js.map +1 -1
  179. package/dist/server/public/forward.js +65 -5
  180. package/dist/server/public/forward.js.map +1 -1
  181. package/dist/server/public/index.d.ts +1 -0
  182. package/dist/server/public/index.js +1 -0
  183. package/dist/server/public/index.js.map +1 -1
  184. package/dist/server/public/listing.d.ts +9 -2
  185. package/dist/server/public/listing.js +30 -9
  186. package/dist/server/public/listing.js.map +1 -1
  187. package/dist/server/public/responses.js +9 -5
  188. package/dist/server/public/responses.js.map +1 -1
  189. package/dist/server/public/system-messages.d.ts +39 -0
  190. package/dist/server/public/system-messages.js +166 -0
  191. package/dist/server/public/system-messages.js.map +1 -0
  192. package/dist/server/public/telemetry.d.ts +9 -0
  193. package/dist/server/public/telemetry.js +42 -6
  194. package/dist/server/public/telemetry.js.map +1 -1
  195. package/dist/server/public/thinking.d.ts +26 -0
  196. package/dist/server/public/thinking.js +62 -0
  197. package/dist/server/public/thinking.js.map +1 -0
  198. package/dist/server/public/trace.d.ts +8 -0
  199. package/dist/server/public/trace.js +17 -0
  200. package/dist/server/public/trace.js.map +1 -1
  201. package/dist/server/public/types.d.ts +8 -0
  202. package/dist/server/shims/index.d.ts +1 -0
  203. package/dist/server/shims/index.js +1 -0
  204. package/dist/server/shims/index.js.map +1 -1
  205. package/dist/server/shims/reminders.d.ts +8 -0
  206. package/dist/server/shims/reminders.js +14 -0
  207. package/dist/server/shims/reminders.js.map +1 -0
  208. package/dist/server/shims/responses.d.ts +33 -9
  209. package/dist/server/shims/responses.js +160 -36
  210. package/dist/server/shims/responses.js.map +1 -1
  211. package/dist/settings/default-migrations.d.ts +34 -0
  212. package/dist/settings/default-migrations.js +47 -0
  213. package/dist/settings/default-migrations.js.map +1 -0
  214. package/dist/settings/schema/atomic-prism.json +23 -9
  215. package/dist/settings/schema/llamacpp-upstream.json +23 -9
  216. package/dist/settings/schema/llamacpp.json +23 -9
  217. package/dist/settings/schema/sglang.json +8 -8
  218. package/dist/settings/schema/vllm.json +8 -8
  219. package/dist/settings/schema.js +1 -0
  220. package/dist/settings/schema.js.map +1 -1
  221. package/dist/settings/store.d.ts +6 -0
  222. package/dist/settings/store.js +18 -1
  223. package/dist/settings/store.js.map +1 -1
  224. package/dist/version.d.ts +1 -1
  225. package/dist/version.js +1 -1
  226. package/package.json +1 -1
@@ -0,0 +1,47 @@
1
+ /**
2
+ * OpenHands, Poolside and Muse Code read their endpoint from the environment only. Older releases
3
+ * persisted it — a marked block in the user's shell rc, `setx` on Windows — which captured every
4
+ * other use of the agent (a cloud key replaced by our placeholder, a dead localhost once the server
5
+ * stops). Now the variables are set only on the process we launch (`childEnv`, and inline in the
6
+ * app's terminal), and Connect removes the block an older release wrote: exactly the region between
7
+ * its paired marker lines, never a user's own export of the same variable. Mirrors
8
+ * `remove_legacy_env_agent_config` in the app's `core/system/commands.rs`; the Windows `setx`
9
+ * variables are removed by the app alone.
10
+ */
11
+ /** The rc files an older release may have written to: which one depended on `$SHELL` back then. */
12
+ const LEGACY_RC_FILES = ['.zshenv', '.bash_profile', '.bashrc'];
13
+ /** `content` without the region between (and including) the paired `marker` lines. */
14
+ export function removeMarkedEnvBlock(content, marker) {
15
+ const lines = content.split('\n');
16
+ if (!lines.some((line) => line.startsWith(marker)))
17
+ return content;
18
+ let inBlock = false;
19
+ return lines
20
+ .filter((line) => {
21
+ if (line.startsWith(marker)) {
22
+ inBlock = !inBlock;
23
+ return false;
24
+ }
25
+ return !inBlock;
26
+ })
27
+ .join('\n');
28
+ }
29
+ /** Remove `marker`'s block from every rc file that has one; files without it are not touched. */
30
+ export async function removeLegacyEnvBlocks(fs, marker) {
31
+ for (const rc of LEGACY_RC_FILES) {
32
+ const content = await fs.read(rc);
33
+ if (content === undefined)
34
+ continue;
35
+ const cleaned = removeMarkedEnvBlock(content, marker);
36
+ if (cleaned !== content)
37
+ await fs.write(rc, cleaned);
38
+ }
39
+ }
40
+ /** The writer of an agent configured through its launch environment alone. */
41
+ export function legacyEnvAgentWriter(marker) {
42
+ return async ({ fs, platform }) => {
43
+ if (platform !== 'win32')
44
+ await removeLegacyEnvBlocks(fs, marker);
45
+ };
46
+ }
47
+ //# sourceMappingURL=legacy-env-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-env-block.js","sourceRoot":"","sources":["../../../src/integrations/configure/legacy-env-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,mGAAmG;AACnG,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,eAAe,EAAE,SAAS,CAAC,CAAA;AAE/D,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,MAAc;IAClE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,OAAO,CAAA;IAClE,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,OAAO,GAAG,CAAC,OAAO,CAAA;YAClB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,CAAC,OAAO,CAAA;IACjB,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,EAAY,EAAE,MAAc;IACtE,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACjC,IAAI,OAAO,KAAK,SAAS;YAAE,SAAQ;QACnC,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACrD,IAAI,OAAO,KAAK,OAAO;YAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QAChC,IAAI,QAAQ,KAAK,OAAO;YAAE,MAAM,qBAAqB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACnE,CAAC,CAAA;AACH,CAAC"}
@@ -1,9 +1,10 @@
1
1
  /**
2
- * MiMo Code — `~/.config/mimocode/mimocode.json`.
2
+ * MiMo Code — `mimocode.jsonc` when there is one, else `mimocode.json`, in `$MIMOCODE_HOME/config`,
3
+ * else `~/.config/mimocode`.
3
4
  *
4
5
  * Port of `configure_mimo` in `src-tauri/src/core/system/commands.rs`. MiMo Code is a fork of
5
6
  * OpenCode and its config is OpenCode's field for field; only the directory, the file name and the
6
- * `$schema` URL differ.
7
+ * `$schema` URL differ. Earlier releases wrote a `$schema` MiMo does not serve; it is corrected.
7
8
  */
8
9
  import type { ConfigureInput } from './registry.js';
9
10
  export declare function configureMimo(input: ConfigureInput): Promise<void>;
@@ -1,18 +1,17 @@
1
1
  /**
2
- * MiMo Code — `~/.config/mimocode/mimocode.json`.
2
+ * MiMo Code — `mimocode.jsonc` when there is one, else `mimocode.json`, in `$MIMOCODE_HOME/config`,
3
+ * else `~/.config/mimocode`.
3
4
  *
4
5
  * Port of `configure_mimo` in `src-tauri/src/core/system/commands.rs`. MiMo Code is a fork of
5
6
  * OpenCode and its config is OpenCode's field for field; only the directory, the file name and the
6
- * `$schema` URL differ.
7
+ * `$schema` URL differ. Earlier releases wrote a `$schema` MiMo does not serve; it is corrected.
7
8
  */
8
9
  import { registerWriter } from './registry.js';
9
- import { writeOpencodeStyleConfig } from './opencode-style.js';
10
- export function configureMimo(input) {
11
- return writeOpencodeStyleConfig(input, {
12
- dir: '.config/mimocode',
13
- file: 'mimocode.json',
14
- schema: 'https://mimo.xiaomi.com/config.json',
15
- lenient: false,
10
+ import { mimoTarget, writeOpencodeStyleConfig } from './opencode-style.js';
11
+ export async function configureMimo(input) {
12
+ return writeOpencodeStyleConfig(input, await mimoTarget(input.fs, input.env), {
13
+ schema: 'https://mimo.xiaomi.com/mimocode/config.json',
14
+ staleSchema: 'https://mimo.xiaomi.com/config.json',
16
15
  });
17
16
  }
18
17
  registerWriter('mimo', configureMimo);
@@ -1 +1 @@
1
- {"version":3,"file":"mimo.js","sourceRoot":"","sources":["../../../src/integrations/configure/mimo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AAE9D,MAAM,UAAU,aAAa,CAAC,KAAqB;IACjD,OAAO,wBAAwB,CAAC,KAAK,EAAE;QACrC,GAAG,EAAE,kBAAkB;QACvB,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,qCAAqC;QAC7C,OAAO,EAAE,KAAK;KACf,CAAC,CAAA;AACJ,CAAC;AAED,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA"}
1
+ {"version":3,"file":"mimo.js","sourceRoot":"","sources":["../../../src/integrations/configure/mimo.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAA;AAE1E,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAqB;IACvD,OAAO,wBAAwB,CAAC,KAAK,EAAE,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;QAC5E,MAAM,EAAE,8CAA8C;QACtD,WAAW,EAAE,qCAAqC;KACnD,CAAC,CAAA;AACJ,CAAC;AAED,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA"}
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Muse Code is the one agent with no writable endpoint configuration at all: the provider is chosen
3
3
  * per invocation with `--provider meta --base-url <url> --model <id>` (see the catalog's run args),
4
- * so `apiUrl` and `model` are accepted for symmetry and never written. Muse only checks that
5
- * `META_API_KEY` is present — the call goes wherever `--base-url` points — so the local server's own
6
- * key (or the `atomic` placeholder) satisfies both ends.
4
+ * and Muse only checks that `META_API_KEY` is present — the call goes wherever `--base-url` points —
5
+ * so the local server's own key (or the `atomic` placeholder) set on the child satisfies both ends.
6
+ * Nothing is persisted; Connect only removes what an older release did (`legacy-env-block.ts`).
7
7
  */
8
8
  import type { ConfigureWriter } from './registry.js';
9
9
  export declare const configureMuse: ConfigureWriter;
@@ -1,13 +1,12 @@
1
1
  /**
2
2
  * Muse Code is the one agent with no writable endpoint configuration at all: the provider is chosen
3
3
  * per invocation with `--provider meta --base-url <url> --model <id>` (see the catalog's run args),
4
- * so `apiUrl` and `model` are accepted for symmetry and never written. Muse only checks that
5
- * `META_API_KEY` is present — the call goes wherever `--base-url` points — so the local server's own
6
- * key (or the `atomic` placeholder) satisfies both ends.
4
+ * and Muse only checks that `META_API_KEY` is present — the call goes wherever `--base-url` points —
5
+ * so the local server's own key (or the `atomic` placeholder) set on the child satisfies both ends.
6
+ * Nothing is persisted; Connect only removes what an older release did (`legacy-env-block.ts`).
7
7
  */
8
+ import { legacyEnvAgentWriter } from './legacy-env-block.js';
8
9
  import { registerWriter } from './registry.js';
9
- import { configureEnvAgent } from './env-agent.js';
10
- const MARKER = '# Atomic Chat - Muse Code Config';
11
- export const configureMuse = (input) => configureEnvAgent(input, { agentId: 'muse', marker: MARKER, prefix: 'META_' });
10
+ export const configureMuse = legacyEnvAgentWriter('# Atomic Chat - Muse Code Config');
12
11
  registerWriter('muse', configureMuse);
13
12
  //# sourceMappingURL=muse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"muse.js","sourceRoot":"","sources":["../../../src/integrations/configure/muse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,MAAM,GAAG,kCAAkC,CAAA;AAEjD,MAAM,CAAC,MAAM,aAAa,GAAoB,CAAC,KAAK,EAAE,EAAE,CACtD,iBAAiB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;AAEhF,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA"}
1
+ {"version":3,"file":"muse.js","sourceRoot":"","sources":["../../../src/integrations/configure/muse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,CAAC,MAAM,aAAa,GAAoB,oBAAoB,CAAC,kCAAkC,CAAC,CAAA;AAEtG,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA"}
@@ -1,13 +1,28 @@
1
1
  /**
2
- * OpenClaude — `~/.openclaude.json` plus `~/.openclaude/.openclaude-profile.json`.
2
+ * OpenClaude — its global config (`~/.openclaude.json`) plus the startup profile
3
+ * (`~/.openclaude/.openclaude-profile.json`).
3
4
  *
4
- * Port of `configure_openclaude` in `src-tauri/src/core/system/commands.rs`. OpenClaude keeps a
5
- * list of provider profiles in its global config and a separate startup-profile file that carries
6
- * the environment its launcher exports; both have to agree, so both are written.
5
+ * Port of `configure_openclaude` / `connect_openclaude` in the app (`src-tauri/src/core/system/
6
+ * claude_config.rs`). OpenClaude keeps a list of provider profiles in its global config and a
7
+ * separate startup-profile file that carries the environment its launcher exports; both have to
8
+ * agree, so both are written. Paths follow OpenClaude 0.34: the config home is
9
+ * `$OPENCLAUDE_CONFIG_DIR`, else `~/.openclaude`; a `.config.json` there is the global config, else
10
+ * `.openclaude.json` in `$OPENCLAUDE_CONFIG_DIR` or the home directory.
7
11
  *
8
- * OpenClaude routes us through its OpenAI-compatible shim and a local Atomic Chat needs no key, so
9
- * `apiKey` is accepted for call-site symmetry and ignored — which is why the keyed and keyless
10
- * cases produce byte-identical files.
12
+ * OpenClaude routes us through its OpenAI-compatible shim and sends the profile's `apiKey` as a
13
+ * bearer token, so the server's key goes into the profile (`atomic` for a keyless server) — without
14
+ * it a keyed server answers 401. Our profile is matched by its id only: one the user made from
15
+ * OpenClaude's own Atomic Chat preset is theirs. With a known window the profile carries
16
+ * `maxContextLength`, and the global `env` an output cap for the model (a profile has no output
17
+ * setting). The global `env` also gets empty values for the shell variables that would make
18
+ * OpenClaude skip its active profile: it applies that `env` before deciding. What every key held
19
+ * before is kept in the sidecars `json-backup.ts` describes, for the app's Disconnect.
11
20
  */
21
+ import type { ConfigFs } from '../config-io.js';
12
22
  import type { ConfigureInput } from './registry.js';
23
+ export interface OpenclaudePaths {
24
+ config: string;
25
+ profile: string;
26
+ }
27
+ export declare function openclaudePaths(fs: ConfigFs, env: NodeJS.ProcessEnv): Promise<OpenclaudePaths>;
13
28
  export declare function configureOpenclaude(input: ConfigureInput): Promise<void>;
@@ -1,56 +1,149 @@
1
1
  /**
2
- * OpenClaude — `~/.openclaude.json` plus `~/.openclaude/.openclaude-profile.json`.
2
+ * OpenClaude — its global config (`~/.openclaude.json`) plus the startup profile
3
+ * (`~/.openclaude/.openclaude-profile.json`).
3
4
  *
4
- * Port of `configure_openclaude` in `src-tauri/src/core/system/commands.rs`. OpenClaude keeps a
5
- * list of provider profiles in its global config and a separate startup-profile file that carries
6
- * the environment its launcher exports; both have to agree, so both are written.
5
+ * Port of `configure_openclaude` / `connect_openclaude` in the app (`src-tauri/src/core/system/
6
+ * claude_config.rs`). OpenClaude keeps a list of provider profiles in its global config and a
7
+ * separate startup-profile file that carries the environment its launcher exports; both have to
8
+ * agree, so both are written. Paths follow OpenClaude 0.34: the config home is
9
+ * `$OPENCLAUDE_CONFIG_DIR`, else `~/.openclaude`; a `.config.json` there is the global config, else
10
+ * `.openclaude.json` in `$OPENCLAUDE_CONFIG_DIR` or the home directory.
7
11
  *
8
- * OpenClaude routes us through its OpenAI-compatible shim and a local Atomic Chat needs no key, so
9
- * `apiKey` is accepted for call-site symmetry and ignored — which is why the keyed and keyless
10
- * cases produce byte-identical files.
12
+ * OpenClaude routes us through its OpenAI-compatible shim and sends the profile's `apiKey` as a
13
+ * bearer token, so the server's key goes into the profile (`atomic` for a keyless server) — without
14
+ * it a keyed server answers 401. Our profile is matched by its id only: one the user made from
15
+ * OpenClaude's own Atomic Chat preset is theirs. With a known window the profile carries
16
+ * `maxContextLength`, and the global `env` an output cap for the model (a profile has no output
17
+ * setting). The global `env` also gets empty values for the shell variables that would make
18
+ * OpenClaude skip its active profile: it applies that `env` before deciding. What every key held
19
+ * before is kept in the sidecars `json-backup.ts` describes, for the app's Disconnect.
11
20
  */
21
+ import { join } from 'node:path';
12
22
  import { AtomicCoreError } from '../../contracts/index.js';
13
- import { canonicalJson, parseJsonStrict } from '../config-io.js';
23
+ import { canonicalJson, keyOr, parseJsonStrict } from '../config-io.js';
24
+ import { configDirFrom, getAt, isOurServerUrl, jsonEqual, ourServerFromUrl, outputCap, readBackup, redo, wholeFileBackup, writeBackup, writeConfigFile, } from './json-backup.js';
14
25
  import { asJsonArray, asJsonObject } from './json-tree.js';
15
26
  import { registerWriter } from './registry.js';
16
- const CONFIG_PATH = '.openclaude.json';
17
- const CONFIG_HOME = '.openclaude';
18
- const PROFILE_PATH = `${CONFIG_HOME}/.openclaude-profile.json`;
19
27
  const ATOMIC_PROFILE_ID = 'provider_atomic_chat';
20
- export async function configureOpenclaude(input) {
21
- const { fs, apiUrl, model } = input;
22
- await fs.mkdirp(CONFIG_HOME);
23
- const text = await fs.read(CONFIG_PATH);
24
- const parsed = text === undefined ? {} : parseJsonStrict(text, fs.absolute(CONFIG_PATH));
25
- const root = asJsonObject(parsed);
26
- if (!root)
27
- throw new AtomicCoreError('IO_ERROR', `${fs.absolute(CONFIG_PATH)} is not a JSON object`);
28
- const entry = {
28
+ const PROVIDER = 'atomic-chat';
29
+ /**
30
+ * With `CLAUDE_CODE_USE_OPENAI` plus a base URL or model (or a complete `ANTHROPIC_*` trio) in the
31
+ * environment, OpenClaude treats the shell as the user's choice and skips its active profile
32
+ * (`hasCompleteProviderSelection`). Empty values in the global config's `env` take a shell's
33
+ * leftovers out of that decision; once our profile applies, OpenClaude clears and sets them itself.
34
+ */
35
+ const SHELL_OVERRIDES = [
36
+ 'CLAUDE_CODE_USE_OPENAI',
37
+ 'OPENAI_BASE_URL',
38
+ 'OPENAI_API_BASE',
39
+ 'OPENAI_MODEL',
40
+ 'ANTHROPIC_BASE_URL',
41
+ 'CLAUDE_CODE_USE_GEMINI_VERTEX',
42
+ ];
43
+ const PROFILE_PATH = ['providerProfiles', { id: ATOMIC_PROFILE_ID }];
44
+ export async function openclaudePaths(fs, env) {
45
+ const dir = configDirFrom(env['OPENCLAUDE_CONFIG_DIR'], fs.home);
46
+ const configHome = dir ?? '.openclaude';
47
+ const legacy = dir === undefined ? `${configHome}/.config.json` : join(configHome, '.config.json');
48
+ const config = (await fs.exists(legacy))
49
+ ? legacy
50
+ : dir === undefined
51
+ ? '.openclaude.json'
52
+ : join(dir, '.openclaude.json');
53
+ const profile = dir === undefined ? `${configHome}/.openclaude-profile.json` : join(dir, '.openclaude-profile.json');
54
+ return { config, profile };
55
+ }
56
+ function writesFor(input) {
57
+ const { apiUrl, model, apiKey, contextLength } = input;
58
+ const window = contextLength !== undefined && contextLength > 0 ? contextLength : undefined;
59
+ const profile = {
29
60
  id: ATOMIC_PROFILE_ID,
30
61
  name: 'Atomic Chat',
31
- provider: 'atomic-chat',
62
+ provider: PROVIDER,
63
+ apiKey: keyOr(apiKey, 'atomic'),
32
64
  baseUrl: apiUrl,
33
65
  model,
34
66
  };
35
- const profiles = asJsonArray(root['providerProfiles']) ?? [];
36
- root['providerProfiles'] = profiles;
37
- // Match on either identifier so a profile written by an older build — or one the user renamed —
38
- // is replaced rather than duplicated. The whole entry goes, extra keys included.
39
- const index = profiles.findIndex((candidate) => {
40
- const object = asJsonObject(candidate);
41
- return object?.['id'] === ATOMIC_PROFILE_ID || object?.['provider'] === 'atomic-chat';
42
- });
43
- if (index >= 0)
44
- profiles[index] = entry;
45
- else
46
- profiles.push(entry);
47
- root['activeProviderProfileId'] = ATOMIC_PROFILE_ID;
48
- await fs.write(CONFIG_PATH, canonicalJson(root));
49
- await fs.write(PROFILE_PATH, canonicalJson({
50
- profile: 'atomic-chat',
51
- env: { OPENAI_BASE_URL: apiUrl, OPENAI_MODEL: model },
67
+ if (window !== undefined)
68
+ profile['maxContextLength'] = window;
69
+ const writes = [
70
+ [PROFILE_PATH, profile],
71
+ [['activeProviderProfileId'], ATOMIC_PROFILE_ID],
72
+ ];
73
+ for (const name of SHELL_OVERRIDES)
74
+ writes.push([['env', name], '']);
75
+ if (window !== undefined) {
76
+ writes.push([
77
+ ['env', 'CLAUDE_CODE_OPENAI_MAX_OUTPUT_TOKENS'],
78
+ JSON.stringify({ [model]: outputCap(window) }),
79
+ ]);
80
+ }
81
+ return writes;
82
+ }
83
+ /** What an earlier release wrote without a backup: our profile and the active pointer at it. */
84
+ function forgetLegacy(root) {
85
+ const profiles = asJsonArray(root['providerProfiles']);
86
+ if (profiles) {
87
+ for (let i = profiles.length - 1; i >= 0; i--) {
88
+ if (asJsonObject(profiles[i])?.['id'] === ATOMIC_PROFILE_ID)
89
+ profiles.splice(i, 1);
90
+ }
91
+ }
92
+ if (root['activeProviderProfileId'] === ATOMIC_PROFILE_ID)
93
+ delete root['activeProviderProfileId'];
94
+ }
95
+ function startupProfileIsOurs(doc, server) {
96
+ const base = getAt(doc, ['env', 'OPENAI_BASE_URL']);
97
+ return (asJsonObject(doc)?.['profile'] === PROVIDER && typeof base === 'string' && isOurServerUrl(server, base));
98
+ }
99
+ /** A startup profile that cannot be parsed counts as absent: OpenClaude ignores it too. */
100
+ async function readStartupProfile(fs, path) {
101
+ const text = await fs.read(path);
102
+ if (text === undefined)
103
+ return undefined;
104
+ try {
105
+ return parseJsonStrict(text, fs.absolute(path));
106
+ }
107
+ catch {
108
+ return undefined;
109
+ }
110
+ }
111
+ export async function configureOpenclaude(input) {
112
+ const { fs, apiUrl, model, apiKey } = input;
113
+ const paths = await openclaudePaths(fs, input.env);
114
+ const text = await fs.read(paths.config);
115
+ const parsed = text === undefined ? {} : parseJsonStrict(text, fs.absolute(paths.config));
116
+ const root = asJsonObject(parsed);
117
+ if (!root)
118
+ throw new AtomicCoreError('IO_ERROR', `${fs.absolute(paths.config)} is not a JSON object`);
119
+ const backup = redo(root, await readBackup(fs, paths.config), text !== undefined, writesFor(input), [], forgetLegacy);
120
+ // Sidecar first: a crash between the two leaves a backup whose values simply do not match yet.
121
+ await writeBackup(fs, paths.config, backup);
122
+ await writeConfigFile(fs, paths.config, canonicalJson(root));
123
+ const doc = {
124
+ profile: PROVIDER,
125
+ env: { OPENAI_BASE_URL: apiUrl, OPENAI_MODEL: model, OPENAI_API_KEY: keyOr(apiKey, 'atomic') },
52
126
  createdAt: new Date().toISOString(),
53
- }));
127
+ };
128
+ const current = await readStartupProfile(fs, paths.profile);
129
+ const previous = await readBackup(fs, paths.profile);
130
+ const entry = previous?.entries[0];
131
+ let existed;
132
+ let before;
133
+ if (entry && current !== undefined && jsonEqual(entry.written, current)) {
134
+ existed = entry.existed;
135
+ before = entry.previous;
136
+ }
137
+ else if (current !== undefined && !startupProfileIsOurs(current, ourServerFromUrl(apiUrl))) {
138
+ existed = true;
139
+ before = current;
140
+ }
141
+ else {
142
+ existed = false;
143
+ before = undefined;
144
+ }
145
+ await writeBackup(fs, paths.profile, wholeFileBackup(existed, before, doc));
146
+ await writeConfigFile(fs, paths.profile, canonicalJson(doc));
54
147
  }
55
148
  registerWriter('openclaude', configureOpenclaude);
56
149
  //# sourceMappingURL=openclaude.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openclaude.js","sourceRoot":"","sources":["../../../src/integrations/configure/openclaude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,WAAW,GAAG,kBAAkB,CAAA;AACtC,MAAM,WAAW,GAAG,aAAa,CAAA;AACjC,MAAM,YAAY,GAAG,GAAG,WAAW,2BAA2B,CAAA;AAC9D,MAAM,iBAAiB,GAAG,sBAAsB,CAAA;AAEhD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAAqB;IAC7D,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;IACnC,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IAE5B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACvC,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;IACxF,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IACjC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAA;IAEpG,MAAM,KAAK,GAAG;QACZ,EAAE,EAAE,iBAAiB;QACrB,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,aAAa;QACvB,OAAO,EAAE,MAAM;QACf,KAAK;KACN,CAAA;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAA;IAC5D,IAAI,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAA;IACnC,gGAAgG;IAChG,iFAAiF;IACjF,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,CAAA;QACtC,OAAO,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,iBAAiB,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,KAAK,aAAa,CAAA;IACvF,CAAC,CAAC,CAAA;IACF,IAAI,KAAK,IAAI,CAAC;QAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,KAAK,CAAA;;QAClC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAEzB,IAAI,CAAC,yBAAyB,CAAC,GAAG,iBAAiB,CAAA;IACnD,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IAEhD,MAAM,EAAE,CAAC,KAAK,CACZ,YAAY,EACZ,aAAa,CAAC;QACZ,OAAO,EAAE,aAAa;QACtB,GAAG,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE;QACrD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CACH,CAAA;AACH,CAAC;AAED,cAAc,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAA"}
1
+ {"version":3,"file":"openclaude.js","sourceRoot":"","sources":["../../../src/integrations/configure/openclaude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EACL,aAAa,EACb,KAAK,EACL,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,IAAI,EACJ,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAG1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,iBAAiB,GAAG,sBAAsB,CAAA;AAChD,MAAM,QAAQ,GAAG,aAAa,CAAA;AAC9B;;;;;GAKG;AACH,MAAM,eAAe,GAAG;IACtB,wBAAwB;IACxB,iBAAiB;IACjB,iBAAiB;IACjB,cAAc;IACd,oBAAoB;IACpB,+BAA+B;CACvB,CAAA;AAEV,MAAM,YAAY,GAAa,CAAC,kBAAkB,EAAE,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAA;AAO9E,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EAAY,EAAE,GAAsB;IACxE,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IAChE,MAAM,UAAU,GAAG,GAAG,IAAI,aAAa,CAAA;IACvC,MAAM,MAAM,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,UAAU,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAClG,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,GAAG,KAAK,SAAS;YACjB,CAAC,CAAC,kBAAkB;YACpB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;IACnC,MAAM,OAAO,GACX,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,UAAU,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAA;IACtG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AAC5B,CAAC;AAED,SAAS,SAAS,CAAC,KAAqB;IACtC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,KAAK,CAAA;IACtD,MAAM,MAAM,GAAG,aAAa,KAAK,SAAS,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAA;IAC3F,MAAM,OAAO,GAAe;QAC1B,EAAE,EAAE,iBAAiB;QACrB,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC/B,OAAO,EAAE,MAAM;QACf,KAAK;KACN,CAAA;IACD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,MAAM,CAAA;IAC9D,MAAM,MAAM,GAAgB;QAC1B,CAAC,YAAY,EAAE,OAAO,CAAC;QACvB,CAAC,CAAC,yBAAyB,CAAC,EAAE,iBAAiB,CAAC;KACjD,CAAA;IACD,KAAK,MAAM,IAAI,IAAI,eAAe;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC;YACV,CAAC,KAAK,EAAE,sCAAsC,CAAC;YAC/C,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;SAC/C,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,gGAAgG;AAChG,SAAS,YAAY,CAAC,IAAgB;IACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAA;IACtD,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,iBAAiB;gBAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACpF,CAAC;IACH,CAAC;IACD,IAAI,IAAI,CAAC,yBAAyB,CAAC,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC,yBAAyB,CAAC,CAAA;AACnG,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAc,EAAE,MAA6B;IACzE,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAA;IACnD,OAAO,CACL,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CACxG,CAAA;AACH,CAAC;AAED,2FAA2F;AAC3F,KAAK,UAAU,kBAAkB,CAAC,EAAY,EAAE,IAAY;IAC1D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAChC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACxC,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAAqB;IAC7D,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAC3C,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;IAElD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACxC,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IACzF,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IACjC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAErG,MAAM,MAAM,GAAG,IAAI,CACjB,IAAI,EACJ,MAAM,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,EAClC,IAAI,KAAK,SAAS,EAClB,SAAS,CAAC,KAAK,CAAC,EAChB,EAAE,EACF,YAAY,CACb,CAAA;IACD,+FAA+F;IAC/F,MAAM,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,MAAM,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IAE5D,MAAM,GAAG,GAAe;QACtB,OAAO,EAAE,QAAQ;QACjB,GAAG,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;QAC9F,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAA;IACD,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;IAC3D,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;IACpD,MAAM,KAAK,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAClC,IAAI,OAAgB,CAAA;IACpB,IAAI,MAA6B,CAAA;IACjC,IAAI,KAAK,IAAI,OAAO,KAAK,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QACxE,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA;QACvB,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAA;IACzB,CAAC;SAAM,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO,GAAG,IAAI,CAAA;QACd,MAAM,GAAG,OAAO,CAAA;IAClB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,KAAK,CAAA;QACf,MAAM,GAAG,SAAS,CAAA;IACpB,CAAC;IACD,MAAM,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;IAC3E,MAAM,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9D,CAAC;AAED,cAAc,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAA"}
@@ -1,24 +1,38 @@
1
1
  /**
2
- * OpenClaw keeps one config for the CLI and both desktop apps in `~/.openclaw/openclaw.json`
2
+ * OpenClaw keeps one config for the CLI and the macOS app in `~/.openclaw/openclaw.json`
3
3
  * (overridable with `OPENCLAW_CONFIG_PATH`); its Gateway watches the file and hot-reloads, so one
4
4
  * write covers everything with no restart.
5
5
  *
6
6
  * The merge has two tiers. Keys that express a decision the user may have made deliberately are
7
- * SEEDED only when absent — `models.mode`, `gateway.mode`, `gateway.auth.mode`,
8
- * `agents.defaults.timeoutSeconds`, and the per-model settings entry. Keys that say "run this model
9
- * now" are always OVERWRITTEN — our provider block and `agents.defaults.model.primary`.
7
+ * SEEDED only when absent — `models.mode`, `gateway.mode`, `gateway.auth.mode` (and that one only
8
+ * when the Gateway has no token or password to expect), and the per-model settings entry. Keys that
9
+ * say "run this model now" are always OVERWRITTEN — our provider block and
10
+ * `agents.defaults.model.primary`. What the keys held before is recorded in
11
+ * `openclaw.json.atomic-chat-backup.json` for the app's Disconnect.
10
12
  *
11
13
  * The one non-obvious rule is `modelPolicy.allow`. When it is non-empty it gates model selection
12
14
  * entirely, so a user restricted to a cloud provider would watch Run "succeed" and then be told our
13
15
  * model is not allowed — hence the `atomic/*` widening. But an absent key or `[]` already means
14
16
  * "allow anything", so writing into it would INTRODUCE a restriction nobody asked for. Those are
15
17
  * left exactly as they are.
18
+ *
19
+ * Mirrors `configure_openclaw_at` in the app's `core/system/commands.rs`, byte for byte.
16
20
  */
17
21
  import type { JsonValue } from '../config-io.js';
18
22
  import type { JsonObject } from './json-tree.js';
19
23
  import type { ConfigureWriter } from './registry.js';
24
+ /** The output cap written next to a known window: a quarter of it, at most 8192 tokens. */
25
+ export declare function outputCapFor(contextLength: number): number;
20
26
  /** Whether an allow-list already covers `modelRef`. A trailing `*` makes the entry a prefix match. */
21
27
  export declare function modelPolicyAllows(list: JsonValue[], modelRef: string): boolean;
28
+ /**
29
+ * Bring a parsed `openclaw.json` into the shape the merge works on without changing what it means:
30
+ * a plain-string `agents.defaults.model` becomes `{ primary: <it> }`, and the
31
+ * `agents.defaults.timeoutSeconds: 240` older releases seeded goes.
32
+ */
33
+ export declare function openclawNormalize(parsed: JsonValue): void;
34
+ /** The keys Connect may overwrite besides our own provider entry. */
35
+ export declare function openclawTrackedPaths(modelRef: string): string[][];
22
36
  /** The whole merge, with no I/O, so every rule above is testable against a plain object. */
23
- export declare function openclawPatchConfig(parsed: JsonValue, apiUrl: string, model: string, apiKey: string): JsonObject;
37
+ export declare function openclawPatchConfig(parsed: JsonValue, apiUrl: string, model: string, apiKey: string, contextLength?: number, gatewaySecretInEnv?: boolean): JsonObject;
24
38
  export declare const configureOpenclaw: ConfigureWriter;
@@ -1,27 +1,43 @@
1
1
  /**
2
- * OpenClaw keeps one config for the CLI and both desktop apps in `~/.openclaw/openclaw.json`
2
+ * OpenClaw keeps one config for the CLI and the macOS app in `~/.openclaw/openclaw.json`
3
3
  * (overridable with `OPENCLAW_CONFIG_PATH`); its Gateway watches the file and hot-reloads, so one
4
4
  * write covers everything with no restart.
5
5
  *
6
6
  * The merge has two tiers. Keys that express a decision the user may have made deliberately are
7
- * SEEDED only when absent — `models.mode`, `gateway.mode`, `gateway.auth.mode`,
8
- * `agents.defaults.timeoutSeconds`, and the per-model settings entry. Keys that say "run this model
9
- * now" are always OVERWRITTEN — our provider block and `agents.defaults.model.primary`.
7
+ * SEEDED only when absent — `models.mode`, `gateway.mode`, `gateway.auth.mode` (and that one only
8
+ * when the Gateway has no token or password to expect), and the per-model settings entry. Keys that
9
+ * say "run this model now" are always OVERWRITTEN — our provider block and
10
+ * `agents.defaults.model.primary`. What the keys held before is recorded in
11
+ * `openclaw.json.atomic-chat-backup.json` for the app's Disconnect.
10
12
  *
11
13
  * The one non-obvious rule is `modelPolicy.allow`. When it is non-empty it gates model selection
12
14
  * entirely, so a user restricted to a cloud provider would watch Run "succeed" and then be told our
13
15
  * model is not allowed — hence the `atomic/*` widening. But an absent key or `[]` already means
14
16
  * "allow anything", so writing into it would INTRODUCE a restriction nobody asked for. Those are
15
17
  * left exactly as they are.
18
+ *
19
+ * Mirrors `configure_openclaw_at` in the app's `core/system/commands.rs`, byte for byte.
16
20
  */
17
21
  import { AtomicCoreError } from '../../contracts/index.js';
18
22
  import { canonicalJson, keyOr, parseJsonLenient } from '../config-io.js';
23
+ import { readBackup, renderBackup, trackKeys, writeBackupText } from './json-key-backup.js';
19
24
  import { asJsonArray, asJsonObject } from './json-tree.js';
20
25
  import { registerWriter } from './registry.js';
21
26
  const PROVIDER_ID = 'atomic';
22
27
  const DEFAULT_PATH = '.openclaw/openclaw.json';
23
- /** Small local models blow past OpenClaw's short default once wrapped in the agent prompt + tools. */
24
- const DEFAULT_TIMEOUT_SECONDS = 240;
28
+ /**
29
+ * Per-request budget on our provider: it covers connecting, the headers and streaming the body, and
30
+ * raises the ~120 s idle watchdog for this provider only — a long prompt on a slow machine needs
31
+ * more before the first token. Unlike `agents.defaults.timeoutSeconds`, it leaves every other model
32
+ * alone.
33
+ */
34
+ const PROVIDER_TIMEOUT_SECONDS = 600;
35
+ /** `agents.defaults.timeoutSeconds` older releases seeded, capping every model's attempt. */
36
+ const LEGACY_AGENT_TIMEOUT_SECONDS = 240;
37
+ /** The output cap written next to a known window: a quarter of it, at most 8192 tokens. */
38
+ export function outputCapFor(contextLength) {
39
+ return Math.min(8192, Math.floor(contextLength / 4));
40
+ }
25
41
  /** Read `<parent>[key]` as an object, creating it when absent; anything else is a hard error. */
26
42
  function childObject(parent, key, label) {
27
43
  if (parent[key] === undefined)
@@ -39,8 +55,34 @@ export function modelPolicyAllows(list, modelRef) {
39
55
  return entry.endsWith('*') ? modelRef.startsWith(entry.slice(0, -1)) : entry === modelRef;
40
56
  });
41
57
  }
58
+ /**
59
+ * Bring a parsed `openclaw.json` into the shape the merge works on without changing what it means:
60
+ * a plain-string `agents.defaults.model` becomes `{ primary: <it> }`, and the
61
+ * `agents.defaults.timeoutSeconds: 240` older releases seeded goes.
62
+ */
63
+ export function openclawNormalize(parsed) {
64
+ const defaults = asJsonObject(asJsonObject(asJsonObject(parsed)?.['agents'])?.['defaults']);
65
+ if (!defaults)
66
+ return;
67
+ if (defaults['timeoutSeconds'] === LEGACY_AGENT_TIMEOUT_SECONDS)
68
+ delete defaults['timeoutSeconds'];
69
+ const model = defaults['model'];
70
+ if (typeof model === 'string')
71
+ defaults['model'] = { primary: model };
72
+ }
73
+ /** The keys Connect may overwrite besides our own provider entry. */
74
+ export function openclawTrackedPaths(modelRef) {
75
+ return [
76
+ ['models', 'mode'],
77
+ ['gateway', 'mode'],
78
+ ['gateway', 'auth', 'mode'],
79
+ ['agents', 'defaults', 'model', 'primary'],
80
+ ['agents', 'defaults', 'models', modelRef],
81
+ ['agents', 'defaults', 'modelPolicy', 'allow'],
82
+ ];
83
+ }
42
84
  /** The whole merge, with no I/O, so every rule above is testable against a plain object. */
43
- export function openclawPatchConfig(parsed, apiUrl, model, apiKey) {
85
+ export function openclawPatchConfig(parsed, apiUrl, model, apiKey, contextLength, gatewaySecretInEnv = false) {
44
86
  const root = asJsonObject(parsed);
45
87
  if (!root)
46
88
  throw new AtomicCoreError('IO_ERROR', 'openclaw.json is not a JSON object');
@@ -50,31 +92,39 @@ export function openclawPatchConfig(parsed, apiUrl, model, apiKey) {
50
92
  models['mode'] = 'merge';
51
93
  const providers = childObject(models, 'providers', 'models.providers');
52
94
  // The catalog entry's `id` is the bare model id our /v1 server reports; OpenClaw builds the ref as
53
- // `<providerId>/<id>`, so prefixing here would double it to `atomic/atomic/…` and break lookup.
95
+ // `<providerId>/<id>`, so prefixing here would double it to `atomic/atomic/…` and break lookup. A
96
+ // known window lets OpenClaw compact before the server refuses; an unknown one is not invented.
97
+ const modelEntry = { id: model, name: model };
98
+ if (contextLength !== undefined) {
99
+ modelEntry['contextWindow'] = contextLength;
100
+ modelEntry['maxTokens'] = outputCapFor(contextLength);
101
+ }
54
102
  providers[PROVIDER_ID] = {
55
103
  baseUrl: apiUrl,
56
104
  apiKey: keyOr(apiKey, 'atomic'),
57
105
  api: 'openai-completions',
58
- models: [{ id: model, name: model }],
106
+ timeoutSeconds: PROVIDER_TIMEOUT_SECONDS,
107
+ models: [modelEntry],
59
108
  };
60
- // The local gateway refuses to open its websocket without connection auth; for a loopback-only
61
- // setup "none" (private-ingress open auth) is what makes the agent reachable with no token.
62
109
  const gateway = childObject(root, 'gateway', 'gateway');
63
110
  if (gateway['mode'] === undefined)
64
111
  gateway['mode'] = 'local';
65
- const auth = childObject(gateway, 'auth', 'gateway.auth');
66
- if (auth['mode'] === undefined)
67
- auth['mode'] = 'none';
112
+ // The local Gateway refuses its websocket without connection auth and, with no mode set, expects a
113
+ // token. With no token or password to expect, "none" (private-ingress open auth) makes it
114
+ // reachable; with one, "none" would switch token auth off.
115
+ const auth = asJsonObject(gateway['auth']);
116
+ const authIsSet = ['mode', 'token', 'password'].some((key) => {
117
+ const value = auth?.[key];
118
+ return value !== undefined && value !== null && value !== '';
119
+ });
120
+ if (!authIsSet && !gatewaySecretInEnv)
121
+ childObject(gateway, 'auth', 'gateway.auth')['mode'] = 'none';
68
122
  const agents = childObject(root, 'agents', 'agents');
69
123
  const defaults = childObject(agents, 'defaults', 'agents.defaults');
70
- if (defaults['timeoutSeconds'] === undefined)
71
- defaults['timeoutSeconds'] = DEFAULT_TIMEOUT_SECONDS;
72
- // Both a plain string and an object are accepted here, but only the object form has room for the
73
- // fallbacks OpenClaw writes itself, so a string is normalised rather than extended.
74
124
  if (asJsonObject(defaults['model']) === undefined)
75
125
  defaults['model'] = {};
76
- const modelEntry = asJsonObject(defaults['model']);
77
- modelEntry['primary'] = modelRef;
126
+ const primary = asJsonObject(defaults['model']);
127
+ primary['primary'] = modelRef;
78
128
  // `agents.defaults.models` holds aliases and per-model settings. Pre-migration builds also read it
79
129
  // as an allowlist, so the entry is still seeded; on current builds it restricts nothing.
80
130
  const settings = childObject(defaults, 'models', 'agents.defaults.models');
@@ -86,14 +136,20 @@ export function openclawPatchConfig(parsed, apiUrl, model, apiKey) {
86
136
  }
87
137
  return root;
88
138
  }
89
- export const configureOpenclaw = async ({ apiUrl, model, apiKey, fs, env, }) => {
139
+ export const configureOpenclaw = async ({ apiUrl, model, apiKey, fs, env, contextLength, }) => {
90
140
  const override = env['OPENCLAW_CONFIG_PATH'];
91
141
  const path = override && override.length > 0 ? override : DEFAULT_PATH;
142
+ const gatewaySecretInEnv = ['OPENCLAW_GATEWAY_TOKEN', 'OPENCLAW_GATEWAY_PASSWORD'].some((name) => (env[name] ?? '').trim() !== '');
92
143
  // OpenClaw reads this file as JSON5, so we must parse with the same leniency or we reject configs
93
144
  // it happily accepts. Comments are dropped on write; every setting is preserved.
94
145
  const text = await fs.read(path);
95
- const parsed = text === undefined ? {} : parseJsonLenient(text, fs.absolute(path));
96
- await fs.write(path, canonicalJson(openclawPatchConfig(parsed, apiUrl, model, apiKey)));
146
+ const base = text === undefined ? {} : parseJsonLenient(text, fs.absolute(path));
147
+ openclawNormalize(base);
148
+ const patched = openclawPatchConfig(JSON.parse(JSON.stringify(base)), apiUrl, model, apiKey, contextLength, gatewaySecretInEnv);
149
+ const previous = await readBackup(fs, path);
150
+ const keys = trackKeys(base, patched, openclawTrackedPaths(`${PROVIDER_ID}/${model}`), previous?.keys ?? []);
151
+ await fs.write(path, canonicalJson(patched));
152
+ await writeBackupText(fs, path, renderBackup({ keys, seeded: [] }));
97
153
  };
98
154
  registerWriter('openclaw', configureOpenclaw);
99
155
  //# sourceMappingURL=openclaw.js.map