opencode-synced 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -76,6 +76,7 @@ Create `~/.config/opencode/opencode-synced.jsonc`:
76
76
  "includeMcpSecrets": false,
77
77
  "includeSessions": false,
78
78
  "includePromptStash": false,
79
+ "includeModelFavorites": true,
79
80
  "extraSecretPaths": [],
80
81
  "extraConfigPaths": [],
81
82
  }
@@ -88,6 +89,7 @@ Create `~/.config/opencode/opencode-synced.jsonc`:
88
89
  - `~/.config/opencode/opencode.json` and `opencode.jsonc`
89
90
  - `~/.config/opencode/AGENTS.md`
90
91
  - `~/.config/opencode/agent/`, `command/`, `mode/`, `tool/`, `themes/`, `plugin/`
92
+ - `~/.local/state/opencode/model.json` (model favorites)
91
93
  - Any extra paths in `extraConfigPaths` (allowlist, files or folders)
92
94
 
93
95
  ### Secrets (private repos only)
@@ -11,3 +11,4 @@ If the user wants a public repo, pass private=false.
11
11
  Include includeSecrets if the user explicitly opts in.
12
12
  Include includeMcpSecrets only if they want MCP secrets committed to a private repo.
13
13
  If the user supplies extra config paths, pass extraConfigPaths.
14
+ Model favorites sync is enabled by default; set includeModelFavorites=false to disable.
package/dist/index.js CHANGED
@@ -112,6 +112,10 @@ export const opencodeConfigSync = async (ctx) => {
112
112
  .boolean()
113
113
  .optional()
114
114
  .describe('Enable prompt stash/history sync (requires includeSecrets)'),
115
+ includeModelFavorites: tool.schema
116
+ .boolean()
117
+ .optional()
118
+ .describe('Sync model favorites (state/model.json)'),
115
119
  create: tool.schema.boolean().optional().describe('Create repo if missing'),
116
120
  private: tool.schema.boolean().optional().describe('Create repo as private'),
117
121
  extraSecretPaths: tool.schema.array(tool.schema.string()).optional(),
@@ -134,6 +138,7 @@ export const opencodeConfigSync = async (ctx) => {
134
138
  includeMcpSecrets: args.includeMcpSecrets,
135
139
  includeSessions: args.includeSessions,
136
140
  includePromptStash: args.includePromptStash,
141
+ includeModelFavorites: args.includeModelFavorites,
137
142
  create: args.create,
138
143
  private: args.private,
139
144
  extraSecretPaths: args.extraSecretPaths,
@@ -12,6 +12,7 @@ export interface SyncConfig {
12
12
  includeMcpSecrets?: boolean;
13
13
  includeSessions?: boolean;
14
14
  includePromptStash?: boolean;
15
+ includeModelFavorites?: boolean;
15
16
  extraSecretPaths?: string[];
16
17
  extraConfigPaths?: string[];
17
18
  }
@@ -22,11 +22,13 @@ export async function chmodIfExists(filePath, mode) {
22
22
  }
23
23
  export function normalizeSyncConfig(config) {
24
24
  const includeSecrets = Boolean(config.includeSecrets);
25
+ const includeModelFavorites = config.includeModelFavorites !== false;
25
26
  return {
26
27
  includeSecrets,
27
28
  includeMcpSecrets: includeSecrets ? Boolean(config.includeMcpSecrets) : false,
28
29
  includeSessions: Boolean(config.includeSessions),
29
30
  includePromptStash: Boolean(config.includePromptStash),
31
+ includeModelFavorites,
30
32
  extraSecretPaths: Array.isArray(config.extraSecretPaths) ? config.extraSecretPaths : [],
31
33
  extraConfigPaths: Array.isArray(config.extraConfigPaths) ? config.extraConfigPaths : [],
32
34
  localRepoPath: config.localRepoPath,
@@ -9,6 +9,7 @@ const DEFAULT_STATE_NAME = 'sync-state.json';
9
9
  const CONFIG_DIRS = ['agent', 'command', 'mode', 'tool', 'themes', 'plugin'];
10
10
  const SESSION_DIRS = ['storage/session', 'storage/message', 'storage/part', 'storage/session_diff'];
11
11
  const PROMPT_STASH_FILES = ['prompt-stash.jsonl', 'prompt-history.jsonl'];
12
+ const MODEL_FAVORITES_FILE = 'model.json';
12
13
  export function resolveHomeDir(env = process.env, platform = process.platform) {
13
14
  if (platform === 'win32') {
14
15
  return env.USERPROFILE ?? env.HOMEDRIVE ?? env.HOME ?? '';
@@ -92,9 +93,11 @@ export function resolveRepoRoot(config, locations) {
92
93
  export function buildSyncPlan(config, locations, repoRoot, platform = process.platform) {
93
94
  const configRoot = locations.configRoot;
94
95
  const dataRoot = path.join(locations.xdg.dataDir, 'opencode');
96
+ const stateRoot = path.join(locations.xdg.stateDir, 'opencode');
95
97
  const repoConfigRoot = path.join(repoRoot, 'config');
96
98
  const repoDataRoot = path.join(repoRoot, 'data');
97
99
  const repoSecretsRoot = path.join(repoRoot, 'secrets');
100
+ const repoStateRoot = path.join(repoRoot, 'state');
98
101
  const repoExtraDir = path.join(repoSecretsRoot, 'extra');
99
102
  const manifestPath = path.join(repoSecretsRoot, 'extra-manifest.json');
100
103
  const repoConfigExtraDir = path.join(repoConfigRoot, 'extra');
@@ -121,6 +124,15 @@ export function buildSyncPlan(config, locations, repoRoot, platform = process.pl
121
124
  isConfigFile: false,
122
125
  });
123
126
  }
127
+ if (config.includeModelFavorites !== false) {
128
+ items.push({
129
+ localPath: path.join(stateRoot, MODEL_FAVORITES_FILE),
130
+ repoPath: path.join(repoStateRoot, MODEL_FAVORITES_FILE),
131
+ type: 'file',
132
+ isSecret: false,
133
+ isConfigFile: false,
134
+ });
135
+ }
124
136
  if (config.includeSecrets) {
125
137
  items.push({
126
138
  localPath: path.join(dataRoot, 'auth.json'),
@@ -147,8 +159,6 @@ export function buildSyncPlan(config, locations, repoRoot, platform = process.pl
147
159
  }
148
160
  }
149
161
  if (config.includePromptStash) {
150
- const stateRoot = path.join(locations.xdg.stateDir, 'opencode');
151
- const repoStateRoot = path.join(repoRoot, 'state');
152
162
  for (const fileName of PROMPT_STASH_FILES) {
153
163
  items.push({
154
164
  localPath: path.join(stateRoot, fileName),
@@ -10,6 +10,7 @@ interface InitOptions {
10
10
  includeMcpSecrets?: boolean;
11
11
  includeSessions?: boolean;
12
12
  includePromptStash?: boolean;
13
+ includeModelFavorites?: boolean;
13
14
  create?: boolean;
14
15
  private?: boolean;
15
16
  extraSecretPaths?: string[];
@@ -83,6 +83,7 @@ export function createSyncService(ctx) {
83
83
  const includeMcpSecrets = config.includeMcpSecrets ? 'enabled' : 'disabled';
84
84
  const includeSessions = config.includeSessions ? 'enabled' : 'disabled';
85
85
  const includePromptStash = config.includePromptStash ? 'enabled' : 'disabled';
86
+ const includeModelFavorites = config.includeModelFavorites ? 'enabled' : 'disabled';
86
87
  const lastPull = state.lastPull ?? 'never';
87
88
  const lastPush = state.lastPush ?? 'never';
88
89
  let changesLabel = 'clean';
@@ -104,6 +105,7 @@ export function createSyncService(ctx) {
104
105
  `MCP secrets: ${includeMcpSecrets}`,
105
106
  `Sessions: ${includeSessions}`,
106
107
  `Prompt stash: ${includePromptStash}`,
108
+ `Model favorites: ${includeModelFavorites}`,
107
109
  `Last pull: ${lastPull}`,
108
110
  `Last push: ${lastPush}`,
109
111
  `Working tree: ${changesLabel}`,
@@ -369,6 +371,7 @@ async function buildConfigFromInit($, options) {
369
371
  includeMcpSecrets: options.includeMcpSecrets ?? false,
370
372
  includeSessions: options.includeSessions ?? false,
371
373
  includePromptStash: options.includePromptStash ?? false,
374
+ includeModelFavorites: options.includeModelFavorites ?? true,
372
375
  extraSecretPaths: options.extraSecretPaths ?? [],
373
376
  extraConfigPaths: options.extraConfigPaths ?? [],
374
377
  localRepoPath: options.localRepoPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-synced",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Sync global opencode config across machines via GitHub.",
5
5
  "author": {
6
6
  "name": "Ian Hildebrand"