@skaile/workspaces 0.41.6 → 0.42.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 (172) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/{asset-feeds-FKD5AB2R.js → asset-feeds-UPJJGR3O.js} +8 -8
  3. package/dist/{asset-feeds-FKD5AB2R.js.map → asset-feeds-UPJJGR3O.js.map} +1 -1
  4. package/dist/asset-manager/index.js +6 -6
  5. package/dist/asset-manager/installer.js +5 -5
  6. package/dist/bridge/drivers/claude-sdk.js +112 -7
  7. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  8. package/dist/bridge/drivers/codex.js +1 -1
  9. package/dist/bridge/drivers/continue.js +2 -2
  10. package/dist/bridge/drivers/echo.js +1 -1
  11. package/dist/bridge/drivers/gemini.js +3 -3
  12. package/dist/bridge/drivers/goose.js +2 -2
  13. package/dist/bridge/drivers/omp.js +1 -1
  14. package/dist/bridge/drivers/opencode.js +2 -2
  15. package/dist/bridge/drivers/qwen.js +3 -3
  16. package/dist/bridge/index.js +2 -2
  17. package/dist/bridge/src/drivers/claude-sdk.d.ts +6 -0
  18. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  19. package/dist/bridge/src/drivers/sanitize-assistant-text.d.ts +53 -0
  20. package/dist/bridge/src/drivers/sanitize-assistant-text.d.ts.map +1 -0
  21. package/dist/{chunk-J4RF5ABK.js → chunk-2BEDUMTA.js} +3 -3
  22. package/dist/{chunk-J4RF5ABK.js.map → chunk-2BEDUMTA.js.map} +1 -1
  23. package/dist/{chunk-5VJVSYXX.js → chunk-3HUUP3JC.js} +41 -3
  24. package/dist/chunk-3HUUP3JC.js.map +1 -0
  25. package/dist/{chunk-SBGHNXJD.js → chunk-3K2CYDBT.js} +17 -7
  26. package/dist/chunk-3K2CYDBT.js.map +1 -0
  27. package/dist/{chunk-2XFTGANB.js → chunk-4HKLAUHJ.js} +5 -5
  28. package/dist/{chunk-2XFTGANB.js.map → chunk-4HKLAUHJ.js.map} +1 -1
  29. package/dist/{chunk-5IXCNMMU.js → chunk-5C3QJSOD.js} +3 -3
  30. package/dist/{chunk-5IXCNMMU.js.map → chunk-5C3QJSOD.js.map} +1 -1
  31. package/dist/{chunk-TNYWP6EQ.js → chunk-5VMVNQGB.js} +6 -6
  32. package/dist/{chunk-TNYWP6EQ.js.map → chunk-5VMVNQGB.js.map} +1 -1
  33. package/dist/{chunk-B5PEERRZ.js → chunk-6IDBWPK2.js} +7 -4
  34. package/dist/chunk-6IDBWPK2.js.map +1 -0
  35. package/dist/{chunk-3KX5W3ZU.js → chunk-7WLJW457.js} +4 -4
  36. package/dist/{chunk-3KX5W3ZU.js.map → chunk-7WLJW457.js.map} +1 -1
  37. package/dist/{chunk-ZJ27BHIH.js → chunk-BXYMGZCI.js} +3 -3
  38. package/dist/{chunk-ZJ27BHIH.js.map → chunk-BXYMGZCI.js.map} +1 -1
  39. package/dist/{chunk-2ZI2FFFN.js → chunk-F5Q2RMH4.js} +229 -76
  40. package/dist/chunk-F5Q2RMH4.js.map +1 -0
  41. package/dist/{chunk-2JCUYKUN.js → chunk-G6FJZG4C.js} +2 -2
  42. package/dist/{chunk-2JCUYKUN.js.map → chunk-G6FJZG4C.js.map} +1 -1
  43. package/dist/{chunk-NQDJQ7WB.js → chunk-GJI6FZ56.js} +8 -4
  44. package/dist/chunk-GJI6FZ56.js.map +1 -0
  45. package/dist/{chunk-JAOXG3LL.js → chunk-HVCZLD5Z.js} +4 -4
  46. package/dist/{chunk-JAOXG3LL.js.map → chunk-HVCZLD5Z.js.map} +1 -1
  47. package/dist/{chunk-IODU6UDT.js → chunk-JZQFZ55W.js} +2 -2
  48. package/dist/{chunk-IODU6UDT.js.map → chunk-JZQFZ55W.js.map} +1 -1
  49. package/dist/{chunk-MO2VGW6U.js → chunk-K5TROTFK.js} +3 -3
  50. package/dist/{chunk-MO2VGW6U.js.map → chunk-K5TROTFK.js.map} +1 -1
  51. package/dist/{chunk-MVXXAXDW.js → chunk-KYQNWFJV.js} +3 -3
  52. package/dist/{chunk-MVXXAXDW.js.map → chunk-KYQNWFJV.js.map} +1 -1
  53. package/dist/{chunk-KM6DCR7A.js → chunk-OCAQH66V.js} +2 -2
  54. package/dist/{chunk-KM6DCR7A.js.map → chunk-OCAQH66V.js.map} +1 -1
  55. package/dist/{chunk-HZXOCRLD.js → chunk-OMAK7GNL.js} +78 -39
  56. package/dist/chunk-OMAK7GNL.js.map +1 -0
  57. package/dist/{chunk-X4FCLBI7.js → chunk-R4H6EJW5.js} +7 -5
  58. package/dist/chunk-R4H6EJW5.js.map +1 -0
  59. package/dist/{chunk-U3TV7SRR.js → chunk-RSK6FDMV.js} +3 -3
  60. package/dist/{chunk-U3TV7SRR.js.map → chunk-RSK6FDMV.js.map} +1 -1
  61. package/dist/{chunk-TB342H55.js → chunk-SURALYSM.js} +4 -4
  62. package/dist/{chunk-TB342H55.js.map → chunk-SURALYSM.js.map} +1 -1
  63. package/dist/{chunk-4NZD7423.js → chunk-WJ3RP2FS.js} +3 -3
  64. package/dist/{chunk-4NZD7423.js.map → chunk-WJ3RP2FS.js.map} +1 -1
  65. package/dist/{chunk-4ZACMAT3.js → chunk-Z3GAAIJK.js} +4 -4
  66. package/dist/{chunk-4ZACMAT3.js.map → chunk-Z3GAAIJK.js.map} +1 -1
  67. package/dist/cli/index.js +34 -34
  68. package/dist/connectors/config.js +5 -5
  69. package/dist/connectors/index.js +7 -7
  70. package/dist/connectors/rclone.js +1 -1
  71. package/dist/connectors/src/connector-manager.d.ts +17 -0
  72. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  73. package/dist/connectors/src/connector-types.d.ts +26 -0
  74. package/dist/connectors/src/connector-types.d.ts.map +1 -1
  75. package/dist/connectors/src/fleet-health-gate.d.ts +53 -36
  76. package/dist/connectors/src/fleet-health-gate.d.ts.map +1 -1
  77. package/dist/connectors/src/fleet-utils.d.ts +11 -2
  78. package/dist/connectors/src/fleet-utils.d.ts.map +1 -1
  79. package/dist/connectors/src/index.d.ts +3 -3
  80. package/dist/connectors/src/index.d.ts.map +1 -1
  81. package/dist/connectors/src/materialized-connectors.d.ts.map +1 -1
  82. package/dist/connectors/src/mount-placeholder.d.ts +19 -0
  83. package/dist/connectors/src/mount-placeholder.d.ts.map +1 -1
  84. package/dist/connectors/src/rclone-process-manager.d.ts +36 -2
  85. package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -1
  86. package/dist/core/index.js +4 -4
  87. package/dist/core/manifest.js +1 -1
  88. package/dist/core/runtime-assets.js +3 -3
  89. package/dist/core/src/index.d.ts +1 -1
  90. package/dist/core/src/index.d.ts.map +1 -1
  91. package/dist/core/src/manifest.d.ts +11 -0
  92. package/dist/core/src/manifest.d.ts.map +1 -1
  93. package/dist/core/src/workspace-config.d.ts +2 -0
  94. package/dist/core/src/workspace-config.d.ts.map +1 -1
  95. package/dist/core/workspace-config.js +2 -2
  96. package/dist/deploy/index.js +4 -4
  97. package/dist/discovery/index.js +2 -2
  98. package/dist/{ensure-sources-EWK7EXKN.js → ensure-sources-TZHDV3BF.js} +8 -8
  99. package/dist/{ensure-sources-EWK7EXKN.js.map → ensure-sources-TZHDV3BF.js.map} +1 -1
  100. package/dist/factory-assets/connectors/deploy.js +7 -7
  101. package/dist/factory-assets/connectors/devserver.js +7 -7
  102. package/dist/factory-assets/connectors/flow/adapter.js +7 -7
  103. package/dist/factory-assets/connectors/flow/engine.js +4 -4
  104. package/dist/factory-assets/connectors/flow/run-flow.js +8 -8
  105. package/dist/factory-assets/connectors/flow.js +7 -7
  106. package/dist/factory-assets/connectors/git.js +7 -7
  107. package/dist/factory-assets/connectors/gmail.js +7 -7
  108. package/dist/factory-assets/connectors/googledrive/driver.d.ts.map +1 -1
  109. package/dist/factory-assets/connectors/googledrive.js +7 -7
  110. package/dist/factory-assets/connectors/local.js +7 -7
  111. package/dist/factory-assets/connectors/mattermost.js +7 -7
  112. package/dist/factory-assets/connectors/memory.js +7 -7
  113. package/dist/factory-assets/connectors/minio.js +7 -7
  114. package/dist/factory-assets/connectors/postgres.js +7 -7
  115. package/dist/factory-assets/connectors/s3.js +7 -7
  116. package/dist/factory-assets/connectors/sharepoint/driver.d.ts.map +1 -1
  117. package/dist/factory-assets/connectors/sharepoint.js +7 -7
  118. package/dist/factory-assets/connectors/sqlite.js +7 -7
  119. package/dist/factory-assets/connectors/static-server.js +7 -7
  120. package/dist/factory-assets/connectors/tunnel.js +7 -7
  121. package/dist/factory-assets/connectors/webdav/driver.d.ts.map +1 -1
  122. package/dist/factory-assets/connectors/webdav.js +7 -7
  123. package/dist/factory-assets/connectors/xstate-store.js +7 -7
  124. package/dist/factory-assets/connectors/xstate.js +7 -7
  125. package/dist/{flows-3MBK2PDN.js → flows-KTBCZ5GQ.js} +3 -3
  126. package/dist/{flows-3MBK2PDN.js.map → flows-KTBCZ5GQ.js.map} +1 -1
  127. package/dist/library/index.js +6 -6
  128. package/dist/library/install.js +4 -4
  129. package/dist/{open-library-QSIPFN5N.js → open-library-EV7UCOFU.js} +9 -9
  130. package/dist/{open-library-QSIPFN5N.js.map → open-library-EV7UCOFU.js.map} +1 -1
  131. package/dist/{paths-KNLBYALO.js → paths-7H5CSBLQ.js} +7 -7
  132. package/dist/{paths-KNLBYALO.js.map → paths-7H5CSBLQ.js.map} +1 -1
  133. package/dist/{plugin-store-CL6CTREE.js → plugin-store-LGLN2QUX.js} +6 -6
  134. package/dist/{plugin-store-CL6CTREE.js.map → plugin-store-LGLN2QUX.js.map} +1 -1
  135. package/dist/runner/index.js +11 -11
  136. package/dist/runner/src/fleet-health-flag-dispatcher.d.ts +3 -2
  137. package/dist/runner/src/fleet-health-flag-dispatcher.d.ts.map +1 -1
  138. package/dist/runner/src/mcp-prompt.d.ts +8 -0
  139. package/dist/runner/src/mcp-prompt.d.ts.map +1 -0
  140. package/dist/runner/src/resource-handler.d.ts +1 -1
  141. package/dist/runner/src/resource-handler.d.ts.map +1 -1
  142. package/dist/runner/src/resources.d.ts +6 -0
  143. package/dist/runner/src/resources.d.ts.map +1 -1
  144. package/dist/runner/src/session-builder.d.ts.map +1 -1
  145. package/dist/sdk/asset-manager.js +6 -6
  146. package/dist/sdk/bridge.js +2 -2
  147. package/dist/sdk/core.js +4 -4
  148. package/dist/sdk/flow.js +4 -4
  149. package/dist/sdk/index.js +11 -11
  150. package/dist/sdk/runner.js +11 -11
  151. package/dist/sdk/session.js +1 -1
  152. package/dist/session/index.js +1 -1
  153. package/dist/session/src/dispatcher.d.ts +8 -0
  154. package/dist/session/src/dispatcher.d.ts.map +1 -1
  155. package/dist/{setup-345XOCH3.js → setup-EVNPECSY.js} +8 -8
  156. package/dist/{setup-345XOCH3.js.map → setup-EVNPECSY.js.map} +1 -1
  157. package/dist/{store-client-W3HKRE46.js → store-client-4XN7IB3R.js} +7 -7
  158. package/dist/{store-client-W3HKRE46.js.map → store-client-4XN7IB3R.js.map} +1 -1
  159. package/dist/tui/index.js +11 -11
  160. package/dist/types/src/events.d.ts +1 -1
  161. package/dist/types/src/events.d.ts.map +1 -1
  162. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  163. package/dist/workspace-plugin/adapters/omp.js +3 -3
  164. package/dist/workspace-plugin/index.js +1 -1
  165. package/package.json +1 -1
  166. package/dist/chunk-2ZI2FFFN.js.map +0 -1
  167. package/dist/chunk-5VJVSYXX.js.map +0 -1
  168. package/dist/chunk-B5PEERRZ.js.map +0 -1
  169. package/dist/chunk-HZXOCRLD.js.map +0 -1
  170. package/dist/chunk-NQDJQ7WB.js.map +0 -1
  171. package/dist/chunk-SBGHNXJD.js.map +0 -1
  172. package/dist/chunk-X4FCLBI7.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/src/open-registry.ts","../cli/src/open-library.ts"],"names":["source"],"mappings":"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","file":"chunk-3KX5W3ZU.js","sourcesContent":["/**\n * open-registry.ts — shared helper to create a full AssetKindRegistry.\n *\n * Bootstraps the registry with all built-in providers (9 core + preset)\n * from @skaile/discovery, plus the extension kind providers (flow from\n * @skaile/workspaces/factory-assets/connectors/flow/engine, knowledge from @skaile/library).\n *\n * This is the single registration point for the CLI. All code paths\n * that need a registry (source sync, lib-status, etc.) should use this.\n */\n\nimport type { AssetKindRegistry } from \"@skaile/workspaces/discovery\";\nimport { createDefaultRegistry } from \"@skaile/workspaces/discovery\";\nimport { flowKindProvider } from \"@skaile/workspaces/factory-assets/connectors/flow/engine\";\nimport { knowledgeKindProvider } from \"@skaile/workspaces/library\";\n\n/**\n * Create a fully-configured AssetKindRegistry with all known providers.\n *\n * Registers:\n * - 9 core kinds (skill, agent, connector, mount, mcp-server, contract, prompt, persona, ruleset)\n * - preset (composition entity)\n * - flow (extension, from @skaile/workspaces/factory-assets/connectors/flow/engine)\n * - knowledge (extension, from @skaile/library)\n *\n * @returns An unfrozen registry (auto-freezes on first read)\n */\nexport function createFullRegistry(): AssetKindRegistry {\n const registry = createDefaultRegistry();\n registry.register(flowKindProvider);\n registry.register(knowledgeKindProvider);\n return registry;\n}\n","/**\n * open-library.ts — shared helpers to open the LocalIndex and the configured\n * Catalog source.\n *\n * Lazy-loads the `@skaile/workspaces/library` subpath and returns the\n * LocalIndex instance (backed by `@libsql/client`; runs on Node and Bun).\n * The catalog-source helper reads\n * `~/.skaile/config.yaml` (and project-level overlay if `projectDir` is given)\n * to decide between {@link RemoteCatalogSource} (default — points at\n * `https://skaile.store`) and a {@link LocalCatalogSource} bound to the most\n * recent local library registered via `skaile source add`.\n */\n\nimport { logErr } from \"./helpers.ts\";\nimport { createFullRegistry } from \"./open-registry.ts\";\n\n/**\n * Open the LocalIndex with the full kind registry. Exits with code 1\n * if the library directory cannot be created.\n *\n * @returns A `LocalIndex` instance ready for use.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibrary() {\n try {\n const { LocalIndex } = await import(\"@skaile/workspaces/library\");\n return new LocalIndex({ kindRegistry: createFullRegistry() });\n } catch (err) {\n logErr(`Could not open LocalIndex: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\n/**\n * Resolve the configured **remote** Catalog source for the CLI.\n *\n * Reads `~/.skaile/config.yaml` (plus the optional project-level overlay) and\n * returns a {@link RemoteCatalogSource} pointing at `catalog.url` (default:\n * `https://skaile.store`). The `cache_ttl: 0` config flag flips the source\n * into air-gapped mode: network reads are disabled, only `skaile update`\n * performs refreshes.\n *\n * **Local-mode rejection.** If the resolved config has `catalog.url: local`\n * this helper throws — callers wanting the dispatched local-or-remote source\n * must use {@link resolveCatalogSource}. Remote-only consumers like\n * `skaile update --catalog-only` rely on this strict behaviour.\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A configured {@link RemoteCatalogSource}.\n * @throws When `catalog.url` is the `local` sentinel.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<\n | import(\"@skaile/workspaces/library\").RemoteCatalogSource\n | import(\"@skaile/workspaces/library\").RestCatalogSource\n> {\n const { resolveConfig, RemoteCatalogSource, RestCatalogSource, isLocalCatalogUrl } = await import(\n \"@skaile/workspaces/library\"\n );\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n if (isLocalCatalogUrl(baseUrl)) {\n throw new Error(\n \"catalog.url is set to 'local' — remote catalog is disabled. \" +\n \"Use `skaile source add <path>` + `skaile source sync` for local sources, \" +\n \"or set `catalog.url: https://skaile.store` in ~/.skaile/config.yaml.\",\n );\n }\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n if (cfg.catalog.framing === \"rest\") {\n return new RestCatalogSource({ baseUrl, cacheTtlMs });\n }\n return new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n}\n\n/**\n * Resolved catalog source plus a close handle for releasing any underlying\n * resources (e.g. the `LocalIndex` SQLite connection in local mode).\n *\n * Callers MUST invoke `close()` when done — typically in a `finally` block.\n * For remote-mode sources `close()` is a no-op, but the contract is uniform\n * so consumers don't have to branch.\n *\n * @docLink cli/dev-guide#open-library\n */\nexport interface ResolvedCatalogSource {\n /** The {@link ICatalogSource} ready for use. */\n source: import(\"@skaile/workspaces/library\").ICatalogSource;\n /** Release any underlying resources (SQLite handle in local mode). */\n close(): void;\n}\n\n/**\n * Resolve the configured Catalog source — local or remote — based on\n * `~/.skaile/config.yaml`.\n *\n * Dispatch:\n * - `catalog.url: local` → opens {@link LocalIndex}, picks the most recently\n * registered local library whose `path` still exists on disk, and returns a\n * {@link LocalCatalogSource} bound to that library. Throws if no usable\n * local library is registered.\n * - any URL → returns {@link RemoteCatalogSource} (same as\n * {@link openCatalogSource}).\n *\n * The returned `close()` releases the underlying `LocalIndex` SQLite handle\n * in local mode (no-op in remote mode). Callers MUST invoke it — typically in\n * a `finally` block — to satisfy `library/CLAUDE.md` § \"Notes for Consumers\".\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A `ResolvedCatalogSource` carrying the source and a close handle.\n * @throws When `local` is configured but no usable local library is registered.\n * @docLink cli/dev-guide#open-library\n */\nexport async function resolveCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<ResolvedCatalogSource> {\n const {\n resolveConfig,\n RemoteCatalogSource,\n RestCatalogSource,\n LocalCatalogSource,\n isLocalCatalogUrl,\n } = await import(\"@skaile/workspaces/library\");\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n\n if (isLocalCatalogUrl(baseUrl)) {\n const fs = await import(\"node:fs\");\n const library = await openLibrary();\n try {\n const sources = await library.listSources();\n type LibraryRow = (typeof sources)[number];\n // Type-narrow: `path` is required for local libraries after the filter.\n const usable = sources\n .filter(\n (s): s is LibraryRow & { path: string } =>\n s.backend === \"local\" && typeof s.path === \"string\" && s.path.length > 0,\n )\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n if (usable.length === 0) {\n throw new Error(\n \"catalog.url is set to 'local' but no local library is registered. \" +\n \"Run `skaile source add <path>` first, then `skaile source sync`.\",\n );\n }\n\n // Prefer the most recently added library whose path still exists.\n const present = usable.find((s) => fs.existsSync(s.path));\n if (!present) {\n const head = usable[0];\n throw new Error(\n `catalog.url is set to 'local' but every registered local library has a missing path on disk. ` +\n `Most recent: ${head.path} (library ${head.id}). ` +\n `Re-register with \\`skaile source add <existing-path>\\` or run \\`skaile source list\\` to inspect.`,\n );\n }\n\n const source = new LocalCatalogSource(\n library,\n present.id,\n present.path,\n createFullRegistry(),\n );\n return { source, close: () => library.close() };\n } catch (err) {\n // Release the handle on any failure during dispatch — otherwise the\n // SQLite WAL state leaks for the lifetime of the process.\n library.close();\n throw err;\n }\n }\n\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n const source =\n cfg.catalog.framing === \"rest\"\n ? new RestCatalogSource({ baseUrl, cacheTtlMs })\n : new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n return { source, close: () => {} };\n}\n\n/**\n * Open the LibraryManager bound to the active LocalIndex.\n * Caller owns lifetime — must call `close()` (returned helper closes the\n * underlying LocalIndex).\n *\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibraryManager(): Promise<{\n manager: import(\"@skaile/workspaces/library\").LibraryManager;\n library: import(\"@skaile/workspaces/library\").LocalIndex;\n close: () => void;\n}> {\n const { LibraryManager } = await import(\"@skaile/workspaces/library\");\n const library = await openLibrary();\n const manager = new LibraryManager(library);\n return { manager, library, close: () => library.close() };\n}\n"]}
1
+ {"version":3,"sources":["../cli/src/open-registry.ts","../cli/src/open-library.ts"],"names":["source"],"mappings":"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","file":"chunk-7WLJW457.js","sourcesContent":["/**\n * open-registry.ts — shared helper to create a full AssetKindRegistry.\n *\n * Bootstraps the registry with all built-in providers (9 core + preset)\n * from @skaile/discovery, plus the extension kind providers (flow from\n * @skaile/workspaces/factory-assets/connectors/flow/engine, knowledge from @skaile/library).\n *\n * This is the single registration point for the CLI. All code paths\n * that need a registry (source sync, lib-status, etc.) should use this.\n */\n\nimport type { AssetKindRegistry } from \"@skaile/workspaces/discovery\";\nimport { createDefaultRegistry } from \"@skaile/workspaces/discovery\";\nimport { flowKindProvider } from \"@skaile/workspaces/factory-assets/connectors/flow/engine\";\nimport { knowledgeKindProvider } from \"@skaile/workspaces/library\";\n\n/**\n * Create a fully-configured AssetKindRegistry with all known providers.\n *\n * Registers:\n * - 9 core kinds (skill, agent, connector, mount, mcp-server, contract, prompt, persona, ruleset)\n * - preset (composition entity)\n * - flow (extension, from @skaile/workspaces/factory-assets/connectors/flow/engine)\n * - knowledge (extension, from @skaile/library)\n *\n * @returns An unfrozen registry (auto-freezes on first read)\n */\nexport function createFullRegistry(): AssetKindRegistry {\n const registry = createDefaultRegistry();\n registry.register(flowKindProvider);\n registry.register(knowledgeKindProvider);\n return registry;\n}\n","/**\n * open-library.ts — shared helpers to open the LocalIndex and the configured\n * Catalog source.\n *\n * Lazy-loads the `@skaile/workspaces/library` subpath and returns the\n * LocalIndex instance (backed by `@libsql/client`; runs on Node and Bun).\n * The catalog-source helper reads\n * `~/.skaile/config.yaml` (and project-level overlay if `projectDir` is given)\n * to decide between {@link RemoteCatalogSource} (default — points at\n * `https://skaile.store`) and a {@link LocalCatalogSource} bound to the most\n * recent local library registered via `skaile source add`.\n */\n\nimport { logErr } from \"./helpers.ts\";\nimport { createFullRegistry } from \"./open-registry.ts\";\n\n/**\n * Open the LocalIndex with the full kind registry. Exits with code 1\n * if the library directory cannot be created.\n *\n * @returns A `LocalIndex` instance ready for use.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibrary() {\n try {\n const { LocalIndex } = await import(\"@skaile/workspaces/library\");\n return new LocalIndex({ kindRegistry: createFullRegistry() });\n } catch (err) {\n logErr(`Could not open LocalIndex: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\n/**\n * Resolve the configured **remote** Catalog source for the CLI.\n *\n * Reads `~/.skaile/config.yaml` (plus the optional project-level overlay) and\n * returns a {@link RemoteCatalogSource} pointing at `catalog.url` (default:\n * `https://skaile.store`). The `cache_ttl: 0` config flag flips the source\n * into air-gapped mode: network reads are disabled, only `skaile update`\n * performs refreshes.\n *\n * **Local-mode rejection.** If the resolved config has `catalog.url: local`\n * this helper throws — callers wanting the dispatched local-or-remote source\n * must use {@link resolveCatalogSource}. Remote-only consumers like\n * `skaile update --catalog-only` rely on this strict behaviour.\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A configured {@link RemoteCatalogSource}.\n * @throws When `catalog.url` is the `local` sentinel.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<\n | import(\"@skaile/workspaces/library\").RemoteCatalogSource\n | import(\"@skaile/workspaces/library\").RestCatalogSource\n> {\n const { resolveConfig, RemoteCatalogSource, RestCatalogSource, isLocalCatalogUrl } = await import(\n \"@skaile/workspaces/library\"\n );\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n if (isLocalCatalogUrl(baseUrl)) {\n throw new Error(\n \"catalog.url is set to 'local' — remote catalog is disabled. \" +\n \"Use `skaile source add <path>` + `skaile source sync` for local sources, \" +\n \"or set `catalog.url: https://skaile.store` in ~/.skaile/config.yaml.\",\n );\n }\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n if (cfg.catalog.framing === \"rest\") {\n return new RestCatalogSource({ baseUrl, cacheTtlMs });\n }\n return new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n}\n\n/**\n * Resolved catalog source plus a close handle for releasing any underlying\n * resources (e.g. the `LocalIndex` SQLite connection in local mode).\n *\n * Callers MUST invoke `close()` when done — typically in a `finally` block.\n * For remote-mode sources `close()` is a no-op, but the contract is uniform\n * so consumers don't have to branch.\n *\n * @docLink cli/dev-guide#open-library\n */\nexport interface ResolvedCatalogSource {\n /** The {@link ICatalogSource} ready for use. */\n source: import(\"@skaile/workspaces/library\").ICatalogSource;\n /** Release any underlying resources (SQLite handle in local mode). */\n close(): void;\n}\n\n/**\n * Resolve the configured Catalog source — local or remote — based on\n * `~/.skaile/config.yaml`.\n *\n * Dispatch:\n * - `catalog.url: local` → opens {@link LocalIndex}, picks the most recently\n * registered local library whose `path` still exists on disk, and returns a\n * {@link LocalCatalogSource} bound to that library. Throws if no usable\n * local library is registered.\n * - any URL → returns {@link RemoteCatalogSource} (same as\n * {@link openCatalogSource}).\n *\n * The returned `close()` releases the underlying `LocalIndex` SQLite handle\n * in local mode (no-op in remote mode). Callers MUST invoke it — typically in\n * a `finally` block — to satisfy `library/CLAUDE.md` § \"Notes for Consumers\".\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A `ResolvedCatalogSource` carrying the source and a close handle.\n * @throws When `local` is configured but no usable local library is registered.\n * @docLink cli/dev-guide#open-library\n */\nexport async function resolveCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<ResolvedCatalogSource> {\n const {\n resolveConfig,\n RemoteCatalogSource,\n RestCatalogSource,\n LocalCatalogSource,\n isLocalCatalogUrl,\n } = await import(\"@skaile/workspaces/library\");\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n\n if (isLocalCatalogUrl(baseUrl)) {\n const fs = await import(\"node:fs\");\n const library = await openLibrary();\n try {\n const sources = await library.listSources();\n type LibraryRow = (typeof sources)[number];\n // Type-narrow: `path` is required for local libraries after the filter.\n const usable = sources\n .filter(\n (s): s is LibraryRow & { path: string } =>\n s.backend === \"local\" && typeof s.path === \"string\" && s.path.length > 0,\n )\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n if (usable.length === 0) {\n throw new Error(\n \"catalog.url is set to 'local' but no local library is registered. \" +\n \"Run `skaile source add <path>` first, then `skaile source sync`.\",\n );\n }\n\n // Prefer the most recently added library whose path still exists.\n const present = usable.find((s) => fs.existsSync(s.path));\n if (!present) {\n const head = usable[0];\n throw new Error(\n `catalog.url is set to 'local' but every registered local library has a missing path on disk. ` +\n `Most recent: ${head.path} (library ${head.id}). ` +\n `Re-register with \\`skaile source add <existing-path>\\` or run \\`skaile source list\\` to inspect.`,\n );\n }\n\n const source = new LocalCatalogSource(\n library,\n present.id,\n present.path,\n createFullRegistry(),\n );\n return { source, close: () => library.close() };\n } catch (err) {\n // Release the handle on any failure during dispatch — otherwise the\n // SQLite WAL state leaks for the lifetime of the process.\n library.close();\n throw err;\n }\n }\n\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n const source =\n cfg.catalog.framing === \"rest\"\n ? new RestCatalogSource({ baseUrl, cacheTtlMs })\n : new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n return { source, close: () => {} };\n}\n\n/**\n * Open the LibraryManager bound to the active LocalIndex.\n * Caller owns lifetime — must call `close()` (returned helper closes the\n * underlying LocalIndex).\n *\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibraryManager(): Promise<{\n manager: import(\"@skaile/workspaces/library\").LibraryManager;\n library: import(\"@skaile/workspaces/library\").LocalIndex;\n close: () => void;\n}> {\n const { LibraryManager } = await import(\"@skaile/workspaces/library\");\n const library = await openLibrary();\n const manager = new LibraryManager(library);\n return { manager, library, close: () => library.close() };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { factoryAssetRoots } from './chunk-JAOXG3LL.js';
1
+ import { factoryAssetRoots } from './chunk-HVCZLD5Z.js';
2
2
  import fs from 'fs';
3
3
  import os from 'os';
4
4
  import path from 'path';
@@ -24,5 +24,5 @@ function aiResourceRoots() {
24
24
  }
25
25
 
26
26
  export { AI_RESOURCES, MONOREPO_ROOT, aiResourceRoots };
27
- //# sourceMappingURL=chunk-ZJ27BHIH.js.map
28
- //# sourceMappingURL=chunk-ZJ27BHIH.js.map
27
+ //# sourceMappingURL=chunk-BXYMGZCI.js.map
28
+ //# sourceMappingURL=chunk-BXYMGZCI.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/src/paths.ts"],"names":[],"mappings":";;;;;;AAMA,IAAM,WAAW,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA;AAW5D,SAAS,iBAAiB,IAAA,EAA6B;AACrD,EAAA,IAAI,GAAA,GAAM,IAAA;AACV,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,IAAI,EAAA,CAAG,WAAW,IAAA,CAAK,IAAA,CAAK,KAAK,YAAY,CAAC,GAAG,OAAO,GAAA;AACxD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC/B,IAAA,IAAI,WAAW,GAAA,EAAK;AACpB,IAAA,GAAA,GAAM,MAAA;AAAA,EACR;AACA,EAAA,OAAO,IAAA;AACT;AAYO,IAAM,aAAA,GAA+B,iBAAiB,QAAQ;AAc9D,IAAM,YAAA,GACX,iBAAA,EAAkB,CAAE,CAAC,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,EAAA,CAAG,OAAA,EAAQ,EAAG,SAAA,EAAW,WAAW;AAoBnE,SAAS,eAAA,GAA4B;AAC1C,EAAA,MAAM,KAAA,GAAkB,CAAC,GAAG,iBAAA,EAAmB,CAAA;AAC/C,EAAA,KAAA,CAAM,IAAA,CAAK,KAAK,IAAA,CAAK,EAAA,CAAG,SAAQ,EAAG,SAAA,EAAW,WAAW,CAAC,CAAA;AAC1D,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,EAAA,CAAG,UAAA,CAAW,CAAC,CAAC,CAAA;AAC3D","file":"chunk-ZJ27BHIH.js","sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { factoryAssetRoots } from \"@skaile/workspaces/core\";\n\nconst __ownDir = path.dirname(fileURLToPath(import.meta.url));\n\n/**\n * Walk up from `from` looking for the monorepo marker (`biome.json`, the\n * repo-root shared tooling config). Returns the matching directory or `null`\n * when none is found within eight levels — the latter is the typical case when\n * `@skaile/workspaces` has been installed via `npm i` without a skaile-dev\n * workspace context. Used only to gate dev-only commands (e.g.\n * `serve --compile-test`); first-party content is located via\n * {@link aiResourceRoots}, not this.\n */\nfunction findMonorepoRoot(from: string): string | null {\n let dir = from;\n for (let i = 0; i < 8; i++) {\n if (fs.existsSync(path.join(dir, \"biome.json\"))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Absolute path to the monorepo root, or `null` when the CLI is running\n * outside the skaile-dev workspace (typical for `npm i -g` installs).\n *\n * Consumers that only make sense inside the workspace (e.g.\n * `skaile serve --compile-test`) MUST check for `null` and report a\n * \"monorepo-only feature\" error before proceeding.\n *\n * @docLink cli/dev-guide#paths\n */\nexport const MONOREPO_ROOT: string | null = findMonorepoRoot(__ownDir);\n\n/**\n * Default content root used by path display and the `validate` command.\n *\n * The primary first-party `factory-assets/` root resolved through the shared\n * `factoryAssetRoots()` helper — the `SKAILE_FACTORY_ASSETS_DIR` override when\n * set, else the in-repo source during dev / bundled `dist/factory-assets/` after\n * `npm i`. Falls back to `~/.skaile/libraries/` — the user-library directory\n * managed by `skaile library add` — when the package cannot be located.\n * Consumers `fs.existsSync` first and degrade to \"no skills / flows discovered\".\n *\n * @docLink cli/dev-guide#paths\n */\nexport const AI_RESOURCES: string =\n factoryAssetRoots()[0] ?? path.join(os.homedir(), \".skaile\", \"libraries\");\n\n/**\n * All content roots that skill / flow discovery should walk, in priority order,\n * filtered to those that exist on disk and de-duplicated.\n *\n * - The first-party `factory-assets/` roots from the shared `factoryAssetRoots()`\n * helper — the `SKAILE_FACTORY_ASSETS_DIR` override layer (when set) ahead of\n * the bundled tree (in-repo source in dev, `dist/factory-assets/` after\n * install). No monorepo special-case.\n * - The user-library dir `~/.skaile/libraries/`.\n *\n * Order is significant: `findSkills` / flow discovery dedupe first-root-wins, so\n * the env override shadows the bundled tree on a name clash.\n *\n * This is the discovery surface used by `findSkills`, flow discovery, and the\n * completion resolvers.\n *\n * @docLink cli/dev-guide#paths\n */\nexport function aiResourceRoots(): string[] {\n const roots: string[] = [...factoryAssetRoots()];\n roots.push(path.join(os.homedir(), \".skaile\", \"libraries\"));\n return [...new Set(roots)].filter((r) => fs.existsSync(r));\n}\n"]}
1
+ {"version":3,"sources":["../cli/src/paths.ts"],"names":[],"mappings":";;;;;;AAMA,IAAM,WAAW,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA;AAW5D,SAAS,iBAAiB,IAAA,EAA6B;AACrD,EAAA,IAAI,GAAA,GAAM,IAAA;AACV,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,IAAI,EAAA,CAAG,WAAW,IAAA,CAAK,IAAA,CAAK,KAAK,YAAY,CAAC,GAAG,OAAO,GAAA;AACxD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC/B,IAAA,IAAI,WAAW,GAAA,EAAK;AACpB,IAAA,GAAA,GAAM,MAAA;AAAA,EACR;AACA,EAAA,OAAO,IAAA;AACT;AAYO,IAAM,aAAA,GAA+B,iBAAiB,QAAQ;AAc9D,IAAM,YAAA,GACX,iBAAA,EAAkB,CAAE,CAAC,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,EAAA,CAAG,OAAA,EAAQ,EAAG,SAAA,EAAW,WAAW;AAoBnE,SAAS,eAAA,GAA4B;AAC1C,EAAA,MAAM,KAAA,GAAkB,CAAC,GAAG,iBAAA,EAAmB,CAAA;AAC/C,EAAA,KAAA,CAAM,IAAA,CAAK,KAAK,IAAA,CAAK,EAAA,CAAG,SAAQ,EAAG,SAAA,EAAW,WAAW,CAAC,CAAA;AAC1D,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,EAAA,CAAG,UAAA,CAAW,CAAC,CAAC,CAAA;AAC3D","file":"chunk-BXYMGZCI.js","sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { factoryAssetRoots } from \"@skaile/workspaces/core\";\n\nconst __ownDir = path.dirname(fileURLToPath(import.meta.url));\n\n/**\n * Walk up from `from` looking for the monorepo marker (`biome.json`, the\n * repo-root shared tooling config). Returns the matching directory or `null`\n * when none is found within eight levels — the latter is the typical case when\n * `@skaile/workspaces` has been installed via `npm i` without a skaile-dev\n * workspace context. Used only to gate dev-only commands (e.g.\n * `serve --compile-test`); first-party content is located via\n * {@link aiResourceRoots}, not this.\n */\nfunction findMonorepoRoot(from: string): string | null {\n let dir = from;\n for (let i = 0; i < 8; i++) {\n if (fs.existsSync(path.join(dir, \"biome.json\"))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Absolute path to the monorepo root, or `null` when the CLI is running\n * outside the skaile-dev workspace (typical for `npm i -g` installs).\n *\n * Consumers that only make sense inside the workspace (e.g.\n * `skaile serve --compile-test`) MUST check for `null` and report a\n * \"monorepo-only feature\" error before proceeding.\n *\n * @docLink cli/dev-guide#paths\n */\nexport const MONOREPO_ROOT: string | null = findMonorepoRoot(__ownDir);\n\n/**\n * Default content root used by path display and the `validate` command.\n *\n * The primary first-party `factory-assets/` root resolved through the shared\n * `factoryAssetRoots()` helper — the `SKAILE_FACTORY_ASSETS_DIR` override when\n * set, else the in-repo source during dev / bundled `dist/factory-assets/` after\n * `npm i`. Falls back to `~/.skaile/libraries/` — the user-library directory\n * managed by `skaile library add` — when the package cannot be located.\n * Consumers `fs.existsSync` first and degrade to \"no skills / flows discovered\".\n *\n * @docLink cli/dev-guide#paths\n */\nexport const AI_RESOURCES: string =\n factoryAssetRoots()[0] ?? path.join(os.homedir(), \".skaile\", \"libraries\");\n\n/**\n * All content roots that skill / flow discovery should walk, in priority order,\n * filtered to those that exist on disk and de-duplicated.\n *\n * - The first-party `factory-assets/` roots from the shared `factoryAssetRoots()`\n * helper — the `SKAILE_FACTORY_ASSETS_DIR` override layer (when set) ahead of\n * the bundled tree (in-repo source in dev, `dist/factory-assets/` after\n * install). No monorepo special-case.\n * - The user-library dir `~/.skaile/libraries/`.\n *\n * Order is significant: `findSkills` / flow discovery dedupe first-root-wins, so\n * the env override shadows the bundled tree on a name clash.\n *\n * This is the discovery surface used by `findSkills`, flow discovery, and the\n * completion resolvers.\n *\n * @docLink cli/dev-guide#paths\n */\nexport function aiResourceRoots(): string[] {\n const roots: string[] = [...factoryAssetRoots()];\n roots.push(path.join(os.homedir(), \".skaile\", \"libraries\"));\n return [...new Set(roots)].filter((r) => fs.existsSync(r));\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import { renderGoogleDriveConfig, renderOneDriveConfig, renderWebDAVConfig } from './chunk-OVRSNIKJ.js';
2
- import { resolveAuthRef, resolveAuth, resolveMountCredentialString, resolveMountCredential } from './chunk-X4FCLBI7.js';
3
- import { PortPool, createFsWatcher, RcloneProcessManager, ensureDirMode } from './chunk-5VJVSYXX.js';
2
+ import { resolveAuthRef, resolveAuth, resolveMountCredentialString, resolveMountCredential } from './chunk-R4H6EJW5.js';
3
+ import { PortPool, createFsWatcher, RcloneProcessManager, ensureDirMode } from './chunk-3HUUP3JC.js';
4
4
  import { pluginRegistry } from './chunk-6E6PKKAD.js';
5
5
  import { computeFlowStateFromSnapshots } from './chunk-X46FY45B.js';
6
6
  import { renderStimulusPrompt } from './chunk-DEYYRFQU.js';
7
7
  import { computeStimulus } from './chunk-IFGTRL2I.js';
8
- import { portableSpawn } from './chunk-MVXXAXDW.js';
8
+ import { portableSpawn } from './chunk-KYQNWFJV.js';
9
9
  import { createLogger } from './chunk-JB35MVBN.js';
10
10
  import { existsSync, mkdirSync, renameSync, writeFileSync, readFileSync, cpSync, statSync, createReadStream, readdirSync, openSync, writeSync, closeSync, chmodSync } from 'fs';
11
11
  import path, { join, dirname, resolve, sep } from 'path';
@@ -2098,7 +2098,15 @@ var GoogleDriveConnector = class extends AbstractConnector {
2098
2098
  log: this.log
2099
2099
  });
2100
2100
  this.log.info("mount ready", { pid: rcloneHandle.pid });
2101
- const state = { rcloneHandle };
2101
+ const state = {
2102
+ rcloneHandle,
2103
+ // Safe to close over the handle directly: GoogleDrive has no token-refresh
2104
+ // recycle (unlike sharepoint/webdav, which dereference a handleRef so the
2105
+ // hook follows the recycled handle). If a refresh/reconfigure path is ever
2106
+ // added here, switch this to the handleRef indirection or it will query a
2107
+ // stale handle.
2108
+ authoritativeSize: (relPath) => this.rclone.statSize(rcloneHandle, relPath)
2109
+ };
2102
2110
  return this.makeHandle(declaration, state, targetDir);
2103
2111
  }
2104
2112
  async disconnect(handle) {
@@ -3578,7 +3586,14 @@ var SharePointConnector = class extends AbstractConnector {
3578
3586
  this.log.info("mount ready", { pid: rcloneHandle.pid });
3579
3587
  handleRef.current = rcloneHandle;
3580
3588
  refresh?.schedule(cred.expiresAt);
3581
- const state = { handleRef, refresh };
3589
+ const state = {
3590
+ handleRef,
3591
+ refresh,
3592
+ authoritativeSize: (relPath) => {
3593
+ const h = handleRef.current;
3594
+ return h ? this.rclone.statSize(h, relPath) : Promise.resolve(null);
3595
+ }
3596
+ };
3582
3597
  return this.makeHandle(declaration, state, targetDir);
3583
3598
  }
3584
3599
  async disconnect(handle) {
@@ -4527,7 +4542,14 @@ var WebDAVConnector = class extends AbstractConnector {
4527
4542
  this.log.info("mount ready", { pid: rcloneHandle.pid });
4528
4543
  handleRef.current = rcloneHandle;
4529
4544
  refresh?.schedule(cred.expiresAt);
4530
- const state = { handleRef, refresh };
4545
+ const state = {
4546
+ handleRef,
4547
+ refresh,
4548
+ authoritativeSize: (relPath) => {
4549
+ const h = handleRef.current;
4550
+ return h ? this.rclone.statSize(h, relPath) : Promise.resolve(null);
4551
+ }
4552
+ };
4531
4553
  return this.makeHandle(declaration, state, targetDir);
4532
4554
  }
4533
4555
  async disconnect(handle) {
@@ -5304,6 +5326,11 @@ var ConnectorStartupError = class extends Error {
5304
5326
  };
5305
5327
 
5306
5328
  // connectors/src/fleet-health-gate.ts
5329
+ function verdictToSurface(verdict) {
5330
+ if (verdict === "healthy") return "open";
5331
+ if (verdict === "degraded") return "ro";
5332
+ return "masked";
5333
+ }
5307
5334
  var FleetHealthGate = class {
5308
5335
  constructor(target, barrier, log, opts) {
5309
5336
  this.target = target;
@@ -5311,106 +5338,115 @@ var FleetHealthGate = class {
5311
5338
  this.log = log;
5312
5339
  this.unhealthyThreshold = Math.max(1, opts?.unhealthyThreshold ?? 2);
5313
5340
  this.healthyThreshold = Math.max(1, opts?.healthyThreshold ?? 2);
5341
+ const initial = opts?.initialSurface ?? "open";
5342
+ this.surface = initial;
5343
+ this.pendingSurface = initial;
5344
+ this.runSurface = initial;
5314
5345
  }
5315
5346
  target;
5316
5347
  barrier;
5317
5348
  log;
5318
5349
  unhealthyThreshold;
5319
5350
  healthyThreshold;
5320
- /** True while the read-only barrier is established over the target. */
5321
- gated = false;
5351
+ /** The barrier surface actually applied to the target right now. */
5352
+ surface;
5322
5353
  /**
5323
- * The gate state that the most recently *enqueued* transition will settle on.
5324
- * Hysteresis is measured against this, not `gated`, so that verdicts arriving
5325
- * while a (slow, async) establish/remove is still in flight are counted toward
5326
- * the post-transition state rather than the stale pre-transition one. Without
5327
- * this, fast healthy verdicts arriving during a slow `establish()` could meet
5328
- * `healthyThreshold` before the gate finished tripping, ungating it on the
5329
- * first healthy verdict afterwards and defeating the threshold.
5354
+ * The surface the most recently *enqueued* transition will settle on.
5355
+ * Hysteresis and re-enqueue de-duping are measured against this, not
5356
+ * `surface`, so verdicts arriving while a (slow, async) barrier op is still in
5357
+ * flight are counted toward the post-transition surface, not the stale one.
5330
5358
  */
5331
- pendingGated = false;
5332
- /** Consecutive same-verdict run length, signed by the *current* run's verdict. */
5333
- unhealthyRun = 0;
5334
- healthyRun = 0;
5335
- /** Serialises establish/remove so overlapping observe() calls can't race. */
5359
+ pendingSurface;
5360
+ /** The surface of the *current* same-verdict run, and its length. */
5361
+ runSurface;
5362
+ runLength = 0;
5363
+ /** Serialises barrier ops so overlapping observe() calls can't race. */
5336
5364
  transition = Promise.resolve();
5337
- /** True while the read-only barrier is established (test/observability hook). */
5365
+ /** True while any read-only barrier (ro or masked) is established. */
5338
5366
  get isGated() {
5339
- return this.gated;
5367
+ return this.surface !== "open";
5368
+ }
5369
+ /** The currently-applied surface (test/observability hook). */
5370
+ get currentSurface() {
5371
+ return this.surface;
5340
5372
  }
5341
5373
  /**
5342
- * Feed one health verdict. Applies hysteresis, then establishes or removes the
5343
- * barrier on a state change. Resolves once the (possibly no-op) transition is
5344
- * applied. Never throws — a failed establish is treated as gated (fail-closed).
5374
+ * Feed one health verdict. Applies hysteresis, then drives the barrier toward
5375
+ * the target surface on a change. Resolves once the (possibly no-op)
5376
+ * transition is applied. Never throws — a failed barrier op stays gated
5377
+ * (fail-closed).
5345
5378
  */
5346
5379
  observe(verdict) {
5347
- if (verdict === "healthy") {
5348
- this.healthyRun += 1;
5349
- this.unhealthyRun = 0;
5350
- if (this.pendingGated && this.healthyRun >= this.healthyThreshold) {
5351
- this.pendingGated = false;
5352
- this.healthyRun = 0;
5353
- return this.enqueue(() => this.ungate());
5354
- }
5380
+ const desired = verdictToSurface(verdict);
5381
+ if (desired === this.runSurface) {
5382
+ this.runLength += 1;
5355
5383
  } else {
5356
- this.unhealthyRun += 1;
5357
- this.healthyRun = 0;
5358
- if (!this.pendingGated && this.unhealthyRun >= this.unhealthyThreshold) {
5359
- this.pendingGated = true;
5360
- this.unhealthyRun = 0;
5361
- return this.enqueue(() => this.gate());
5362
- }
5384
+ this.runSurface = desired;
5385
+ this.runLength = 1;
5386
+ }
5387
+ const threshold = desired === "open" ? this.healthyThreshold : this.unhealthyThreshold;
5388
+ if (desired !== this.pendingSurface && this.runLength >= threshold) {
5389
+ this.pendingSurface = desired;
5390
+ this.runLength = 0;
5391
+ return this.enqueue(() => this.apply(desired));
5363
5392
  }
5364
5393
  return this.transition;
5365
5394
  }
5366
5395
  /**
5367
- * Tear the gate down. If currently gated, removes the barrier so a leftover
5368
- * read-only tmpfs is not leaked. Call only after the connector above the target
5369
- * is disconnected (top-down, no leaked mount).
5396
+ * Tear the gate down. If any barrier is established (or in flight), removes it
5397
+ * so a leftover read-only surface is not leaked. Call only after the connector
5398
+ * above the target is disconnected (top-down, no leaked mount).
5370
5399
  */
5371
5400
  dispose() {
5372
- if (!this.gated && !this.pendingGated) return this.transition;
5373
- this.pendingGated = false;
5374
- return this.enqueue(() => this.ungate());
5401
+ if (this.surface === "open" && this.pendingSurface === "open") return this.transition;
5402
+ this.pendingSurface = "open";
5403
+ return this.enqueue(() => this.apply("open"));
5375
5404
  }
5376
5405
  enqueue(step) {
5377
5406
  this.transition = this.transition.then(step, step);
5378
5407
  return this.transition;
5379
5408
  }
5380
- async gate() {
5381
- if (this.gated) {
5382
- this.pendingGated = true;
5409
+ /** Drive the barrier to `desired`, fail-closed to `masked` on any throw. */
5410
+ async apply(desired) {
5411
+ if (this.surface === desired) {
5412
+ this.pendingSurface = desired;
5383
5413
  return;
5384
5414
  }
5385
5415
  try {
5416
+ if (desired === "open") {
5417
+ await this.barrier.remove(this.target, this.log);
5418
+ this.surface = "open";
5419
+ this.log?.info("fleet mount recovered \u2014 gate lifted, writable again", {
5420
+ target: this.target
5421
+ });
5422
+ return;
5423
+ }
5424
+ if (desired === "ro") {
5425
+ if (this.barrier.exposeReadOnly) {
5426
+ await this.barrier.exposeReadOnly(this.target, this.log);
5427
+ } else {
5428
+ await this.barrier.establish(this.target, this.log);
5429
+ }
5430
+ this.surface = "ro";
5431
+ this.log?.warn("fleet mount upload-degraded \u2014 gated read-only (content visible)", {
5432
+ target: this.target
5433
+ });
5434
+ return;
5435
+ }
5386
5436
  await this.barrier.establish(this.target, this.log);
5387
- this.gated = true;
5388
- this.log?.warn("fleet mount unhealthy \u2014 gated read-only", { target: this.target });
5437
+ this.surface = "masked";
5438
+ this.log?.warn("fleet mount unhealthy \u2014 gated read-only (masked)", { target: this.target });
5389
5439
  } catch (err) {
5390
- this.gated = true;
5440
+ const safe = "masked";
5441
+ this.surface = safe;
5442
+ this.pendingSurface = safe;
5391
5443
  this.log?.error(
5392
- "fleet read-only gate establish threw \u2014 treating as gated (fail-closed)",
5444
+ `fleet read-only gate transition to '${desired}' threw \u2014 biasing to '${safe}' (fail-closed)`,
5393
5445
  err,
5394
- {
5395
- target: this.target
5396
- }
5446
+ { target: this.target }
5397
5447
  );
5398
5448
  }
5399
5449
  }
5400
- async ungate() {
5401
- if (!this.gated) return;
5402
- try {
5403
- await this.barrier.remove(this.target, this.log);
5404
- } catch (err) {
5405
- this.pendingGated = true;
5406
- this.log?.error("fleet read-only gate remove failed \u2014 staying gated", err, {
5407
- target: this.target
5408
- });
5409
- return;
5410
- }
5411
- this.gated = false;
5412
- this.log?.info("fleet mount recovered \u2014 gate lifted, writable again", { target: this.target });
5413
- }
5414
5450
  };
5415
5451
  function isFleetManaged(connectorId) {
5416
5452
  const raw = process.env.SKAILE_FLEET_MANAGED_MOUNTS ?? "";
@@ -5563,11 +5599,52 @@ var RoMountPlaceholderBarrier = class {
5563
5599
  log?.debug("deferred mount live; degraded barrier lifted", { target, mode });
5564
5600
  }
5565
5601
  }
5602
+ async exposeReadOnly(target, log) {
5603
+ const mode = this.modes.get(target);
5604
+ if (mode === "ro-bind") return;
5605
+ if (mode === "mount") {
5606
+ let unmounted = await this.run("umount", [target]).then(
5607
+ () => true,
5608
+ () => false
5609
+ );
5610
+ if (!unmounted) {
5611
+ unmounted = await this.run("umount", ["-l", target]).then(
5612
+ () => true,
5613
+ () => false
5614
+ );
5615
+ }
5616
+ if (!unmounted) {
5617
+ log?.error(
5618
+ "deferred mount barrier: could not unmount opaque mask to expose read-only surface \u2014 staying masked",
5619
+ void 0,
5620
+ { target }
5621
+ );
5622
+ return;
5623
+ }
5624
+ }
5625
+ try {
5626
+ await this.run("mount", ["--bind", target, target]);
5627
+ await this.run("mount", ["-o", "remount,ro,bind", target]);
5628
+ this.modes.set(target, "ro-bind");
5629
+ log?.info("deferred mount barrier downgraded to read-only (content visible)", { target });
5630
+ } catch (err) {
5631
+ const chmodOk = await chmod(target, 365).then(
5632
+ () => true,
5633
+ () => false
5634
+ );
5635
+ this.modes.set(target, chmodOk ? "chmod" : "unprotected");
5636
+ log?.error(
5637
+ chmodOk ? "deferred mount read-only-readable surface degraded to chmod (ro bind unavailable) \u2014 a write by the owning uid could bypass it" : "deferred mount read-only-readable surface FAILED (ro bind and chmod both unavailable) \u2014 target may be writable",
5638
+ err instanceof Error ? err : void 0,
5639
+ { target }
5640
+ );
5641
+ }
5642
+ }
5566
5643
  async remove(target, log) {
5567
5644
  const mode = this.modes.get(target);
5568
5645
  if (!mode) return;
5569
5646
  this.modes.delete(target);
5570
- if (mode === "mount") {
5647
+ if (mode === "mount" || mode === "ro-bind") {
5571
5648
  let unmounted = false;
5572
5649
  try {
5573
5650
  await this.run("umount", [target]);
@@ -5638,6 +5715,9 @@ function parseFleetHealthPollMs(raw = process.env.SKAILE_FLEET_HEALTH_POLL_MS) {
5638
5715
  function hasKnownPrefix(ref) {
5639
5716
  return KNOWN_PREFIXES.some((p) => ref.startsWith(p));
5640
5717
  }
5718
+ function isStrictlyNested(child, parent) {
5719
+ return child.startsWith(`${parent}/`);
5720
+ }
5641
5721
  async function resolveFields(declaration, fields, chain) {
5642
5722
  const resolved = {};
5643
5723
  for (const field of fields) {
@@ -5750,6 +5830,8 @@ var ConnectorManager = class {
5750
5830
  }
5751
5831
  opts;
5752
5832
  active = /* @__PURE__ */ new Map();
5833
+ // Allocated absolute mount target → owning connector id; collisions rejected at setup, released on disconnect.
5834
+ mountTargets = /* @__PURE__ */ new Map();
5753
5835
  workspaceDir;
5754
5836
  chain;
5755
5837
  secrets;
@@ -5865,6 +5947,35 @@ var ConnectorManager = class {
5865
5947
  const mountPath = mountConf?.target ?? `.mounts/${declaration.id}`;
5866
5948
  return resolve(this.workspaceDir, mountPath);
5867
5949
  }
5950
+ // Record absPath → id: same-id is idempotent, an exact-equal collision throws
5951
+ // (naming both ids + the path) so a silent shadow fails at setup, nesting warns.
5952
+ reserveMountTarget(id, absPath) {
5953
+ const owner = this.mountTargets.get(absPath);
5954
+ if (owner === id) return;
5955
+ if (owner !== void 0) {
5956
+ throw new Error(
5957
+ `Mount target collision: connectors "${owner}" and "${id}" both resolve to "${absPath}". Each filesystem connector needs a distinct mount.target.`
5958
+ );
5959
+ }
5960
+ for (const [otherPath, otherId] of this.mountTargets) {
5961
+ if (otherId === id) continue;
5962
+ if (isStrictlyNested(absPath, otherPath) || isStrictlyNested(otherPath, absPath)) {
5963
+ this.mgrLog.warn("nested mount target overlap between connectors", {
5964
+ connectorId: id,
5965
+ otherConnectorId: otherId,
5966
+ target: absPath,
5967
+ otherTarget: otherPath
5968
+ });
5969
+ }
5970
+ }
5971
+ this.mountTargets.set(absPath, id);
5972
+ }
5973
+ /** Release every mount target owned by `id` (on disconnect). */
5974
+ releaseMountTarget(id) {
5975
+ for (const [path2, owner] of [...this.mountTargets]) {
5976
+ if (owner === id) this.mountTargets.delete(path2);
5977
+ }
5978
+ }
5868
5979
  /**
5869
5980
  * Build a `ConnectContext` for a connector, resolving fields and — for
5870
5981
  * filesystem-face connectors — allocating the mount-target directory.
@@ -5882,6 +5993,7 @@ var ConnectorManager = class {
5882
5993
  }
5883
5994
  if (connector.filesystem != null) {
5884
5995
  const absPath = this.resolveMountTarget(declaration);
5996
+ this.reserveMountTarget(declaration.id, absPath);
5885
5997
  if (!existsSync(absPath)) mkdirSync(absPath, { recursive: true });
5886
5998
  ctx.mountTarget = absPath;
5887
5999
  }
@@ -5943,6 +6055,9 @@ var ConnectorManager = class {
5943
6055
  */
5944
6056
  async connectAll(declarations, options) {
5945
6057
  this.mgrLog.info("connectAll start", { count: declarations.length });
6058
+ for (const decl of declarations) {
6059
+ if (decl.mount != null) this.reserveMountTarget(decl.id, this.resolveMountTarget(decl));
6060
+ }
5946
6061
  const results = [];
5947
6062
  const eager = [];
5948
6063
  const deferred = [];
@@ -6160,10 +6275,33 @@ var ConnectorManager = class {
6160
6275
  * writable* degraded mount that the local probe cannot. The runner watches the
6161
6276
  * `<workspace>/.skaile/fleet-health/<connectorId>` flag and forwards its verdict
6162
6277
  * here. Unknown / non-fleet ids are ignored.
6278
+ *
6279
+ * The verdict drives the gate across three surfaces (writable / read-only-
6280
+ * readable / masked): `healthy` lifts any barrier, `degraded` downgrades to a
6281
+ * read-only surface that keeps the live content visible, `error` keeps the
6282
+ * opaque mask.
6283
+ *
6284
+ * A deferred remote mount may have been brought up with the *static* boot-time
6285
+ * barrier (it was not fleet-managed at connect — e.g. the host bind landed
6286
+ * late, after `connectAll` placed the not-ready barrier). When a fleet verdict
6287
+ * later arrives for such a connector, a gate is created lazily over that same
6288
+ * barrier (seeded `masked`, matching the static barrier already in place) so the
6289
+ * authoritative platform signal can lift or downgrade it — otherwise a late-
6290
+ * arriving live mount stays masked forever even after it goes healthy.
6163
6291
  */
6164
6292
  async reportFleetHealth(connectorId, verdict) {
6165
6293
  const entry = this.active.get(connectorId);
6166
- if (!entry?.fleetHealthGate) return;
6294
+ if (!entry) return;
6295
+ if (!entry.fleetHealthGate) {
6296
+ if (!entry.placeholderTarget) return;
6297
+ entry.fleetHealthTarget = entry.placeholderTarget;
6298
+ entry.fleetHealthGate = new FleetHealthGate(
6299
+ entry.placeholderTarget,
6300
+ this.placeholderBarrier,
6301
+ this.mgrLog,
6302
+ { initialSurface: "masked" }
6303
+ );
6304
+ }
6167
6305
  await entry.fleetHealthGate.observe(verdict).catch(() => {
6168
6306
  });
6169
6307
  }
@@ -6252,6 +6390,7 @@ var ConnectorManager = class {
6252
6390
  });
6253
6391
  }
6254
6392
  this.active.clear();
6393
+ this.mountTargets.clear();
6255
6394
  this.mgrLog.info("disconnectAll complete");
6256
6395
  }
6257
6396
  // ── Hot-plug ──────────────────────────────────────────────────────────────────
@@ -6297,6 +6436,7 @@ var ConnectorManager = class {
6297
6436
  });
6298
6437
  return handle;
6299
6438
  } catch (err) {
6439
+ this.releaseMountTarget(declaration.id);
6300
6440
  const msg = err instanceof Error ? err.message : String(err);
6301
6441
  this.opts.onStatusChange?.({
6302
6442
  type: "connector_status",
@@ -6338,6 +6478,7 @@ var ConnectorManager = class {
6338
6478
  if (entry.fleetHealthGate) await entry.fleetHealthGate.dispose().catch(() => {
6339
6479
  });
6340
6480
  this.active.delete(id);
6481
+ this.releaseMountTarget(id);
6341
6482
  this.opts.onStatusChange?.({
6342
6483
  type: "connector_status",
6343
6484
  connectorId: id,
@@ -6865,7 +7006,7 @@ function buildConnectorPromptSection(manager, options) {
6865
7006
  sections.push(buildFilesystemSection(manager, fsConnectors));
6866
7007
  }
6867
7008
  if (toolConnectors.length > 0) {
6868
- sections.push(buildToolSection(toolConnectors, shellAccess));
7009
+ sections.push(buildToolSection(manager, toolConnectors, shellAccess));
6869
7010
  }
6870
7011
  return sections.join("\n\n");
6871
7012
  }
@@ -6920,7 +7061,7 @@ function appendGitAuthNotes(lines, manager, fsConnectors) {
6920
7061
  );
6921
7062
  }
6922
7063
  }
6923
- function buildToolSection(toolConnectors, shellAccess) {
7064
+ function buildToolSection(manager, toolConnectors, shellAccess) {
6924
7065
  const lines = ["## Connectors", ""];
6925
7066
  lines.push("Currently registered connectors (id \u2014 driver, access):");
6926
7067
  for (const r of toolConnectors) {
@@ -6931,6 +7072,18 @@ function buildToolSection(toolConnectors, shellAccess) {
6931
7072
  "Additional connectors may be registered mid-session by the host \u2014 notably shared-state stores (driver: `xstate-store`, e.g. `session`, `presence`, per-component stores). Re-enumerate with `connector_list` whenever you need the live set."
6932
7073
  );
6933
7074
  lines.push("");
7075
+ for (const r of toolConnectors) {
7076
+ let instructions;
7077
+ try {
7078
+ instructions = manager.get(r.id).declaration.instructions;
7079
+ } catch {
7080
+ }
7081
+ if (instructions && instructions.trim().length > 0) {
7082
+ lines.push(`Guidance for \`${r.id}\`:`);
7083
+ lines.push(instructions.trim());
7084
+ lines.push("");
7085
+ }
7086
+ }
6934
7087
  if (shellAccess) {
6935
7088
  lines.push("Discover connectors:");
6936
7089
  lines.push("- `connector_list` tool \u2014 returns the live connector set as JSON.");
@@ -8458,5 +8611,5 @@ function createConnector() {
8458
8611
  }
8459
8612
 
8460
8613
  export { AbstractConnector, BUILTIN_CONNECTOR_CATALOG, ConnectorFieldMissingError, ConnectorManager, ConnectorStartupError, DEFAULT_REACTIVE_COOLDOWN_MS, DeployConnector, DevServerConnector, FleetHealthGate, FlowAdapter, GitConnector, GmailConnector, GoogleDriveConnector, LocalConnector, LogBuffer, ManagedGitconfigCollisionError, MattermostConnector, MemoryConnector, MinIOConnector, NOT_READY_SENTINEL, PROACTIVE_RCLONE_REFRESH_MARGIN_MS, PostgresConnector, RoMountPlaceholderBarrier, S3Connector, SQLiteConnector, SharePointConnector, StaticServerConnector, TunnelConnector, WebDAVConnector, XStateConnector, XStateStoreConnector, __test, atomicReplaceCredential, buildConnectorPromptSection, buildSdkConnectorTools, createConnector, createConnector10, createConnector11, createConnector12, createConnector13, createConnector14, createConnector15, createConnector16, createConnector17, createConnector18, createConnector19, createConnector2, createConnector3, createConnector4, createConnector5, createConnector6, createConnector7, createConnector8, createConnector9, createRcloneTokenRefresh, createWorktree, defaultMountPlaceholderBarrier, defaultSpawn, ensureFleetMounted, findGitRoot, findMissingPackages, getConnector, installNpmPackages, isFleetManaged, isPackageResolvable, listConnectors, listWorktrees, probeFleetHealth, registerBuiltinConnectors, removeMountBlock, renderCredentialHelperScript, tryGetConnector, worktreeRegistry, writeHelperScript, writeMountBlock };
8461
- //# sourceMappingURL=chunk-2ZI2FFFN.js.map
8462
- //# sourceMappingURL=chunk-2ZI2FFFN.js.map
8614
+ //# sourceMappingURL=chunk-F5Q2RMH4.js.map
8615
+ //# sourceMappingURL=chunk-F5Q2RMH4.js.map