shortcutxl 0.3.76 → 0.3.77

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 (173) hide show
  1. package/BINARY-INVENTORY.json +813 -813
  2. package/CHANGELOG.md +6 -0
  3. package/dist/ai/models.d.ts +10 -6
  4. package/dist/ai/models.generated.d.ts +72 -0
  5. package/dist/ai/models.generated.js +33 -0
  6. package/dist/ai/models.js +36 -13
  7. package/dist/ai/providers/anthropic.d.ts +4 -2
  8. package/dist/ai/providers/anthropic.js +59 -29
  9. package/dist/ai/providers/azure-openai-responses.d.ts +2 -1
  10. package/dist/ai/providers/azure-openai-responses.js +4 -20
  11. package/dist/ai/providers/google-vertex.d.ts +8 -2
  12. package/dist/ai/providers/google-vertex.js +66 -54
  13. package/dist/ai/providers/google.js +15 -48
  14. package/dist/ai/providers/openai-completions.d.ts +4 -1
  15. package/dist/ai/providers/openai-completions.js +26 -10
  16. package/dist/ai/providers/openai-reasoning.d.ts +5 -0
  17. package/dist/ai/providers/openai-reasoning.js +13 -0
  18. package/dist/ai/providers/openai-responses-shared.js +1 -1
  19. package/dist/ai/providers/openai-responses.d.ts +6 -2
  20. package/dist/ai/providers/openai-responses.js +28 -23
  21. package/dist/ai/providers/simple-options.d.ts +2 -3
  22. package/dist/ai/providers/simple-options.js +4 -6
  23. package/dist/ai/types.d.ts +19 -2
  24. package/dist/app/agent-session-runtime-adapter.js +7 -6
  25. package/dist/app/approvals/approval-errors.d.ts +15 -0
  26. package/dist/app/approvals/approval-errors.js +14 -0
  27. package/dist/app/approvals/runtime-approval-gates.d.ts +1 -2
  28. package/dist/app/approvals/tool-approval.d.ts +1 -0
  29. package/dist/app/approvals/tool-approval.js +11 -23
  30. package/dist/app/approvals/types.d.ts +0 -14
  31. package/dist/app/approvals/types.js +0 -2
  32. package/dist/app/background/tool-summaries.js +0 -2
  33. package/dist/app/local/tools/execute-code/executor.d.ts +1 -1
  34. package/dist/app/local/tools/execute-code/executor.js +20 -10
  35. package/dist/app/local/tools/execute-code/tool.js +21 -2
  36. package/dist/app/permissions/runtime-approval-flow.d.ts +1 -5
  37. package/dist/app/permissions/runtime-approval-flow.js +0 -28
  38. package/dist/app/permissions/tool-gates.d.ts +2 -3
  39. package/dist/app/permissions/tool-gates.js +3 -81
  40. package/dist/app/prompts/shared-guidelines.js +2 -2
  41. package/dist/app/providers/google-vertex-gateway.js +4 -51
  42. package/dist/app/providers/model-registry.d.ts +1 -0
  43. package/dist/app/providers/model-registry.js +39 -0
  44. package/dist/app/providers/model-resolver.js +10 -7
  45. package/dist/app/providers/register-shortcut-provider.js +2 -6
  46. package/dist/app/providers/shortcut-api-v2-transport.js +4 -0
  47. package/dist/app/providers/shortcut-llm-proxy-client.d.ts +2 -2
  48. package/dist/app/providers/shortcut-llm-proxy-client.js +1 -0
  49. package/dist/app/resources/package-manager.js +2 -123
  50. package/dist/app/resources/resource-patterns.d.ts +9 -0
  51. package/dist/app/resources/resource-patterns.js +120 -0
  52. package/dist/app/session/forked-agent.d.ts +2 -2
  53. package/dist/app/session/model-manager.js +3 -2
  54. package/dist/app/session/session-lifecycle.js +3 -2
  55. package/dist/app/session/session-models.d.ts +2 -0
  56. package/dist/app/session/session-models.js +14 -6
  57. package/dist/app/settings-manager.d.ts +3 -3
  58. package/dist/app/shared/tools/execute-code/mog.d.ts +3 -1
  59. package/dist/app/shared/tools/execute-code/mog.js +18 -2
  60. package/dist/app/tools/execute-code/index.d.ts +1 -0
  61. package/dist/app/tools/execute-code/index.js +3 -1
  62. package/dist/app/tools/find-ignore-files.d.ts +3 -0
  63. package/dist/app/tools/find-ignore-files.js +33 -0
  64. package/dist/app/tools/find.js +2 -21
  65. package/dist/app/tools/llm-analysis.js +0 -2
  66. package/dist/app/tools/refresh-context.d.ts +1 -1
  67. package/dist/app/tools/session-settings/update-session-settings.js +2 -2
  68. package/dist/app/tools/take-screenshot.js +0 -2
  69. package/dist/app/tools/task/runner.js +1 -2
  70. package/dist/app/tools/task/task.d.ts +1 -3
  71. package/dist/app/tools/task/task.js +20 -40
  72. package/dist/autocomplete/core.d.ts +33 -0
  73. package/dist/autocomplete/core.js +113 -0
  74. package/dist/{tui → autocomplete}/fuzzy.d.ts +0 -1
  75. package/dist/{tui → autocomplete}/fuzzy.js +0 -1
  76. package/dist/{tui/autocomplete.d.ts → autocomplete/index.d.ts} +0 -1
  77. package/dist/{tui/autocomplete.js → autocomplete/index.js} +62 -158
  78. package/dist/cli/args.js +1 -1
  79. package/dist/cli/list-models.js +1 -1
  80. package/dist/cli.js +25535 -28515
  81. package/dist/contracts/agent-session-store.d.ts +1 -1
  82. package/dist/contracts/agent-settings.d.ts +1 -0
  83. package/dist/contracts/agent-settings.js +2 -1
  84. package/dist/contracts/model-call.d.ts +1 -1
  85. package/dist/contracts/model-stream.d.ts +1 -0
  86. package/dist/contracts/model-stream.js +1 -0
  87. package/dist/contracts/wire.d.ts +2 -6
  88. package/dist/core/agent-engine.js +1 -1
  89. package/dist/core/core-types.d.ts +1 -21
  90. package/dist/core/defaults.d.ts +1 -1
  91. package/dist/core/defaults.js +9 -1
  92. package/dist/core/prompts/agent-guidelines.d.ts +4 -5
  93. package/dist/core/prompts/agent-guidelines.js +28 -42
  94. package/dist/core/session-schema.d.ts +1 -1
  95. package/dist/embedded-agent/ai-invoke.js +5 -3
  96. package/dist/embedded-agent/anthropic-messages-transport.d.ts +5 -20
  97. package/dist/embedded-agent/anthropic-messages-transport.js +23 -786
  98. package/dist/embedded-agent/bootstrap.js +2 -2
  99. package/dist/embedded-agent/compose.js +8 -7
  100. package/dist/embedded-agent/gateway-base-url.d.ts +3 -0
  101. package/dist/embedded-agent/gateway-base-url.js +35 -0
  102. package/dist/embedded-agent/google-vertex-transport.d.ts +2 -10
  103. package/dist/embedded-agent/google-vertex-transport.js +20 -117
  104. package/dist/embedded-agent/host-runtime-options.d.ts +0 -8
  105. package/dist/embedded-agent/host-runtime-options.js +10 -2
  106. package/dist/embedded-agent/host-tools/invoke-llm/contract.d.ts +1 -1
  107. package/dist/embedded-agent/host-tools/invoke-llm/contract.js +3 -1
  108. package/dist/embedded-agent/host-tools/sandbox-llm/contract.d.ts +8 -3
  109. package/dist/embedded-agent/host-tools/sandbox-llm/contract.js +12 -8
  110. package/dist/embedded-agent/host-tools/sandbox-llm/index.d.ts +1 -1
  111. package/dist/embedded-agent/host-tools/sandbox-llm/index.js +1 -1
  112. package/dist/embedded-agent/host-tools/take-screenshot/contract.d.ts +0 -2
  113. package/dist/embedded-agent/host-tools/take-screenshot/contract.js +1 -3
  114. package/dist/embedded-agent/host-tools/take-screenshot/index.d.ts +1 -1
  115. package/dist/embedded-agent/host-tools/take-screenshot/index.js +1 -1
  116. package/dist/embedded-agent/host-tools/task/agents/clone.js +1 -2
  117. package/dist/embedded-agent/host-tools/task/contract.js +1 -1
  118. package/dist/embedded-agent/model-selection.d.ts +0 -6
  119. package/dist/embedded-agent/model-selection.js +15 -8
  120. package/dist/embedded-agent/openai-completions-transport.d.ts +2 -10
  121. package/dist/embedded-agent/openai-completions-transport.js +20 -120
  122. package/dist/embedded-agent/openai-responses-transport.d.ts +2 -10
  123. package/dist/embedded-agent/openai-responses-transport.js +15 -170
  124. package/dist/embedded-agent/prompt/build.js +1 -2
  125. package/dist/embedded-agent/provider-native-request.d.ts +24 -0
  126. package/dist/embedded-agent/provider-native-request.js +64 -0
  127. package/dist/embedded-agent/run-stats.d.ts +1 -1
  128. package/dist/embedded-agent/stream.d.ts +3 -9
  129. package/dist/embedded-agent/stream.js +11 -19
  130. package/dist/main.js +2 -13
  131. package/dist/rpc/rpc-approval-gates.js +1 -2
  132. package/dist/shell/approvals/runtime-approval-gates.js +1 -3
  133. package/dist/shell/components/selectors/model-selector.js +2 -1
  134. package/dist/shell/components/selectors/session-selector-search.js +1 -1
  135. package/dist/shell/components/selectors/thinking-selector.js +7 -6
  136. package/dist/shell/index.d.ts +0 -1
  137. package/dist/shell/index.js +0 -1
  138. package/dist/shell/interactive/interactive-mode.js +3 -1
  139. package/dist/shell/theme/runtime.d.ts +1 -1
  140. package/dist/shell/theme/runtime.js +1 -0
  141. package/dist/shortcut-model-catalog.d.ts +7 -2
  142. package/dist/shortcut-model-catalog.js +127 -10
  143. package/dist/tui/components/editor.d.ts +1 -1
  144. package/dist/tui/components/editor.js +1 -1
  145. package/dist/tui/components/settings-list.js +1 -1
  146. package/dist/tui/editor-component.d.ts +1 -1
  147. package/dist/tui/index.d.ts +0 -7
  148. package/dist/tui/index.js +0 -5
  149. package/native-app/main/index.js +3199 -47
  150. package/native-app/main/{photon_rs-SoVDgheu.js → photon_rs-XkYyYTVA.js} +2 -2
  151. package/native-app/package.json +1 -1
  152. package/native-app/preload/index.cjs +2 -0
  153. package/native-app/renderer/assets/{index-OhGE0UY4.css → index-B9UxxO8s.css} +4 -2
  154. package/native-app/renderer/assets/{index-CFc-oZuS.js → index-CtherCML.js} +231 -4
  155. package/native-app/renderer/index.html +2 -2
  156. package/package.json +16 -3
  157. package/skills/add-custom-model/SKILL.md +52 -0
  158. package/user-docs/dist/shortcutxl-docs.pdf +0 -0
  159. package/xll/ShortcutXL.xll +0 -0
  160. package/xll/python/Lib/site-packages/httpx-0.28.1.dist-info/RECORD +1 -1
  161. package/xll/python/Lib/site-packages/idna-3.18.dist-info/RECORD +1 -1
  162. package/xll/python/Lib/site-packages/pip-26.1.2.dist-info/RECORD +3 -3
  163. package/xll/python/Lib/site-packages/pywin32-311.dist-info/RECORD +2 -2
  164. package/xll/python/Scripts/httpx.exe +0 -0
  165. package/xll/python/Scripts/idna.exe +0 -0
  166. package/xll/python/Scripts/pip.exe +0 -0
  167. package/xll/python/Scripts/pip3.13.exe +0 -0
  168. package/xll/python/Scripts/pip3.exe +0 -0
  169. package/xll/python/Scripts/pywin32_postinstall.exe +0 -0
  170. package/xll/python/Scripts/pywin32_testall.exe +0 -0
  171. package/dist/shell/approvals/task-spawn-approval.d.ts +0 -20
  172. package/dist/shell/approvals/task-spawn-approval.js +0 -93
  173. /package/dist/{tui → autocomplete}/skill-autocomplete.js +0 -0
@@ -36,6 +36,28 @@ const OpenAICompletionsCompatSchema = Type.Object({
36
36
  openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
37
37
  vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema)
38
38
  });
39
+ const EnabledReasoningLevelSchema = Type.Union([
40
+ Type.Literal('minimal'),
41
+ Type.Literal('low'),
42
+ Type.Literal('medium'),
43
+ Type.Literal('high'),
44
+ Type.Literal('xhigh'),
45
+ Type.Literal('max')
46
+ ]);
47
+ const ModelCapabilitiesSchema = Type.Object({
48
+ reasoning: Type.Optional(Type.Object({
49
+ control: Type.Union([
50
+ Type.Literal('adaptive-effort'),
51
+ Type.Literal('effort'),
52
+ Type.Literal('thinking-level'),
53
+ Type.Literal('budget'),
54
+ Type.Literal('fixed')
55
+ ]),
56
+ levels: Type.Array(EnabledReasoningLevelSchema, { minItems: 1, uniqueItems: true }),
57
+ defaultLevel: EnabledReasoningLevelSchema,
58
+ supportsOff: Type.Boolean()
59
+ }))
60
+ });
39
61
  // Schema for custom model definition
40
62
  // Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
41
63
  const ModelDefinitionSchema = Type.Object({
@@ -52,6 +74,7 @@ const ModelDefinitionSchema = Type.Object({
52
74
  })),
53
75
  contextWindow: Type.Optional(Type.Number()),
54
76
  maxTokens: Type.Optional(Type.Number()),
77
+ capabilities: Type.Optional(ModelCapabilitiesSchema),
55
78
  headers: Type.Optional(Type.Record(Type.String(), Type.String())),
56
79
  compat: Type.Optional(OpenAICompletionsCompatSchema)
57
80
  });
@@ -68,6 +91,7 @@ const ModelOverrideSchema = Type.Object({
68
91
  })),
69
92
  contextWindow: Type.Optional(Type.Number()),
70
93
  maxTokens: Type.Optional(Type.Number()),
94
+ capabilities: Type.Optional(ModelCapabilitiesSchema),
71
95
  headers: Type.Optional(Type.Record(Type.String(), Type.String())),
72
96
  compat: Type.Optional(OpenAICompletionsCompatSchema)
73
97
  });
@@ -141,6 +165,9 @@ function applyModelOverride(model, override) {
141
165
  result.contextWindow = override.contextWindow;
142
166
  if (override.maxTokens !== undefined)
143
167
  result.maxTokens = override.maxTokens;
168
+ if (override.capabilities !== undefined) {
169
+ result.capabilities = override.capabilities;
170
+ }
144
171
  // Merge cost (partial override)
145
172
  if (override.cost) {
146
173
  result.cost = {
@@ -321,6 +348,12 @@ export class ModelRegistry {
321
348
  }
322
349
  }
323
350
  validateConfig(config) {
351
+ const validateReasoningCapabilities = (label, capabilities) => {
352
+ const reasoning = capabilities?.reasoning;
353
+ if (reasoning && !reasoning.levels.includes(reasoning.defaultLevel)) {
354
+ throw new Error(`${label}: capabilities.reasoning.defaultLevel must be included in levels.`);
355
+ }
356
+ };
324
357
  for (const [providerName, providerConfig] of Object.entries(config.providers)) {
325
358
  const hasProviderApi = !!providerConfig.api;
326
359
  const models = providerConfig.models ?? [];
@@ -352,6 +385,10 @@ export class ModelRegistry {
352
385
  throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
353
386
  if (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)
354
387
  throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
388
+ validateReasoningCapabilities(`Provider ${providerName}, model ${modelDef.id}`, modelDef.capabilities);
389
+ }
390
+ for (const [modelId, override] of Object.entries(providerConfig.modelOverrides ?? {})) {
391
+ validateReasoningCapabilities(`Provider ${providerName}, model override ${modelId}`, override.capabilities);
355
392
  }
356
393
  }
357
394
  }
@@ -398,6 +435,7 @@ export class ModelRegistry {
398
435
  cost: modelDef.cost ?? defaultCost,
399
436
  contextWindow: modelDef.contextWindow ?? 128000,
400
437
  maxTokens: modelDef.maxTokens ?? 16384,
438
+ capabilities: modelDef.capabilities,
401
439
  headers,
402
440
  compat: modelDef.compat
403
441
  });
@@ -538,6 +576,7 @@ export class ModelRegistry {
538
576
  cost: modelDef.cost,
539
577
  contextWindow: modelDef.contextWindow,
540
578
  maxTokens: modelDef.maxTokens,
579
+ capabilities: modelDef.capabilities,
541
580
  headers,
542
581
  compat: modelDef.compat
543
582
  });
@@ -2,6 +2,7 @@
2
2
  * Model resolution, scoping, and initial selection
3
3
  */
4
4
  import chalk from 'chalk';
5
+ import { resolveModelReasoningLevel } from '../../ai/models.js';
5
6
  import { DEFAULT_THINKING_LEVEL, isValidThinkingLevel } from '../../core/defaults.js';
6
7
  import { SHORTCUT_MODEL_ID, SHORTCUT_OPENAI_MODEL_ID, SHORTCUT_PROVIDER_ID } from '../../model-ids.js';
7
8
  export function formatModelRef(model) {
@@ -40,7 +41,7 @@ export const defaultModelPerProvider = {
40
41
  anthropic: SHORTCUT_MODEL_ID.ClaudeOpus5,
41
42
  openai: SHORTCUT_OPENAI_MODEL_ID,
42
43
  'azure-openai-responses': SHORTCUT_OPENAI_MODEL_ID,
43
- google: 'gemini-2.5-pro',
44
+ google: 'gemini-3-flash-preview',
44
45
  'google-vertex': 'gemini-3-pro-preview',
45
46
  openrouter: `openai/${SHORTCUT_OPENAI_MODEL_ID}`,
46
47
  'vercel-ai-gateway': 'anthropic/claude-opus-5',
@@ -321,16 +322,18 @@ export async function findInitialModel(options) {
321
322
  console.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));
322
323
  process.exit(1);
323
324
  }
324
- return { model: found, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };
325
+ return {
326
+ model: found,
327
+ thinkingLevel: resolveModelReasoningLevel(found, undefined),
328
+ fallbackMessage: undefined
329
+ };
325
330
  }
326
331
  // 2. Try saved default from settings
327
332
  if (defaultProvider && defaultModelId) {
328
333
  const found = modelRegistry.find(defaultProvider, defaultModelId);
329
334
  if (found) {
330
335
  model = found;
331
- if (defaultThinkingLevel) {
332
- thinkingLevel = defaultThinkingLevel;
333
- }
336
+ thinkingLevel = resolveModelReasoningLevel(found, defaultThinkingLevel);
334
337
  return { model, thinkingLevel, fallbackMessage: undefined };
335
338
  }
336
339
  }
@@ -344,7 +347,7 @@ export async function findInitialModel(options) {
344
347
  if (match) {
345
348
  return {
346
349
  model: match,
347
- thinkingLevel: DEFAULT_THINKING_LEVEL,
350
+ thinkingLevel: resolveModelReasoningLevel(match, undefined),
348
351
  fallbackMessage: undefined
349
352
  };
350
353
  }
@@ -353,7 +356,7 @@ export async function findInitialModel(options) {
353
356
  // If no default found, use first available
354
357
  return {
355
358
  model: availableModels[0],
356
- thinkingLevel: DEFAULT_THINKING_LEVEL,
359
+ thinkingLevel: resolveModelReasoningLevel(availableModels[0], undefined),
357
360
  fallbackMessage: undefined
358
361
  };
359
362
  }
@@ -14,7 +14,7 @@ import { streamSimpleOpenAICompletions } from '../../ai/providers/openai-complet
14
14
  import { streamSimpleOpenAIResponses } from '../../ai/providers/openai-responses.js';
15
15
  import { createRunContinuationFetch } from '../../ai/run-continuation.js';
16
16
  import { NPM_PACKAGE_NAME, VERSION } from '../../config.js';
17
- import { gatewayBaseUrlForTransport } from '../../embedded-agent/gateway-base-url.js';
17
+ import { gatewayModelForTransport } from '../../embedded-agent/gateway-base-url.js';
18
18
  import { OPENAI_PRIORITY_SERVICE_TIER, shortcutProviderFastModeForContext, shortcutSpeedFromOptions, withProviderFastModeHeaders, withProviderFastModePayloadOverride } from '../../embedded-agent/provider-fast-mode.js';
19
19
  import { SHORTCUT_PROVIDER_ID } from '../../model-ids.js';
20
20
  import { createShortcutModelDefinitions } from '../../shortcut-model-catalog.js';
@@ -116,11 +116,7 @@ export function createShortcutApiV2Dispatcher(getExtraHeaders) {
116
116
  // SDK appends "/chat/completions" to baseURL and needs the "/v1" segment;
117
117
  // Anthropic builds its own full path). Shared with the standalone transports
118
118
  // so the two paths cannot disagree.
119
- const nativeModel = {
120
- ...model,
121
- api: transport,
122
- baseUrl: gatewayBaseUrlForTransport(model.baseUrl, transport)
123
- };
119
+ const nativeModel = gatewayModelForTransport(model, model.baseUrl, transport);
124
120
  const providerFastModeKind = providerFastModeKindForTransport(transport);
125
121
  const fastMode = providerFastModeKind
126
122
  ? shortcutProviderFastModeForContext({
@@ -13,7 +13,11 @@
13
13
  * Returns `undefined` for anything else so callers can decide how to fail.
14
14
  */
15
15
  import { SHORTCUT_MODEL_ID } from '../../model-ids.js';
16
+ import { resolveShortcutModelProtocol } from '../../shortcut-model-catalog.js';
16
17
  export function resolveShortcutApiV2Transport(modelId) {
18
+ const catalogProtocol = resolveShortcutModelProtocol(modelId);
19
+ if (catalogProtocol)
20
+ return catalogProtocol;
17
21
  const normalized = modelId.trim().toLowerCase();
18
22
  // Shortcut-hosted "Pivot" and Fireworks GLM both speak OpenAI completions.
19
23
  if (normalized === SHORTCUT_MODEL_ID.Hosted ||
@@ -9,6 +9,7 @@
9
9
  * call funnels through one transport keyed by model — there is no separate
10
10
  * `/api/llm` proxy for helpers.
11
11
  */
12
+ import type { ReasoningLevel } from '../../ai/types.js';
12
13
  import type { AgentModelRegistry } from '../../contracts/agent-model.js';
13
14
  export interface ShortcutLlmAttribution {
14
15
  continuationRunId?: string;
@@ -25,8 +26,7 @@ export interface ShortcutLlmProxyRequest {
25
26
  model: string;
26
27
  messages: ShortcutLlmMessage[];
27
28
  tools?: unknown[];
28
- effort_level?: string;
29
- thinking_type?: string;
29
+ reasoning?: ReasoningLevel;
30
30
  max_tokens?: number;
31
31
  max_output_tokens?: number;
32
32
  speed?: 'fast' | 'standard';
@@ -146,6 +146,7 @@ export function createShortcutLlmProxyClient(options) {
146
146
  apiKey,
147
147
  continuationRunId: attribution?.continuationRunId,
148
148
  maxTokens: request.max_tokens ?? request.max_output_tokens,
149
+ reasoning: request.reasoning,
149
150
  signal: callOptions?.signal,
150
151
  headers,
151
152
  userMessageId: attribution?.userMessageId,
@@ -8,14 +8,14 @@
8
8
  * resolved resource to support diagnostics and conflict detection.
9
9
  */
10
10
  import ignore from 'ignore';
11
- import { minimatch } from 'minimatch';
12
11
  import { spawn, spawnSync } from 'node:child_process';
13
12
  import { createHash } from 'node:crypto';
14
13
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
15
14
  import { homedir, tmpdir } from 'node:os';
16
- import { basename, dirname, join, relative, resolve, sep } from 'node:path';
15
+ import { dirname, join, relative, resolve, sep } from 'node:path';
17
16
  import { CONFIG_DIR_NAME, getBundledSkillsDir } from '../../config.js';
18
17
  import { parseGitUrl } from '../../shared/scm/git.js';
18
+ import { applyPatterns, isEnabledByOverrides } from './resource-patterns.js';
19
19
  /** Timeout for npm/git network operations. */
20
20
  const NETWORK_TIMEOUT_MS = 10000;
21
21
  function isOfflineModeEnabled() {
@@ -365,127 +365,6 @@ function collectResourceFiles(dir, resourceType) {
365
365
  }
366
366
  return collectFiles(dir, FILE_PATTERNS[resourceType]);
367
367
  }
368
- function matchesAnyPattern(filePath, patterns, baseDir) {
369
- const rel = relative(baseDir, filePath);
370
- const name = basename(filePath);
371
- const isSkillFile = name === 'SKILL.md';
372
- const parentDir = isSkillFile ? dirname(filePath) : undefined;
373
- const parentRel = isSkillFile ? relative(baseDir, parentDir) : undefined;
374
- const parentName = isSkillFile ? basename(parentDir) : undefined;
375
- return patterns.some((pattern) => {
376
- if (minimatch(rel, pattern) || minimatch(name, pattern) || minimatch(filePath, pattern)) {
377
- return true;
378
- }
379
- if (!isSkillFile)
380
- return false;
381
- return (minimatch(parentRel, pattern) ||
382
- minimatch(parentName, pattern) ||
383
- minimatch(parentDir, pattern));
384
- });
385
- }
386
- function normalizeExactPattern(pattern) {
387
- if (pattern.startsWith('./') || pattern.startsWith('.\\')) {
388
- return pattern.slice(2);
389
- }
390
- return pattern;
391
- }
392
- function matchesAnyExactPattern(filePath, patterns, baseDir) {
393
- if (patterns.length === 0)
394
- return false;
395
- const rel = relative(baseDir, filePath);
396
- const name = basename(filePath);
397
- const isSkillFile = name === 'SKILL.md';
398
- const parentDir = isSkillFile ? dirname(filePath) : undefined;
399
- const parentRel = isSkillFile ? relative(baseDir, parentDir) : undefined;
400
- return patterns.some((pattern) => {
401
- const normalized = normalizeExactPattern(pattern);
402
- if (normalized === rel || normalized === filePath) {
403
- return true;
404
- }
405
- if (!isSkillFile)
406
- return false;
407
- return normalized === parentRel || normalized === parentDir;
408
- });
409
- }
410
- function getOverridePatterns(entries) {
411
- return entries.filter((pattern) => pattern.startsWith('!') || pattern.startsWith('+') || pattern.startsWith('-'));
412
- }
413
- function isEnabledByOverrides(filePath, patterns, baseDir) {
414
- const overrides = getOverridePatterns(patterns);
415
- const excludes = overrides
416
- .filter((pattern) => pattern.startsWith('!'))
417
- .map((pattern) => pattern.slice(1));
418
- const forceIncludes = overrides
419
- .filter((pattern) => pattern.startsWith('+'))
420
- .map((pattern) => pattern.slice(1));
421
- const forceExcludes = overrides
422
- .filter((pattern) => pattern.startsWith('-'))
423
- .map((pattern) => pattern.slice(1));
424
- let enabled = true;
425
- if (excludes.length > 0 && matchesAnyPattern(filePath, excludes, baseDir)) {
426
- enabled = false;
427
- }
428
- if (forceIncludes.length > 0 && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {
429
- enabled = true;
430
- }
431
- if (forceExcludes.length > 0 && matchesAnyExactPattern(filePath, forceExcludes, baseDir)) {
432
- enabled = false;
433
- }
434
- return enabled;
435
- }
436
- /**
437
- * Apply patterns to paths and return a Set of enabled paths.
438
- * Pattern types:
439
- * - Plain patterns: include matching paths
440
- * - `!pattern`: exclude matching paths
441
- * - `+path`: force-include exact path (overrides exclusions)
442
- * - `-path`: force-exclude exact path (overrides force-includes)
443
- */
444
- function applyPatterns(allPaths, patterns, baseDir) {
445
- const includes = [];
446
- const excludes = [];
447
- const forceIncludes = [];
448
- const forceExcludes = [];
449
- for (const p of patterns) {
450
- if (p.startsWith('+')) {
451
- forceIncludes.push(p.slice(1));
452
- }
453
- else if (p.startsWith('-')) {
454
- forceExcludes.push(p.slice(1));
455
- }
456
- else if (p.startsWith('!')) {
457
- excludes.push(p.slice(1));
458
- }
459
- else {
460
- includes.push(p);
461
- }
462
- }
463
- // Step 1: Apply includes (or all if no includes)
464
- let result;
465
- if (includes.length === 0) {
466
- result = [...allPaths];
467
- }
468
- else {
469
- result = allPaths.filter((filePath) => matchesAnyPattern(filePath, includes, baseDir));
470
- }
471
- // Step 2: Apply excludes
472
- if (excludes.length > 0) {
473
- result = result.filter((filePath) => !matchesAnyPattern(filePath, excludes, baseDir));
474
- }
475
- // Step 3: Force-include (add back from allPaths, overriding exclusions)
476
- if (forceIncludes.length > 0) {
477
- for (const filePath of allPaths) {
478
- if (!result.includes(filePath) && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {
479
- result.push(filePath);
480
- }
481
- }
482
- }
483
- // Step 4: Force-exclude (remove even if included or force-included)
484
- if (forceExcludes.length > 0) {
485
- result = result.filter((filePath) => !matchesAnyExactPattern(filePath, forceExcludes, baseDir));
486
- }
487
- return new Set(result);
488
- }
489
368
  /**
490
369
  * Default PackageManager implementation.
491
370
  *
@@ -0,0 +1,9 @@
1
+ export declare function isEnabledByOverrides(filePath: string, patterns: string[], baseDir: string): boolean;
2
+ /**
3
+ * Apply resource include/exclude patterns to paths.
4
+ *
5
+ * Plain patterns include glob matches, `!pattern` excludes glob matches,
6
+ * `+path` force-includes an exact path, and `-path` force-excludes one.
7
+ */
8
+ export declare function applyPatterns(allPaths: string[], patterns: string[], baseDir: string): Set<string>;
9
+ //# sourceMappingURL=resource-patterns.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { Minimatch } from 'minimatch';
2
+ import { basename, dirname, relative, sep } from 'node:path';
3
+ const RESOURCE_PATTERN_OPTIONS = {
4
+ // Resource filters have always been case-sensitive on every platform. Keep
5
+ // that contract explicit rather than inheriting platform-specific behavior.
6
+ nocase: false,
7
+ // Preserve the minimatch semantics used before these helpers were extracted.
8
+ nocomment: false,
9
+ nonegate: false
10
+ };
11
+ function compilePatterns(patterns) {
12
+ return patterns.map((pattern) => new Minimatch(normalizePathSeparators(pattern), RESOURCE_PATTERN_OPTIONS));
13
+ }
14
+ function normalizePathSeparators(path) {
15
+ return path.split(sep).join('/');
16
+ }
17
+ function matchCandidates(filePath, baseDir) {
18
+ const relativePath = relative(baseDir, filePath);
19
+ const candidates = [relativePath, basename(filePath), filePath];
20
+ if (basename(filePath) === 'SKILL.md') {
21
+ const parentDir = dirname(filePath);
22
+ candidates.push(relative(baseDir, parentDir), basename(parentDir), parentDir);
23
+ }
24
+ return candidates.map(normalizePathSeparators);
25
+ }
26
+ function matchesAnyPattern(filePath, patterns, baseDir) {
27
+ const candidates = matchCandidates(filePath, baseDir);
28
+ return patterns.some((pattern) => candidates.some((candidate) => pattern.match(candidate)));
29
+ }
30
+ function normalizeExactPattern(pattern) {
31
+ pattern = normalizePathSeparators(pattern);
32
+ if (pattern.startsWith('./') || pattern.startsWith('.\\')) {
33
+ return pattern.slice(2);
34
+ }
35
+ return pattern;
36
+ }
37
+ function matchesAnyExactPattern(filePath, patterns, baseDir) {
38
+ if (patterns.length === 0)
39
+ return false;
40
+ const relativePath = normalizePathSeparators(relative(baseDir, filePath));
41
+ const candidates = [relativePath, normalizePathSeparators(filePath)];
42
+ if (basename(filePath) === 'SKILL.md') {
43
+ const parentDir = dirname(filePath);
44
+ candidates.push(normalizePathSeparators(relative(baseDir, parentDir)), normalizePathSeparators(parentDir));
45
+ }
46
+ return patterns.some((pattern) => candidates.includes(normalizeExactPattern(pattern)));
47
+ }
48
+ function getOverridePatterns(entries) {
49
+ return entries.filter((pattern) => pattern.startsWith('!') || pattern.startsWith('+') || pattern.startsWith('-'));
50
+ }
51
+ export function isEnabledByOverrides(filePath, patterns, baseDir) {
52
+ const overrides = getOverridePatterns(patterns);
53
+ const excludes = overrides
54
+ .filter((pattern) => pattern.startsWith('!'))
55
+ .map((pattern) => pattern.slice(1));
56
+ const forceIncludes = overrides
57
+ .filter((pattern) => pattern.startsWith('+'))
58
+ .map((pattern) => pattern.slice(1));
59
+ const forceExcludes = overrides
60
+ .filter((pattern) => pattern.startsWith('-'))
61
+ .map((pattern) => pattern.slice(1));
62
+ const excludeMatchers = compilePatterns(excludes);
63
+ let enabled = true;
64
+ if (excludeMatchers.length > 0 && matchesAnyPattern(filePath, excludeMatchers, baseDir)) {
65
+ enabled = false;
66
+ }
67
+ if (forceIncludes.length > 0 && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {
68
+ enabled = true;
69
+ }
70
+ if (forceExcludes.length > 0 && matchesAnyExactPattern(filePath, forceExcludes, baseDir)) {
71
+ enabled = false;
72
+ }
73
+ return enabled;
74
+ }
75
+ /**
76
+ * Apply resource include/exclude patterns to paths.
77
+ *
78
+ * Plain patterns include glob matches, `!pattern` excludes glob matches,
79
+ * `+path` force-includes an exact path, and `-path` force-excludes one.
80
+ */
81
+ export function applyPatterns(allPaths, patterns, baseDir) {
82
+ const includes = [];
83
+ const excludes = [];
84
+ const forceIncludes = [];
85
+ const forceExcludes = [];
86
+ for (const pattern of patterns) {
87
+ if (pattern.startsWith('+')) {
88
+ forceIncludes.push(pattern.slice(1));
89
+ }
90
+ else if (pattern.startsWith('-')) {
91
+ forceExcludes.push(pattern.slice(1));
92
+ }
93
+ else if (pattern.startsWith('!')) {
94
+ excludes.push(pattern.slice(1));
95
+ }
96
+ else {
97
+ includes.push(pattern);
98
+ }
99
+ }
100
+ const includeMatchers = compilePatterns(includes);
101
+ const excludeMatchers = compilePatterns(excludes);
102
+ let result = includeMatchers.length === 0
103
+ ? [...allPaths]
104
+ : allPaths.filter((filePath) => matchesAnyPattern(filePath, includeMatchers, baseDir));
105
+ if (excludeMatchers.length > 0) {
106
+ result = result.filter((filePath) => !matchesAnyPattern(filePath, excludeMatchers, baseDir));
107
+ }
108
+ for (const filePath of allPaths) {
109
+ if (forceIncludes.length > 0 &&
110
+ !result.includes(filePath) &&
111
+ matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {
112
+ result.push(filePath);
113
+ }
114
+ }
115
+ if (forceExcludes.length > 0) {
116
+ result = result.filter((filePath) => !matchesAnyExactPattern(filePath, forceExcludes, baseDir));
117
+ }
118
+ return new Set(result);
119
+ }
120
+ //# sourceMappingURL=resource-patterns.js.map
@@ -14,8 +14,8 @@
14
14
  *
15
15
  * Global concurrency is still capped to avoid overwhelming the LLM proxy.
16
16
  */
17
- import type { AssistantMessage, Message, Model, ThinkingLevel, ToolCall } from '../../ai/types.js';
18
- import type { ToolDefinition, ToolExecutionContext } from '../../core/core-types.js';
17
+ import type { AssistantMessage, Message, Model, ToolCall } from '../../ai/types.js';
18
+ import type { ThinkingLevel, ToolDefinition, ToolExecutionContext } from '../../core/core-types.js';
19
19
  import type { ShortcutAuthRecovery } from '../providers/shortcut-auth-recovery.js';
20
20
  export type { ThinkingLevel };
21
21
  export interface ForkedAgentParentContext {
@@ -6,7 +6,8 @@
6
6
  * Stable deps (agent, registries, managers) are constructor-injected.
7
7
  * Part of the AgentSession extracted modules.
8
8
  */
9
- import { clampThinkingLevel, computeNextModel, cycleThinkingLevel as computeNextThinkingLevel, filterInteractiveSelectableModels, getAvailableThinkingLevels } from './session-models.js';
9
+ import { resolveModelReasoningLevel } from '../../ai/models.js';
10
+ import { computeNextModel, cycleThinkingLevel as computeNextThinkingLevel, filterInteractiveSelectableModels } from './session-models.js';
10
11
  // ============================================================================
11
12
  // Manager
12
13
  // ============================================================================
@@ -47,7 +48,7 @@ export class ModelManager {
47
48
  }
48
49
  /** Set thinking level, clamped to model capabilities. Persists only on change. */
49
50
  setThinkingLevel(level) {
50
- const effective = clampThinkingLevel(level, getAvailableThinkingLevels(this._agent.state.model));
51
+ const effective = resolveModelReasoningLevel(this._agent.state.model, level);
51
52
  const isChanging = effective !== this._agent.state.thinkingLevel;
52
53
  this._agent.setThinkingLevel(effective);
53
54
  if (isChanging) {
@@ -5,8 +5,8 @@
5
5
  * existing sessions. Each function takes an explicit params object containing
6
6
  * the dependencies it needs, rather than reaching into class state.
7
7
  */
8
+ import { resolveModelReasoningLevel } from '../../ai/models.js';
8
9
  import { configureAgentTempDir } from '../../config.js';
9
- import { DEFAULT_THINKING_LEVEL } from '../../core/index.js';
10
10
  /**
11
11
  * Create a new session, optionally with initial messages and parent tracking.
12
12
  * Returns true if completed, false if cancelled by extension.
@@ -119,7 +119,8 @@ export async function executeSwitchSession(params) {
119
119
  const hasThinkingEntry = sessionManager
120
120
  .getBranch()
121
121
  .some((entry) => entry.type === 'thinking_level_change');
122
- const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
122
+ const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ??
123
+ resolveModelReasoningLevel(agent.state.model, undefined);
123
124
  if (hasThinkingEntry) {
124
125
  // Restore thinking level if saved (setThinkingLevel clamps to model capabilities)
125
126
  setThinkingLevel(sessionContext.thinkingLevel);
@@ -16,6 +16,8 @@ export interface ModelCycleResult {
16
16
  export declare const THINKING_LEVELS: ThinkingLevel[];
17
17
  /** Thinking levels including xhigh (for supported models) */
18
18
  export declare const THINKING_LEVELS_WITH_XHIGH: ThinkingLevel[];
19
+ /** Complete ordering used only when clamping a stale selection after a model switch. */
20
+ export declare const ALL_THINKING_LEVELS: ThinkingLevel[];
19
21
  /** Check if a model supports thinking/reasoning. */
20
22
  export declare function supportsThinking(model: Model<any> | undefined): boolean;
21
23
  /** Check if a model supports xhigh thinking. */
@@ -5,7 +5,7 @@
5
5
  * AgentSession delegates to these for cycling math and level clamping,
6
6
  * then handles persistence and extension events itself.
7
7
  */
8
- import { modelsAreEqual, supportsXhigh } from '../../ai/models.js';
8
+ import { getModelReasoningLevels, modelsAreEqual } from '../../ai/models.js';
9
9
  import { SHORTCUT_MODEL_ID, SHORTCUT_OPENAI_MODEL_ID } from '../../model-ids.js';
10
10
  // ============================================================================
11
11
  // Constants
@@ -21,6 +21,16 @@ export const THINKING_LEVELS_WITH_XHIGH = [
21
21
  'high',
22
22
  'xhigh'
23
23
  ];
24
+ /** Complete ordering used only when clamping a stale selection after a model switch. */
25
+ export const ALL_THINKING_LEVELS = [
26
+ 'off',
27
+ 'minimal',
28
+ 'low',
29
+ 'medium',
30
+ 'high',
31
+ 'xhigh',
32
+ 'max'
33
+ ];
24
34
  /** Models shown in interactive model controls for known providers. Unlisted providers show all. */
25
35
  const INTERACTIVE_MODELS_PER_PROVIDER = {
26
36
  shortcut: new Set([
@@ -42,13 +52,11 @@ export function supportsThinking(model) {
42
52
  }
43
53
  /** Check if a model supports xhigh thinking. */
44
54
  export function supportsXhighThinking(model) {
45
- return model ? supportsXhigh(model) : false;
55
+ return model ? getModelReasoningLevels(model).includes('xhigh') : false;
46
56
  }
47
57
  /** Get available thinking levels for a given model. */
48
58
  export function getAvailableThinkingLevels(model) {
49
- if (!supportsThinking(model))
50
- return ['off'];
51
- return supportsXhighThinking(model) ? THINKING_LEVELS_WITH_XHIGH : THINKING_LEVELS;
59
+ return model ? getModelReasoningLevels(model) : ['off'];
52
60
  }
53
61
  /**
54
62
  * Clamp a thinking level to the nearest available level.
@@ -57,7 +65,7 @@ export function getAvailableThinkingLevels(model) {
57
65
  export function clampThinkingLevel(level, availableLevels) {
58
66
  if (availableLevels.includes(level))
59
67
  return level;
60
- const ordered = THINKING_LEVELS_WITH_XHIGH;
68
+ const ordered = ALL_THINKING_LEVELS;
61
69
  const available = new Set(availableLevels);
62
70
  const requestedIndex = ordered.indexOf(level);
63
71
  if (requestedIndex === -1) {
@@ -93,7 +93,7 @@ export interface Settings {
93
93
  lastChangelogVersion?: string;
94
94
  defaultProvider?: string;
95
95
  defaultModel?: string;
96
- defaultThinkingLevel?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
96
+ defaultThinkingLevel?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
97
97
  transport?: TransportSetting;
98
98
  steeringMode?: 'all' | 'one-at-a-time';
99
99
  followUpMode?: 'all' | 'one-at-a-time';
@@ -220,8 +220,8 @@ export declare class SettingsManager {
220
220
  getFollowUpMode(): 'all' | 'one-at-a-time';
221
221
  getTheme(): string | undefined;
222
222
  setTheme(theme: string): void;
223
- getDefaultThinkingLevel(): 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | undefined;
224
- setDefaultThinkingLevel(level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'): void;
223
+ getDefaultThinkingLevel(): 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | undefined;
224
+ setDefaultThinkingLevel(level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'): void;
225
225
  getTransport(): TransportSetting;
226
226
  getRetryEnabled(): boolean;
227
227
  setRetryEnabled(enabled: boolean): void;
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { type CellEdit, type SheetEnginePool } from '@shortcut/mog-sandbox-runtime';
9
9
  import type { ToolDefinition } from '../../../../core/core-types.js';
10
+ import { type ApprovalGate } from '../../../approvals/types.js';
11
+ import type { ExcelApprovalPayload } from '../../../local/tools/execute-code/approval-payload.js';
10
12
  interface SheetExecResult {
11
13
  ok: boolean;
12
14
  output?: string;
@@ -20,6 +22,6 @@ declare const schema: import("@sinclair/typebox").TObject<{
20
22
  description: import("@sinclair/typebox").TString;
21
23
  code: import("@sinclair/typebox").TString;
22
24
  }>;
23
- export declare function createSheetExecTool(pool: SheetEnginePool): ToolDefinition<typeof schema, SheetExecResult>;
25
+ export declare function createSheetExecTool(pool: SheetEnginePool, approval?: ApprovalGate<ExcelApprovalPayload>): ToolDefinition<typeof schema, SheetExecResult>;
24
26
  export {};
25
27
  //# sourceMappingURL=mog.d.ts.map