offsite 0.0.12 → 0.0.14

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 (81) hide show
  1. package/apps/server/dist/main.mjs +172 -86
  2. package/apps/server/dist/main.mjs.map +1 -1
  3. package/apps/web/dist/assets/{angular-html-DNGrmdhg.js → angular-html-6NaagU1P.js} +1 -1
  4. package/apps/web/dist/assets/{angular-ts-D4hBqsOh.js → angular-ts-D8XutLPw.js} +1 -1
  5. package/apps/web/dist/assets/{apl-CYvdPOPE.js → apl-BKJEkz6Z.js} +1 -1
  6. package/apps/web/dist/assets/{astro-BqtVnRyx.js → astro-DkrGLOry.js} +1 -1
  7. package/apps/web/dist/assets/{blade-BPJV2sdT.js → blade-BIc0yPkX.js} +1 -1
  8. package/apps/web/dist/assets/{c-CBQDE6Uf.js → c-Ds8U4gsq.js} +1 -1
  9. package/apps/web/dist/assets/{chapel-BHOESU2p.js → chapel-COXTL8xW.js} +1 -1
  10. package/apps/web/dist/assets/{cobol-CMpvzrel.js → cobol-D0VSGQqK.js} +1 -1
  11. package/apps/web/dist/assets/{coffee-Bv27C06e.js → coffee-DBrey7sA.js} +1 -1
  12. package/apps/web/dist/assets/{cpp-MTwxWDTP.js → cpp-SKUDYlNR.js} +1 -1
  13. package/apps/web/dist/assets/{crystal-CI5fSUCy.js → crystal-CoTn_b8r.js} +1 -1
  14. package/apps/web/dist/assets/{css-BW8DHcmj.js → css-BErHy7fN.js} +1 -1
  15. package/apps/web/dist/assets/{edge-C2HOl06F.js → edge-CACFpVrz.js} +1 -1
  16. package/apps/web/dist/assets/{elixir-OV4G1_r7.js → elixir-aPcGiByD.js} +1 -1
  17. package/apps/web/dist/assets/{elm-BF0pK-yg.js → elm-DN5FfPkL.js} +1 -1
  18. package/apps/web/dist/assets/{erb-DFQCtOmK.js → erb-Dj675b5b.js} +1 -1
  19. package/apps/web/dist/assets/{git-rebase-C9nAAu5A.js → git-rebase-DepNW1h5.js} +1 -1
  20. package/apps/web/dist/assets/{glimmer-js-B9gnYdT1.js → glimmer-js-fCJatm6u.js} +1 -1
  21. package/apps/web/dist/assets/{glimmer-ts-BkG38Inm.js → glimmer-ts-YwpKoyPh.js} +1 -1
  22. package/apps/web/dist/assets/{glsl-wwo6dKBr.js → glsl-PGMqKJzL.js} +1 -1
  23. package/apps/web/dist/assets/{graphql-tQJRbYuy.js → graphql-3IK2PC2Y.js} +1 -1
  24. package/apps/web/dist/assets/{hack-C9e9oyUG.js → hack-C8CJl4zQ.js} +1 -1
  25. package/apps/web/dist/assets/{haml-CTolMb7J.js → haml-CiYnV6_a.js} +1 -1
  26. package/apps/web/dist/assets/{handlebars-CrJTM5vD.js → handlebars-C4m4mY7m.js} +1 -1
  27. package/apps/web/dist/assets/{html-Be6zOrn3.js → html-D1Ar4Xkj.js} +1 -1
  28. package/apps/web/dist/assets/{html-derivative-10Bvy_Et.js → html-derivative-CwhughXj.js} +1 -1
  29. package/apps/web/dist/assets/{http-GZlGWwa-.js → http-pzvpiwNw.js} +1 -1
  30. package/apps/web/dist/assets/{hurl-DEYfhn1R.js → hurl-hkZwo5Ou.js} +1 -1
  31. package/apps/web/dist/assets/{index-CiQ326rG.js → index-BOrJ0-iI.js} +143 -143
  32. package/apps/web/dist/assets/{java-BsFb26JS.js → java-CjDcLNWV.js} +1 -1
  33. package/apps/web/dist/assets/{javascript-DDLm5bzW.js → javascript-B1pleYoe.js} +1 -1
  34. package/apps/web/dist/assets/{jinja-NBeNjUXf.js → jinja-erX4wFzj.js} +1 -1
  35. package/apps/web/dist/assets/{jison-DKz4RK3A.js → jison-CajpWJAS.js} +1 -1
  36. package/apps/web/dist/assets/{json-Bg4r8xCd.js → json-CwL6i1-C.js} +1 -1
  37. package/apps/web/dist/assets/{jsx-BMnPLKsa.js → jsx-DmOLIUT0.js} +1 -1
  38. package/apps/web/dist/assets/{julia-Wll5K4al.js → julia-DK5bpj3S.js} +1 -1
  39. package/apps/web/dist/assets/{just-BLn1iI69.js → just-BtwHGit4.js} +1 -1
  40. package/apps/web/dist/assets/{latex-D15HRF2E.js → latex-Dnf1mLFf.js} +1 -1
  41. package/apps/web/dist/assets/{liquid-COHkGI02.js → liquid-Bv72E2Is.js} +1 -1
  42. package/apps/web/dist/assets/{lua-CkbAAxOH.js → lua-94ufuXur.js} +1 -1
  43. package/apps/web/dist/assets/{marko-Dmgo6IU5.js → marko-BKL0CGzx.js} +1 -1
  44. package/apps/web/dist/assets/{mdc-D_OV_cCt.js → mdc-DNhqDQoU.js} +1 -1
  45. package/apps/web/dist/assets/{nginx-ADn2lIMW.js → nginx-BcYwGlC2.js} +1 -1
  46. package/apps/web/dist/assets/{nim-C6zTq4FI.js → nim-CRMgcK-K.js} +1 -1
  47. package/apps/web/dist/assets/{org-D9XGvcFV.js → org-DfnsnSld.js} +1 -1
  48. package/apps/web/dist/assets/{perl-B7-K-xLH.js → perl-BEwyXv2a.js} +1 -1
  49. package/apps/web/dist/assets/{php-CO9ZzQRp.js → php-CG9qDJ82.js} +1 -1
  50. package/apps/web/dist/assets/{pug-BaAyPwTO.js → pug-Dg3kkpP7.js} +1 -1
  51. package/apps/web/dist/assets/{qml-Cp3pyCa-.js → qml-Vs1TgYWl.js} +1 -1
  52. package/apps/web/dist/assets/{r-CT05_vfW.js → r-CFy73Kus.js} +1 -1
  53. package/apps/web/dist/assets/{razor-D5rHsTSp.js → razor-Dcng6YrP.js} +1 -1
  54. package/apps/web/dist/assets/{regexp-D6kzd_X5.js → regexp-Bwbv2WPD.js} +1 -1
  55. package/apps/web/dist/assets/{rst-AkFwrhnR.js → rst-Cul2jxkE.js} +1 -1
  56. package/apps/web/dist/assets/{ruby-LNJDVfMG.js → ruby-TMvLq4yj.js} +1 -1
  57. package/apps/web/dist/assets/{sas-C8o3xi__.js → sas-D8HC__R6.js} +1 -1
  58. package/apps/web/dist/assets/{scss-Ch7Tact0.js → scss-dK6Y8mdp.js} +1 -1
  59. package/apps/web/dist/assets/{shellscript-CN-vf6fZ.js → shellscript-BrObD5cd.js} +1 -1
  60. package/apps/web/dist/assets/{shellsession-CxId-awN.js → shellsession-gwVDz4P8.js} +1 -1
  61. package/apps/web/dist/assets/{soy-PXtFJtGw.js → soy-BF1mzKmn.js} +1 -1
  62. package/apps/web/dist/assets/{sql-B7js2_Lu.js → sql-rY-oq1Hg.js} +1 -1
  63. package/apps/web/dist/assets/{stata-C0Zwsf36.js → stata-DBh-WI4L.js} +1 -1
  64. package/apps/web/dist/assets/{surrealql-DawzxLLe.js → surrealql-DxG1DYQM.js} +1 -1
  65. package/apps/web/dist/assets/{svelte-CbCoXemF.js → svelte-IUUmpoTZ.js} +1 -1
  66. package/apps/web/dist/assets/{templ-CQyn0W4C.js → templ-DSD9ChjE.js} +1 -1
  67. package/apps/web/dist/assets/{tex-FeZKQwyK.js → tex-ClrklzW1.js} +1 -1
  68. package/apps/web/dist/assets/{ts-tags-KsJvoinT.js → ts-tags-CiWqjPoE.js} +1 -1
  69. package/apps/web/dist/assets/{tsx-Cw6pGPeZ.js → tsx-BVdH_4RP.js} +1 -1
  70. package/apps/web/dist/assets/{twig-Cj9MLPms.js → twig-bBlRyqC3.js} +1 -1
  71. package/apps/web/dist/assets/{typescript-DwZR66Da.js → typescript-BWvsrxJs.js} +1 -1
  72. package/apps/web/dist/assets/{typst--K-bHYFW.js → typst-CoUU-sfH.js} +1 -1
  73. package/apps/web/dist/assets/{vue-BrB0TrD_.js → vue-0_DBul4P.js} +1 -1
  74. package/apps/web/dist/assets/{vue-html-BgNSGBvl.js → vue-html-feH37mKg.js} +1 -1
  75. package/apps/web/dist/assets/{vue-vine-C2qLo1pd.js → vue-vine-xWSVrEzZ.js} +1 -1
  76. package/apps/web/dist/assets/{xml-DzdlZG_g.js → xml-RE-6RA5e.js} +1 -1
  77. package/apps/web/dist/assets/{xsl-D3HxAJEY.js → xsl-DzQQ-zeR.js} +1 -1
  78. package/apps/web/dist/assets/{yaml-SX7TQG-a.js → yaml-BfSzomC9.js} +1 -1
  79. package/apps/web/dist/index.html +1 -1
  80. package/apps/web/dist/sw.js +1 -1
  81. package/package.json +1 -1
@@ -56,8 +56,13 @@ const deprecatedModels = {
56
56
  opencode: []
57
57
  };
58
58
  const defaultModels = {
59
+ codex: "gpt-6.1-sol",
59
60
  claude: "claude-opus-5-5",
60
- codex: null,
61
+ opencode: null
62
+ };
63
+ const defaultEfforts = {
64
+ codex: "high",
65
+ claude: "high",
61
66
  opencode: null
62
67
  };
63
68
  //#endregion
@@ -776,8 +781,13 @@ function readJson(name) {
776
781
  }
777
782
  }
778
783
  function writeJson(name, value) {
779
- const file = path.join(home, name);
784
+ let file = path.join(home, name);
780
785
  mkdirSync(home, { recursive: true });
786
+ try {
787
+ file = realpathSync(file);
788
+ } catch (error) {
789
+ if (!hasCode(error, "ENOENT")) throw error;
790
+ }
781
791
  writeFileSync(`${file}.tmp`, `${JSON.stringify(value, null, 2)}\n`, { mode: 384 });
782
792
  renameSync(`${file}.tmp`, file);
783
793
  }
@@ -788,58 +798,31 @@ const modelSetting = z.strictObject({
788
798
  hidden: z.boolean(),
789
799
  effort: z.string().nullable()
790
800
  });
801
+ const posixDir = z.string().refine((value) => path.posix.isAbsolute(value), "must be an absolute path").nullable().default(null);
802
+ const platformDirs = z.strictObject({
803
+ macos: posixDir,
804
+ linux: posixDir,
805
+ windows: z.string().refine((value) => path.win32.isAbsolute(value), "must be an absolute path").nullable().default(null)
806
+ }).prefault({});
807
+ function accountSchema(provider) {
808
+ return z.strictObject({
809
+ id: z.string(),
810
+ provider: z.literal(provider),
811
+ name: z.string(),
812
+ configDir: platformDirs,
813
+ enabled: z.boolean().default(true),
814
+ hiddenModels: z.record(z.string(), z.boolean()).default({})
815
+ });
816
+ }
791
817
  const configSchema = z.strictObject({
792
- claudeBaseDir: z.string().refine((value) => path.isAbsolute(value), "must be an absolute path").default(path.join(os.homedir(), ".claude")),
818
+ claudeBaseDir: platformDirs,
819
+ claudeAccounts: z.array(accountSchema("claude")).default([]),
820
+ codexAccounts: z.array(accountSchema("codex")).default([]),
793
821
  enabledProviders: z.strictObject({
794
822
  claude: z.boolean().default(true),
795
823
  codex: z.boolean().default(true),
796
824
  opencode: z.boolean().default(true)
797
825
  }).prefault({}),
798
- composer: z.strictObject({
799
- provider: z.enum([
800
- "claude",
801
- "codex",
802
- "opencode"
803
- ]).default("claude"),
804
- claude: z.strictObject({
805
- accountId: z.string().nullable().default(null),
806
- model: z.string().nullable().default(null),
807
- effort: z.enum([
808
- "low",
809
- "medium",
810
- "high",
811
- "xhigh",
812
- "max"
813
- ]).nullable().default(null),
814
- mode: z.enum([
815
- "default",
816
- "acceptEdits",
817
- "bypassPermissions",
818
- "plan",
819
- "dontAsk",
820
- "auto"
821
- ]).nullable().default("bypassPermissions"),
822
- plan: z.boolean().default(false)
823
- }).prefault({}),
824
- codex: z.strictObject({
825
- accountId: z.string().nullable().default(null),
826
- model: z.string().nullable().default(null),
827
- effort: z.string().nullable().default(null),
828
- mode: z.enum([
829
- "read-only",
830
- "auto",
831
- "full-access"
832
- ]).nullable().default("auto"),
833
- plan: z.boolean().default(false)
834
- }).prefault({}),
835
- opencode: z.strictObject({
836
- accountId: z.null().default(null),
837
- model: z.string().nullable().default(null),
838
- effort: z.string().nullable().default(null),
839
- mode: z.string().nullable().default(null),
840
- plan: z.boolean().default(false)
841
- }).prefault({})
842
- }).prefault({}),
843
826
  commitMessage: z.strictObject({
844
827
  provider: z.enum([
845
828
  "claude",
@@ -876,13 +859,16 @@ const configSchema = z.strictObject({
876
859
  }).prefault({})
877
860
  }).prefault({})
878
861
  });
879
- const defaults = configSchema.parse({});
862
+ const defaults$1 = configSchema.parse({});
880
863
  function platform() {
881
864
  if (process.platform === "darwin") return "macos";
882
865
  if (process.platform === "linux") return "linux";
883
866
  if (process.platform === "win32") return "windows";
884
867
  throw new Error(`unsupported platform ${process.platform}`);
885
868
  }
869
+ function claudeBaseDir() {
870
+ return readConfig().claudeBaseDir[platform()] ?? path.join(os.homedir(), ".claude");
871
+ }
886
872
  function defaultShell() {
887
873
  if (process.platform === "win32") return process.env.COMSPEC ?? "cmd.exe";
888
874
  return os.userInfo().shell ?? "/bin/sh";
@@ -890,9 +876,10 @@ function defaultShell() {
890
876
  function configInfo() {
891
877
  return {
892
878
  config: readConfig(),
893
- defaults,
879
+ defaults: defaults$1,
894
880
  platform: platform(),
895
- defaultShell: defaultShell()
881
+ defaultShell: defaultShell(),
882
+ defaultClaudeBaseDir: path.join(os.homedir(), ".claude")
896
883
  };
897
884
  }
898
885
  function readConfig() {
@@ -901,13 +888,13 @@ function readConfig() {
901
888
  user = readJson("config.json");
902
889
  } catch (error) {
903
890
  console.warn(`invalid ${configFile}, using the default config: ${error}`);
904
- return structuredClone(defaults);
891
+ return structuredClone(defaults$1);
905
892
  }
906
- if (user === null) return structuredClone(defaults);
893
+ if (user === null) return structuredClone(defaults$1);
907
894
  const result = configSchema.safeParse(user);
908
895
  if (!result.success) {
909
896
  console.warn(`invalid ${configFile}, using the default config:\n${z.prettifyError(result.error)}`);
910
- return structuredClone(defaults);
897
+ return structuredClone(defaults$1);
911
898
  }
912
899
  return result.data;
913
900
  }
@@ -915,7 +902,7 @@ function saveConfig(value) {
915
902
  const result = configSchema.safeParse(value);
916
903
  if (!result.success) throw new Error(z.prettifyError(result.error));
917
904
  writeJson("config.json", result.data);
918
- process.env.CLAUDE_CONFIG_DIR = result.data.claudeBaseDir;
905
+ process.env.CLAUDE_CONFIG_DIR = claudeBaseDir();
919
906
  broadcast({
920
907
  type: "config",
921
908
  config: result.data
@@ -2723,7 +2710,7 @@ async function find(provider, paths) {
2723
2710
  }
2724
2711
  function watchSessions() {
2725
2712
  for (const watcher of watchers) watcher.close();
2726
- watchers = [["claude", path.join(readConfig().claudeBaseDir, "projects")], ["codex", path.join(codexBaseDir, "sessions")]].flatMap(([provider, dir]) => {
2713
+ watchers = [["claude", path.join(claudeBaseDir(), "projects")], ["codex", path.join(codexBaseDir, "sessions")]].flatMap(([provider, dir]) => {
2727
2714
  if (!readConfig().enabledProviders[provider]) return [];
2728
2715
  try {
2729
2716
  const watcher = watch(dir, { recursive: true }, () => refreshSessions(provider));
@@ -2919,14 +2906,15 @@ function providerName(provider) {
2919
2906
  return providerNames[provider];
2920
2907
  }
2921
2908
  function storedAccounts() {
2922
- return (readJson("accounts.json") ?? []).map((item) => ({
2923
- id: item.id,
2924
- provider: item.provider,
2925
- name: item.name,
2926
- configDir: item.configDir,
2927
- enabled: item.enabled ?? true,
2928
- hiddenModels: item.hiddenModels ?? {}
2929
- }));
2909
+ const config = readConfig();
2910
+ return [...config.claudeAccounts, ...config.codexAccounts].flatMap((item) => {
2911
+ const configDir = item.configDir[platform()];
2912
+ if (configDir === null) return [];
2913
+ return [{
2914
+ ...item,
2915
+ configDir
2916
+ }];
2917
+ });
2930
2918
  }
2931
2919
  function assertEnabled(provider, accountId) {
2932
2920
  if (!readConfig().enabledProviders[provider]) throw new Error(`${providerName(provider)} is disabled in Settings`);
@@ -3006,11 +2994,13 @@ async function capabilities(provider, accountId, cwd) {
3006
2994
  hidden: deprecated,
3007
2995
  effort: null
3008
2996
  };
2997
+ const preferred = defaultEfforts[provider];
2998
+ const effort = preferred === null ? null : model.efforts.includes(preferred) ? preferred : model.efforts.at(-1) ?? null;
3009
2999
  return {
3010
3000
  ...model,
3011
3001
  deprecated,
3012
3002
  hidden: overrides[model.value] ?? setting.hidden,
3013
- effort: setting.effort
3003
+ effort: setting.effort ?? effort
3014
3004
  };
3015
3005
  })
3016
3006
  };
@@ -3025,29 +3015,50 @@ function providerCapabilities(provider, accountId, cwd) {
3025
3015
  }
3026
3016
  }
3027
3017
  function addAccount(provider, name, configDir) {
3028
- saveAccounts([...storedAccounts(), {
3029
- id: randomUUID(),
3030
- provider,
3031
- ...validAccount(name, configDir),
3032
- enabled: true,
3033
- hiddenModels: {}
3034
- }]);
3018
+ const account = validAccount(name, configDir);
3019
+ const config = readConfig();
3020
+ const key = `${provider}Accounts`;
3021
+ saveConfig({
3022
+ ...config,
3023
+ [key]: [...config[key], {
3024
+ id: randomUUID(),
3025
+ provider,
3026
+ name: account.name,
3027
+ configDir: { [platform()]: account.configDir },
3028
+ enabled: true,
3029
+ hiddenModels: {}
3030
+ }]
3031
+ });
3035
3032
  }
3036
3033
  async function updateAccount(update) {
3037
3034
  const before = storedAccounts().find((item) => item.id === update.id);
3038
3035
  if (before === void 0) throw new Error("That account was removed");
3039
3036
  const account = validAccount(update.name, update.configDir);
3040
- saveAccounts(storedAccounts().map((item) => item.id === update.id ? {
3041
- ...item,
3042
- ...account,
3043
- enabled: update.enabled,
3044
- hiddenModels: update.hiddenModels
3045
- } : item));
3037
+ const config = readConfig();
3038
+ const key = `${before.provider}Accounts`;
3039
+ saveConfig({
3040
+ ...config,
3041
+ [key]: config[key].map((item) => item.id === update.id ? {
3042
+ ...item,
3043
+ name: account.name,
3044
+ configDir: {
3045
+ ...item.configDir,
3046
+ [platform()]: account.configDir
3047
+ },
3048
+ enabled: update.enabled,
3049
+ hiddenModels: update.hiddenModels
3050
+ } : item)
3051
+ });
3046
3052
  forgetClaude(update.id);
3047
3053
  if (before.enabled && !update.enabled) await stopAccount(before);
3048
3054
  }
3049
3055
  function removeAccount(id) {
3050
- saveAccounts(storedAccounts().filter((item) => item.id !== id));
3056
+ const config = readConfig();
3057
+ saveConfig({
3058
+ ...config,
3059
+ claudeAccounts: config.claudeAccounts.filter((item) => item.id !== id),
3060
+ codexAccounts: config.codexAccounts.filter((item) => item.id !== id)
3061
+ });
3051
3062
  forgetClaude(id);
3052
3063
  }
3053
3064
  function validAccount(name, configDir) {
@@ -3063,9 +3074,6 @@ function validAccount(name, configDir) {
3063
3074
  };
3064
3075
  throw new Error("Use an absolute config directory or one starting with ~/");
3065
3076
  }
3066
- function saveAccounts(items) {
3067
- writeJson("accounts.json", items);
3068
- }
3069
3077
  //#endregion
3070
3078
  //#region src/lib/claude/claude.ts
3071
3079
  const efforts = [
@@ -3239,7 +3247,7 @@ async function recordUsage(accountId, probe) {
3239
3247
  }
3240
3248
  }
3241
3249
  function isLinked(configDir) {
3242
- const base = readConfig().claudeBaseDir;
3250
+ const base = claudeBaseDir();
3243
3251
  try {
3244
3252
  if (realpathSync(configDir) === realpathSync(base)) return true;
3245
3253
  return realpathSync(path.join(configDir, "projects")) === realpathSync(path.join(base, "projects"));
@@ -3695,7 +3703,7 @@ function text$1(value) {
3695
3703
  //#endregion
3696
3704
  //#region src/lib/claude/history.ts
3697
3705
  async function sessionFile(sessionId) {
3698
- const projectsDir = path.join(readConfig().claudeBaseDir, "projects");
3706
+ const projectsDir = path.join(claudeBaseDir(), "projects");
3699
3707
  for (const dir of await readdir(projectsDir)) {
3700
3708
  const file = path.join(projectsDir, dir, `${sessionId}.jsonl`);
3701
3709
  try {
@@ -5624,6 +5632,81 @@ function send(connection, event) {
5624
5632
  });
5625
5633
  }
5626
5634
  //#endregion
5635
+ //#region src/storage/state.ts
5636
+ const stateFile = path.join(home, "state.json");
5637
+ const stateSchema = z.strictObject({ composer: z.strictObject({
5638
+ provider: z.enum([
5639
+ "claude",
5640
+ "codex",
5641
+ "opencode"
5642
+ ]).default("claude"),
5643
+ claude: z.strictObject({
5644
+ accountId: z.string().nullable().default(null),
5645
+ model: z.string().nullable().default(null),
5646
+ effort: z.enum([
5647
+ "low",
5648
+ "medium",
5649
+ "high",
5650
+ "xhigh",
5651
+ "max"
5652
+ ]).nullable().default(null),
5653
+ mode: z.enum([
5654
+ "default",
5655
+ "acceptEdits",
5656
+ "bypassPermissions",
5657
+ "plan",
5658
+ "dontAsk",
5659
+ "auto"
5660
+ ]).nullable().default("bypassPermissions"),
5661
+ plan: z.boolean().default(false)
5662
+ }).prefault({}),
5663
+ codex: z.strictObject({
5664
+ accountId: z.string().nullable().default(null),
5665
+ model: z.string().nullable().default(null),
5666
+ effort: z.string().nullable().default(null),
5667
+ mode: z.enum([
5668
+ "read-only",
5669
+ "auto",
5670
+ "full-access"
5671
+ ]).nullable().default("auto"),
5672
+ plan: z.boolean().default(false)
5673
+ }).prefault({}),
5674
+ opencode: z.strictObject({
5675
+ accountId: z.null().default(null),
5676
+ model: z.string().nullable().default(null),
5677
+ effort: z.string().nullable().default(null),
5678
+ mode: z.string().nullable().default(null),
5679
+ plan: z.boolean().default(false)
5680
+ }).prefault({})
5681
+ }).prefault({}) });
5682
+ const defaults = stateSchema.parse({});
5683
+ function readComposer() {
5684
+ let user;
5685
+ try {
5686
+ user = readJson("state.json");
5687
+ } catch (error) {
5688
+ console.warn(`invalid ${stateFile}, using the default state: ${error}`);
5689
+ return structuredClone(defaults.composer);
5690
+ }
5691
+ if (user === null) return structuredClone(defaults.composer);
5692
+ const result = stateSchema.safeParse(user);
5693
+ if (!result.success) {
5694
+ console.warn(`invalid ${stateFile}, using the default state:\n${z.prettifyError(result.error)}`);
5695
+ return structuredClone(defaults.composer);
5696
+ }
5697
+ return result.data.composer;
5698
+ }
5699
+ function saveComposer(value) {
5700
+ const result = stateSchema.safeParse({ composer: value });
5701
+ if (!result.success) throw new Error(z.prettifyError(result.error));
5702
+ writeJson("state.json", result.data);
5703
+ broadcast({
5704
+ type: "composer",
5705
+ composer: result.data.composer
5706
+ });
5707
+ return result.data.composer;
5708
+ }
5709
+ //#endregion
5627
5710
  //#region src/api/socket.ts
5628
5711
  const handlers = {
5629
5712
  ping: () => null,
@@ -5631,6 +5714,7 @@ const handlers = {
5631
5714
  refreshAll();
5632
5715
  return {
5633
5716
  ...configInfo(),
5717
+ composer: readComposer(),
5634
5718
  hostname: os.hostname(),
5635
5719
  projects: projects$1(),
5636
5720
  sessions: sessions(),
@@ -5639,6 +5723,8 @@ const handlers = {
5639
5723
  };
5640
5724
  },
5641
5725
  "config.get": () => configInfo(),
5726
+ "composer.get": () => readComposer(),
5727
+ "composer.save": (params) => saveComposer(params),
5642
5728
  "config.save": async (params) => {
5643
5729
  const before = readConfig();
5644
5730
  const saved = saveConfig(params);
@@ -5647,7 +5733,7 @@ const handlers = {
5647
5733
  "codex",
5648
5734
  "opencode"
5649
5735
  ]) if (before.enabledProviders[provider] && !saved.enabledProviders[provider]) await stopProvider(provider);
5650
- if (saved.claudeBaseDir === before.claudeBaseDir && JSON.stringify(saved.enabledProviders) === JSON.stringify(before.enabledProviders)) return saved;
5736
+ if (JSON.stringify(saved.claudeBaseDir) === JSON.stringify(before.claudeBaseDir) && JSON.stringify(saved.enabledProviders) === JSON.stringify(before.enabledProviders)) return saved;
5651
5737
  watchSessions();
5652
5738
  refreshAll();
5653
5739
  publishAccounts();
@@ -5907,7 +5993,7 @@ if (args.command === "unpair") {
5907
5993
  process.exit(0);
5908
5994
  }
5909
5995
  lockHome();
5910
- process.env.CLAUDE_CONFIG_DIR = readConfig().claudeBaseDir;
5996
+ process.env.CLAUDE_CONFIG_DIR = claudeBaseDir();
5911
5997
  watchSessions();
5912
5998
  refreshAll();
5913
5999
  if (findClaude() === null) {