@co0ontty/wand 4.8.0 → 4.9.0-beta.g68a0791

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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "8688b5cf30adc66cff2a50d9cfa34a6b1b9a4adc",
3
- "builtAt": "2026-07-17T00:33:01.780Z",
4
- "version": "4.8.0",
5
- "channel": "stable"
2
+ "commit": "68a079166c78753758bb0c06b975a6bf7a7634a5",
3
+ "builtAt": "2026-07-17T01:39:27.757Z",
4
+ "version": "4.9.0-beta.g68a0791",
5
+ "channel": "beta"
6
6
  }
package/dist/config.d.ts CHANGED
@@ -7,7 +7,7 @@ import type { WandStorage } from "./storage.js";
7
7
  * 升级路径:老 JSON 里仍存有这些字段时,首次启动会被搬到 DB(见 migrateLegacyPreferencesToDb),
8
8
  * 然后下一次 saveConfig 写回 JSON 时它们会被剥离(见 stripPreferenceFields)。
9
9
  */
10
- export declare const PREFERENCE_KEYS: readonly ["defaultProvider", "defaultSessionKind", "defaultMode", "defaultCwd", "defaultModel", "defaultCodexModel", "defaultOpenCodeModel", "commitCli", "commitModel", "commitAiSource", "systemAi", "defaultThinkingEffort", "structuredRunner", "language", "cardDefaults", "inheritEnv"];
10
+ export declare const PREFERENCE_KEYS: readonly ["defaultProvider", "defaultSessionKind", "defaultMode", "defaultCwd", "defaultModel", "defaultCodexModel", "defaultOpenCodeModel", "defaultGrokModel", "commitCli", "commitModel", "commitAiSource", "systemAi", "defaultThinkingEffort", "structuredRunner", "language", "cardDefaults", "inheritEnv"];
11
11
  export type PreferenceKey = (typeof PREFERENCE_KEYS)[number];
12
12
  export declare function isPreferenceKey(key: string): key is PreferenceKey;
13
13
  export declare const defaultConfig: () => WandConfig;
@@ -44,10 +44,11 @@ export declare function writePreferenceToStorage(config: WandConfig, storage: Wa
44
44
  export declare function validateCommitAiConfig(config: Pick<WandConfig, "commitAiSource" | "systemAi">): void;
45
45
  export declare function normalizeCardDefaults(input: unknown): CardExpandDefaults;
46
46
  export declare function isExecutionMode(value: unknown): value is ExecutionMode;
47
- export declare function getProviderDefaultModels(config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel">): {
47
+ export declare function getProviderDefaultModels(config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel">): {
48
48
  claude: string;
49
49
  codex: string;
50
50
  opencode: string;
51
+ grok: string;
51
52
  };
52
- export declare function getDefaultModelForProvider(config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel">, provider: SessionProvider | undefined): string;
53
+ export declare function getDefaultModelForProvider(config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel">, provider: SessionProvider | undefined): string;
53
54
  export declare function normalizeMode(input: string | undefined, fallback: ExecutionMode): ExecutionMode;
package/dist/config.js CHANGED
@@ -29,6 +29,7 @@ export const PREFERENCE_KEYS = [
29
29
  "defaultModel",
30
30
  "defaultCodexModel",
31
31
  "defaultOpenCodeModel",
32
+ "defaultGrokModel",
32
33
  "commitCli",
33
34
  "commitModel",
34
35
  "commitAiSource",
@@ -71,6 +72,7 @@ export const defaultConfig = () => ({
71
72
  defaultModel: "",
72
73
  defaultCodexModel: "",
73
74
  defaultOpenCodeModel: "",
75
+ defaultGrokModel: "",
74
76
  commitCli: "claude",
75
77
  commitModel: "",
76
78
  commitAiSource: "cli",
@@ -313,6 +315,11 @@ export function applyStoragePreferences(config, storage) {
313
315
  if (typeof v === "string")
314
316
  config.defaultOpenCodeModel = v.trim();
315
317
  }
318
+ if (storage.hasPreference(preferenceStorageKey("defaultGrokModel"))) {
319
+ const v = storage.getPreference(preferenceStorageKey("defaultGrokModel"), defaults.defaultGrokModel ?? "");
320
+ if (typeof v === "string")
321
+ config.defaultGrokModel = v.trim();
322
+ }
316
323
  if (storage.hasPreference(preferenceStorageKey("commitCli"))) {
317
324
  const v = storage.getPreference(preferenceStorageKey("commitCli"), defaults.commitCli ?? "claude");
318
325
  if (v === "claude" || v === "codex" || v === "opencode")
@@ -407,6 +414,12 @@ export function writePreferenceToStorage(config, storage, key, value, options =
407
414
  config.defaultOpenCodeModel = v;
408
415
  break;
409
416
  }
417
+ case "defaultGrokModel": {
418
+ const v = typeof value === "string" ? value.trim() : "";
419
+ storage.setPreference(dbKey, v);
420
+ config.defaultGrokModel = v;
421
+ break;
422
+ }
410
423
  case "commitCli": {
411
424
  if (value !== "claude" && value !== "codex" && value !== "opencode")
412
425
  throw new Error(`无效 commit CLI: ${value}`);
@@ -633,6 +646,7 @@ function mergeWithDefaults(input) {
633
646
  defaultModel: typeof input.defaultModel === "string" ? input.defaultModel.trim() : defaults.defaultModel,
634
647
  defaultCodexModel: typeof input.defaultCodexModel === "string" ? input.defaultCodexModel.trim() : defaults.defaultCodexModel,
635
648
  defaultOpenCodeModel: typeof input.defaultOpenCodeModel === "string" ? input.defaultOpenCodeModel.trim() : defaults.defaultOpenCodeModel,
649
+ defaultGrokModel: typeof input.defaultGrokModel === "string" ? input.defaultGrokModel.trim() : defaults.defaultGrokModel,
636
650
  commitCli: input.commitCli === "codex" || input.commitCli === "opencode" ? input.commitCli : "claude",
637
651
  commitModel: typeof input.commitModel === "string" ? input.commitModel.trim() : defaults.commitModel,
638
652
  commitAiSource: input.commitAiSource === "api" ? "api" : "cli",
@@ -649,11 +663,18 @@ export function getProviderDefaultModels(config) {
649
663
  claude: (config.defaultModel ?? "").trim(),
650
664
  codex: (config.defaultCodexModel ?? "").trim(),
651
665
  opencode: (config.defaultOpenCodeModel ?? "").trim(),
666
+ grok: (config.defaultGrokModel ?? "").trim(),
652
667
  };
653
668
  }
654
669
  export function getDefaultModelForProvider(config, provider) {
655
670
  const defaults = getProviderDefaultModels(config);
656
- return provider === "codex" ? defaults.codex : provider === "opencode" ? defaults.opencode : provider === "grok" ? "" : defaults.claude;
671
+ if (provider === "codex")
672
+ return defaults.codex;
673
+ if (provider === "opencode")
674
+ return defaults.opencode;
675
+ if (provider === "grok")
676
+ return defaults.grok;
677
+ return defaults.claude;
657
678
  }
658
679
  export function normalizeMode(input, fallback) {
659
680
  return isExecutionMode(input) ? input : fallback;
package/dist/models.d.ts CHANGED
@@ -34,10 +34,19 @@ export interface ModelCache {
34
34
  models: ClaudeModelInfo[];
35
35
  codexModels: ClaudeModelInfo[];
36
36
  opencodeModels: ClaudeModelInfo[];
37
+ grokModels: ClaudeModelInfo[];
37
38
  claudeVersion: string | null;
38
39
  opencodeVersion: string | null;
39
40
  refreshedAt: string;
40
41
  }
42
+ /**
43
+ * Parse `grok models` human-readable output:
44
+ *
45
+ * Default model: grok-4.5
46
+ * Available models:
47
+ * * grok-4.5 (default)
48
+ */
49
+ export declare function parseGrokModels(stdout: string): ClaudeModelInfo[];
41
50
  /** Parse `opencode models`, whose stable machine-friendly output is one provider/model id per line. */
42
51
  export declare function parseOpenCodeModels(stdout: string): ClaudeModelInfo[];
43
52
  /** Parse the machine-readable model registry emitted by the installed Codex CLI. */
package/dist/models.js CHANGED
@@ -29,6 +29,10 @@ const CODEX_FALLBACK_MODELS = [
29
29
  const OPENCODE_FALLBACK_MODELS = [
30
30
  { id: "default", label: "跟随 OpenCode 默认", alias: true },
31
31
  ];
32
+ const GROK_FALLBACK_MODELS = [
33
+ { id: "default", label: "跟随 Grok 默认", alias: true },
34
+ { id: "grok-4.5", label: "grok-4.5" },
35
+ ];
32
36
  let cache = null;
33
37
  function cloneModels(models) {
34
38
  return models.map((model) => ({ ...model }));
@@ -193,6 +197,7 @@ function createInitialCache(options) {
193
197
  }),
194
198
  codexModels: cloneModels(CODEX_FALLBACK_MODELS),
195
199
  opencodeModels: cloneModels(OPENCODE_FALLBACK_MODELS),
200
+ grokModels: cloneModels(GROK_FALLBACK_MODELS),
196
201
  claudeVersion: null,
197
202
  opencodeVersion: null,
198
203
  refreshedAt: now.toISOString(),
@@ -253,6 +258,15 @@ async function probeOpenCode(runner, env) {
253
258
  : null;
254
259
  return { models, version };
255
260
  }
261
+ async function probeGrokModels(runner, env) {
262
+ try {
263
+ const { stdout } = await runner("grok", ["models"], { env, timeout: 8000 });
264
+ return parseGrokModels(stdout);
265
+ }
266
+ catch {
267
+ return cloneModels(GROK_FALLBACK_MODELS);
268
+ }
269
+ }
256
270
  function createOfficialModelsApi(apiKey) {
257
271
  const client = new Anthropic({ apiKey });
258
272
  return {
@@ -319,6 +333,47 @@ function mergeVerifications(previous, models, verifiedIds, claudeVersion, now) {
319
333
  }
320
334
  return [...byId.values()];
321
335
  }
336
+ /**
337
+ * Parse `grok models` human-readable output:
338
+ *
339
+ * Default model: grok-4.5
340
+ * Available models:
341
+ * * grok-4.5 (default)
342
+ */
343
+ export function parseGrokModels(stdout) {
344
+ const stripAnsi = (line) => line.replace(/\x1b\[[0-?]*[ -\/]*[@-~]/g, "");
345
+ const lines = stdout.split(/\r?\n/).map((line) => stripAnsi(line).trim()).filter(Boolean);
346
+ let defaultModel = "";
347
+ const ids = [];
348
+ for (const line of lines) {
349
+ const defaultMatch = line.match(/^Default model:\s*([A-Za-z0-9][A-Za-z0-9._:-]{0,127})\s*$/i);
350
+ if (defaultMatch) {
351
+ defaultModel = defaultMatch[1];
352
+ continue;
353
+ }
354
+ const bulletMatch = line.match(/^\*+\s*([A-Za-z0-9][A-Za-z0-9._:-]{0,127})(?:\s*\(.*\))?\s*$/);
355
+ if (bulletMatch) {
356
+ ids.push(bulletMatch[1]);
357
+ continue;
358
+ }
359
+ // Some builds may print plain model ids after the "Available models" header.
360
+ if (/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(line) && !/^(available|default)\b/i.test(line)) {
361
+ ids.push(line);
362
+ }
363
+ }
364
+ const unique = Array.from(new Set(ids.filter((id) => id && id !== "default")));
365
+ if (defaultModel && !unique.includes(defaultModel))
366
+ unique.unshift(defaultModel);
367
+ if (!unique.length && !defaultModel)
368
+ return cloneModels(GROK_FALLBACK_MODELS);
369
+ const defaultLabel = defaultModel
370
+ ? `${defaultModel}(Grok 默认)`
371
+ : "跟随 Grok 默认";
372
+ return [
373
+ { id: "default", label: defaultLabel, alias: true },
374
+ ...unique.map((id) => ({ id, label: id })),
375
+ ];
376
+ }
322
377
  /** Parse `opencode models`, whose stable machine-friendly output is one provider/model id per line. */
323
378
  export function parseOpenCodeModels(stdout) {
324
379
  const ids = Array.from(new Set(stdout
@@ -397,10 +452,11 @@ export async function refreshModels(options = {}) {
397
452
  const now = options.now?.() ?? new Date();
398
453
  const env = resolveProbeEnv(options);
399
454
  const runner = options.commandRunner ?? defaultCommandRunner;
400
- const [claudeVersion, codexModels, opencode, apiModels] = await Promise.all([
455
+ const [claudeVersion, codexModels, opencode, grokModels, apiModels] = await Promise.all([
401
456
  probeClaudeVersion(runner, env),
402
457
  probeCodexModels(runner, env),
403
458
  probeOpenCode(runner, env),
459
+ probeGrokModels(runner, env),
404
460
  listClaudeModelsFromApi(options, env),
405
461
  ]);
406
462
  const priorVerifications = loadClaudeVerifications(options.storage);
@@ -427,6 +483,7 @@ export async function refreshModels(options = {}) {
427
483
  }),
428
484
  codexModels,
429
485
  opencodeModels: opencode.models,
486
+ grokModels,
430
487
  claudeVersion,
431
488
  opencodeVersion: opencode.version,
432
489
  refreshedAt: now.toISOString(),
@@ -20,6 +20,7 @@ function publicConfig(config) {
20
20
  defaultModel: defaultModels.claude,
21
21
  defaultCodexModel: defaultModels.codex,
22
22
  defaultOpenCodeModel: defaultModels.opencode,
23
+ defaultGrokModel: defaultModels.grok,
23
24
  defaultModels,
24
25
  };
25
26
  }
@@ -184,6 +185,8 @@ export function registerSettingsRoutes(app, deps) {
184
185
  stagePreference("defaultCodexModel", body.defaultModels.codex);
185
186
  if (Object.hasOwn(body.defaultModels, "opencode"))
186
187
  stagePreference("defaultOpenCodeModel", body.defaultModels.opencode);
188
+ if (Object.hasOwn(body.defaultModels, "grok"))
189
+ stagePreference("defaultGrokModel", body.defaultModels.grok);
187
190
  }
188
191
  if (body.systemAi !== undefined) {
189
192
  if (!body.systemAi || typeof body.systemAi !== "object" || Array.isArray(body.systemAi)) {
@@ -252,6 +255,7 @@ export function registerSettingsRoutes(app, deps) {
252
255
  defaultModel: defaults.claude,
253
256
  defaultCodexModel: defaults.codex,
254
257
  defaultOpenCodeModel: defaults.opencode,
258
+ defaultGrokModel: defaults.grok,
255
259
  defaultModels: defaults,
256
260
  });
257
261
  });
@@ -264,6 +268,7 @@ export function registerSettingsRoutes(app, deps) {
264
268
  defaultModel: defaults.claude,
265
269
  defaultCodexModel: defaults.codex,
266
270
  defaultOpenCodeModel: defaults.opencode,
271
+ defaultGrokModel: defaults.grok,
267
272
  defaultModels: defaults,
268
273
  });
269
274
  }
package/dist/server.js CHANGED
@@ -197,6 +197,7 @@ const CONNECTED_APP_PREFERENCE_KEYS = new Set([
197
197
  "defaultModel",
198
198
  "defaultCodexModel",
199
199
  "defaultOpenCodeModel",
200
+ "defaultGrokModel",
200
201
  "defaultModels",
201
202
  "defaultThinkingEffort",
202
203
  "defaultProvider",
@@ -717,6 +718,7 @@ export async function startServer(config, configPath, options = {}) {
717
718
  defaultModel: defaultModels.claude,
718
719
  defaultCodexModel: defaultModels.codex,
719
720
  defaultOpenCodeModel: defaultModels.opencode,
721
+ defaultGrokModel: defaultModels.grok,
720
722
  defaultModels,
721
723
  defaultThinkingEffort: config.defaultThinkingEffort ?? "off",
722
724
  commandPresets: config.commandPresets,
@@ -13,6 +13,6 @@ export interface SessionAiContext {
13
13
  */
14
14
  export declare function resolveSessionProvider(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command">): SessionProvider;
15
15
  /** Build the provider-specific settings used by session-adjacent AI actions. */
16
- export declare function resolveSessionAiContext(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command" | "selectedModel" | "thinkingEffort">, config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultThinkingEffort" | "inheritEnv">): SessionAiContext;
16
+ export declare function resolveSessionAiContext(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command" | "selectedModel" | "thinkingEffort">, config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel" | "defaultThinkingEffort" | "inheritEnv">): SessionAiContext;
17
17
  /** Build the AI context for quick-commit actions from their global preferences. */
18
- export declare function resolveCommitAiContext(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command" | "selectedModel" | "thinkingEffort">, config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultThinkingEffort" | "inheritEnv" | "commitCli" | "commitModel" | "commitAiSource" | "systemAi">): SessionAiContext;
18
+ export declare function resolveCommitAiContext(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command" | "selectedModel" | "thinkingEffort">, config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel" | "defaultThinkingEffort" | "inheritEnv" | "commitCli" | "commitModel" | "commitAiSource" | "systemAi">): SessionAiContext;
@@ -5,10 +5,16 @@ import { getDefaultModelForProvider } from "./config.js";
5
5
  * still identify Codex through structuredState, runner, or command.
6
6
  */
7
7
  export function resolveSessionProvider(snapshot) {
8
- if (snapshot.provider === "claude" || snapshot.provider === "codex" || snapshot.provider === "opencode") {
8
+ if (snapshot.provider === "claude"
9
+ || snapshot.provider === "codex"
10
+ || snapshot.provider === "opencode"
11
+ || snapshot.provider === "grok") {
9
12
  return snapshot.provider;
10
13
  }
11
- if (snapshot.structuredState?.provider === "claude" || snapshot.structuredState?.provider === "codex" || snapshot.structuredState?.provider === "opencode") {
14
+ if (snapshot.structuredState?.provider === "claude"
15
+ || snapshot.structuredState?.provider === "codex"
16
+ || snapshot.structuredState?.provider === "opencode"
17
+ || snapshot.structuredState?.provider === "grok") {
12
18
  return snapshot.structuredState.provider;
13
19
  }
14
20
  const runner = snapshot.runner ?? snapshot.structuredState?.runner;
@@ -16,11 +22,17 @@ export function resolveSessionProvider(snapshot) {
16
22
  return "codex";
17
23
  if (runner === "opencode-cli-run")
18
24
  return "opencode";
25
+ if (runner === "grok-cli-headless")
26
+ return "grok";
19
27
  if (runner === "claude-cli" || runner === "claude-cli-print" || runner === "claude-sdk")
20
28
  return "claude";
21
29
  if (/^codex\b/i.test(snapshot.command.trim()))
22
30
  return "codex";
23
- return /^opencode\b/i.test(snapshot.command.trim()) ? "opencode" : "claude";
31
+ if (/^opencode\b/i.test(snapshot.command.trim()))
32
+ return "opencode";
33
+ if (/^grok\b/i.test(snapshot.command.trim()))
34
+ return "grok";
35
+ return "claude";
24
36
  }
25
37
  function normalizeModel(value) {
26
38
  const model = value?.trim();
package/dist/types.d.ts CHANGED
@@ -112,6 +112,8 @@ export interface WandConfig {
112
112
  defaultCodexModel?: string;
113
113
  /** 新建 OpenCode 会话时默认使用的 provider/model。留空则由 opencode 自行决定。 */
114
114
  defaultOpenCodeModel?: string;
115
+ /** 新建 Grok 会话时默认使用的模型。留空则不传 --model,由 grok 自行决定。 */
116
+ defaultGrokModel?: string;
115
117
  /** 快捷提交生成 commit message / tag 时使用的 CLI。 */
116
118
  commitCli?: SessionProvider;
117
119
  /** 快捷提交专用模型。留空则跟随所选 CLI 的默认模型。 */