@skaile/workspaces 6.8.0 → 6.8.1

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 (120) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{asset-feeds-NU5UOO5F.js → asset-feeds-R75MH2WW.js} +6 -6
  3. package/dist/{asset-feeds-NU5UOO5F.js.map → asset-feeds-R75MH2WW.js.map} +1 -1
  4. package/dist/asset-manager/index.js +1 -1
  5. package/dist/{chunk-757G6TTZ.js → chunk-56PIAGD6.js} +2 -2
  6. package/dist/{chunk-757G6TTZ.js.map → chunk-56PIAGD6.js.map} +1 -1
  7. package/dist/{chunk-YZD7DUEF.js → chunk-62NNP7LU.js} +3 -3
  8. package/dist/{chunk-YZD7DUEF.js.map → chunk-62NNP7LU.js.map} +1 -1
  9. package/dist/{chunk-K6HCOTOZ.js → chunk-7O2CR5SZ.js} +5 -5
  10. package/dist/{chunk-K6HCOTOZ.js.map → chunk-7O2CR5SZ.js.map} +1 -1
  11. package/dist/{chunk-KHWGUXSF.js → chunk-7RBFYW24.js} +3 -3
  12. package/dist/{chunk-KHWGUXSF.js.map → chunk-7RBFYW24.js.map} +1 -1
  13. package/dist/{chunk-E3KABQS3.js → chunk-BGATDUYX.js} +3 -3
  14. package/dist/{chunk-E3KABQS3.js.map → chunk-BGATDUYX.js.map} +1 -1
  15. package/dist/{chunk-3NJFPGEB.js → chunk-DXBHGNSI.js} +3 -3
  16. package/dist/{chunk-3NJFPGEB.js.map → chunk-DXBHGNSI.js.map} +1 -1
  17. package/dist/{chunk-PMZMG3HC.js → chunk-E5AZA2FL.js} +3 -3
  18. package/dist/{chunk-PMZMG3HC.js.map → chunk-E5AZA2FL.js.map} +1 -1
  19. package/dist/{chunk-YGP6XEPA.js → chunk-EDKTS44C.js} +3 -3
  20. package/dist/{chunk-YGP6XEPA.js.map → chunk-EDKTS44C.js.map} +1 -1
  21. package/dist/{chunk-2I5HNM7K.js → chunk-I4DI5DAX.js} +8 -8
  22. package/dist/{chunk-2I5HNM7K.js.map → chunk-I4DI5DAX.js.map} +1 -1
  23. package/dist/{chunk-XCGDRLMH.js → chunk-JAGBPHXB.js} +3 -3
  24. package/dist/{chunk-XCGDRLMH.js.map → chunk-JAGBPHXB.js.map} +1 -1
  25. package/dist/{chunk-7YOHUX2M.js → chunk-LZ3E6TML.js} +4 -4
  26. package/dist/{chunk-7YOHUX2M.js.map → chunk-LZ3E6TML.js.map} +1 -1
  27. package/dist/{chunk-5TLMHB2U.js → chunk-N2W7OJC6.js} +6 -3
  28. package/dist/chunk-N2W7OJC6.js.map +1 -0
  29. package/dist/{chunk-DRHJRTAS.js → chunk-N65H7YYI.js} +3 -3
  30. package/dist/{chunk-DRHJRTAS.js.map → chunk-N65H7YYI.js.map} +1 -1
  31. package/dist/{chunk-LJ6PLEDU.js → chunk-NAEXYRHR.js} +309 -44
  32. package/dist/chunk-NAEXYRHR.js.map +1 -0
  33. package/dist/{chunk-K7ZGY2BY.js → chunk-OLZE4IHX.js} +17 -9
  34. package/dist/chunk-OLZE4IHX.js.map +1 -0
  35. package/dist/{chunk-RDIGVPXX.js → chunk-PKC2AHOB.js} +2 -2
  36. package/dist/{chunk-RDIGVPXX.js.map → chunk-PKC2AHOB.js.map} +1 -1
  37. package/dist/{chunk-ZBA4P5TD.js → chunk-SAL72A7T.js} +2 -2
  38. package/dist/{chunk-ZBA4P5TD.js.map → chunk-SAL72A7T.js.map} +1 -1
  39. package/dist/{chunk-HKRME377.js → chunk-SVMIUCTT.js} +3 -3
  40. package/dist/{chunk-HKRME377.js.map → chunk-SVMIUCTT.js.map} +1 -1
  41. package/dist/{chunk-3QX2X77G.js → chunk-VQFA5DR7.js} +3 -3
  42. package/dist/{chunk-3QX2X77G.js.map → chunk-VQFA5DR7.js.map} +1 -1
  43. package/dist/{chunk-YHNPWSSH.js → chunk-YMO4ZDLC.js} +8 -8
  44. package/dist/{chunk-YHNPWSSH.js.map → chunk-YMO4ZDLC.js.map} +1 -1
  45. package/dist/{chunk-Q6FKWPRO.js → chunk-Z5EPCIB6.js} +5 -5
  46. package/dist/{chunk-Q6FKWPRO.js.map → chunk-Z5EPCIB6.js.map} +1 -1
  47. package/dist/{claude-code-AESK7XO4.js → claude-code-DS26HI3K.js} +4 -4
  48. package/dist/{claude-code-AESK7XO4.js.map → claude-code-DS26HI3K.js.map} +1 -1
  49. package/dist/cli/index.js +45 -45
  50. package/dist/connectors/config.js +1 -1
  51. package/dist/connectors/index.js +2 -2
  52. package/dist/connectors/src/connector-manager.d.ts +66 -2
  53. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  54. package/dist/connectors/src/connector-prompt.d.ts.map +1 -1
  55. package/dist/connectors/src/connector-types.d.ts +6 -0
  56. package/dist/connectors/src/connector-types.d.ts.map +1 -1
  57. package/dist/connectors/src/fleet-utils.d.ts +33 -0
  58. package/dist/connectors/src/fleet-utils.d.ts.map +1 -1
  59. package/dist/connectors/src/index.d.ts +2 -2
  60. package/dist/connectors/src/index.d.ts.map +1 -1
  61. package/dist/{connectors-5ZZRVAPD.js → connectors-3ST6PGWP.js} +5 -5
  62. package/dist/{connectors-5ZZRVAPD.js.map → connectors-3ST6PGWP.js.map} +1 -1
  63. package/dist/{ensure-sources-VLJ7AUUK.js → ensure-sources-VELKRM6X.js} +4 -4
  64. package/dist/{ensure-sources-VLJ7AUUK.js.map → ensure-sources-VELKRM6X.js.map} +1 -1
  65. package/dist/factory-assets/connectors/box.js +2 -2
  66. package/dist/factory-assets/connectors/deploy.js +2 -2
  67. package/dist/factory-assets/connectors/devserver.js +2 -2
  68. package/dist/factory-assets/connectors/flow/adapter.js +2 -2
  69. package/dist/factory-assets/connectors/flow/run-flow.js +3 -3
  70. package/dist/factory-assets/connectors/flow.js +2 -2
  71. package/dist/factory-assets/connectors/git.js +2 -2
  72. package/dist/factory-assets/connectors/gmail.js +2 -2
  73. package/dist/factory-assets/connectors/googledrive.js +2 -2
  74. package/dist/factory-assets/connectors/local.js +2 -2
  75. package/dist/factory-assets/connectors/mattermost.js +2 -2
  76. package/dist/factory-assets/connectors/memory.js +2 -2
  77. package/dist/factory-assets/connectors/minio.js +2 -2
  78. package/dist/factory-assets/connectors/postgres.js +2 -2
  79. package/dist/factory-assets/connectors/s3.js +2 -2
  80. package/dist/factory-assets/connectors/sharepoint.js +2 -2
  81. package/dist/factory-assets/connectors/sqlite.js +2 -2
  82. package/dist/factory-assets/connectors/static-server.js +2 -2
  83. package/dist/factory-assets/connectors/tunnel.js +2 -2
  84. package/dist/factory-assets/connectors/webdav.js +2 -2
  85. package/dist/factory-assets/connectors/xstate-store.js +2 -2
  86. package/dist/factory-assets/connectors/xstate.js +2 -2
  87. package/dist/{helpers-APXGTZ5A.js → helpers-LWNKX56Y.js} +4 -4
  88. package/dist/{helpers-APXGTZ5A.js.map → helpers-LWNKX56Y.js.map} +1 -1
  89. package/dist/{library-publish-B5HL4OBE.js → library-publish-WJVCT2IK.js} +17 -17
  90. package/dist/{library-publish-B5HL4OBE.js.map → library-publish-WJVCT2IK.js.map} +1 -1
  91. package/dist/{open-library-F56D46K7.js → open-library-Q7QZJY5D.js} +5 -5
  92. package/dist/{open-library-F56D46K7.js.map → open-library-Q7QZJY5D.js.map} +1 -1
  93. package/dist/{project-GLTP6VFV.js → project-WVPRL7CP.js} +13 -13
  94. package/dist/{project-GLTP6VFV.js.map → project-WVPRL7CP.js.map} +1 -1
  95. package/dist/runner/index.js +7 -7
  96. package/dist/runner/src/resource-handler.d.ts +1 -1
  97. package/dist/runner/src/resource-handler.d.ts.map +1 -1
  98. package/dist/runner/src/resources.d.ts +1 -0
  99. package/dist/runner/src/resources.d.ts.map +1 -1
  100. package/dist/runner/src/session-resource-handlers.d.ts.map +1 -1
  101. package/dist/sdk/asset-manager.js +1 -1
  102. package/dist/sdk/index.js +7 -7
  103. package/dist/sdk/runner.js +7 -7
  104. package/dist/{serve-preflight-EHLBSNUE.js → serve-preflight-24YWWYUG.js} +6 -6
  105. package/dist/{serve-preflight-EHLBSNUE.js.map → serve-preflight-24YWWYUG.js.map} +1 -1
  106. package/dist/{setup-PMZLMFCD.js → setup-F5JX64UP.js} +5 -5
  107. package/dist/{setup-PMZLMFCD.js.map → setup-F5JX64UP.js.map} +1 -1
  108. package/dist/{source-QNSGAM3S.js → source-DG5IAAGZ.js} +14 -14
  109. package/dist/{source-QNSGAM3S.js.map → source-DG5IAAGZ.js.map} +1 -1
  110. package/dist/{source-manifest-publish-AI725AVE.js → source-manifest-publish-76S2JD3O.js} +16 -16
  111. package/dist/{source-manifest-publish-AI725AVE.js.map → source-manifest-publish-76S2JD3O.js.map} +1 -1
  112. package/dist/tui/index.js +7 -7
  113. package/dist/workspace-plugin/adapters/mcp.js +4 -4
  114. package/dist/workspace-plugin/adapters/omp.js +7 -7
  115. package/dist/workspace-plugin/index.js +1 -1
  116. package/dist/workspace-plugin/src/tools/connectors.d.ts.map +1 -1
  117. package/package.json +1 -1
  118. package/dist/chunk-5TLMHB2U.js.map +0 -1
  119. package/dist/chunk-K7ZGY2BY.js.map +0 -1
  120. package/dist/chunk-LJ6PLEDU.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { declaredConnectErrorKind, ClassifiedConnectError, withConnectErrorKind } from './chunk-BRPEW3UL.js';
2
- import { readUnavailableMarker, OAuthRequiredError, ConnectorFieldMissingError, LegacyAuthGrammarError, ConnectorStartupError, resolveAuthRef } from './chunk-ZBA4P5TD.js';
2
+ import { readUnavailableMarker, OAuthRequiredError, ConnectorFieldMissingError, LegacyAuthGrammarError, ConnectorStartupError, resolveAuthRef } from './chunk-SAL72A7T.js';
3
3
  import { EventNormalizer } from './chunk-XIIIGLSL.js';
4
4
  import { resolveModelTier } from './chunk-SBNUXJ6E.js';
5
5
  import { createHarness } from './chunk-SILFO5RY.js';
@@ -8282,33 +8282,100 @@ async function isMountpoint(dir, mountinfoPath) {
8282
8282
  async function probeFleetMount(dir, mountinfoPath, { list }) {
8283
8283
  const st = await stat(dir);
8284
8284
  if (!st.isDirectory()) {
8285
- throw new Error(`fleet mountpoint ${dir} is not a directory`);
8285
+ throw new FleetMountDeadError(`fleet mountpoint ${dir} is not a directory`);
8286
8286
  }
8287
8287
  if (list) await readdir(dir);
8288
8288
  if (await isMountpoint(dir, mountinfoPath) === false) {
8289
- throw new Error(
8289
+ throw new FleetMountDeadError(
8290
8290
  `fleet mountpoint ${dir} is a plain directory, not a mount \u2014 the host bind is absent or landed on a different path`
8291
8291
  );
8292
8292
  }
8293
8293
  }
8294
+ var FleetMountDeadError = class extends Error {
8295
+ constructor(message) {
8296
+ super(message);
8297
+ this.name = "FleetMountDeadError";
8298
+ }
8299
+ };
8300
+ var DEAD_ERRNO_CODES = /* @__PURE__ */ new Set([
8301
+ "ENOENT",
8302
+ "ENOTCONN",
8303
+ "ENOTDIR",
8304
+ "EACCES",
8305
+ "EPERM",
8306
+ "ELOOP"
8307
+ ]);
8308
+ function classifyProbeFailure(err) {
8309
+ if (err instanceof FleetMountDeadError) return "dead";
8310
+ const code = err?.code;
8311
+ if (typeof code === "string" && DEAD_ERRNO_CODES.has(code)) return "dead";
8312
+ return "pending";
8313
+ }
8314
+ var FLEET_MOUNT_CONNECTING_CODE = "FLEET_MOUNT_CONNECTING";
8315
+ var FleetMountConnectingError = class extends Error {
8316
+ code = FLEET_MOUNT_CONNECTING_CODE;
8317
+ dir;
8318
+ constructor(dir, message, options) {
8319
+ super(message, options);
8320
+ this.name = "FleetMountConnectingError";
8321
+ this.dir = dir;
8322
+ }
8323
+ };
8324
+ function isFleetMountConnectingError(err) {
8325
+ return err instanceof Error && err.code === FLEET_MOUNT_CONNECTING_CODE;
8326
+ }
8327
+ var inflightProbes = /* @__PURE__ */ new Map();
8328
+ function sharedListingProbe(dir, mountinfoPath) {
8329
+ const key = `${dir}\0${mountinfoPath}`;
8330
+ const running = inflightProbes.get(key);
8331
+ if (running) return running;
8332
+ const probe = probeFleetMount(dir, mountinfoPath, { list: true }).finally(() => {
8333
+ if (inflightProbes.get(key) === probe) inflightProbes.delete(key);
8334
+ });
8335
+ probe.catch(() => {
8336
+ });
8337
+ inflightProbes.set(key, probe);
8338
+ return probe;
8339
+ }
8294
8340
  async function ensureFleetMounted(dir, log, options) {
8295
8341
  const timeoutMs = options?.timeoutMs ?? 3e3;
8296
8342
  const pollIntervalMs = options?.pollIntervalMs ?? 100;
8297
8343
  const mountinfoPath = options?.mountinfoPath ?? testMountinfoOverride() ?? MOUNTINFO_PATH;
8344
+ const raceDeadline = options?.deadline ?? withFsDeadline;
8298
8345
  const deadline = Date.now() + timeoutMs;
8299
- let lastErr = null;
8346
+ let lastAnswer = null;
8347
+ let lastMiss = null;
8348
+ let lastWasMiss = false;
8300
8349
  while (Date.now() < deadline) {
8350
+ const budget = Math.max(1, deadline - Date.now());
8301
8351
  try {
8302
- await probeFleetMount(dir, mountinfoPath, { list: true });
8352
+ await raceDeadline(
8353
+ `fleet readiness ${dir}`,
8354
+ () => sharedListingProbe(dir, mountinfoPath),
8355
+ budget
8356
+ );
8303
8357
  log.info("fleet bind mount verified", { dir });
8304
8358
  return;
8305
8359
  } catch (err) {
8306
- lastErr = err;
8360
+ lastWasMiss = err instanceof FsDeadlineError;
8361
+ if (lastWasMiss) lastMiss = { err, fair: budget * 2 >= timeoutMs };
8362
+ else lastAnswer = err;
8363
+ if (deadline - Date.now() < 2 * pollIntervalMs) break;
8307
8364
  await new Promise((resolve9) => setTimeout(resolve9, pollIntervalMs));
8365
+ if (deadline - Date.now() < pollIntervalMs) break;
8308
8366
  }
8309
8367
  }
8310
- throw new Error(
8311
- `fleet mount ${dir} not ready after ${timeoutMs}ms \u2014 check SKAILE_FLEET_MANAGED_MOUNTS env var and host bind: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}`
8368
+ const deciding = lastWasMiss && lastMiss !== null && (lastMiss.fair || lastAnswer === null) ? lastMiss.err : lastAnswer ?? lastMiss?.err ?? null;
8369
+ const detail = deciding instanceof Error ? deciding.message : String(deciding);
8370
+ if (deciding !== null && classifyProbeFailure(deciding) === "dead") {
8371
+ throw new Error(
8372
+ `fleet mount ${dir} not ready after ${timeoutMs}ms \u2014 check SKAILE_FLEET_MANAGED_MOUNTS env var and host bind: ${detail}`
8373
+ );
8374
+ }
8375
+ throw new FleetMountConnectingError(
8376
+ dir,
8377
+ `fleet mount ${dir} is still connecting: its readiness check did not pass within ${timeoutMs}ms (${detail})`,
8378
+ { cause: deciding }
8312
8379
  );
8313
8380
  }
8314
8381
  var LIVENESS_TIMEOUT_MS = 2e3;
@@ -8460,6 +8527,19 @@ var MountLedger = class {
8460
8527
  };
8461
8528
 
8462
8529
  // connectors/src/connector-manager.ts
8530
+ var FLEET_RETRY_INITIAL_DELAY_MS = 1e3;
8531
+ var FLEET_RETRY_MAX_DELAY_MS = 3e4;
8532
+ function fleetMountConnectingMessage(id) {
8533
+ return `Mount "${id}" is still connecting: its first readiness check has not passed yet, so nothing is read from or written to it. Retry shortly.`;
8534
+ }
8535
+ var ConnectorConnectingError = class extends Error {
8536
+ connectorId;
8537
+ constructor(id) {
8538
+ super(fleetMountConnectingMessage(id));
8539
+ this.name = "ConnectorConnectingError";
8540
+ this.connectorId = id;
8541
+ }
8542
+ };
8463
8543
  var KNOWN_PREFIXES = ["env:", "forge:", "op:", "kp:", "oauth:"];
8464
8544
  function missingTokenMediatorMessage(connectorId) {
8465
8545
  return `Connector '${connectorId}' uses 'auth: backend' but no token mediator is wired (standalone CLI does not have one \u2014 use 'pat:env:NAME' instead).`;
@@ -8601,6 +8681,11 @@ var ConnectorManager = class {
8601
8681
  mgrLog;
8602
8682
  /** Aborted on dispose; threaded into every `connect()` via `ctx.abortSignal`. */
8603
8683
  disposeController = new AbortController();
8684
+ /**
8685
+ * The last `watchAll` arguments, so a mount that turns live after it ran
8686
+ * (a still-connecting fleet mount) gets its watcher then.
8687
+ */
8688
+ watchRequest;
8604
8689
  // ── Private helpers ──────────────────────────────────────────────────────────
8605
8690
  /**
8606
8691
  * Wrap the user-supplied `TokenMediator` so `reason: 'initial'` calls for an
@@ -8885,6 +8970,17 @@ var ConnectorManager = class {
8885
8970
  continue;
8886
8971
  }
8887
8972
  const outcome = await this.runConnect(decl);
8973
+ if (outcome.ok && outcome.connecting) {
8974
+ results.push({
8975
+ id: decl.id,
8976
+ connected: false,
8977
+ connecting: true,
8978
+ mountPath: outcome.handle.mountPath,
8979
+ error: fleetMountConnectingMessage(decl.id),
8980
+ access: decl.access
8981
+ });
8982
+ continue;
8983
+ }
8888
8984
  if (outcome.ok) {
8889
8985
  results.push({
8890
8986
  id: decl.id,
@@ -8900,13 +8996,14 @@ var ConnectorManager = class {
8900
8996
  const report = { results };
8901
8997
  this.mgrLog.info("connectAll complete", {
8902
8998
  connected: results.filter((r) => r.connected).length,
8903
- failed: results.filter((r) => !r.connected).length
8999
+ connecting: results.filter((r) => r.connecting).length,
9000
+ failed: results.filter((r) => !r.connected && !r.connecting).length
8904
9001
  });
8905
9002
  if (options?.failOnReadWriteError) {
8906
9003
  const declById = new Map(declarations.map((d) => [d.id, d]));
8907
9004
  const failedRw = results.filter((r) => {
8908
9005
  const decl = declById.get(r.id);
8909
- return !r.connected && decl !== void 0 && resolveAccessPolicy(decl).required;
9006
+ return !r.connected && !r.connecting && decl !== void 0 && resolveAccessPolicy(decl).required;
8910
9007
  }).map((r) => ({ id: r.id, error: r.error ?? "unknown error" }));
8911
9008
  for (const f of failedRw) {
8912
9009
  const decl = declById.get(f.id);
@@ -8948,6 +9045,8 @@ var ConnectorManager = class {
8948
9045
  connectorId: decl.id,
8949
9046
  status: "connecting"
8950
9047
  });
9048
+ let connector;
9049
+ let ctx;
8951
9050
  try {
8952
9051
  if (typeof decl.driver !== "string" || decl.driver === "") {
8953
9052
  throw new ClassifiedConnectError(
@@ -8955,7 +9054,7 @@ var ConnectorManager = class {
8955
9054
  "config"
8956
9055
  );
8957
9056
  }
8958
- const connector = await this.resolveConnector(decl.driver);
9057
+ connector = await this.resolveConnector(decl.driver);
8959
9058
  connector.setLogger?.(
8960
9059
  createLogger({
8961
9060
  kind: "connector",
@@ -8963,7 +9062,8 @@ var ConnectorManager = class {
8963
9062
  instance: decl.id
8964
9063
  })
8965
9064
  );
8966
- const ctx = await this.buildConnectContext(decl, connector);
9065
+ ctx = await this.buildConnectContext(decl, connector);
9066
+ const live = { connector, ctx };
8967
9067
  const handle = await this.withSpan(
8968
9068
  "connector.connect",
8969
9069
  {
@@ -8971,7 +9071,7 @@ var ConnectorManager = class {
8971
9071
  "skaile.connector.driver": decl.driver,
8972
9072
  "skaile.connector.operation": "connect"
8973
9073
  },
8974
- () => connector.connect(decl, ctx)
9074
+ () => live.connector.connect(decl, live.ctx)
8975
9075
  );
8976
9076
  this.active.set(decl.id, { connector, handle, declaration: decl });
8977
9077
  this.mounts.commit(decl.id);
@@ -8983,6 +9083,8 @@ var ConnectorManager = class {
8983
9083
  });
8984
9084
  return { ok: true, handle };
8985
9085
  } catch (err) {
9086
+ const pending = connector && ctx ? this.registerConnecting(decl, connector, ctx, err) : void 0;
9087
+ if (pending) return { ok: true, handle: pending, connecting: true };
8986
9088
  const live = this.active.get(decl.id);
8987
9089
  await this.mounts.rollback(
8988
9090
  decl.id,
@@ -9010,6 +9112,122 @@ var ConnectorManager = class {
9010
9112
  return { ok: false, error: err, message, ...errorKind ? { errorKind } : {} };
9011
9113
  }
9012
9114
  }
9115
+ /**
9116
+ * Keep a fleet mount whose readiness check missed its deadline (or failed
9117
+ * transiently) registered as `connecting`, and retry it in the background.
9118
+ * Returns the provisional handle, or `undefined` when `err` is not that case
9119
+ * and the connect is a plain failure.
9120
+ *
9121
+ * The provisional handle has status `connecting`, so every path that writes
9122
+ * back or acts on the mount (sync, hibernate/close hooks, watchers, tool
9123
+ * calls, the runner's resource requests) skips or refuses it until it is live.
9124
+ * No `connected` or `error` status is sent until a retry gives a verdict.
9125
+ */
9126
+ registerConnecting(decl, connector, ctx, err) {
9127
+ if (!isFleetMountConnectingError(err)) return void 0;
9128
+ if (connector.filesystem == null || ctx.mountTarget === void 0) return void 0;
9129
+ if (this.active.has(decl.id)) return void 0;
9130
+ if (this.disposeController.signal.aborted) return void 0;
9131
+ const handle = {
9132
+ id: decl.id,
9133
+ driver: connector.name ?? decl.driver,
9134
+ access: decl.access,
9135
+ status: "connecting",
9136
+ mountPath: ctx.mountTarget,
9137
+ state: { fleetManaged: true }
9138
+ };
9139
+ const entry = { connector, handle, declaration: decl };
9140
+ this.active.set(decl.id, entry);
9141
+ this.mounts.commit(decl.id);
9142
+ this.failedConnectors.delete(decl.id);
9143
+ this.mgrLog.warn("fleet mount still connecting; retrying in the background", {
9144
+ id: decl.id,
9145
+ driver: decl.driver,
9146
+ error: scrubLogText(err instanceof Error ? err.message : String(err))
9147
+ });
9148
+ this.retryConnecting(entry, ctx).catch((loopErr) => {
9149
+ this.mgrLog.error("fleet mount retry loop failed", void 0, {
9150
+ id: decl.id,
9151
+ error: scrubLogText(loopErr instanceof Error ? loopErr.message : String(loopErr))
9152
+ });
9153
+ });
9154
+ return handle;
9155
+ }
9156
+ /**
9157
+ * Retry a `connecting` fleet mount with a doubling wait until it connects,
9158
+ * fails with a dead verdict, or its entry is disconnected or replaced. The
9159
+ * retry is the driver's own `connect`, so a driver that does more after the
9160
+ * readiness check (git: branch, watcher) does it once the mount answers.
9161
+ */
9162
+ async retryConnecting(entry, ctx) {
9163
+ const { declaration: decl, connector } = entry;
9164
+ const signal = this.disposeController.signal;
9165
+ const initial = this.opts.fleetMountRetry?.initialDelayMs ?? FLEET_RETRY_INITIAL_DELAY_MS;
9166
+ const max = this.opts.fleetMountRetry?.maxDelayMs ?? FLEET_RETRY_MAX_DELAY_MS;
9167
+ const current = () => !signal.aborted && this.active.get(decl.id) === entry;
9168
+ let delay = initial;
9169
+ let attempts = 0;
9170
+ while (true) {
9171
+ await abortableDelay(delay, signal);
9172
+ if (!current()) return;
9173
+ attempts++;
9174
+ let handle;
9175
+ try {
9176
+ handle = await connector.connect(decl, ctx);
9177
+ } catch (err) {
9178
+ if (!current()) return;
9179
+ if (isFleetMountConnectingError(err)) {
9180
+ delay = Math.min(delay * 2, max);
9181
+ continue;
9182
+ }
9183
+ this.failConnecting(entry, err);
9184
+ return;
9185
+ }
9186
+ if (!current()) {
9187
+ await connector.disconnect(handle).catch(() => {
9188
+ });
9189
+ return;
9190
+ }
9191
+ entry.handle = handle;
9192
+ this.mgrLog.info("fleet mount connected after retry", { id: decl.id, attempts });
9193
+ this.opts.onStatusChange?.({
9194
+ type: "connector_status",
9195
+ connectorId: decl.id,
9196
+ status: "connected"
9197
+ });
9198
+ this.startWatcher(decl.id, entry);
9199
+ return;
9200
+ }
9201
+ }
9202
+ /** A background retry of a `connecting` mount got a dead verdict: fail it as a connect would. */
9203
+ failConnecting(entry, err) {
9204
+ const decl = entry.declaration;
9205
+ this.active.delete(decl.id);
9206
+ this.mounts.release(decl.id);
9207
+ const message = redactCredentials(err instanceof Error ? err.message : String(err));
9208
+ this.recordFailure(decl, message);
9209
+ const errorKind = classifyConnectError(err);
9210
+ this.mgrLog.error("fleet mount failed while connecting", void 0, {
9211
+ id: decl.id,
9212
+ driver: decl.driver,
9213
+ error: scrubLogText(message),
9214
+ ...errorKind ? { errorKind } : {}
9215
+ });
9216
+ this.opts.onStatusChange?.({
9217
+ type: "connector_status",
9218
+ connectorId: decl.id,
9219
+ status: "error",
9220
+ error: message,
9221
+ ...errorKind ? { errorKind } : {}
9222
+ });
9223
+ }
9224
+ /**
9225
+ * Throw {@link ConnectorConnectingError} when `entry` is a mount still
9226
+ * `connecting`: work on it would land on a path not yet verified.
9227
+ */
9228
+ assertNotConnecting(id, entry) {
9229
+ if (entry.handle.status === "connecting") throw new ConnectorConnectingError(id);
9230
+ }
9013
9231
  /**
9014
9232
  * Fail `decl` with the error a previous build's `connectAll` carried over,
9015
9233
  * without calling its driver. Same records and events as a failed attempt.
@@ -9054,7 +9272,7 @@ var ConnectorManager = class {
9054
9272
  await this.unwatchAll();
9055
9273
  for (const [id, entry] of this.active) {
9056
9274
  try {
9057
- await entry.connector.disconnect(entry.handle);
9275
+ if (entry.handle.status !== "connecting") await entry.connector.disconnect(entry.handle);
9058
9276
  } catch {
9059
9277
  }
9060
9278
  this.opts.onStatusChange?.({
@@ -9066,6 +9284,7 @@ var ConnectorManager = class {
9066
9284
  this.active.clear();
9067
9285
  this.mounts.clear();
9068
9286
  this.failedConnectors.clear();
9287
+ this.watchRequest = void 0;
9069
9288
  this.mgrLog.info("disconnectAll complete");
9070
9289
  }
9071
9290
  // ── Hot-plug ──────────────────────────────────────────────────────────────────
@@ -9073,6 +9292,13 @@ var ConnectorManager = class {
9073
9292
  * Connect a single connector (hot-plug). Resolves fields and allocates
9074
9293
  * mount target if the connector has a filesystem face.
9075
9294
  *
9295
+ * A fleet mount whose readiness check missed its deadline resolves too, with
9296
+ * a provisional handle whose `status` is `"connecting"`: it is registered and
9297
+ * retried in the background, and `onStatusChange` reports `connected` (or
9298
+ * `error`) when a retry decides. Until then its `mountPath` is unverified:
9299
+ * a caller must check `status === "connected"` before it reads or writes
9300
+ * there itself.
9301
+ *
9076
9302
  * @returns The `ConnectorHandle` for subsequent operations.
9077
9303
  */
9078
9304
  async connect(declaration) {
@@ -9130,7 +9356,7 @@ var ConnectorManager = class {
9130
9356
  },
9131
9357
  async () => {
9132
9358
  try {
9133
- await entry.connector.disconnect(entry.handle);
9359
+ if (entry.handle.status !== "connecting") await entry.connector.disconnect(entry.handle);
9134
9360
  } finally {
9135
9361
  this.active.delete(id);
9136
9362
  this.failedConnectors.delete(id);
@@ -9150,33 +9376,44 @@ var ConnectorManager = class {
9150
9376
  * For filesystem-face connectors, nested-mount-path exclusion logic is applied.
9151
9377
  */
9152
9378
  watchAll(callback, options) {
9153
- const allMountPaths = [...this.active.values()].map((e) => e.handle.mountPath).filter((p) => p != null);
9154
- for (const [id, entry] of this.active) {
9155
- if (!entry.connector.watch) continue;
9156
- if (!resolveAccessPolicy(entry.declaration).watch) continue;
9157
- let mergedOptions = options;
9158
- const myPath = entry.handle.mountPath;
9159
- if (myPath) {
9160
- const nestedPaths = allMountPaths.filter((p) => p !== myPath && p.startsWith(`${myPath}/`)).map((p) => `${p}/**`);
9161
- if (nestedPaths.length > 0) {
9162
- mergedOptions = {
9163
- ...options,
9164
- ignored: [...options?.ignored ?? [], ...nestedPaths]
9165
- };
9166
- }
9167
- }
9168
- try {
9169
- entry.watchHandle = entry.connector.watch(
9170
- entry.handle,
9171
- (event) => callback(id, event),
9172
- mergedOptions
9173
- );
9174
- } catch {
9379
+ this.watchRequest = { callback, ...options !== void 0 ? { options } : {} };
9380
+ for (const [id, entry] of this.active) this.startWatcher(id, entry);
9381
+ }
9382
+ /**
9383
+ * Start `entry`'s watcher for the last `watchAll` request, if there was one
9384
+ * and the connector watches. A still-connecting mount is skipped: its path
9385
+ * is not verified, and its watcher starts when it connects.
9386
+ */
9387
+ startWatcher(id, entry) {
9388
+ const request = this.watchRequest;
9389
+ if (!request) return;
9390
+ if (!entry.connector.watch) return;
9391
+ if (entry.handle.status === "connecting") return;
9392
+ if (!resolveAccessPolicy(entry.declaration).watch) return;
9393
+ const { callback, options } = request;
9394
+ let mergedOptions = options;
9395
+ const myPath = entry.handle.mountPath;
9396
+ if (myPath) {
9397
+ const nestedPaths = [...this.active.values()].map((e) => e.handle.mountPath).filter((p) => p != null && p !== myPath && p.startsWith(`${myPath}/`)).map((p) => `${p}/**`);
9398
+ if (nestedPaths.length > 0) {
9399
+ mergedOptions = {
9400
+ ...options,
9401
+ ignored: [...options?.ignored ?? [], ...nestedPaths]
9402
+ };
9175
9403
  }
9176
9404
  }
9405
+ try {
9406
+ entry.watchHandle = entry.connector.watch(
9407
+ entry.handle,
9408
+ (event) => callback(id, event),
9409
+ mergedOptions
9410
+ );
9411
+ } catch {
9412
+ }
9177
9413
  }
9178
- /** Stop all active watchers. */
9414
+ /** Stop all active watchers. A mount that turns live later is not watched either. */
9179
9415
  async unwatchAll() {
9416
+ this.watchRequest = void 0;
9180
9417
  for (const [, entry] of this.active) {
9181
9418
  if (entry.watchHandle) {
9182
9419
  try {
@@ -9302,6 +9539,7 @@ var ConnectorManager = class {
9302
9539
  if (!entry.connector.filesystem) {
9303
9540
  throw new Error(`Connector "${id}" has no filesystem face`);
9304
9541
  }
9542
+ this.assertNotConnecting(id, entry);
9305
9543
  await this.assertMountNotDead(id);
9306
9544
  return entry.connector.filesystem.sync(entry.handle, options);
9307
9545
  }
@@ -9354,6 +9592,14 @@ var ConnectorManager = class {
9354
9592
  */
9355
9593
  async checkMountHealth(id) {
9356
9594
  const entry = this.active.get(id);
9595
+ if (entry?.handle.status === "connecting") {
9596
+ return {
9597
+ status: "stale",
9598
+ errorClass: "mount_connecting",
9599
+ detail: fleetMountConnectingMessage(id),
9600
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
9601
+ };
9602
+ }
9357
9603
  if (!entry || entry.handle.status !== "connected") return null;
9358
9604
  const host = this.fleetHealthVerdicts.get(id);
9359
9605
  const liveness = await this.checkMountLiveness(id);
@@ -9431,6 +9677,7 @@ var ConnectorManager = class {
9431
9677
  }
9432
9678
  async read(id, path) {
9433
9679
  const entry = this.get(id);
9680
+ this.assertNotConnecting(id, entry);
9434
9681
  const tools = this.requireToolFace(id, entry);
9435
9682
  if (!tools.read) {
9436
9683
  throw new Error(`Connector "${id}" tool face does not implement "read"`);
@@ -9447,6 +9694,7 @@ var ConnectorManager = class {
9447
9694
  }
9448
9695
  async write(id, path, content) {
9449
9696
  const entry = this.get(id);
9697
+ this.assertNotConnecting(id, entry);
9450
9698
  if (entry.declaration.access === "read-only") {
9451
9699
  throw new Error(`Connector "${id}" is read-only`);
9452
9700
  }
@@ -9466,6 +9714,7 @@ var ConnectorManager = class {
9466
9714
  }
9467
9715
  async delete(id, path) {
9468
9716
  const entry = this.get(id);
9717
+ this.assertNotConnecting(id, entry);
9469
9718
  if (entry.declaration.access === "read-only") {
9470
9719
  throw new Error(`Connector "${id}" is read-only`);
9471
9720
  }
@@ -9485,6 +9734,7 @@ var ConnectorManager = class {
9485
9734
  }
9486
9735
  async list(id, path, options) {
9487
9736
  const entry = this.get(id);
9737
+ this.assertNotConnecting(id, entry);
9488
9738
  const tools = this.requireToolFace(id, entry);
9489
9739
  if (!tools.list) {
9490
9740
  throw new Error(`Connector "${id}" tool face does not implement "list"`);
@@ -9501,6 +9751,7 @@ var ConnectorManager = class {
9501
9751
  }
9502
9752
  async search(id, query, options) {
9503
9753
  const entry = this.get(id);
9754
+ this.assertNotConnecting(id, entry);
9504
9755
  const tools = this.requireToolFace(id, entry);
9505
9756
  if (!tools.search) {
9506
9757
  throw new Error(`Connector "${id}" tool face does not implement "search"`);
@@ -9524,6 +9775,7 @@ var ConnectorManager = class {
9524
9775
  */
9525
9776
  async executeOp(id, operation, args) {
9526
9777
  const entry = this.get(id);
9778
+ this.assertNotConnecting(id, entry);
9527
9779
  const tools = this.requireToolFace(id, entry);
9528
9780
  const ops = tools.describeOperations(entry.handle);
9529
9781
  const opDesc = ops.find((o) => o.name === operation);
@@ -9583,6 +9835,19 @@ var ConnectorManager = class {
9583
9835
  return buildSkillBody(descriptor, ops, shellAccess);
9584
9836
  }
9585
9837
  };
9838
+ function abortableDelay(ms, signal) {
9839
+ if (signal.aborted) return Promise.resolve();
9840
+ return new Promise((resolve9) => {
9841
+ const done = () => {
9842
+ clearTimeout(timer);
9843
+ signal.removeEventListener("abort", done);
9844
+ resolve9();
9845
+ };
9846
+ const timer = setTimeout(done, ms);
9847
+ timer.unref?.();
9848
+ signal.addEventListener("abort", done, { once: true });
9849
+ });
9850
+ }
9586
9851
  function redactMarker(marker) {
9587
9852
  return {
9588
9853
  ...marker,
@@ -10073,16 +10338,16 @@ function buildFilesystemSection(manager, fsConnectors, toolsMounted) {
10073
10338
  lines.push(`| ${c.id} | ${c.driver} | \`${mountPath}/\` | ${c.access} |`);
10074
10339
  } else {
10075
10340
  anyUnavailable = true;
10076
- const state = c.status === "error" ? "failed" : "syncing";
10341
+ const state = c.status === "error" ? "failed" : "connecting";
10077
10342
  lines.push(
10078
- `| ${c.id} | ${c.driver} | \`${mountPath}/\` | unavailable (${state}) \u2014 read-only, do not write |`
10343
+ `| ${c.id} | ${c.driver} | \`${mountPath}/\` | unavailable (${state}) \u2014 do not write |`
10079
10344
  );
10080
10345
  }
10081
10346
  }
10082
10347
  if (anyUnavailable) {
10083
10348
  lines.push("");
10084
10349
  lines.push(
10085
- "> **Unavailable mounts are read-only at the filesystem layer.** A mount marked `unavailable (syncing / failed)` is not live yet \u2014 its directory is mounted read-only, so writes fail. Do not create files there: the contents are not the real workspace, and anything you write would be a phantom that diverges from the remote once it mounts. Wait for it to become writable (watch the connector status)."
10350
+ `> **Unavailable mounts are not live yet.** A mount marked \`unavailable (connecting)\` has not answered its first readiness check; the runner keeps retrying and the mount turns live without a restart. Until then nothing is synced from or to it, and requests addressed to it fail with \`still connecting \u2026 Retry shortly\`. Do not create files there: anything you write would not be the real workspace. Check again (${toolsMounted ? "`connector_list`" : "`skaile connector list`"}) before writing.`
10086
10351
  );
10087
10352
  }
10088
10353
  if (fsConnectors.some((c) => isFleetManaged2(manager, c.id))) {
@@ -13717,6 +13982,6 @@ function describeFlowOperations() {
13717
13982
  return new FlowAdapter().tools.describeOperations({ access: "read-write" });
13718
13983
  }
13719
13984
 
13720
- export { AbstractConnector, BUILTIN_CONNECTOR_CATALOG, BoxConnector, CONNECT_FAILURE_CARRY_OVER_TTL_MS, ClassifierSubpromptRunner, ConnectFailureCarryOver, ConnectorManager, DeployConnector, DevServerConnector, FlowAdapter, GitConnector, GmailConnector, GoogleDriveConnector, LocalConnector, LogBuffer, ManagedGitconfigCollisionError, MattermostConnector, MemoryConnector, MinIOConnector, NO_ACTIVE_FLOW_ERROR, PortPool, PostgresConnector, S3Connector, S3FetchStoppedError, S3PresignedRequestError, S3_PRESIGN_BATCH, SQLiteConnector, SessionInlineSubFlowRunner, SessionNodeExecutor, SessionSubpromptRunner, SharePointConnector, StaticServerConnector, SubFlowContractError, TunnelConnector, WebDAVConnector, XStateConnector, XStateStoreConnector, atomicReplaceCredential, buildConnectorListPayload, buildConnectorPromptSection, buildConnectorToolDefs, buildFlowPromptEvent, buildFlowToolDefs, buildLazyFlowToolDefs, buildLazySdkFlowTools, buildSdkConnectorTools, buildSdkFlowTools, checkFleetMountLiveness, classifierQuestion, classifyConnectError, createConnector, createConnector10, createConnector11, createConnector12, createConnector13, createConnector14, createConnector15, createConnector16, createConnector17, createConnector18, createConnector19, createConnector2, createConnector20, createConnector3, createConnector4, createConnector5, createConnector6, createConnector7, createConnector8, createConnector9, createFsWatcher, createWorktree, defaultSpawn, describeFlowOperations, driveOrchestratorTurn, ensureDirMode, ensureFleetMounted, ensureRefreshAttemptStamp, findGitRoot, findMissingPackages, getConnector, installNpmPackages, isFleetManaged, isPackageResolvable, listConnectors, listWorktrees, missingTokenMediatorMessage, normalizeRuntimeFlow, parseListObjectsV2, presignScopePrefix, presignableKey, readGitSyncStatus, registerBuiltinConnectors, removeMountBlock, removeUnavailableMountBlock, renderCredentialHelperScript, resolveAccessPolicy, tryGetConnector, worktreeRegistry, writeHelperScript, writeMountBlock, writeUnavailableMountBlock, writeUserGitconfigInclude };
13721
- //# sourceMappingURL=chunk-LJ6PLEDU.js.map
13722
- //# sourceMappingURL=chunk-LJ6PLEDU.js.map
13985
+ export { AbstractConnector, BUILTIN_CONNECTOR_CATALOG, BoxConnector, CONNECT_FAILURE_CARRY_OVER_TTL_MS, ClassifierSubpromptRunner, ConnectFailureCarryOver, ConnectorConnectingError, ConnectorManager, DeployConnector, DevServerConnector, FleetMountConnectingError, FlowAdapter, GitConnector, GmailConnector, GoogleDriveConnector, LocalConnector, LogBuffer, ManagedGitconfigCollisionError, MattermostConnector, MemoryConnector, MinIOConnector, NO_ACTIVE_FLOW_ERROR, PortPool, PostgresConnector, S3Connector, S3FetchStoppedError, S3PresignedRequestError, S3_PRESIGN_BATCH, SQLiteConnector, SessionInlineSubFlowRunner, SessionNodeExecutor, SessionSubpromptRunner, SharePointConnector, StaticServerConnector, SubFlowContractError, TunnelConnector, WebDAVConnector, XStateConnector, XStateStoreConnector, atomicReplaceCredential, buildConnectorListPayload, buildConnectorPromptSection, buildConnectorToolDefs, buildFlowPromptEvent, buildFlowToolDefs, buildLazyFlowToolDefs, buildLazySdkFlowTools, buildSdkConnectorTools, buildSdkFlowTools, checkFleetMountLiveness, classifierQuestion, classifyConnectError, createConnector, createConnector10, createConnector11, createConnector12, createConnector13, createConnector14, createConnector15, createConnector16, createConnector17, createConnector18, createConnector19, createConnector2, createConnector20, createConnector3, createConnector4, createConnector5, createConnector6, createConnector7, createConnector8, createConnector9, createFsWatcher, createWorktree, defaultSpawn, describeFlowOperations, driveOrchestratorTurn, ensureDirMode, ensureFleetMounted, ensureRefreshAttemptStamp, findGitRoot, findMissingPackages, fleetMountConnectingMessage, getConnector, installNpmPackages, isFleetManaged, isFleetMountConnectingError, isPackageResolvable, listConnectors, listWorktrees, missingTokenMediatorMessage, normalizeRuntimeFlow, parseListObjectsV2, presignScopePrefix, presignableKey, readGitSyncStatus, registerBuiltinConnectors, removeMountBlock, removeUnavailableMountBlock, renderCredentialHelperScript, resolveAccessPolicy, tryGetConnector, worktreeRegistry, writeHelperScript, writeMountBlock, writeUnavailableMountBlock, writeUserGitconfigInclude };
13986
+ //# sourceMappingURL=chunk-NAEXYRHR.js.map
13987
+ //# sourceMappingURL=chunk-NAEXYRHR.js.map