@skaile/workspaces 0.38.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/dist/{asset-feeds-W6JNAGNQ.js → asset-feeds-NOHUJ4XZ.js} +24 -6
  3. package/dist/asset-feeds-NOHUJ4XZ.js.map +1 -0
  4. package/dist/asset-manager/index.js +1 -1
  5. package/dist/{chunk-GL3MUJ5L.js → chunk-22Q5R7SM.js} +2 -2
  6. package/dist/{chunk-GL3MUJ5L.js.map → chunk-22Q5R7SM.js.map} +1 -1
  7. package/dist/{chunk-DQLRTCA2.js → chunk-3P7HBSSD.js} +43 -14
  8. package/dist/chunk-3P7HBSSD.js.map +1 -0
  9. package/dist/{chunk-6LW7Q53Z.js → chunk-6BEGKO2Q.js} +3 -3
  10. package/dist/{chunk-6LW7Q53Z.js.map → chunk-6BEGKO2Q.js.map} +1 -1
  11. package/dist/{chunk-KM6IWBDN.js → chunk-B5LHVPE2.js} +2 -2
  12. package/dist/{chunk-KM6IWBDN.js.map → chunk-B5LHVPE2.js.map} +1 -1
  13. package/dist/{chunk-A26MZ2GW.js → chunk-BGVQKQCP.js} +3 -3
  14. package/dist/{chunk-A26MZ2GW.js.map → chunk-BGVQKQCP.js.map} +1 -1
  15. package/dist/{chunk-P7CIT445.js → chunk-C5UK3JK7.js} +21 -14
  16. package/dist/chunk-C5UK3JK7.js.map +1 -0
  17. package/dist/{chunk-ZDKJHQY2.js → chunk-JXT46QFC.js} +2 -2
  18. package/dist/{chunk-ZDKJHQY2.js.map → chunk-JXT46QFC.js.map} +1 -1
  19. package/dist/{chunk-UAYAK7N4.js → chunk-O66LT7UI.js} +49 -3
  20. package/dist/chunk-O66LT7UI.js.map +1 -0
  21. package/dist/{chunk-OW32SQU3.js → chunk-RM2KAMGD.js} +243 -80
  22. package/dist/chunk-RM2KAMGD.js.map +1 -0
  23. package/dist/{chunk-O4PANZI2.js → chunk-XNMABEHH.js} +3 -3
  24. package/dist/{chunk-O4PANZI2.js.map → chunk-XNMABEHH.js.map} +1 -1
  25. package/dist/{chunk-6KKNROBU.js → chunk-XZNPKJXU.js} +4 -4
  26. package/dist/{chunk-6KKNROBU.js.map → chunk-XZNPKJXU.js.map} +1 -1
  27. package/dist/cli/index.js +30 -26
  28. package/dist/cli/index.js.map +1 -1
  29. package/dist/cli/src/asset-feeds.d.ts +8 -5
  30. package/dist/cli/src/asset-feeds.d.ts.map +1 -1
  31. package/dist/cli/src/commands/manage.d.ts +6 -5
  32. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  33. package/dist/cli/src/commands/source.d.ts +8 -0
  34. package/dist/cli/src/commands/source.d.ts.map +1 -1
  35. package/dist/connectors/index.js +2 -2
  36. package/dist/connectors/rclone.js +1 -1
  37. package/dist/connectors/src/connector-manager.d.ts +1 -1
  38. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  39. package/dist/connectors/src/connector-types.d.ts +5 -1
  40. package/dist/connectors/src/connector-types.d.ts.map +1 -1
  41. package/dist/connectors/src/rclone-process-manager.d.ts +9 -0
  42. package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -1
  43. package/dist/discovery/index.js +2 -2
  44. package/dist/{ensure-sources-AGORTKJC.js → ensure-sources-XITKRBLU.js} +5 -5
  45. package/dist/{ensure-sources-AGORTKJC.js.map → ensure-sources-XITKRBLU.js.map} +1 -1
  46. package/dist/factory-assets/connectors/deploy.js +2 -2
  47. package/dist/factory-assets/connectors/devserver.js +2 -2
  48. package/dist/factory-assets/connectors/flow/adapter.js +2 -2
  49. package/dist/factory-assets/connectors/flow/run-flow.js +3 -3
  50. package/dist/factory-assets/connectors/flow.js +2 -2
  51. package/dist/factory-assets/connectors/git/driver.d.ts +3 -0
  52. package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
  53. package/dist/factory-assets/connectors/git.js +2 -2
  54. package/dist/factory-assets/connectors/gmail.js +2 -2
  55. package/dist/factory-assets/connectors/googledrive.js +2 -2
  56. package/dist/factory-assets/connectors/local.js +2 -2
  57. package/dist/factory-assets/connectors/mattermost.js +2 -2
  58. package/dist/factory-assets/connectors/memory.js +2 -2
  59. package/dist/factory-assets/connectors/minio.js +2 -2
  60. package/dist/factory-assets/connectors/postgres/adapter.d.ts.map +1 -1
  61. package/dist/factory-assets/connectors/postgres.js +2 -2
  62. package/dist/factory-assets/connectors/s3.js +2 -2
  63. package/dist/factory-assets/connectors/sharepoint.js +2 -2
  64. package/dist/factory-assets/connectors/sqlite.js +2 -2
  65. package/dist/factory-assets/connectors/static-server.js +2 -2
  66. package/dist/factory-assets/connectors/tunnel.js +2 -2
  67. package/dist/factory-assets/connectors/webdav.js +2 -2
  68. package/dist/factory-assets/connectors/xstate-store.js +2 -2
  69. package/dist/factory-assets/connectors/xstate.js +2 -2
  70. package/dist/library/index.js +3 -3
  71. package/dist/library/src/remote/remote-catalog-source.d.ts +11 -1
  72. package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -1
  73. package/dist/{open-library-WTN7QLN7.js → open-library-5KJOZHG7.js} +6 -6
  74. package/dist/{open-library-WTN7QLN7.js.map → open-library-5KJOZHG7.js.map} +1 -1
  75. package/dist/plugins/index.js +1 -1
  76. package/dist/plugins/src/catalog-source.d.ts +52 -0
  77. package/dist/plugins/src/catalog-source.d.ts.map +1 -1
  78. package/dist/plugins/src/index.d.ts +1 -1
  79. package/dist/plugins/src/index.d.ts.map +1 -1
  80. package/dist/runner/index.js +4 -4
  81. package/dist/runner/src/ai-credential-refresh.d.ts +55 -23
  82. package/dist/runner/src/ai-credential-refresh.d.ts.map +1 -1
  83. package/dist/runner/src/ai-credential-retry.d.ts +79 -0
  84. package/dist/runner/src/ai-credential-retry.d.ts.map +1 -0
  85. package/dist/runner/src/credential-rotated.d.ts +33 -0
  86. package/dist/runner/src/credential-rotated.d.ts.map +1 -0
  87. package/dist/runner/src/resource-handler.d.ts +6 -0
  88. package/dist/runner/src/resource-handler.d.ts.map +1 -1
  89. package/dist/runner/src/runner-capabilities.d.ts +8 -0
  90. package/dist/runner/src/runner-capabilities.d.ts.map +1 -1
  91. package/dist/runner/src/serve-credentials.d.ts +14 -0
  92. package/dist/runner/src/serve-credentials.d.ts.map +1 -1
  93. package/dist/runner/src/serve.d.ts.map +1 -1
  94. package/dist/runner/src/session-resource-handlers.d.ts +4 -1
  95. package/dist/runner/src/session-resource-handlers.d.ts.map +1 -1
  96. package/dist/sdk/asset-manager.js +1 -1
  97. package/dist/sdk/index.js +4 -4
  98. package/dist/sdk/runner.js +4 -4
  99. package/dist/secrets/index.js +2 -2
  100. package/dist/tui/index.js +4 -4
  101. package/dist/workspace-plugin/index.js +1 -1
  102. package/package.json +1 -1
  103. package/dist/asset-feeds-W6JNAGNQ.js.map +0 -1
  104. package/dist/chunk-DQLRTCA2.js.map +0 -1
  105. package/dist/chunk-OW32SQU3.js.map +0 -1
  106. package/dist/chunk-P7CIT445.js.map +0 -1
  107. package/dist/chunk-UAYAK7N4.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { WorkspacePlugin } from './chunk-GL3MUJ5L.js';
1
+ import { WorkspacePlugin } from './chunk-22Q5R7SM.js';
2
2
  import { WebSocketServerTransport } from './chunk-WQ7DE5UC.js';
3
3
  import { assembleSystemPrompt, buildCapabilitiesPromptSection } from './chunk-W3UDISS2.js';
4
4
  import { PROTOCOL_VERSION } from './chunk-TDSRLMDB.js';
@@ -6,7 +6,7 @@ import { EventNormalizer } from './chunk-5IXCNMMU.js';
6
6
  import { classifyClaudeSdkError } from './chunk-GAH4YRCI.js';
7
7
  import { createDriver } from './chunk-KM6DCR7A.js';
8
8
  import { deployCatalogEntry, undeployCatalogEntry } from './chunk-LV2HPH3C.js';
9
- import { registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, ConnectorStartupError, buildSdkConnectorTools } from './chunk-DQLRTCA2.js';
9
+ import { registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, ConnectorStartupError, buildSdkConnectorTools } from './chunk-3P7HBSSD.js';
10
10
  import { loadConnectorDeclarations, SecretProviderChain, PreMintedSecretProvider, InMemorySecretProvider, deriveSingleMaterializedConnectorDeclaration } from './chunk-WLWHOA3S.js';
11
11
  import { renderStimulusPrompt, buildOrchestratorPrompt } from './chunk-DEYYRFQU.js';
12
12
  import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-FBIQ4QPF.js';
@@ -19,7 +19,7 @@ import { __require } from './chunk-NSBPE2FW.js';
19
19
  import pc from 'picocolors';
20
20
  import { Marked } from 'marked';
21
21
  import { markedTerminal } from 'marked-terminal';
22
- import { readdirSync, existsSync, readFileSync, unlinkSync, mkdirSync, writeFileSync, statSync, watch, chmodSync, openSync, readSync, closeSync } from 'fs';
22
+ import { readdirSync, existsSync, readFileSync, statSync, rmSync, unlinkSync, mkdirSync, writeFileSync, watch, chmodSync, openSync, readSync, closeSync } from 'fs';
23
23
  import path4, { join, resolve, relative, sep, isAbsolute, dirname, basename } from 'path';
24
24
  import { homedir } from 'os';
25
25
  import * as z5 from 'zod';
@@ -2400,6 +2400,12 @@ async function handleResourceRequest(command, manager, emit) {
2400
2400
  function getMimeType(filename) {
2401
2401
  return mime.getType(filename) ?? "application/octet-stream";
2402
2402
  }
2403
+ var HTML_CLOSE_TAG_RE = /<\/html>/i;
2404
+ function stripStaleHtmlTail(content, contentType) {
2405
+ if (!contentType.toLowerCase().startsWith("text/html")) return content;
2406
+ const m = HTML_CLOSE_TAG_RE.exec(content);
2407
+ return m ? content.slice(0, m.index + m[0].length) : content;
2408
+ }
2403
2409
  function isBinaryFile(filePath) {
2404
2410
  try {
2405
2411
  const fd = openSync(filePath, "r");
@@ -2415,7 +2421,7 @@ function isBinaryFile(filePath) {
2415
2421
  }
2416
2422
  }
2417
2423
  function handleMountResourceRequest(command, manager, emit) {
2418
- const { requestId, connectorId: mountId, operation, path: reqPath, content } = command;
2424
+ const { requestId, connectorId: mountId, operation, path: reqPath, options, content } = command;
2419
2425
  try {
2420
2426
  const entry = manager.get(mountId);
2421
2427
  const mountPath = entry.handle.mountPath;
@@ -2430,22 +2436,30 @@ function handleMountResourceRequest(command, manager, emit) {
2430
2436
  let data;
2431
2437
  switch (operation) {
2432
2438
  case "list": {
2433
- const entries = readdirSync(targetPath, { withFileTypes: true });
2434
- data = entries.filter((e) => !e.name.startsWith(".")).map((e) => {
2435
- const entryPath = reqPath ? join(reqPath, e.name) : e.name;
2436
- const result = {
2437
- name: e.name,
2438
- path: entryPath,
2439
- type: e.isDirectory() ? "directory" : "file"
2440
- };
2441
- if (!e.isDirectory()) {
2442
- try {
2443
- result.size = statSync(join(targetPath, e.name)).size;
2444
- } catch {
2439
+ const recursive = Boolean(options?.recursive);
2440
+ const collected = [];
2441
+ const walk = (absDir, relDir) => {
2442
+ for (const e of readdirSync(absDir, { withFileTypes: true })) {
2443
+ if (e.name.startsWith(".")) continue;
2444
+ const entryRel = relDir ? `${relDir}/${e.name}` : e.name;
2445
+ const isDir = e.isDirectory();
2446
+ const result = {
2447
+ name: e.name,
2448
+ path: entryRel,
2449
+ type: isDir ? "directory" : "file"
2450
+ };
2451
+ if (!isDir) {
2452
+ try {
2453
+ result.size = statSync(join(absDir, e.name)).size;
2454
+ } catch {
2455
+ }
2445
2456
  }
2457
+ collected.push(result);
2458
+ if (isDir && recursive) walk(join(absDir, e.name), entryRel);
2446
2459
  }
2447
- return result;
2448
- });
2460
+ };
2461
+ walk(targetPath, reqPath ?? "");
2462
+ data = collected;
2449
2463
  break;
2450
2464
  }
2451
2465
  case "read": {
@@ -2459,7 +2473,7 @@ function handleMountResourceRequest(command, manager, emit) {
2459
2473
  };
2460
2474
  } else {
2461
2475
  data = {
2462
- data: readFileSync(targetPath, "utf-8"),
2476
+ data: stripStaleHtmlTail(readFileSync(targetPath, "utf-8"), contentType),
2463
2477
  contentType,
2464
2478
  encoding: "utf-8"
2465
2479
  };
@@ -2479,7 +2493,11 @@ function handleMountResourceRequest(command, manager, emit) {
2479
2493
  break;
2480
2494
  }
2481
2495
  case "delete": {
2482
- unlinkSync(targetPath);
2496
+ if (statSync(targetPath).isDirectory()) {
2497
+ rmSync(targetPath, { recursive: true, force: true });
2498
+ } else {
2499
+ unlinkSync(targetPath);
2500
+ }
2483
2501
  data = true;
2484
2502
  break;
2485
2503
  }
@@ -2497,9 +2515,46 @@ function handleMountResourceRequest(command, manager, emit) {
2497
2515
  });
2498
2516
  }
2499
2517
  }
2518
+ var MINT_RETRY_MAX_ATTEMPTS = 3;
2519
+ var MINT_RETRY_BASE_DELAY_MS = 2e3;
2520
+ var MINT_RETRY_MAX_DELAY_MS = 5e3;
2521
+ function isTransientMintFailure(code) {
2522
+ return code === "backend-error";
2523
+ }
2524
+ function mintRetryDelayMs(retryNumber) {
2525
+ const delay = MINT_RETRY_BASE_DELAY_MS * 2 ** Math.max(0, retryNumber - 1);
2526
+ return Math.min(delay, MINT_RETRY_MAX_DELAY_MS);
2527
+ }
2528
+ async function retryTransientMint(attempt, deps) {
2529
+ const maxAttempts = deps.maxAttempts ?? MINT_RETRY_MAX_ATTEMPTS;
2530
+ let result = await attempt();
2531
+ for (let n = 1; n < maxAttempts; n++) {
2532
+ if (result.ok || !isTransientMintFailure(result.code)) return result;
2533
+ const nextDelayMs = mintRetryDelayMs(n);
2534
+ deps.onRetry?.({ attempt: n, nextDelayMs, code: result.code });
2535
+ await deps.sleep(nextDelayMs);
2536
+ result = await attempt();
2537
+ }
2538
+ return result;
2539
+ }
2540
+ function computeRejectedFingerprint(accessToken) {
2541
+ if (!accessToken) return void 0;
2542
+ return createHash("sha256").update(accessToken).digest("hex").slice(0, 16);
2543
+ }
2544
+ function buildRefreshCredentialInput(args) {
2545
+ const base = {
2546
+ kind: "ai-credentials",
2547
+ id: args.configId,
2548
+ reason: args.reason
2549
+ };
2550
+ if (args.reason !== "retry-401") return base;
2551
+ const rejectedFingerprint = computeRejectedFingerprint(args.rejectedToken);
2552
+ return rejectedFingerprint ? { ...base, rejectedFingerprint } : base;
2553
+ }
2500
2554
 
2501
2555
  // runner/src/ai-credential-refresh.ts
2502
2556
  var PROACTIVE_AI_REFRESH_MARGIN_MS = 5 * 60 * 1e3;
2557
+ var STALE_REARM_MS = 9 * 60 * 60 * 1e3;
2503
2558
  function createAiCredentialRefreshScheduler(deps) {
2504
2559
  const now = deps.now ?? (() => Date.now());
2505
2560
  const setTimeoutImpl = deps.setTimeoutImpl ?? ((handler, ms) => {
@@ -2510,64 +2565,135 @@ function createAiCredentialRefreshScheduler(deps) {
2510
2565
  clearTimeout(handle);
2511
2566
  });
2512
2567
  const marginMs = deps.marginMs ?? PROACTIVE_AI_REFRESH_MARGIN_MS;
2568
+ const logError = deps.logError ?? deps.log;
2513
2569
  let timer = null;
2570
+ let transientRetryCount = 0;
2571
+ let lastSuccessAt = null;
2572
+ let isStatic = false;
2573
+ let inStaleGuard = false;
2514
2574
  function cancel() {
2515
2575
  if (timer !== null) {
2516
2576
  clearTimeoutImpl(timer);
2517
2577
  timer = null;
2518
2578
  }
2519
2579
  }
2580
+ function armTimer(handler, ms) {
2581
+ cancel();
2582
+ timer = setTimeoutImpl(handler, ms);
2583
+ timer.unref?.();
2584
+ }
2585
+ function isStale() {
2586
+ return lastSuccessAt !== null && now() - lastSuccessAt > STALE_REARM_MS;
2587
+ }
2520
2588
  async function fire() {
2521
2589
  timer = null;
2522
- let next;
2590
+ let outcome;
2523
2591
  try {
2524
- next = await deps.refresh();
2592
+ outcome = await deps.refresh();
2525
2593
  } catch (err) {
2526
- deps.log(
2527
- `[ai-credential-refresh] refresh threw: ${err instanceof Error ? err.message : String(err)}; reactive 401 path remains as safety net`
2594
+ logError(
2595
+ `[ai-credential-refresh] refresh threw: ${err instanceof Error ? err.message : String(err)}; treating as transient`
2528
2596
  );
2597
+ outcome = { status: "transient" };
2598
+ }
2599
+ if (outcome.status === "ok") {
2600
+ schedule(outcome.expiresAt);
2529
2601
  return;
2530
2602
  }
2531
- if (next === void 0) {
2532
- deps.log(
2533
- "[ai-credential-refresh] refresh returned no expiry; reactive 401 path remains as safety net"
2603
+ if (outcome.status === "terminal") {
2604
+ transientRetryCount = 0;
2605
+ inStaleGuard = false;
2606
+ logError(
2607
+ "[ai-credential-refresh] proactive refresh hit a terminal failure; not re-arming (reactive 401 path remains the safety net)"
2608
+ );
2609
+ return;
2610
+ }
2611
+ if (transientRetryCount < MINT_RETRY_MAX_ATTEMPTS - 1) {
2612
+ transientRetryCount += 1;
2613
+ inStaleGuard = false;
2614
+ const delayMs = mintRetryDelayMs(transientRetryCount);
2615
+ logError(
2616
+ `[ai-credential-refresh] proactive refresh transient failure; bounded retry ${transientRetryCount}/${MINT_RETRY_MAX_ATTEMPTS - 1} in ${Math.round(delayMs / 1e3)}s`
2534
2617
  );
2618
+ armTimer(() => void fire(), delayMs);
2535
2619
  return;
2536
2620
  }
2537
- schedule(next);
2621
+ transientRetryCount = 0;
2622
+ inStaleGuard = true;
2623
+ logError(
2624
+ `[ai-credential-refresh] proactive refresh failed after ${MINT_RETRY_MAX_ATTEMPTS} attempts; reactive 401 path is the fallback, re-checking in ${Math.round(STALE_REARM_MS / 36e5)}h`
2625
+ );
2626
+ armTimer(() => void fire(), STALE_REARM_MS);
2538
2627
  }
2539
2628
  function schedule(expiresAtIso) {
2540
2629
  cancel();
2630
+ inStaleGuard = false;
2541
2631
  if (!expiresAtIso) {
2632
+ isStatic = true;
2633
+ transientRetryCount = 0;
2634
+ lastSuccessAt = now();
2542
2635
  return;
2543
2636
  }
2544
2637
  const expiresAtMs = Date.parse(expiresAtIso);
2545
2638
  if (!Number.isFinite(expiresAtMs)) return;
2639
+ isStatic = false;
2640
+ transientRetryCount = 0;
2641
+ lastSuccessAt = now();
2546
2642
  const delayMs = expiresAtMs - now() - marginMs;
2547
2643
  if (delayMs <= 0) {
2548
2644
  deps.log(
2549
2645
  `[ai-credential-refresh] token within ${marginMs / 1e3}s of expiry; refreshing now`
2550
2646
  );
2551
- timer = setTimeoutImpl(() => {
2552
- void fire();
2553
- }, 0);
2647
+ armTimer(() => void fire(), 0);
2554
2648
  } else {
2555
2649
  deps.log(
2556
2650
  `[ai-credential-refresh] scheduled in ${Math.round(delayMs / 1e3)}s (expiresAt=${expiresAtIso})`
2557
2651
  );
2558
- timer = setTimeoutImpl(() => {
2559
- void fire();
2560
- }, delayMs);
2652
+ armTimer(() => void fire(), delayMs);
2561
2653
  }
2562
- timer.unref?.();
2654
+ }
2655
+ function ensureArmed() {
2656
+ if (isStatic) return;
2657
+ if (timer !== null && !inStaleGuard && !isStale()) return;
2658
+ deps.log("[ai-credential-refresh] ensureArmed: reviving idle/stale schedule");
2659
+ transientRetryCount = 0;
2660
+ inStaleGuard = false;
2661
+ armTimer(() => void fire(), 0);
2563
2662
  }
2564
2663
  return {
2565
2664
  schedule,
2665
+ ensureArmed,
2566
2666
  cancel,
2567
2667
  isPending: () => timer !== null
2568
2668
  };
2569
2669
  }
2570
2670
 
2671
+ // runner/src/credential-rotated.ts
2672
+ var AI_PROVIDER_CREDENTIAL_SUBKIND = "ai-provider-credential";
2673
+ function isCredentialRotatedSignal(msg) {
2674
+ if (!msg || typeof msg !== "object") return false;
2675
+ const m = msg;
2676
+ if (m.type !== "log_entry") return false;
2677
+ const entry = m.entry;
2678
+ if (!entry || typeof entry !== "object") return false;
2679
+ return entry.source?.subkind === AI_PROVIDER_CREDENTIAL_SUBKIND && entry.data?.credentialRotated === true;
2680
+ }
2681
+ async function handleCredentialRotatedSignal(deps) {
2682
+ deps.log("[serve] credentialRotated broadcast received; re-pulling ai-credentials");
2683
+ try {
2684
+ const result = await deps.repull();
2685
+ if (result.ok) {
2686
+ deps.log("[serve] credentialRotated: re-pulled fresh token and rewrote .credentials.json");
2687
+ } else {
2688
+ deps.logError(`[serve] credentialRotated: re-pull failed (code=${result.code})`);
2689
+ }
2690
+ } catch (err) {
2691
+ deps.logError(
2692
+ `[serve] credentialRotated: re-pull threw: ${err instanceof Error ? err.message : String(err)}`
2693
+ );
2694
+ }
2695
+ }
2696
+
2571
2697
  // runner/src/compaction/prompt.ts
2572
2698
  var DEFAULT_COMPACTION_PROMPT = `You are being asked to compact this conversation into a structured summary.
2573
2699
  This summary will replace the full conversation history when the session
@@ -2949,16 +3075,6 @@ function buildLifecycleHandler(deps) {
2949
3075
  return { ok: true };
2950
3076
  };
2951
3077
  }
2952
- function readResolvedConnectorSecret(instancePath, id) {
2953
- if (!existsSync(instancePath)) return void 0;
2954
- try {
2955
- const parsed = JSON.parse(readFileSync(instancePath, "utf8"));
2956
- const value = parsed.resolvedSecrets?.[`connector:${id}`];
2957
- return typeof value === "string" ? value : void 0;
2958
- } catch {
2959
- return void 0;
2960
- }
2961
- }
2962
3078
  function asDeclaration(declaration) {
2963
3079
  if (declaration !== null && typeof declaration === "object" && typeof declaration.id === "string" && typeof declaration.driver === "string") {
2964
3080
  return declaration;
@@ -2978,7 +3094,12 @@ function buildSessionResourceHandlers(deps) {
2978
3094
  return { ok: false, code: "invalid_declaration", message: "declaration missing id/driver" };
2979
3095
  }
2980
3096
  if (input.preMintedToken) {
2981
- getPreMintedSecrets()?.set(kind, decl.id, toPreMinted(input.preMintedToken));
3097
+ const ps = getPreMintedSecrets();
3098
+ if (ps) ps.set(kind, decl.id, toPreMinted(input.preMintedToken));
3099
+ else
3100
+ log(
3101
+ `[session-resource] preMintedToken provided but secret store not ready \u2014 ${kind}:${decl.id}`
3102
+ );
2982
3103
  }
2983
3104
  try {
2984
3105
  await rm.connect(decl);
@@ -2994,7 +3115,7 @@ function buildSessionResourceHandlers(deps) {
2994
3115
  log(`[session-resource] runner.add_${kind} connected ${decl.id}`);
2995
3116
  return { ok: true, id: decl.id };
2996
3117
  }
2997
- async function attachConnectorInstance(name) {
3118
+ async function attachConnectorInstance(name, preMintedToken) {
2998
3119
  if (!name) {
2999
3120
  return { ok: false, code: "invalid_input", message: "name is required" };
3000
3121
  }
@@ -3020,14 +3141,20 @@ function buildSessionResourceHandlers(deps) {
3020
3141
  }
3021
3142
  const rm = getResourceManager();
3022
3143
  if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
3023
- const token = readResolvedConnectorSecret(join(root, name, ".instance.json"), decl.id);
3024
- if (token !== void 0) {
3025
- getPreMintedSecrets()?.set("connector", decl.id, { ok: true, token, expiresAt: null });
3144
+ if (preMintedToken) {
3145
+ const ps = getPreMintedSecrets();
3146
+ if (ps) ps.set("connector", decl.id, toPreMinted(preMintedToken));
3147
+ else
3148
+ log(
3149
+ `[session-resource] preMintedToken provided but secret store not ready \u2014 connector:${decl.id}`
3150
+ );
3026
3151
  }
3027
3152
  try {
3028
3153
  await rm.connect(decl);
3029
3154
  } catch (err) {
3030
- getPreMintedSecrets()?.unset("connector", decl.id);
3155
+ if (preMintedToken) {
3156
+ getPreMintedSecrets()?.unset("connector", decl.id);
3157
+ }
3031
3158
  const message = err instanceof Error ? err.message : String(err);
3032
3159
  log(`[session-resource] runner.attach_instance connector failed for ${decl.id}: ${message}`);
3033
3160
  return { ok: false, code: "connector_connect_failed", message };
@@ -3255,7 +3382,8 @@ var addMcpServerInputSchema = z5.strictObject({
3255
3382
  });
3256
3383
  var attachInstanceInputSchema = z5.strictObject({
3257
3384
  kind: z5.string(),
3258
- name: z5.string()
3385
+ name: z5.string(),
3386
+ preMintedToken: preMintedTokenSchema
3259
3387
  });
3260
3388
  var removeResourceInput = z5.strictObject({
3261
3389
  id: z5.string()
@@ -3346,7 +3474,11 @@ function buildRunnerCapabilities(handlers) {
3346
3474
  input: attachInstanceInputSchema,
3347
3475
  handler: async (input) => {
3348
3476
  if (!handlers.attachInstance) return notImplemented("runner.attach_instance");
3349
- return handlers.attachInstance({ kind: input.kind, name: input.name });
3477
+ return handlers.attachInstance({
3478
+ kind: input.kind,
3479
+ name: input.name,
3480
+ preMintedToken: input.preMintedToken
3481
+ });
3350
3482
  }
3351
3483
  }),
3352
3484
  defineCapability({
@@ -3487,6 +3619,20 @@ function extractClaudeAiOauthExpiresAt(json) {
3487
3619
  }
3488
3620
  return null;
3489
3621
  }
3622
+ function readCurrentClaudeAccessToken(home) {
3623
+ const credPath = join(home, ".claude", ".credentials.json");
3624
+ if (!existsSync(credPath)) return null;
3625
+ let parsed;
3626
+ try {
3627
+ parsed = JSON.parse(readFileSync(credPath, "utf-8"));
3628
+ } catch {
3629
+ return null;
3630
+ }
3631
+ if (!parsed || typeof parsed !== "object") return null;
3632
+ const obj = parsed;
3633
+ const raw = obj.claudeAiOauth?.accessToken ?? obj.accessToken;
3634
+ return typeof raw === "string" && raw.length > 0 ? raw : null;
3635
+ }
3490
3636
 
3491
3637
  // runner/src/session-stimulus.ts
3492
3638
  var DEFAULT_COALESCE_MS = 50;
@@ -3760,6 +3906,10 @@ async function startAgentServer(opts) {
3760
3906
  });
3761
3907
  };
3762
3908
  let aiProviderConfigId;
3909
+ const sleep = (ms) => new Promise((resolve3) => {
3910
+ const t = setTimeout(resolve3, ms);
3911
+ t.unref?.();
3912
+ });
3763
3913
  async function mintAndPersistAiCredential(args) {
3764
3914
  if (!transport.connected || aiProviderConfigId === void 0) {
3765
3915
  return {
@@ -3770,22 +3920,19 @@ async function startAgentServer(opts) {
3770
3920
  }
3771
3921
  const targetConfigId = args.configId || aiProviderConfigId;
3772
3922
  try {
3773
- const result = await capabilityRegistry.invokeRemote("host.refresh_credential", {
3774
- kind: "ai-credentials",
3775
- id: targetConfigId,
3776
- reason: args.reason
3923
+ const home = process.env.HOME || homedir();
3924
+ const refreshInput = buildRefreshCredentialInput({
3925
+ configId: targetConfigId,
3926
+ reason: args.reason,
3927
+ rejectedToken: args.reason === "retry-401" ? readCurrentClaudeAccessToken(home) : null
3777
3928
  });
3929
+ const result = await capabilityRegistry.invokeRemote(
3930
+ "host.refresh_credential",
3931
+ refreshInput
3932
+ );
3778
3933
  if (!result?.ok) {
3779
3934
  return result ?? { ok: false, code: "backend-error", message: "no result from host" };
3780
3935
  }
3781
- const home = process.env.HOME ?? homedir();
3782
- if (!home) {
3783
- return {
3784
- ok: false,
3785
- code: "backend-error",
3786
- message: "HOME env var unset; cannot rewrite credentials file"
3787
- };
3788
- }
3789
3936
  await mergeAndRewriteCredentialsFile(home, result.token, result.expiresAt ?? null);
3790
3937
  aiCredentialRefreshScheduler.schedule(result.expiresAt ?? null);
3791
3938
  return result;
@@ -3797,22 +3944,27 @@ async function startAgentServer(opts) {
3797
3944
  const aiCredentialRefreshScheduler = createAiCredentialRefreshScheduler({
3798
3945
  refresh: async () => {
3799
3946
  const result = await mintAndPersistAiCredential({ reason: "refresh" });
3800
- if (!result.ok) {
3801
- log(
3802
- `[serve] proactive AI refresh failed (code=${result.code}); leaving reactive path as fallback`
3803
- );
3804
- return void 0;
3947
+ if (result.ok) {
3948
+ return { status: "ok", expiresAt: result.expiresAt ?? null };
3805
3949
  }
3806
- return result.expiresAt ?? null;
3950
+ return isTransientMintFailure(result.code) ? { status: "transient" } : { status: "terminal" };
3807
3951
  },
3808
- log
3952
+ log,
3953
+ // Scheduler/refresh failures must be visible in `skaile session logs` and
3954
+ // the debug panel, so route them through the error-level structured logger.
3955
+ logError: (line) => serverLog.error(line)
3809
3956
  });
3810
3957
  const onAuthError = async (args) => {
3811
3958
  log("[serve] auth error: invoking host.refresh_credential capability");
3812
- const result = await mintAndPersistAiCredential({
3813
- configId: args.configId,
3814
- reason: "retry-401"
3815
- });
3959
+ const result = await retryTransientMint(
3960
+ () => mintAndPersistAiCredential({ configId: args.configId, reason: "retry-401" }),
3961
+ {
3962
+ sleep,
3963
+ onRetry: ({ attempt, nextDelayMs, code }) => serverLog.error(
3964
+ `[serve] auth error: transient mint failure (code=${code}); retry ${attempt} in ${Math.round(nextDelayMs / 1e3)}s`
3965
+ )
3966
+ }
3967
+ );
3816
3968
  if (!result.ok) {
3817
3969
  log(`[serve] auth error: mint failed (code=${result.code}); surfacing`);
3818
3970
  } else {
@@ -4440,7 +4592,7 @@ async function startAgentServer(opts) {
4440
4592
  // connect path; everything else stays on the MCP attach path.
4441
4593
  attachInstance: async (input) => {
4442
4594
  if (input.kind === "connector") {
4443
- return attachConnectorInstance(input.name);
4595
+ return attachConnectorInstance(input.name, input.preMintedToken);
4444
4596
  }
4445
4597
  return mcpHandlers.attachInstance ? mcpHandlers.attachInstance(input) : {
4446
4598
  ok: false,
@@ -4699,6 +4851,9 @@ async function startAgentServer(opts) {
4699
4851
  log(
4700
4852
  `[serve] configure cfg keys=${Object.keys(cfg).join(",")} sharedState=${cfg.sharedState ? cfg.sharedState.length : "undefined"} resourceManager=${resourceManager ? "set" : "null"}`
4701
4853
  );
4854
+ if (aiProviderConfigId) {
4855
+ aiCredentialRefreshScheduler.ensureArmed();
4856
+ }
4702
4857
  let pendingResumeSessionId;
4703
4858
  const cfgResumeSessionId = cfg.resumeSessionId;
4704
4859
  const cfgExpectedSig = cfg.expectedCapabilitySignature;
@@ -5060,6 +5215,14 @@ async function startAgentServer(opts) {
5060
5215
  }
5061
5216
  async function handleCommand(cmd) {
5062
5217
  const inbound = cmd;
5218
+ if (isCredentialRotatedSignal(cmd)) {
5219
+ await handleCredentialRotatedSignal({
5220
+ repull: () => mintAndPersistAiCredential({ reason: "refresh" }),
5221
+ log,
5222
+ logError: (line) => serverLog.error(line)
5223
+ });
5224
+ return;
5225
+ }
5063
5226
  if (inbound.type === "capability_invoked") {
5064
5227
  await dispatchRunnerCapabilityInvocation(
5065
5228
  { callId: inbound.callId ?? "", name: inbound.name ?? "", input: inbound.input },
@@ -5339,6 +5502,6 @@ function touchSession(state) {
5339
5502
  return { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
5340
5503
  }
5341
5504
 
5342
- export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, MarkdownStreamer, PreInitRingSink, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, builtinCapabilities, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, createAgentSession, createSessionStimulusBus, defineCapability, deleteSession, dispatchRunnerCapabilityInvocation, emitSystemPromptComposed, ensureGitConfigInclude, extractClaudeAiOauthExpiresAt, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, installPreInitRingSink, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadSession, loadSessionById, mcpAuthSecretKey, newSession, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveMixin, runAgentChat, saveSession, setCurrentSession, startAgentServer, touchSession, writeClaudeCodeCredentialsFile };
5343
- //# sourceMappingURL=chunk-OW32SQU3.js.map
5344
- //# sourceMappingURL=chunk-OW32SQU3.js.map
5505
+ export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, MarkdownStreamer, PreInitRingSink, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, builtinCapabilities, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, createAgentSession, createSessionStimulusBus, defineCapability, deleteSession, dispatchRunnerCapabilityInvocation, emitSystemPromptComposed, ensureGitConfigInclude, extractClaudeAiOauthExpiresAt, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, installPreInitRingSink, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadSession, loadSessionById, mcpAuthSecretKey, newSession, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveMixin, runAgentChat, saveSession, setCurrentSession, startAgentServer, stripStaleHtmlTail, touchSession, writeClaudeCodeCredentialsFile };
5506
+ //# sourceMappingURL=chunk-RM2KAMGD.js.map
5507
+ //# sourceMappingURL=chunk-RM2KAMGD.js.map