claude-scionos 4.1.7 → 4.1.9

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.fr.md CHANGED
@@ -93,7 +93,7 @@ Backends de stockage sécurisés :
93
93
  - macOS : Keychain
94
94
  - Linux : Secret Service via `secret-tool`
95
95
 
96
- Sous Windows, si le fichier local du token est vide ou corrompu, `claude-scionos` le traite désormais comme absent au lieu d'essayer de l'utiliser. Il faut relancer `claude-scionos auth login` pour enregistrer un nouveau token.
96
+ Sous Windows, `claude-scionos` laisse maintenant PowerShell gérer uniquement le chiffrement et le déchiffrement DPAPI, tandis que Node.js écrit et lit directement le fichier sécurisé. Cela corrige le cas où le fichier du token était créé mais restait vide. Si un ancien fichier local est vide ou corrompu, `claude-scionos` le traite comme absent au lieu d'essayer de l'utiliser. Il faut relancer `claude-scionos auth login` pour enregistrer un nouveau token.
97
97
 
98
98
  Gestion du token :
99
99
 
@@ -137,6 +137,7 @@ Cas courants :
137
137
  - `Claude Code CLI not found` : installer `@anthropic-ai/claude-code`
138
138
  - `Git Bash is required on Windows` : installer Git for Windows
139
139
  - `ANTHROPIC_AUTH_TOKEN ... is required when using --no-prompt` : définir la variable d'environnement ou stocker le token au préalable
140
+ - `Secure token file was created but no encrypted content was written` : mettre à jour vers `4.1.9` ou plus récent, puis relancer `claude-scionos auth login`
140
141
  - `Stored token` est indiqué comme absent sous Windows alors qu'un login a déjà été fait : relancer `claude-scionos auth login`, car le fichier DPAPI local peut être vide ou corrompu
141
142
  - `secret-tool not found` : installer un client Secret Service sous Linux ou utiliser la variable d'environnement
142
143
 
package/README.md CHANGED
@@ -93,7 +93,7 @@ Secure storage backends:
93
93
  - macOS: Keychain
94
94
  - Linux: Secret Service via `secret-tool`
95
95
 
96
- On Windows, if the secure token file is empty or corrupted, `claude-scionos` now treats it as missing instead of trying to use it. Run `claude-scionos auth login` again to store a fresh token.
96
+ On Windows, `claude-scionos` now lets PowerShell handle only DPAPI encryption and decryption, while Node.js writes and reads the secure token file directly. This fixes the case where the secure token file was created but left empty. If an older file is empty or corrupted, `claude-scionos` treats it as missing instead of trying to use it. Run `claude-scionos auth login` again to store a fresh token.
97
97
 
98
98
  Manage the token with:
99
99
 
@@ -137,6 +137,7 @@ Common cases:
137
137
  - `Claude Code CLI not found`: install `@anthropic-ai/claude-code`
138
138
  - `Git Bash is required on Windows`: install Git for Windows
139
139
  - `ANTHROPIC_AUTH_TOKEN ... is required when using --no-prompt`: set the environment variable or store the token first
140
+ - `Secure token file was created but no encrypted content was written`: update to `4.1.9` or later, then re-run `claude-scionos auth login`
140
141
  - `Stored token` is missing on Windows even though you already logged in: re-run `claude-scionos auth login` because the local DPAPI token file may be empty or corrupted
141
142
  - `secret-tool not found`: install a Secret Service client on Linux or rely on the environment variable
142
143
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-scionos",
3
- "version": "4.1.7",
3
+ "version": "4.1.9",
4
4
  "description": "RouterLab launcher, strategy proxy and secure token wrapper for Claude Code CLI",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -48,7 +48,7 @@
48
48
  "devDependencies": {
49
49
  "@eslint/js": "^10.0.1",
50
50
  "eslint": "^10.2.0",
51
- "globals": "^17.4.0",
51
+ "globals": "^17.5.0",
52
52
  "vitest": "^4.1.4"
53
53
  }
54
54
  }
package/src/routerlab.js CHANGED
@@ -234,6 +234,23 @@ function hasVerifiedModelIds(modelIds) {
234
234
  return Array.isArray(modelIds) && modelIds.length > 0;
235
235
  }
236
236
 
237
+ function hasExploitableModelIds(modelIds, serviceValue = DEFAULT_SERVICE) {
238
+ if (!hasVerifiedModelIds(modelIds)) {
239
+ return false;
240
+ }
241
+
242
+ const serviceStrategies = getServiceStrategies(serviceValue);
243
+ const knownModelIds = new Set(
244
+ serviceStrategies.flatMap((strategy) => getRequiredModels(strategy)),
245
+ );
246
+
247
+ if (knownModelIds.size === 0) {
248
+ return false;
249
+ }
250
+
251
+ return modelIds.some((modelId) => knownModelIds.has(modelId));
252
+ }
253
+
237
254
  function assessStrategy(strategyValue, modelIds = [], serviceValue = DEFAULT_SERVICE) {
238
255
  const serviceLabel = getServiceLabel(serviceValue);
239
256
  const strategy = findStrategy(strategyValue, serviceValue);
@@ -256,7 +273,7 @@ function assessStrategy(strategyValue, modelIds = [], serviceValue = DEFAULT_SER
256
273
  };
257
274
  }
258
275
 
259
- if (!hasVerifiedModelIds(modelIds)) {
276
+ if (!hasExploitableModelIds(modelIds, serviceValue)) {
260
277
  return {
261
278
  available: true,
262
279
  level: 'unknown',
@@ -316,7 +333,7 @@ function assessStrategyLaunch(strategyValue, modelIds = [], serviceValue = DEFAU
316
333
  };
317
334
  }
318
335
 
319
- if (!requiredModels.length || !hasVerifiedModelIds(modelIds)) {
336
+ if (!requiredModels.length || !hasExploitableModelIds(modelIds, serviceValue)) {
320
337
  return {
321
338
  ready: availability.level !== 'unavailable',
322
339
  note: availability.note,
@@ -351,7 +368,7 @@ function assessStrategyLaunch(strategyValue, modelIds = [], serviceValue = DEFAU
351
368
  }
352
369
 
353
370
  function getFallbackStrategy(strategyValue, modelIds = [], serviceValue = DEFAULT_SERVICE) {
354
- if (hasVerifiedModelIds(modelIds)) {
371
+ if (hasExploitableModelIds(modelIds, serviceValue)) {
355
372
  return assessStrategyLaunch(strategyValue, modelIds, serviceValue).ready ? strategyValue : null;
356
373
  }
357
374
 
@@ -448,14 +465,10 @@ function storeToken(token, serviceValue = DEFAULT_SERVICE) {
448
465
  const tokenFile = getWindowsTokenFile(service.value);
449
466
  const encodedToken = encodeTokenForPowerShell(token);
450
467
  fs.mkdirSync(path.dirname(tokenFile), {recursive: true});
451
- runPowerShell(
452
- `$token = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${encodedToken}')); if ([string]::IsNullOrEmpty($token)) { throw "Token input is empty" }; $secure = ConvertTo-SecureString $token -AsPlainText -Force; $encrypted = ConvertFrom-SecureString $secure; Set-Content -Path $env:SCIONOS_TOKEN_FILE -Value $encrypted -NoNewline`,
453
- {
454
- env: {
455
- SCIONOS_TOKEN_FILE: tokenFile,
456
- },
457
- },
468
+ const encrypted = runPowerShell(
469
+ `$token = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${encodedToken}')); if ([string]::IsNullOrEmpty($token)) { throw "Token input is empty" }; $secure = ConvertTo-SecureString $token -AsPlainText -Force; ConvertFrom-SecureString $secure`,
458
470
  );
471
+ fs.writeFileSync(tokenFile, encrypted, 'utf8');
459
472
 
460
473
  if (!hasNonEmptyWindowsTokenFile(tokenFile)) {
461
474
  throw new Error('Secure token file was created but no encrypted content was written');
@@ -522,16 +535,17 @@ function getStoredToken(serviceValue = DEFAULT_SERVICE) {
522
535
  return null;
523
536
  }
524
537
 
538
+ const encrypted = fs.readFileSync(tokenFile, 'utf8').trim();
539
+ if (!encrypted) {
540
+ return null;
541
+ }
542
+
543
+ const encodedEncrypted = encodeTokenForPowerShell(encrypted);
525
544
  const token = runPowerShell(
526
- '$secure = Get-Content -Path $env:SCIONOS_TOKEN_FILE -Raw | ConvertTo-SecureString; $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure); try { [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr) } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) }',
527
- {
528
- env: {
529
- SCIONOS_TOKEN_FILE: tokenFile,
530
- },
531
- },
545
+ `$secure = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${encodedEncrypted}')) | ConvertTo-SecureString; $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure); try { [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr) } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) }`,
532
546
  );
533
547
  return token || null;
534
- }
548
+ }
535
549
 
536
550
  if (process.platform === 'darwin') {
537
551
  const result = runCommand('security', [
@@ -628,6 +642,7 @@ export {
628
642
  getServiceStrategies,
629
643
  getStoredToken,
630
644
  getStoredTokenStatus,
645
+ hasExploitableModelIds,
631
646
  getStrategyChoices,
632
647
  hasVerifiedModelIds,
633
648
  listStrategies,