shortcutxl 0.3.62 → 0.3.63
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/BINARY-INVENTORY.json +813 -813
- package/CHANGELOG.md +2 -2
- package/binary-provenance.json +7 -7
- package/dist/app/providers/model-registry.d.ts +3 -0
- package/dist/app/providers/model-registry.js +13 -3
- package/dist/app/providers/model-resolver.js +15 -4
- package/dist/cli.js +65 -7
- package/dist/embedded-agent/model-registry.d.ts +1 -0
- package/dist/embedded-agent/model-registry.js +36 -4
- package/dist/main.js +30 -1
- package/dist/model-ids.d.ts +8 -0
- package/dist/model-ids.js +6 -0
- package/package.json +1 -1
- package/user-docs/dist/shortcutxl-docs.pdf +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.3.
|
|
3
|
+
## [0.3.63]
|
|
4
4
|
|
|
5
5
|
- **Windows runtime security** - Updated the embedded Windows SQLite DLL used by ShortcutXL's bundled Python runtime.
|
|
6
|
-
- **Default model update** - Updated the default model to Fable.
|
|
6
|
+
- **Default model update** - Updated the default model to Fable for individual users, while team accounts continue to use Opus 4.8.
|
|
7
7
|
|
|
8
8
|
## [0.3.61]
|
|
9
9
|
|
package/binary-provenance.json
CHANGED
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
"builtBy": "third-party",
|
|
51
51
|
"verification": "Downloaded from python.org CPython release artifacts; verify upstream SHA/signature before vendoring."
|
|
52
52
|
},
|
|
53
|
-
{
|
|
54
|
-
"pattern": "xll/python/sqlite3.dll",
|
|
55
|
-
"source": "SQLite official precompiled Windows x64 DLL",
|
|
56
|
-
"version": "3.53.2",
|
|
57
|
-
"builtBy": "third-party",
|
|
58
|
-
"verification": "Downloaded from sqlite.org sqlite-dll-win-x64-3530200.zip; upstream SHA3-256 is b898ced2e0627999d7d0b9d554ea53086a9b165e52ae743277d115dcd39e6868, and vendor-python.ps1 verifies extracted sqlite3.dll SHA256 73b045c910fc19a069bae2e2c7ebb5ea66fe6c85f166535a6e07e09155cd9e6d before copying."
|
|
59
|
-
},
|
|
53
|
+
{
|
|
54
|
+
"pattern": "xll/python/sqlite3.dll",
|
|
55
|
+
"source": "SQLite official precompiled Windows x64 DLL",
|
|
56
|
+
"version": "3.53.2",
|
|
57
|
+
"builtBy": "third-party",
|
|
58
|
+
"verification": "Downloaded from sqlite.org sqlite-dll-win-x64-3530200.zip; upstream SHA3-256 is b898ced2e0627999d7d0b9d554ea53086a9b165e52ae743277d115dcd39e6868, and vendor-python.ps1 verifies extracted sqlite3.dll SHA256 73b045c910fc19a069bae2e2c7ebb5ea66fe6c85f166535a6e07e09155cd9e6d before copying."
|
|
59
|
+
},
|
|
60
60
|
{
|
|
61
61
|
"pattern": "xll/python/vcruntime*.dll",
|
|
62
62
|
"source": "Microsoft Visual C++ runtime library bundled with CPython Windows embeddable runtime",
|
|
@@ -14,6 +14,7 @@ export declare class ModelRegistry {
|
|
|
14
14
|
private customProviderApiKeys;
|
|
15
15
|
private registeredProviders;
|
|
16
16
|
private registeredOAuthProviderIds;
|
|
17
|
+
private modelAvailabilityFilter;
|
|
17
18
|
private loadError;
|
|
18
19
|
constructor(authStorage: AuthStorage, modelsJsonPath?: string | undefined);
|
|
19
20
|
/**
|
|
@@ -24,6 +25,8 @@ export declare class ModelRegistry {
|
|
|
24
25
|
* Get any error from loading models.json (undefined if no error).
|
|
25
26
|
*/
|
|
26
27
|
getError(): string | undefined;
|
|
28
|
+
setModelAvailabilityFilter(filter?: (model: Model<Api>) => boolean): void;
|
|
29
|
+
private getPolicyAllowedModels;
|
|
27
30
|
private loadModels;
|
|
28
31
|
/** Load built-in models and apply provider/model overrides */
|
|
29
32
|
private loadBuiltInModels;
|
|
@@ -169,6 +169,7 @@ export class ModelRegistry {
|
|
|
169
169
|
customProviderApiKeys = new Map();
|
|
170
170
|
registeredProviders = new Map();
|
|
171
171
|
registeredOAuthProviderIds = new Set();
|
|
172
|
+
modelAvailabilityFilter = () => true;
|
|
172
173
|
loadError = undefined;
|
|
173
174
|
constructor(authStorage, modelsJsonPath = join(getAgentDir(), 'models.json')) {
|
|
174
175
|
this.authStorage = authStorage;
|
|
@@ -207,6 +208,12 @@ export class ModelRegistry {
|
|
|
207
208
|
getError() {
|
|
208
209
|
return this.loadError;
|
|
209
210
|
}
|
|
211
|
+
setModelAvailabilityFilter(filter) {
|
|
212
|
+
this.modelAvailabilityFilter = filter ?? (() => true);
|
|
213
|
+
}
|
|
214
|
+
getPolicyAllowedModels() {
|
|
215
|
+
return this.models.filter((model) => this.modelAvailabilityFilter(model));
|
|
216
|
+
}
|
|
210
217
|
loadModels() {
|
|
211
218
|
// Load custom models and overrides from models.json
|
|
212
219
|
const { models: customModels, overrides, modelOverrides, error } = this.modelsJsonPath
|
|
@@ -403,25 +410,28 @@ export class ModelRegistry {
|
|
|
403
410
|
* If models.json had errors, returns only built-in models.
|
|
404
411
|
*/
|
|
405
412
|
getAll() {
|
|
406
|
-
return this.
|
|
413
|
+
return this.getPolicyAllowedModels();
|
|
407
414
|
}
|
|
408
415
|
/**
|
|
409
416
|
* Get only models that have auth configured.
|
|
410
417
|
* This is a fast check that doesn't refresh OAuth tokens.
|
|
411
418
|
*/
|
|
412
419
|
getAvailable() {
|
|
413
|
-
return this.
|
|
420
|
+
return this.getPolicyAllowedModels().filter((m) => this.authStorage.hasAuth(m.provider));
|
|
414
421
|
}
|
|
415
422
|
/**
|
|
416
423
|
* Find a model by provider and ID.
|
|
417
424
|
*/
|
|
418
425
|
find(provider, modelId) {
|
|
419
|
-
return this.
|
|
426
|
+
return this.getPolicyAllowedModels().find((m) => m.provider === provider && m.id === modelId);
|
|
420
427
|
}
|
|
421
428
|
/**
|
|
422
429
|
* Get API key for a model.
|
|
423
430
|
*/
|
|
424
431
|
async getApiKey(model) {
|
|
432
|
+
if (!this.modelAvailabilityFilter(model)) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
425
435
|
return this.authStorage.getApiKey(model.provider);
|
|
426
436
|
}
|
|
427
437
|
/**
|
|
@@ -54,6 +54,12 @@ export const defaultModelPerProvider = {
|
|
|
54
54
|
opencode: SHORTCUT_MODEL_ID.ClaudeOpus48,
|
|
55
55
|
'kimi-coding': 'kimi-k2-thinking'
|
|
56
56
|
};
|
|
57
|
+
function getDefaultModelCandidatesForProvider(provider) {
|
|
58
|
+
if (provider === SHORTCUT_PROVIDER_ID) {
|
|
59
|
+
return [SHORTCUT_MODEL_ID.ClaudeFable5, SHORTCUT_MODEL_ID.ClaudeOpus48];
|
|
60
|
+
}
|
|
61
|
+
return [defaultModelPerProvider[provider]].filter((modelId) => !!modelId);
|
|
62
|
+
}
|
|
57
63
|
/**
|
|
58
64
|
* Helper to check if a model ID looks like an alias (no date suffix)
|
|
59
65
|
* Dates are typically in format: -20241022 or -20250929
|
|
@@ -320,10 +326,15 @@ export async function findInitialModel(options) {
|
|
|
320
326
|
if (availableModels.length > 0) {
|
|
321
327
|
// Try to find a default model from known providers
|
|
322
328
|
for (const provider of Object.keys(defaultModelPerProvider)) {
|
|
323
|
-
const defaultId
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
329
|
+
for (const defaultId of getDefaultModelCandidatesForProvider(provider)) {
|
|
330
|
+
const match = availableModels.find((m) => m.provider === provider && m.id === defaultId);
|
|
331
|
+
if (match) {
|
|
332
|
+
return {
|
|
333
|
+
model: match,
|
|
334
|
+
thinkingLevel: DEFAULT_THINKING_LEVEL,
|
|
335
|
+
fallbackMessage: undefined
|
|
336
|
+
};
|
|
337
|
+
}
|
|
327
338
|
}
|
|
328
339
|
}
|
|
329
340
|
// If no default found, use first available
|
package/dist/cli.js
CHANGED
|
@@ -39508,6 +39508,12 @@ var init_policy = __esm({
|
|
|
39508
39508
|
});
|
|
39509
39509
|
|
|
39510
39510
|
// src/model-ids.ts
|
|
39511
|
+
function isShortcutTeamRestrictedModel(model) {
|
|
39512
|
+
return model?.provider === SHORTCUT_PROVIDER_ID && model.id === SHORTCUT_MODEL_ID.ClaudeFable5;
|
|
39513
|
+
}
|
|
39514
|
+
function isShortcutModelAllowedForTeamAccount(model, teamAccount) {
|
|
39515
|
+
return !teamAccount || !isShortcutTeamRestrictedModel(model);
|
|
39516
|
+
}
|
|
39511
39517
|
function isShortcutFastModeModel(model) {
|
|
39512
39518
|
return model?.id === SHORTCUT_MODEL_ID.ClaudeOpus48 || model?.id === SHORTCUT_MODEL_ID.Gpt55;
|
|
39513
39519
|
}
|
|
@@ -152736,6 +152742,7 @@ var init_model_registry = __esm({
|
|
|
152736
152742
|
customProviderApiKeys = /* @__PURE__ */ new Map();
|
|
152737
152743
|
registeredProviders = /* @__PURE__ */ new Map();
|
|
152738
152744
|
registeredOAuthProviderIds = /* @__PURE__ */ new Set();
|
|
152745
|
+
modelAvailabilityFilter = () => true;
|
|
152739
152746
|
loadError = void 0;
|
|
152740
152747
|
/**
|
|
152741
152748
|
* Reload models from disk (built-in + custom from models.json).
|
|
@@ -152759,6 +152766,12 @@ var init_model_registry = __esm({
|
|
|
152759
152766
|
getError() {
|
|
152760
152767
|
return this.loadError;
|
|
152761
152768
|
}
|
|
152769
|
+
setModelAvailabilityFilter(filter2) {
|
|
152770
|
+
this.modelAvailabilityFilter = filter2 ?? (() => true);
|
|
152771
|
+
}
|
|
152772
|
+
getPolicyAllowedModels() {
|
|
152773
|
+
return this.models.filter((model) => this.modelAvailabilityFilter(model));
|
|
152774
|
+
}
|
|
152762
152775
|
loadModels() {
|
|
152763
152776
|
const {
|
|
152764
152777
|
models: customModels,
|
|
@@ -152958,25 +152971,28 @@ File: ${modelsJsonPath}`
|
|
|
152958
152971
|
* If models.json had errors, returns only built-in models.
|
|
152959
152972
|
*/
|
|
152960
152973
|
getAll() {
|
|
152961
|
-
return this.
|
|
152974
|
+
return this.getPolicyAllowedModels();
|
|
152962
152975
|
}
|
|
152963
152976
|
/**
|
|
152964
152977
|
* Get only models that have auth configured.
|
|
152965
152978
|
* This is a fast check that doesn't refresh OAuth tokens.
|
|
152966
152979
|
*/
|
|
152967
152980
|
getAvailable() {
|
|
152968
|
-
return this.
|
|
152981
|
+
return this.getPolicyAllowedModels().filter((m3) => this.authStorage.hasAuth(m3.provider));
|
|
152969
152982
|
}
|
|
152970
152983
|
/**
|
|
152971
152984
|
* Find a model by provider and ID.
|
|
152972
152985
|
*/
|
|
152973
152986
|
find(provider, modelId) {
|
|
152974
|
-
return this.
|
|
152987
|
+
return this.getPolicyAllowedModels().find((m3) => m3.provider === provider && m3.id === modelId);
|
|
152975
152988
|
}
|
|
152976
152989
|
/**
|
|
152977
152990
|
* Get API key for a model.
|
|
152978
152991
|
*/
|
|
152979
152992
|
async getApiKey(model) {
|
|
152993
|
+
if (!this.modelAvailabilityFilter(model)) {
|
|
152994
|
+
return void 0;
|
|
152995
|
+
}
|
|
152980
152996
|
return this.authStorage.getApiKey(model.provider);
|
|
152981
152997
|
}
|
|
152982
152998
|
/**
|
|
@@ -153143,6 +153159,12 @@ function resolveExactModelRef(availableModels, requested) {
|
|
|
153143
153159
|
error: `Ambiguous model "${requested}". Use one of: ${matches.map(formatModelRef).join(", ")}.`
|
|
153144
153160
|
};
|
|
153145
153161
|
}
|
|
153162
|
+
function getDefaultModelCandidatesForProvider(provider) {
|
|
153163
|
+
if (provider === SHORTCUT_PROVIDER_ID) {
|
|
153164
|
+
return [SHORTCUT_MODEL_ID.ClaudeFable5, SHORTCUT_MODEL_ID.ClaudeOpus48];
|
|
153165
|
+
}
|
|
153166
|
+
return [defaultModelPerProvider[provider]].filter((modelId) => !!modelId);
|
|
153167
|
+
}
|
|
153146
153168
|
function isAlias(id) {
|
|
153147
153169
|
if (id.endsWith("-latest")) return true;
|
|
153148
153170
|
const datePattern = /-\d{8}$/;
|
|
@@ -153339,10 +153361,15 @@ async function findInitialModel(options2) {
|
|
|
153339
153361
|
const availableModels = await modelRegistry2.getAvailable();
|
|
153340
153362
|
if (availableModels.length > 0) {
|
|
153341
153363
|
for (const provider of Object.keys(defaultModelPerProvider)) {
|
|
153342
|
-
const defaultId
|
|
153343
|
-
|
|
153344
|
-
|
|
153345
|
-
|
|
153364
|
+
for (const defaultId of getDefaultModelCandidatesForProvider(provider)) {
|
|
153365
|
+
const match2 = availableModels.find((m3) => m3.provider === provider && m3.id === defaultId);
|
|
153366
|
+
if (match2) {
|
|
153367
|
+
return {
|
|
153368
|
+
model: match2,
|
|
153369
|
+
thinkingLevel: DEFAULT_THINKING_LEVEL,
|
|
153370
|
+
fallbackMessage: void 0
|
|
153371
|
+
};
|
|
153372
|
+
}
|
|
153346
153373
|
}
|
|
153347
153374
|
}
|
|
153348
153375
|
return {
|
|
@@ -484102,6 +484129,24 @@ function getFastModeDisabledReasonForUser(userInfo) {
|
|
|
484102
484129
|
function resolvePromptEngine(userInfo) {
|
|
484103
484130
|
return isMogRuntimeEnabledForUser(userInfo) && isMogSdkAvailable() ? "mog" : "com";
|
|
484104
484131
|
}
|
|
484132
|
+
function applyShortcutModelPolicyForUser(modelRegistry2, userInfo) {
|
|
484133
|
+
const teamAccount = Boolean(userInfo?.teamId);
|
|
484134
|
+
modelRegistry2.setModelAvailabilityFilter(
|
|
484135
|
+
(model) => isShortcutModelAllowedForTeamAccount(model, teamAccount)
|
|
484136
|
+
);
|
|
484137
|
+
}
|
|
484138
|
+
async function moveSessionOffPolicyDeniedModel(session, modelRegistry2) {
|
|
484139
|
+
const currentModel = session?.model;
|
|
484140
|
+
if (!session || !currentModel) return;
|
|
484141
|
+
if (modelRegistry2.find(currentModel.provider, currentModel.id)) return;
|
|
484142
|
+
const availableModels = await modelRegistry2.getAvailable();
|
|
484143
|
+
const fallback = availableModels.find(
|
|
484144
|
+
(model) => model.provider === SHORTCUT_PROVIDER_ID && model.id === SHORTCUT_MODEL_ID.ClaudeOpus48
|
|
484145
|
+
) ?? availableModels.find((model) => model.provider === SHORTCUT_PROVIDER_ID) ?? availableModels[0];
|
|
484146
|
+
if (fallback) {
|
|
484147
|
+
await session.setModel(fallback);
|
|
484148
|
+
}
|
|
484149
|
+
}
|
|
484105
484150
|
async function refreshSessionForMogPolicyChange(session) {
|
|
484106
484151
|
if (!session) return;
|
|
484107
484152
|
await session.reload();
|
|
@@ -484179,6 +484224,7 @@ async function main(args) {
|
|
|
484179
484224
|
}
|
|
484180
484225
|
});
|
|
484181
484226
|
let shortcutUserInfo = await refreshShortcutUserInfoLoggerContext(authStorage, clientLogger);
|
|
484227
|
+
applyShortcutModelPolicyForUser(modelRegistry2, shortcutUserInfo);
|
|
484182
484228
|
const mogConfigured = isNewSheetEnabled();
|
|
484183
484229
|
const mogRuntimeEnabled = isMogRuntimeEnabledForUser(shortcutUserInfo);
|
|
484184
484230
|
const mogSdkAvailable = mogRuntimeEnabled && isMogSdkAvailable();
|
|
@@ -484451,6 +484497,15 @@ async function main(args) {
|
|
|
484451
484497
|
});
|
|
484452
484498
|
if (refreshedShortcutUserInfo !== void 0) {
|
|
484453
484499
|
shortcutUserInfo = refreshedShortcutUserInfo;
|
|
484500
|
+
applyShortcutModelPolicyForUser(modelRegistry2, shortcutUserInfo);
|
|
484501
|
+
if (parsed.model && sessionOptions.model && !modelRegistry2.find(sessionOptions.model.provider, sessionOptions.model.id)) {
|
|
484502
|
+
console.error(
|
|
484503
|
+
source_default.red(
|
|
484504
|
+
`Model ${sessionOptions.model.provider}/${sessionOptions.model.id} is not available for team accounts.`
|
|
484505
|
+
)
|
|
484506
|
+
);
|
|
484507
|
+
process.exit(1);
|
|
484508
|
+
}
|
|
484454
484509
|
}
|
|
484455
484510
|
}
|
|
484456
484511
|
sessionOptions.fastModeAllowed = isFastModeAllowedForUser(shortcutUserInfo);
|
|
@@ -484667,6 +484722,7 @@ async function main(args) {
|
|
|
484667
484722
|
const previousMogRuntimeEnabled = isMogRuntimeEnabledForUser(shortcutUserInfo);
|
|
484668
484723
|
const userInfo = await resolveShortcutUserInfo(authStorage);
|
|
484669
484724
|
shortcutUserInfo = userInfo;
|
|
484725
|
+
applyShortcutModelPolicyForUser(modelRegistry2, shortcutUserInfo);
|
|
484670
484726
|
setDefaultEnginePrompts(resolvePromptEngine(shortcutUserInfo));
|
|
484671
484727
|
const resolvedUserId = userInfo?.userId ?? userId;
|
|
484672
484728
|
if (userInfo) {
|
|
@@ -484689,6 +484745,7 @@ async function main(args) {
|
|
|
484689
484745
|
isFastModeAllowedForUser(userInfo),
|
|
484690
484746
|
getFastModeDisabledReasonForUser(userInfo) ?? "team"
|
|
484691
484747
|
);
|
|
484748
|
+
await moveSessionOffPolicyDeniedModel(sessionRef, modelRegistry2);
|
|
484692
484749
|
setRemoteControlTeamAccount(Boolean(userInfo?.teamId));
|
|
484693
484750
|
if (isMogRuntimeEnabledForUser(shortcutUserInfo) !== previousMogRuntimeEnabled) {
|
|
484694
484751
|
await refreshSessionForMogPolicyChange(sessionRef);
|
|
@@ -484722,6 +484779,7 @@ async function main(args) {
|
|
|
484722
484779
|
});
|
|
484723
484780
|
const previousMogRuntimeEnabled = isMogRuntimeEnabledForUser(shortcutUserInfo);
|
|
484724
484781
|
shortcutUserInfo = null;
|
|
484782
|
+
applyShortcutModelPolicyForUser(modelRegistry2, shortcutUserInfo);
|
|
484725
484783
|
setDefaultEnginePrompts(resolvePromptEngine(shortcutUserInfo));
|
|
484726
484784
|
sessionRef?.setFastModeAllowed(false, "login");
|
|
484727
484785
|
setRemoteControlTeamAccount(false);
|
|
@@ -28,6 +28,7 @@ export interface CreateShortcutXLAgentModelOptions {
|
|
|
28
28
|
readonly baseUrl?: string;
|
|
29
29
|
readonly availableModelIds?: readonly string[];
|
|
30
30
|
readonly gatewayModelIds?: readonly string[];
|
|
31
|
+
readonly teamAccount?: boolean;
|
|
31
32
|
}
|
|
32
33
|
export interface CreateShortcutXLAgentModelRegistryOptions extends CreateShortcutXLAgentModelOptions {
|
|
33
34
|
getAccessToken?: () => Promise<string | undefined>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SHORTCUT_MODEL_ID } from '../model-ids.js';
|
|
1
|
+
import { isShortcutModelAllowedForTeamAccount, SHORTCUT_MODEL_ID } from '../model-ids.js';
|
|
2
2
|
import { createShortcutPublicModelDefinitions, DEFAULT_SHORTCUT_MODEL_ID } from '../shortcut-model-catalog.js';
|
|
3
3
|
/** Provider tag the registry uses to gate auth and model lookup. */
|
|
4
4
|
export const ShortcutXLAgentProviderId = {
|
|
@@ -27,6 +27,34 @@ function formatGatewayModelName(modelId) {
|
|
|
27
27
|
.join(' ');
|
|
28
28
|
}
|
|
29
29
|
function createGatewayModel(modelId, baseUrl) {
|
|
30
|
+
if (modelId === 'qwen/qwen3.7-max') {
|
|
31
|
+
return {
|
|
32
|
+
id: modelId,
|
|
33
|
+
name: 'Qwen 3.7 Max',
|
|
34
|
+
api: 'shortcut-llm',
|
|
35
|
+
provider: ShortcutXLAgentProviderId.Shortcut,
|
|
36
|
+
baseUrl,
|
|
37
|
+
reasoning: true,
|
|
38
|
+
input: ['text'],
|
|
39
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
40
|
+
contextWindow: 1_000_000,
|
|
41
|
+
maxTokens: 128000
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (modelId === 'qwen/qwen3.7-plus') {
|
|
45
|
+
return {
|
|
46
|
+
id: modelId,
|
|
47
|
+
name: 'Qwen 3.7 Plus',
|
|
48
|
+
api: 'shortcut-llm',
|
|
49
|
+
provider: ShortcutXLAgentProviderId.Shortcut,
|
|
50
|
+
baseUrl,
|
|
51
|
+
reasoning: true,
|
|
52
|
+
input: ['text', 'image'],
|
|
53
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
54
|
+
contextWindow: 1_000_000,
|
|
55
|
+
maxTokens: 128000
|
|
56
|
+
};
|
|
57
|
+
}
|
|
30
58
|
return {
|
|
31
59
|
id: modelId,
|
|
32
60
|
name: formatGatewayModelName(modelId),
|
|
@@ -90,8 +118,10 @@ function resolveShortcutXLAgentModel(modelId, options = {}) {
|
|
|
90
118
|
: undefined;
|
|
91
119
|
}
|
|
92
120
|
const selectableModels = getSelectableModels(models, options);
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
const defaultModelId = options.teamAccount
|
|
122
|
+
? ShortcutXLAgentModelId.ClaudeOpus48
|
|
123
|
+
: DEFAULT_SHORTCUTXL_AGENT_MODEL_ID;
|
|
124
|
+
return selectableModels.find((model) => model.id === defaultModelId) ?? selectableModels[0];
|
|
95
125
|
}
|
|
96
126
|
/** Predicate: is this an internal-only model that should never appear in UI selectors? */
|
|
97
127
|
function isInternalModel(modelId) {
|
|
@@ -101,7 +131,9 @@ function getSelectableModels(models, options = {}) {
|
|
|
101
131
|
const availableModelIds = options.availableModelIds === undefined
|
|
102
132
|
? undefined
|
|
103
133
|
: new Set(options.availableModelIds.map((modelId) => modelId.trim()).filter(Boolean));
|
|
104
|
-
return models.filter((model) => !isInternalModel(model.id) &&
|
|
134
|
+
return models.filter((model) => !isInternalModel(model.id) &&
|
|
135
|
+
isShortcutModelAllowedForTeamAccount(model, options.teamAccount === true) &&
|
|
136
|
+
(!availableModelIds || availableModelIds.has(model.id)));
|
|
105
137
|
}
|
|
106
138
|
/** Build a `AgentModelRegistry` over the ShortcutXL model catalog. */
|
|
107
139
|
export function createShortcutXLAgentModelRegistry(options = {}) {
|
package/dist/main.js
CHANGED
|
@@ -60,7 +60,7 @@ import { SHORTCUT_API_HEADERS } from './endpoints.js';
|
|
|
60
60
|
import { createLocalAgentSession } from './local/index.js';
|
|
61
61
|
import { handleConfigCommand, handleShortcutAuthCommand, handleXllStartupStatus, isTruthyEnvFlag, prepareInitialMessage, readPipedStdin, runInteractiveShell, validateAgentMode } from './main-helpers.js';
|
|
62
62
|
import { getCurrentMode, MODE, setCurrentMode } from './mode-names.js';
|
|
63
|
-
import { SHORTCUT_PROVIDER_ID } from './model-ids.js';
|
|
63
|
+
import { isShortcutModelAllowedForTeamAccount, SHORTCUT_MODEL_ID, SHORTCUT_PROVIDER_ID } from './model-ids.js';
|
|
64
64
|
import { attachSessionUpload, BashApprovalComponent, createApprovalGate, createBatchingApprovalGate, createInteractiveSessionClient, createNetworkPrompt, createPrintModeSessionClient, createSandboxBashTool, createShortySlashCommand, ensureWslSandbox, ExcelApprovalComponent, exportFromFile, FileAccessApprovalComponent, getTraceHooks, hasCustomExtensionUI, initTheme, InteractiveMode, isDistroInstalled, isWsl2Available, KeybindingsManager, runPrintMode, SANDBOX_DISTRO, startCronStatusPolling, startDurableMemoryStatusUpdater, startLoopStatusPolling, startSkillProposalStatusUpdater, stopThemeWatcher, SwitchModeApprovalComponent, TaskSpawnApprovalComponent } from './shell/index.js';
|
|
65
65
|
import { resolveStartupXll } from './startup/startup-xll.js';
|
|
66
66
|
import { printTimings, time } from './startup/timings.js';
|
|
@@ -354,6 +354,24 @@ function getFastModeDisabledReasonForUser(userInfo) {
|
|
|
354
354
|
function resolvePromptEngine(userInfo) {
|
|
355
355
|
return isMogRuntimeEnabledForUser(userInfo) && isMogSdkAvailable() ? 'mog' : 'com';
|
|
356
356
|
}
|
|
357
|
+
function applyShortcutModelPolicyForUser(modelRegistry, userInfo) {
|
|
358
|
+
const teamAccount = Boolean(userInfo?.teamId);
|
|
359
|
+
modelRegistry.setModelAvailabilityFilter((model) => isShortcutModelAllowedForTeamAccount(model, teamAccount));
|
|
360
|
+
}
|
|
361
|
+
async function moveSessionOffPolicyDeniedModel(session, modelRegistry) {
|
|
362
|
+
const currentModel = session?.model;
|
|
363
|
+
if (!session || !currentModel)
|
|
364
|
+
return;
|
|
365
|
+
if (modelRegistry.find(currentModel.provider, currentModel.id))
|
|
366
|
+
return;
|
|
367
|
+
const availableModels = await modelRegistry.getAvailable();
|
|
368
|
+
const fallback = availableModels.find((model) => model.provider === SHORTCUT_PROVIDER_ID && model.id === SHORTCUT_MODEL_ID.ClaudeOpus48) ??
|
|
369
|
+
availableModels.find((model) => model.provider === SHORTCUT_PROVIDER_ID) ??
|
|
370
|
+
availableModels[0];
|
|
371
|
+
if (fallback) {
|
|
372
|
+
await session.setModel(fallback);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
357
375
|
async function refreshSessionForMogPolicyChange(session) {
|
|
358
376
|
if (!session)
|
|
359
377
|
return;
|
|
@@ -441,6 +459,7 @@ export async function main(args) {
|
|
|
441
459
|
}
|
|
442
460
|
});
|
|
443
461
|
let shortcutUserInfo = await refreshShortcutUserInfoLoggerContext(authStorage, clientLogger);
|
|
462
|
+
applyShortcutModelPolicyForUser(modelRegistry, shortcutUserInfo);
|
|
444
463
|
const mogConfigured = isNewSheetEnabled();
|
|
445
464
|
const mogRuntimeEnabled = isMogRuntimeEnabledForUser(shortcutUserInfo);
|
|
446
465
|
const mogSdkAvailable = mogRuntimeEnabled && isMogSdkAvailable();
|
|
@@ -725,6 +744,13 @@ export async function main(args) {
|
|
|
725
744
|
});
|
|
726
745
|
if (refreshedShortcutUserInfo !== undefined) {
|
|
727
746
|
shortcutUserInfo = refreshedShortcutUserInfo;
|
|
747
|
+
applyShortcutModelPolicyForUser(modelRegistry, shortcutUserInfo);
|
|
748
|
+
if (parsed.model &&
|
|
749
|
+
sessionOptions.model &&
|
|
750
|
+
!modelRegistry.find(sessionOptions.model.provider, sessionOptions.model.id)) {
|
|
751
|
+
console.error(chalk.red(`Model ${sessionOptions.model.provider}/${sessionOptions.model.id} is not available for team accounts.`));
|
|
752
|
+
process.exit(1);
|
|
753
|
+
}
|
|
728
754
|
}
|
|
729
755
|
}
|
|
730
756
|
sessionOptions.fastModeAllowed = isFastModeAllowedForUser(shortcutUserInfo);
|
|
@@ -955,6 +981,7 @@ export async function main(args) {
|
|
|
955
981
|
const previousMogRuntimeEnabled = isMogRuntimeEnabledForUser(shortcutUserInfo);
|
|
956
982
|
const userInfo = await resolveShortcutUserInfo(authStorage);
|
|
957
983
|
shortcutUserInfo = userInfo;
|
|
984
|
+
applyShortcutModelPolicyForUser(modelRegistry, shortcutUserInfo);
|
|
958
985
|
setDefaultEnginePrompts(resolvePromptEngine(shortcutUserInfo));
|
|
959
986
|
const resolvedUserId = userInfo?.userId ?? userId;
|
|
960
987
|
if (userInfo) {
|
|
@@ -976,6 +1003,7 @@ export async function main(args) {
|
|
|
976
1003
|
}
|
|
977
1004
|
});
|
|
978
1005
|
sessionRef?.setFastModeAllowed(isFastModeAllowedForUser(userInfo), getFastModeDisabledReasonForUser(userInfo) ?? 'team');
|
|
1006
|
+
await moveSessionOffPolicyDeniedModel(sessionRef, modelRegistry);
|
|
979
1007
|
setRemoteControlTeamAccount(Boolean(userInfo?.teamId));
|
|
980
1008
|
if (isMogRuntimeEnabledForUser(shortcutUserInfo) !== previousMogRuntimeEnabled) {
|
|
981
1009
|
await refreshSessionForMogPolicyChange(sessionRef);
|
|
@@ -1010,6 +1038,7 @@ export async function main(args) {
|
|
|
1010
1038
|
});
|
|
1011
1039
|
const previousMogRuntimeEnabled = isMogRuntimeEnabledForUser(shortcutUserInfo);
|
|
1012
1040
|
shortcutUserInfo = null;
|
|
1041
|
+
applyShortcutModelPolicyForUser(modelRegistry, shortcutUserInfo);
|
|
1013
1042
|
setDefaultEnginePrompts(resolvePromptEngine(shortcutUserInfo));
|
|
1014
1043
|
sessionRef?.setFastModeAllowed(false, 'login');
|
|
1015
1044
|
setRemoteControlTeamAccount(false);
|
package/dist/model-ids.d.ts
CHANGED
|
@@ -15,6 +15,14 @@ export declare const SHORTCUT_MODEL_REF: {
|
|
|
15
15
|
readonly Gpt55: "shortcut/gpt-5.5-2026-04-23";
|
|
16
16
|
readonly FreeModel: "shortcut/free-model";
|
|
17
17
|
};
|
|
18
|
+
export declare function isShortcutTeamRestrictedModel(model: {
|
|
19
|
+
readonly provider?: string;
|
|
20
|
+
readonly id?: string;
|
|
21
|
+
} | undefined): boolean;
|
|
22
|
+
export declare function isShortcutModelAllowedForTeamAccount(model: {
|
|
23
|
+
readonly provider?: string;
|
|
24
|
+
readonly id?: string;
|
|
25
|
+
} | undefined, teamAccount: boolean): boolean;
|
|
18
26
|
export declare function isShortcutFastModeModel(model: {
|
|
19
27
|
readonly provider?: string;
|
|
20
28
|
readonly id?: string;
|
package/dist/model-ids.js
CHANGED
|
@@ -15,6 +15,12 @@ export const SHORTCUT_MODEL_REF = {
|
|
|
15
15
|
Gpt55: `${SHORTCUT_PROVIDER_ID}/${SHORTCUT_MODEL_ID.Gpt55}`,
|
|
16
16
|
FreeModel: `${SHORTCUT_PROVIDER_ID}/${SHORTCUT_MODEL_ID.FreeModel}`
|
|
17
17
|
};
|
|
18
|
+
export function isShortcutTeamRestrictedModel(model) {
|
|
19
|
+
return model?.provider === SHORTCUT_PROVIDER_ID && model.id === SHORTCUT_MODEL_ID.ClaudeFable5;
|
|
20
|
+
}
|
|
21
|
+
export function isShortcutModelAllowedForTeamAccount(model, teamAccount) {
|
|
22
|
+
return !teamAccount || !isShortcutTeamRestrictedModel(model);
|
|
23
|
+
}
|
|
18
24
|
export function isShortcutFastModeModel(model) {
|
|
19
25
|
return model?.id === SHORTCUT_MODEL_ID.ClaudeOpus48 || model?.id === SHORTCUT_MODEL_ID.Gpt55;
|
|
20
26
|
}
|
package/package.json
CHANGED
|
Binary file
|