@skaile/workspaces 0.48.0 → 0.48.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -0
- package/dist/{asset-feeds-DLRQWELS.js → asset-feeds-O6R6J4RI.js} +7 -7
- package/dist/{asset-feeds-DLRQWELS.js.map → asset-feeds-O6R6J4RI.js.map} +1 -1
- package/dist/asset-manager/index.js +5 -5
- package/dist/asset-manager/installer.js +4 -4
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/asset-manager/src/installer.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +91 -1
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +1 -1
- package/dist/bridge/drivers/continue.js +2 -2
- package/dist/bridge/drivers/echo.js +1 -1
- package/dist/bridge/drivers/gemini.js +3 -3
- package/dist/bridge/drivers/goose.js +2 -2
- package/dist/bridge/drivers/omp.js +1 -1
- package/dist/bridge/drivers/opencode.js +2 -2
- package/dist/bridge/drivers/qwen.js +3 -3
- package/dist/bridge/index.js +2 -2
- package/dist/bridge/src/drivers/claude-sdk.d.ts +30 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/types.d.ts +21 -0
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-HOEP5CJQ.js → chunk-33WB7VFV.js} +3 -3
- package/dist/{chunk-HOEP5CJQ.js.map → chunk-33WB7VFV.js.map} +1 -1
- package/dist/{chunk-P6HRQPXC.js → chunk-3A3OACI2.js} +2 -2
- package/dist/{chunk-P6HRQPXC.js.map → chunk-3A3OACI2.js.map} +1 -1
- package/dist/{chunk-Z3ZRI2AE.js → chunk-4IGNQG6E.js} +3 -3
- package/dist/{chunk-Z3ZRI2AE.js.map → chunk-4IGNQG6E.js.map} +1 -1
- package/dist/{chunk-Z3GAAIJK.js → chunk-6AD3NS7R.js} +4 -4
- package/dist/{chunk-Z3GAAIJK.js.map → chunk-6AD3NS7R.js.map} +1 -1
- package/dist/{chunk-RSK6FDMV.js → chunk-6VUP6XHK.js} +3 -3
- package/dist/{chunk-RSK6FDMV.js.map → chunk-6VUP6XHK.js.map} +1 -1
- package/dist/{chunk-7UYT3SNF.js → chunk-BWCGSGAC.js} +7 -7
- package/dist/{chunk-7UYT3SNF.js.map → chunk-BWCGSGAC.js.map} +1 -1
- package/dist/{chunk-7KCG5LBG.js → chunk-CK3O5BCT.js} +11 -10
- package/dist/chunk-CK3O5BCT.js.map +1 -0
- package/dist/{chunk-2RVTJJWY.js → chunk-EBSIZYM6.js} +5 -5
- package/dist/{chunk-2RVTJJWY.js.map → chunk-EBSIZYM6.js.map} +1 -1
- package/dist/{chunk-FAALG3QN.js → chunk-HNORRENR.js} +3 -3
- package/dist/{chunk-FAALG3QN.js.map → chunk-HNORRENR.js.map} +1 -1
- package/dist/{chunk-4VPRAG35.js → chunk-LTUTK2Q3.js} +14 -12
- package/dist/chunk-LTUTK2Q3.js.map +1 -0
- package/dist/{chunk-OCAQH66V.js → chunk-N5AE5SOC.js} +28 -2
- package/dist/chunk-N5AE5SOC.js.map +1 -0
- package/dist/{chunk-5C3QJSOD.js → chunk-OYMSCV7T.js} +3 -3
- package/dist/{chunk-5C3QJSOD.js.map → chunk-OYMSCV7T.js.map} +1 -1
- package/dist/{chunk-LLOXWWB6.js → chunk-P4BDTJMI.js} +85 -4
- package/dist/chunk-P4BDTJMI.js.map +1 -0
- package/dist/{chunk-WTFJFW7F.js → chunk-PBO6SCT2.js} +2 -2
- package/dist/{chunk-WTFJFW7F.js.map → chunk-PBO6SCT2.js.map} +1 -1
- package/dist/{chunk-4OCZBSBY.js → chunk-RAIRWFAN.js} +3 -3
- package/dist/chunk-RAIRWFAN.js.map +1 -0
- package/dist/{chunk-G3GODNHM.js → chunk-SDAKQCOB.js} +3 -3
- package/dist/{chunk-G3GODNHM.js.map → chunk-SDAKQCOB.js.map} +1 -1
- package/dist/{chunk-UEHPL3KU.js → chunk-SXT6BAQJ.js} +2 -2
- package/dist/{chunk-UEHPL3KU.js.map → chunk-SXT6BAQJ.js.map} +1 -1
- package/dist/{chunk-3VBQJZYL.js → chunk-WBF7JLTY.js} +3 -3
- package/dist/{chunk-3VBQJZYL.js.map → chunk-WBF7JLTY.js.map} +1 -1
- package/dist/{chunk-DFCX5YY5.js → chunk-YERSEKB2.js} +5 -5
- package/dist/{chunk-DFCX5YY5.js.map → chunk-YERSEKB2.js.map} +1 -1
- package/dist/{chunk-T2CIVTTC.js → chunk-ZJ3VRPOI.js} +7 -3
- package/dist/chunk-ZJ3VRPOI.js.map +1 -0
- package/dist/cli/index.js +89 -37
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/source.d.ts +18 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/connectors/config.js +4 -4
- package/dist/connectors/index.js +6 -6
- package/dist/connectors/rclone.js +1 -1
- package/dist/connectors/src/config.d.ts.map +1 -1
- package/dist/connectors/src/materialized-connectors.d.ts.map +1 -1
- package/dist/core/index.js +3 -3
- package/dist/core/runtime-assets.js +2 -2
- package/dist/core/src/workspace-config.d.ts +7 -0
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/workspace-config.js +1 -1
- package/dist/deploy/index.js +3 -3
- package/dist/{ensure-sources-KLCGXVE6.js → ensure-sources-EE7Z2HKS.js} +5 -5
- package/dist/{ensure-sources-KLCGXVE6.js.map → ensure-sources-EE7Z2HKS.js.map} +1 -1
- package/dist/factory-assets/connectors/deploy.js +6 -6
- package/dist/factory-assets/connectors/devserver.js +6 -6
- package/dist/factory-assets/connectors/flow/adapter.js +6 -6
- package/dist/factory-assets/connectors/flow/engine.js +3 -3
- package/dist/factory-assets/connectors/flow/run-flow.js +7 -7
- package/dist/factory-assets/connectors/flow.js +6 -6
- package/dist/factory-assets/connectors/git.js +6 -6
- package/dist/factory-assets/connectors/gmail.js +6 -6
- package/dist/factory-assets/connectors/googledrive.js +6 -6
- package/dist/factory-assets/connectors/local.js +6 -6
- package/dist/factory-assets/connectors/mattermost.js +6 -6
- package/dist/factory-assets/connectors/memory.js +6 -6
- package/dist/factory-assets/connectors/minio.js +6 -6
- package/dist/factory-assets/connectors/postgres.js +6 -6
- package/dist/factory-assets/connectors/s3.js +6 -6
- package/dist/factory-assets/connectors/sharepoint.js +6 -6
- package/dist/factory-assets/connectors/sqlite.js +6 -6
- package/dist/factory-assets/connectors/static-server.js +6 -6
- package/dist/factory-assets/connectors/tunnel.js +6 -6
- package/dist/factory-assets/connectors/webdav.js +6 -6
- package/dist/factory-assets/connectors/xstate-store.js +6 -6
- package/dist/factory-assets/connectors/xstate.js +6 -6
- package/dist/{flows-PNDUCOJR.js → flows-AAHXXXCH.js} +3 -3
- package/dist/{flows-PNDUCOJR.js.map → flows-AAHXXXCH.js.map} +1 -1
- package/dist/library/index.js +4 -4
- package/dist/library/install.js +3 -3
- package/dist/library/src/local/db.d.ts.map +1 -1
- package/dist/library/src/local/local-catalog-source.d.ts +12 -0
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
- package/dist/{open-library-COHFCT4N.js → open-library-TXJMFG34.js} +7 -7
- package/dist/{open-library-COHFCT4N.js.map → open-library-TXJMFG34.js.map} +1 -1
- package/dist/{paths-2SYXGTZJ.js → paths-OMVC4UWY.js} +6 -6
- package/dist/{paths-2SYXGTZJ.js.map → paths-OMVC4UWY.js.map} +1 -1
- package/dist/{plugin-store-UNENLB56.js → plugin-store-JWJHIPUT.js} +5 -5
- package/dist/{plugin-store-UNENLB56.js.map → plugin-store-JWJHIPUT.js.map} +1 -1
- package/dist/runner/index.js +10 -10
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +5 -5
- package/dist/sdk/bridge.js +2 -2
- package/dist/sdk/core.js +3 -3
- package/dist/sdk/flow.js +3 -3
- package/dist/sdk/index.js +10 -10
- package/dist/sdk/runner.js +10 -10
- package/dist/{setup-AYH6SR4U.js → setup-ETNBVZQA.js} +7 -7
- package/dist/{setup-AYH6SR4U.js.map → setup-ETNBVZQA.js.map} +1 -1
- package/dist/{store-client-U4FMAIWX.js → store-client-SLFAAKSV.js} +6 -6
- package/dist/{store-client-U4FMAIWX.js.map → store-client-SLFAAKSV.js.map} +1 -1
- package/dist/tui/index.js +10 -10
- package/dist/workspace-plugin/adapters/mcp.js +1 -1
- package/dist/workspace-plugin/adapters/omp.js +3 -3
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4OCZBSBY.js.map +0 -1
- package/dist/chunk-4VPRAG35.js.map +0 -1
- package/dist/chunk-7KCG5LBG.js.map +0 -1
- package/dist/chunk-LLOXWWB6.js.map +0 -1
- package/dist/chunk-OCAQH66V.js.map +0 -1
- package/dist/chunk-T2CIVTTC.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../connectors/src/fs-utils.ts","../connectors/src/port-pool.ts","../connectors/src/watcher.ts","../connectors/src/rclone-process-manager.ts"],"names":["mkdir"],"mappings":"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","file":"chunk-4OCZBSBY.js","sourcesContent":["/**\n * Shared filesystem helpers for connector infrastructure.\n *\n * @docLink packages/connectors/api-reference#fs-utils\n */\n\nimport { chmod, mkdir } from \"node:fs/promises\";\nimport type { Logger } from \"@skaile/workspaces/types\";\n\n/**\n * mkdir(recursive) + chmod 0o770 in one call. The post-mkdir `chmod` is the\n * load-bearing piece: `mkdir(mode:)` is ANDed with the process umask\n * (typically 022 → effective mode 0o750), which strips the group-write bit\n * that `fusermount3` requires on the rclone mountpoint and rclone needs on\n * its vfs cache directory. Explicit `chmod` is umask-immune.\n *\n * EPERM on `chmod` is swallowed: when a foreign uid pre-created the\n * directory (a stray uid-1000 process inside the container or a host-side\n * platform process writing through the project bind-mount), the runner\n * cannot chmod it. The platform's agent container entrypoint runs as root\n * and heals the subtree on the next restart — see\n * `platform/docker/agent/entrypoint.sh` `_skaile_heal_ownership`. A debug\n * line is emitted when a logger is supplied so the rare-but-real heal\n * trigger is observable in session logs without adding noise on the happy\n * path.\n *\n * The chmod is *idempotent* (the syscall always fires, but a no-op when\n * the mode is already 0o770), not a no-op — kernel behaviour for chmod is\n * \"set\", not \"set-if-different\".\n *\n * @param dir Absolute or relative path to ensure exists at mode 0o770.\n * @param log Optional logger. When provided, EPERM-on-chmod emits a\n * `debug`-level entry under whatever taxonomy the caller's logger uses.\n */\nexport async function ensureDirMode(dir: string, log?: Logger): Promise<void> {\n await mkdir(dir, { recursive: true });\n try {\n await chmod(dir, 0o770);\n } catch (err) {\n log?.debug(\"chmod 0770 skipped (EPERM — entrypoint heal expected)\", {\n path: dir,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n","/**\n * PortPool — allocates ports from a [min, max] range, checks OS for collisions.\n */\n\nimport { createConnection } from \"node:net\";\n\n/**\n * Allocates TCP ports from a `[min, max]` range with OS-level collision detection.\n * Used by service connector adapters (devserver, static-server) to assign local ports.\n * @docLink packages/connectors/api-reference#port-pool\n */\nexport class PortPool {\n private readonly min: number;\n private readonly max: number;\n private readonly inUse = new Set<number>();\n\n constructor(range: [number, number]) {\n this.min = range[0];\n this.max = range[1];\n }\n\n /** Allocate the next free port from the range. Checks OS for collisions. */\n async allocate(): Promise<number> {\n for (let port = this.min; port <= this.max; port++) {\n if (this.inUse.has(port)) continue;\n if (!(await PortPool.isPortFree(port))) {\n this.inUse.add(port);\n continue;\n }\n this.inUse.add(port);\n return port;\n }\n throw new Error(`No free port in range ${this.min}-${this.max}`);\n }\n\n /** Mark a port as in-use (for explicit port args or registered instances). */\n reserve(port: number): void {\n this.inUse.add(port);\n }\n\n /** Return a port to the pool. */\n release(port: number): void {\n this.inUse.delete(port);\n }\n\n /** Check if a port is currently tracked as in-use. */\n isInUse(port: number): boolean {\n return this.inUse.has(port);\n }\n\n /** Quick TCP connect test — returns true if nothing is listening. */\n static isPortFree(port: number, host = \"127.0.0.1\"): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = createConnection({ port, host });\n socket.once(\"connect\", () => {\n socket.destroy();\n resolve(false);\n });\n socket.once(\"error\", () => {\n socket.destroy();\n resolve(true);\n });\n socket.setTimeout(500, () => {\n socket.destroy();\n resolve(true);\n });\n });\n }\n}\n","/**\n * Shared filesystem watcher factory for mountable adapters.\n *\n * Uses chokidar for cross-platform, debounced file watching.\n *\n * Automatically reads .gitignore from the watched directory and merges\n * those patterns into chokidar's ignore list. This prevents scanning\n * large generated directories (node_modules, dist, .next, etc.) that\n * most projects already declare as ignored.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { createLogger } from \"@skaile/workspaces/core/logging\";\n// Static import so bun --compile bundles chokidar into the binary. A dynamic\n// `await import(\"chokidar\")` is not seen by the compiler's static analyzer\n// and fails at runtime inside the /$bunfs/ virtual filesystem.\nimport chokidar from \"chokidar\";\nimport type { ConnectorChangeEvent } from \"./connector-types.js\";\nimport type { WatchHandle, WatchOptions } from \"./shared-types.js\";\n\n/**\n * Convert a glob pattern to a matcher function.\n *\n * Chokidar 5 changed string matchers to exact equality (`===`) instead of\n * glob matching. We convert our patterns to functions so chokidar can still\n * filter correctly.\n */\nfunction globToMatcher(pattern: string): (path: string) => boolean {\n // Simple segment-name patterns: **/NAME/** or **/NAME\n // Match any path that contains /NAME/ or ends with /NAME\n const segmentMatch = pattern.match(/^\\*\\*\\/([^*/?]+)\\/\\*\\*$/);\n if (segmentMatch) {\n const name = segmentMatch[1];\n return (p: string) => p.includes(`/${name}/`) || p.endsWith(`/${name}`) || p === name;\n }\n\n // Dot-prefixed segment: **/.NAME or **/.NAME/**\n const dotSegment = pattern.match(/^\\*\\*\\/(\\.[\\w#]+)(?:\\/\\*\\*)?$/);\n if (dotSegment) {\n const name = dotSegment[1];\n return (p: string) => p.includes(`/${name}/`) || p.endsWith(`/${name}`) || p === name;\n }\n\n // Extension wildcard: **/*.EXT.* or **/*.EXT\n const extMatch = pattern.match(/^\\*\\*\\/\\*(\\.\\w+(?:\\.\\*)?)/);\n if (extMatch) {\n const suffix = extMatch[1];\n if (suffix.endsWith(\".*\")) {\n // e.g. **/*.tmp.* -> match any file with .tmp. in it\n const base = suffix.slice(0, -2);\n return (p: string) => p.includes(base);\n }\n return (p: string) => p.endsWith(suffix);\n }\n\n // Suffix wildcard: **/*SUFFIX (e.g. **/*~)\n const suffixMatch = pattern.match(/^\\*\\*\\/\\*(.+)$/);\n if (suffixMatch) {\n const sfx = suffixMatch[1];\n return (p: string) => p.endsWith(sfx);\n }\n\n // Fallback: convert simple globs to regex\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"{{GLOBSTAR}}\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/\\?/g, \"[^/]\")\n .replace(/\\{\\{GLOBSTAR\\}\\}/g, \".*\");\n const re = new RegExp(`^${escaped}$`);\n return (p: string) => re.test(p);\n}\n\nconst DEFAULT_IGNORED: Array<string | ((path: string) => boolean)> = [\n (p: string) => p.includes(\"/.git/\") || p.endsWith(\"/.git\"),\n (p: string) => p.includes(\"/node_modules/\") || p.endsWith(\"/node_modules\"),\n (p: string) => p.includes(\"/.connectors/\") || p.endsWith(\"/.connectors\"),\n // Atomic-write tempfiles (Bun.write creates `<name>.tmp.<pid>.<ts>` then renames).\n // These vanish between readdir and fs.watch, causing EINVAL that crashes the process.\n (p: string) => /\\.tmp\\.\\d/.test(p),\n // Editor swap/backup files that also race with save operations.\n (p: string) => p.endsWith(\".swp\"),\n (p: string) => p.endsWith(\".swx\"),\n (p: string) => p.includes(\"/.#\"),\n (p: string) => p.endsWith(\"~\"),\n];\n/**\n * Default chokidar `awaitWriteFinish` stability threshold (ms). Exported so the\n * rclone process manager can reuse the same write-stabilization concept when\n * gating a flush on a quiescent mount.\n */\nexport const DEFAULT_DEBOUNCE_MS = 150;\n\n/**\n * Parse a .gitignore file into glob patterns suitable for chokidar's `ignored` option.\n * Handles comments, blank lines, directory patterns, and root-relative patterns.\n * Negation patterns (!) are skipped - chokidar cannot un-ignore.\n */\nfunction parseGitignore(rootDir: string): Array<(path: string) => boolean> {\n const gitignorePath = join(rootDir, \".gitignore\");\n if (!existsSync(gitignorePath)) return [];\n\n try {\n const content = readFileSync(gitignorePath, \"utf-8\");\n const matchers: Array<(path: string) => boolean> = [];\n\n for (const raw of content.split(\"\\n\")) {\n const line = raw.trim();\n if (!line || line.startsWith(\"#\") || line.startsWith(\"!\")) continue;\n\n let pattern = line;\n\n // Strip leading / (root-relative -> convert to rootDir-relative)\n if (pattern.startsWith(\"/\")) {\n pattern = pattern.slice(1);\n } else if (!pattern.includes(\"/\")) {\n // Bare name like \"node_modules\" or \"*.log\" -> match anywhere\n pattern = `**/${pattern}`;\n }\n\n // Directory pattern (trailing /) -> ensure it matches contents too\n if (pattern.endsWith(\"/\")) {\n matchers.push(globToMatcher(`${pattern}**`));\n } else {\n matchers.push(globToMatcher(pattern));\n // Also match as directory (e.g. \"dist\" should match \"dist/\" and \"dist/**\")\n if (!pattern.includes(\"*\") && !pattern.includes(\".\")) {\n matchers.push(globToMatcher(`${pattern}/**`));\n }\n }\n }\n\n return matchers;\n } catch {\n return [];\n }\n}\n\ntype ChokidarAction = \"create\" | \"edit\" | \"delete\";\n\nconst CHOKIDAR_EVENT_MAP: Record<string, ChokidarAction> = {\n add: \"create\",\n change: \"edit\",\n unlink: \"delete\",\n addDir: \"create\",\n unlinkDir: \"delete\",\n};\n\n/**\n * Create a cross-platform filesystem watcher on `rootDir` using chokidar.\n * Auto-reads `.gitignore` from `rootDir` and merges those patterns into the ignore list.\n * @param rootDir - Absolute path to the directory to watch.\n * @param callback - Called with each `ConnectorChangeEvent` (create / edit / delete).\n * @param options - Debounce interval and additional ignore patterns.\n * @returns A `WatchHandle` — call `.close()` to stop watching.\n * @docLink packages/connectors/api-reference#create-fs-watcher\n */\nexport async function createFsWatcher(\n rootDir: string,\n callback: (event: ConnectorChangeEvent) => void,\n options?: WatchOptions,\n): Promise<WatchHandle> {\n const log = createLogger({ kind: \"connector\", subkind: \"watcher\", instance: rootDir });\n const gitignorePatterns = parseGitignore(rootDir);\n // Convert any remaining string patterns from options to matcher functions\n // (chokidar 5 treats strings as exact equality, not globs)\n const optionsIgnored = (options?.ignored ?? []).map((entry) =>\n typeof entry === \"string\" ? globToMatcher(entry) : entry,\n );\n const ignored = [...DEFAULT_IGNORED, ...gitignorePatterns, ...optionsIgnored];\n const debounceMs = options?.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n\n const watcher = chokidar.watch(rootDir, {\n ignoreInitial: true,\n ignored,\n awaitWriteFinish: { stabilityThreshold: debounceMs, pollInterval: 50 },\n usePolling: false,\n });\n\n // Swallow transient watch errors (EINVAL/ENOENT when a file vanishes between\n // readdir and fs.watch). Without this handler, chokidar rethrows and the\n // agent process dies.\n watcher.on(\"error\", (err) => {\n const message = err instanceof Error ? err.message : String(err);\n log.warn(\"watcher error (non-fatal)\", { message });\n });\n\n for (const [chokidarEvent, action] of Object.entries(CHOKIDAR_EVENT_MAP)) {\n (watcher as { on(event: string, fn: (fullPath: string) => void): void }).on(\n chokidarEvent,\n (fullPath: string) => {\n const rel = relative(rootDir, fullPath);\n if (!rel || rel.startsWith(\"..\")) return;\n // Normalize to forward slashes\n const normalizedPath = rel.split(\"\\\\\").join(\"/\");\n callback({ path: normalizedPath, action, source: \"filesystem\" });\n },\n );\n }\n\n return {\n close: () => watcher.close(),\n };\n}\n","/**\n * RcloneProcessManager — supervises an rclone FUSE subprocess per mount.\n *\n * Responsibilities:\n * - Spawn rclone with a per-mount config + cache dir, wait for the FUSE\n * mountpoint to appear, then return a handle.\n * - Pipe rclone's JSON-formatted log lines into the parent driver's\n * {@link Logger} via a child source `${driverName}+rclone`.\n * - Coordinate graceful stop (flush → SIGTERM → fusermount fallback).\n * - Expose `flush` (POST /vfs/refresh + poll /vfs/stats), `statSize`\n * (operations/stat → authoritative remote size, backing the read-path\n * stale-tail gate) and `status` (process liveness + cache-dir size).\n *\n * Cross-link: see `workspaces/core/CLAUDE.md` § Logging for the\n * `createLogger` / `LogStore` contract, and\n * `_devlog/specs/2026-05-01-debug-logging-design.md` for the source taxonomy.\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport {\n cp,\n mkdir,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport type { Readable } from \"node:stream\";\nimport type { Logger } from \"@skaile/workspaces/types\";\nimport { ensureDirMode } from \"./fs-utils.js\";\nimport { PortPool } from \"./port-pool.js\";\nimport { DEFAULT_DEBOUNCE_MS } from \"./watcher.js\";\n\n/** Module-level pool for rclone remote-control (rc) ports. */\nconst RCLONE_RC_PORTS = new PortPool([55000, 56000]);\n\n/** Default rclone `--vfs-write-back` delay; raised from 5s so a rapidly-rewritten file settles before upload (avoids mid-write \"sizes differ\" aborts). */\nexport const DEFAULT_VFS_WRITE_BACK = \"30s\";\n\n/** Consecutive failed upload retries for one object before a stuck-upload error is surfaced. */\nexport const DEFAULT_UPLOAD_STUCK_THRESHOLD = 3;\n\n/**\n * Stabilization gate defaults for {@link RcloneProcessManager.flush}. Before\n * forcing an upload we wait until the vfs cache dir has had no write for\n * `thresholdMs`, bounded by `timeoutMs` so close/hibernate never blocks\n * forever. `pollMs` reuses the watcher's write-stabilization debounce.\n */\nconst STABILIZE_THRESHOLD_MS = 1_500;\nconst STABILIZE_TIMEOUT_MS = 30_000;\nconst STABILIZE_POLL_MS = DEFAULT_DEBOUNCE_MS;\n\n/**\n * Spawn-time configuration for a single rclone FUSE mount.\n * @docLink packages/connectors/api-reference#rclone-spawn-config\n */\nexport interface RcloneSpawnConfig {\n /** Logical mount id; used as `instance` and as part of the rclone config filename. */\n mountId: string;\n /**\n * Driver name (e.g. \"sharepoint\", \"webdav\"); used to derive the rclone\n * subprocess child logger subkind: `${driverName}+rclone`.\n */\n driverName: string;\n /** Absolute path inside the container where rclone will FUSE-mount. Created if missing. */\n mountPoint: string;\n /** Absolute path inside the container for the vfs cache. Created if missing. */\n cacheDir: string;\n /** Full INI text for rclone.conf (one [remote] section, named `skaile-<mountId>`). */\n rcloneConfig: string;\n /** Remote spec, e.g. `skaile-foo:/Clients/KADK`. */\n remote: string;\n /** rclone --vfs-cache-mode value. */\n vfsCacheMode: \"minimal\" | \"writes\" | \"full\";\n /** Per-mount cache size cap. Default: '5G'. */\n cacheMaxSize?: string;\n /** Per-mount cache age cap. Default: '168h'. */\n cacheMaxAge?: string;\n /**\n * Skip rclone's post-transfer size + checksum verification by appending\n * `--ignore-size --ignore-checksum`. Default: false (verification on).\n *\n * Escape hatch for remotes that mutate uploaded bytes server-side (notably\n * SharePoint Online normalising LF→CRLF on text/html), which makes the\n * remote object a different size/hash than the local source. rclone reads\n * that as `corrupted on transfer`, deletes the upload, and retries forever,\n * so the file never durably lands. Enabling this trades integrity\n * verification for sync-ability and must only be set by drivers that have\n * confirmed the mutation is benign. Off-by-default; wired per-driver, never\n * globally.\n */\n ignoreSizeCheck?: boolean;\n /**\n * rclone `--vfs-write-back` delay (e.g. '30s', '1m'). Controls how long a\n * dirty file sits before rclone starts uploading it. Default:\n * {@link DEFAULT_VFS_WRITE_BACK}. Raise it when the agent rewrites files\n * faster than they upload, to avoid mid-write \"sizes differ\" aborts.\n */\n vfsWriteBack?: string;\n /**\n * Consecutive upload retries for one object before {@link onUploadStuck}\n * fires. Default: {@link DEFAULT_UPLOAD_STUCK_THRESHOLD}.\n */\n uploadStuckThreshold?: number;\n /**\n * Optional hook invoked once per object when its upload has failed\n * `uploadStuckThreshold` times in a row. spawn() always also logs an\n * error-level entry through the `${driverName}+rclone` child logger; this\n * hook lets callers surface the stranded file elsewhere (e.g. a sync event).\n */\n onUploadStuck?: (object: string, tries: number) => void;\n /**\n * Optional hook invoked when rclone reports an OAuth auth failure (notably\n * `invalid_client` / `couldn't fetch token`, the symptom of an expired\n * access token that rclone cannot self-refresh). Wired by the mount driver\n * to the reactive arm of its token-refresh controller. Fires per matching\n * log line; the controller dedupes via its in-flight guard + cooldown.\n */\n onAuthError?: () => void;\n /**\n * Parent driver Logger — already tagged\n * `{kind:\"mount\", subkind:<driver>, instance:<mountId>}` by ConnectorManager.\n * Used for manager-level events; rclone subprocess events go through the\n * derived `child({subkind: \\`${driverName}+rclone\\`})` logger.\n */\n log: Logger;\n}\n\n/**\n * Handle returned by `RcloneProcessManager.spawn()` once the FUSE mountpoint is confirmed.\n * @docLink packages/connectors/api-reference#rclone-handle\n */\nexport interface RcloneHandle {\n /** OS process id of the rclone subprocess. */\n pid: number;\n /** Confirmed FUSE mountpoint (echo of input). */\n mountPoint: string;\n /** Cache directory (echo of input). */\n cacheDir: string;\n /** The local rc API address rclone is bound to, e.g. '127.0.0.1:54321'. */\n rcAddr: string;\n}\n\ninterface InternalEntry {\n proc: ChildProcess;\n configPath: string;\n port: number;\n mountPoint: string;\n cacheDir: string;\n /** The full spawn config, retained so `reconfigure` can recycle the process. */\n spawnConfig: RcloneSpawnConfig;\n log: Logger;\n rcloneLog: Logger;\n /**\n * Last few stderr lines for diagnostic purposes (used in spawn-failure\n * messages).\n */\n recentStderr: string[];\n}\n\nconst HANDLES = new Map<number, InternalEntry>();\n\n/**\n * Manages rclone FUSE subprocesses for mount drivers. Stateless across instances —\n * the internal handle registry is module-scoped so a fresh `RcloneProcessManager`\n * can still find handles created by a previous instance.\n * @docLink packages/connectors/api-reference#rclone-process-manager\n */\nexport class RcloneProcessManager {\n /**\n * @param now Injectable clock (ms) used only to timestamp the quarantine dir\n * on a poisoned-cache reset, so the move-aside name is deterministic in tests.\n */\n constructor(private readonly now: () => number = Date.now) {}\n\n /**\n * Spawn an rclone FUSE mount with one-shot poisoned-cache recovery. Delegates\n * to {@link spawnOnce}; if that fails specifically because the persistent VFS\n * cache was poisoned (a prior container SIGKILLed mid-write left `vfs`/`vfsMeta`\n * referencing missing backing files), quarantine the cache and retry the mount\n * exactly once on a clean rebuild from the authoritative remote.\n *\n * The retry is single-shot and bounded: if the fresh-cache mount also fails the\n * cause is connectivity/token (not the cache), so the error propagates without\n * a second reset — never a reset/respawn loop. A non-poison failure, or a\n * poison failure with nothing to quarantine, propagates immediately.\n */\n async spawn(config: RcloneSpawnConfig): Promise<RcloneHandle> {\n try {\n return await this.spawnOnce(config);\n } catch (err) {\n if (!(err instanceof CachePoisonedMountError)) throw err;\n let quarantined: string | null;\n try {\n quarantined = await quarantineCacheDir(config.cacheDir, this.now());\n } catch (qErr) {\n // Quarantine itself failed (disk full, EPERM) — surface the ORIGINAL\n // mount error, not the quarantine error, so triage sees the real cause.\n config.log.warn(\"rclone vfs-cache quarantine failed — surfacing original mount error\", {\n cacheDir: config.cacheDir,\n error: qErr instanceof Error ? qErr.message : String(qErr),\n });\n throw err;\n }\n if (!quarantined) {\n // Nothing to quarantine — not actually a poisoned cache; rethrow.\n throw err;\n }\n config.log.warn(\n \"rclone mount failed on a poisoned vfs cache — quarantined it and retrying the mount once\",\n { cacheDir: config.cacheDir, quarantined },\n );\n // Single retry on the now-clean cache. If this also fails, propagate —\n // do NOT quarantine/retry again (the cause is no longer the cache).\n return await this.spawnOnce(config);\n }\n }\n\n /**\n * Spawn an rclone FUSE mount. Resolves once the mountpoint is confirmed\n * present in `/proc/self/mounts`. Throws on timeout, on early exit, or\n * if invariants are violated. A readiness-timeout accompanied by the\n * poisoned-cache log signature throws {@link CachePoisonedMountError} so the\n * public {@link spawn} can apply its quarantine-and-retry recovery.\n */\n protected async spawnOnce(config: RcloneSpawnConfig): Promise<RcloneHandle> {\n if (!path.isAbsolute(config.mountPoint)) {\n throw new Error(`mountPoint must be absolute: ${config.mountPoint}`);\n }\n if (!path.isAbsolute(config.cacheDir)) {\n throw new Error(`cacheDir must be absolute: ${config.cacheDir}`);\n }\n\n // Defence-in-depth: the per-connector driver already chmods these via\n // ensureDirMode, but direct callers that bypass the driver still need\n // mountPoint and cacheDir to be group-writable for fusermount3 / vfs.\n await ensureDirMode(config.mountPoint, config.log);\n await ensureDirMode(config.cacheDir, config.log);\n\n const configPath = path.join(\n tmpdir(),\n `rclone-${config.mountId}-${randomBytes(6).toString(\"hex\")}.conf`,\n );\n await writeFile(configPath, config.rcloneConfig, { mode: 0o600 });\n\n const port = await RCLONE_RC_PORTS.allocate();\n const rcAddr = `127.0.0.1:${port}`;\n const rcloneLog = config.log.child({ subkind: `${config.driverName}+rclone` });\n\n config.log.info(\"rclone spawn starting\", {\n mountPoint: config.mountPoint,\n remote: config.remote,\n vfsCacheMode: config.vfsCacheMode,\n });\n\n const args = _buildRcloneArgs(config, { configPath, rcAddr });\n\n const proc = spawn(\"rclone\", args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\n // Per-process tracker for the upload-stuck observability gate. When an\n // object's upload retry count crosses the threshold we log once at error\n // level (the stream otherwise stays at INFO and the failure is silent).\n const routeCtx: RcloneLogRouteContext = {\n stuckThreshold: config.uploadStuckThreshold ?? DEFAULT_UPLOAD_STUCK_THRESHOLD,\n alertedObjects: new Set<string>(),\n itemNotFoundCounts: new Map<string, number>(),\n onUploadStuck: (object, tries) => {\n rcloneLog.error(\n \"rclone upload repeatedly failing — file may be stranded in this session's cache\",\n undefined,\n { object, tries, event: \"sync_status\", phase: \"error\" },\n );\n config.onUploadStuck?.(object, tries);\n },\n onAuthError: config.onAuthError,\n };\n\n const recentStderr: string[] = [];\n const stderrTail = (line: string) => {\n recentStderr.push(line);\n if (recentStderr.length > 20) recentStderr.shift();\n };\n\n // Set once if any rclone log line carries the poisoned-cache signature, so a\n // subsequent mount-readiness failure is classified as recoverable. Applied to\n // the RAW line so it matches whether rclone emits JSON or plaintext (the\n // signature is a substring of the JSON-encoded `msg` either way).\n let cachePoisonObserved = false;\n const noteCachePoison = (line: string) => {\n if (!cachePoisonObserved && _isCachePoisonLine(line)) cachePoisonObserved = true;\n };\n\n const stdoutHandler = (line: string) => {\n noteCachePoison(line);\n _routeRcloneLogLine(line, rcloneLog, routeCtx);\n };\n const stderrHandler = (line: string) => {\n stderrTail(line);\n noteCachePoison(line);\n _routeRcloneLogLine(line, rcloneLog, routeCtx);\n };\n\n if (proc.stdout) attachLineSplitter(proc.stdout, stdoutHandler);\n if (proc.stderr) attachLineSplitter(proc.stderr, stderrHandler);\n\n let earlyExitCode: number | null = null;\n let earlyExitSignal: NodeJS.Signals | null = null;\n const earlyExit = new Promise<void>((resolve) => {\n proc.once(\"exit\", (code, signal) => {\n earlyExitCode = code;\n earlyExitSignal = signal;\n resolve();\n });\n });\n\n const mountReady = waitFor(\n async () => {\n if (earlyExitCode !== null || earlyExitSignal !== null) return false;\n return await isMountpoint(config.mountPoint);\n },\n { timeoutMs: 15_000, intervalMs: 100 },\n );\n\n const ready = await Promise.race([mountReady, earlyExit.then(() => false)]);\n\n if (!ready) {\n try {\n if (proc.exitCode === null && proc.signalCode === null) {\n proc.kill(\"SIGKILL\");\n }\n } catch {\n // ignore\n }\n await unlink(configPath).catch(() => {});\n RCLONE_RC_PORTS.release(port);\n const tail =\n recentStderr.length > 0 ? `\\nstderr tail:\\n${recentStderr.slice(-5).join(\"\\n\")}` : \"\";\n const message = `rclone failed to mount ${config.remote} at ${config.mountPoint}${tail}`;\n // A poisoned cache is recoverable — signal spawn() to quarantine + retry.\n if (cachePoisonObserved) {\n throw new CachePoisonedMountError(message);\n }\n throw new Error(message);\n }\n\n const pid = proc.pid;\n if (pid === undefined) {\n // Should never happen if mountReady resolved true, but defend anyway.\n proc.kill(\"SIGKILL\");\n await unlink(configPath).catch(() => {});\n RCLONE_RC_PORTS.release(port);\n throw new Error(\"rclone process has no pid after successful mount\");\n }\n\n const entry: InternalEntry = {\n proc,\n configPath,\n port,\n mountPoint: config.mountPoint,\n cacheDir: config.cacheDir,\n spawnConfig: config,\n log: config.log,\n rcloneLog,\n recentStderr,\n };\n HANDLES.set(pid, entry);\n\n proc.on(\"exit\", (code) => {\n // If the entry is still in the registry, this was unplanned.\n if (HANDLES.has(pid)) {\n config.log.warn(\"rclone exited unexpectedly\", { code, pid });\n }\n });\n\n config.log.info(\"rclone mountpoint confirmed\", { pid });\n\n return { pid, mountPoint: config.mountPoint, cacheDir: config.cacheDir, rcAddr };\n }\n\n /**\n * Stop an rclone subprocess. Attempts a flush first, then SIGTERM, then\n * SIGKILL + fusermount3 if `graceMs` elapses without the mountpoint\n * disappearing.\n *\n * `graceMs` bounds both the flush stabilization gate and the SIGTERM→SIGKILL\n * window — it is *not* a single total wall-clock cap: the flush also waits on\n * rclone's `/vfs/stats` drain (its own 60s ceiling) between the two.\n */\n async stop(handle: RcloneHandle, opts?: { graceMs?: number }): Promise<void> {\n const graceMs = opts?.graceMs ?? 30_000;\n const entry = HANDLES.get(handle.pid);\n if (!entry) {\n return;\n }\n\n try {\n // Bound the stabilization gate by graceMs so stop() doesn't silently add\n // the full default stabilize timeout on top of the caller's budget.\n await this.flush(handle, { stabilizeTimeoutMs: graceMs });\n } catch (err) {\n entry.log.warn(\"rclone flush before stop failed\", {\n pid: handle.pid,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n entry.log.info(\"rclone stop initiated\", { pid: handle.pid });\n\n // Remove FIRST so the exit handler doesn't fire the unplanned-exit warning.\n HANDLES.delete(handle.pid);\n\n try {\n entry.proc.kill(\"SIGTERM\");\n } catch {\n // ignore — process may already be gone\n }\n\n const unmounted = await waitFor(async () => !(await isMountpoint(entry.mountPoint)), {\n timeoutMs: graceMs,\n intervalMs: 200,\n });\n\n if (!unmounted) {\n try {\n entry.proc.kill(\"SIGKILL\");\n } catch {\n // ignore\n }\n await new Promise<void>((resolve) => {\n const fuse = spawn(\"fusermount3\", [\"-u\", entry.mountPoint], { stdio: \"ignore\" });\n fuse.once(\"exit\", () => resolve());\n fuse.once(\"error\", () => resolve());\n });\n entry.log.warn(\"rclone hard-killed\", { pid: handle.pid });\n }\n\n RCLONE_RC_PORTS.release(entry.port);\n await unlink(entry.configPath).catch(() => {});\n }\n\n /**\n * Apply a freshly-rendered rclone INI to a running mount by recycling the\n * process: flush + stop the current rclone, then re-spawn at the same\n * mountpoint/cacheDir with the new config. Returns the new handle.\n *\n * rclone holds the OAuth token in memory (baked into the config at spawn);\n * there is no rc command to swap it on a live `onedrive` backend, so a\n * recycle is the reliable way to apply a refreshed token. The vfs cache dir\n * is reused, so the remount revalidates rather than re-downloads. During the\n * brief unmount window the read-only mount-placeholder barrier underneath is\n * exposed (writes fail with EROFS, not EIO) — see ConnectorManager's\n * read-only-until-ready guarantee.\n */\n async reconfigure(handle: RcloneHandle, rcloneConfig: string): Promise<RcloneHandle> {\n const entry = HANDLES.get(handle.pid);\n if (!entry) {\n throw new Error(`rclone handle not found (pid=${handle.pid})`);\n }\n const nextConfig: RcloneSpawnConfig = { ...entry.spawnConfig, rcloneConfig };\n entry.log.info(\"rclone reconfigure — recycling process to apply refreshed credential\", {\n pid: handle.pid,\n });\n await this.stop(handle, { graceMs: 30_000 });\n return this.spawn(nextConfig);\n }\n\n /**\n * Force rclone to upload pending writes, then wait until the in-use\n * counter reaches zero.\n *\n * Before issuing the refresh it waits for the vfs cache dir to go quiescent\n * (no write for `stabilityThresholdMs`, bounded by `stabilizeTimeoutMs`) so a\n * close/hibernate-triggered flush doesn't snapshot a half-written file and\n * trigger rclone's mid-write \"sizes differ\" abort. Pass `stabilize: false`\n * to skip the gate.\n */\n async flush(\n handle: RcloneHandle,\n opts?: { stabilize?: boolean; stabilityThresholdMs?: number; stabilizeTimeoutMs?: number },\n ): Promise<void> {\n const entry = HANDLES.get(handle.pid);\n if (!entry) {\n throw new Error(`rclone handle not found (pid=${handle.pid})`);\n }\n\n if (opts?.stabilize !== false) {\n const thresholdMs = opts?.stabilityThresholdMs ?? STABILIZE_THRESHOLD_MS;\n const timeoutMs = opts?.stabilizeTimeoutMs ?? STABILIZE_TIMEOUT_MS;\n // Scan only the vfs content subtree (agent writes land here). The sibling\n // `vfsMeta/` tree is rclone housekeeping whose churn would never settle.\n const scanDir = await vfsContentDir(entry.cacheDir);\n const quiescent = await awaitQuiescent(scanDir, {\n thresholdMs,\n timeoutMs,\n pollMs: STABILIZE_POLL_MS,\n });\n if (!quiescent) {\n entry.log.warn(\"rclone cache did not stabilize before flush — proceeding anyway\", {\n pid: handle.pid,\n thresholdMs,\n timeoutMs,\n });\n }\n }\n\n const refreshRes = await fetch(`http://${handle.rcAddr}/vfs/refresh?recursive=true`, {\n method: \"POST\",\n });\n if (!refreshRes.ok) {\n const body = await refreshRes.text().catch(() => \"\");\n throw new Error(`rclone /vfs/refresh failed: ${refreshRes.status} ${body}`);\n }\n\n const ok = await waitFor(\n async () => {\n const r = await fetch(`http://${handle.rcAddr}/vfs/stats`, { method: \"GET\" });\n if (!r.ok) return false;\n const body = (await r.json()) as { inUse?: number; [k: string]: unknown };\n return body.inUse === 0;\n },\n { timeoutMs: 60_000, intervalMs: 500 },\n );\n if (!ok) {\n throw new Error(`rclone flush did not drain within 60s (pid=${handle.pid})`);\n }\n }\n\n /**\n * Authoritative remote byte size for a mount-relative path, via rclone's\n * `operations/stat` rc endpoint. Backs the mount read-path stale-tail gate:\n * `operations/stat` hits the backend object directly, so it returns the true\n * remote size even when the VFS cache is serving a non-truncated item (and\n * `statSync` on the FUSE mount reports the inflated length). Returns `null`\n * when the handle is unknown, the object is missing / a directory, or the\n * call fails — the caller then trusts the on-disk bytes.\n */\n async statSize(handle: RcloneHandle, relPath: string): Promise<number | null> {\n const entry = HANDLES.get(handle.pid);\n if (!entry) return null;\n return fetchAuthoritativeSize(handle.rcAddr, entry.spawnConfig.remote, relPath);\n }\n\n /** Liveness + cache-dir size. */\n async status(handle: RcloneHandle): Promise<{ alive: boolean; cacheBytes: number }> {\n const entry = HANDLES.get(handle.pid);\n if (!entry) {\n return { alive: false, cacheBytes: 0 };\n }\n const alive = entry.proc.exitCode === null && entry.proc.signalCode === null;\n const cacheBytes = await dirSize(entry.cacheDir);\n return { alive, cacheBytes };\n }\n}\n\ninterface RcloneJsonLine {\n level?: string;\n msg?: string;\n source?: string;\n time?: string;\n object?: string;\n error?: unknown;\n}\n\n/**\n * Per-process state threaded through {@link _routeRcloneLogLine} so it can\n * detect a sustained upload failure (the same object failing to upload K times\n * in a row) and surface it exactly once, instead of letting rclone retry\n * silently at INFO level forever.\n */\nexport interface RcloneLogRouteContext {\n /** Consecutive retries for one object before {@link onUploadStuck} fires. */\n stuckThreshold?: number;\n /** Objects already alerted on, to fire once and not on every later retry. */\n alertedObjects?: Set<string>;\n /** Per-object consecutive `itemNotFound` count; escalates at {@link stuckThreshold}. */\n itemNotFoundCounts?: Map<string, number>;\n /** Called the first time an object crosses {@link stuckThreshold}. */\n onUploadStuck?: (object: string, tries: number) => void;\n /** Called when a line matches an OAuth auth-failure pattern. */\n onAuthError?: () => void;\n}\n\n/** rclone's vfs write-back failure line: \"... failed to upload try #3, will retry ...\". */\nconst UPLOAD_FAIL_RE = /failed to upload.*?try #(\\d+)/i;\n/** rclone's vfs write-back success line, used to reset the per-object alert. */\nconst UPLOAD_OK_RE = /upload succeeded/i;\n/**\n * OAuth token-level failures rclone emits when the access token is expired and\n * it cannot self-refresh (the Skaile-managed-Entra `client_secret`-stripped\n * case). `invalid_client` / `couldn't fetch token` is the confirmed prod\n * symptom; the rest cover the equivalent MSAL/refresh-grant token failures.\n * Bare HTTP `401` is intentionally excluded — rclone retries many transient\n * 401s internally without needing a token refresh; only these token-level\n * failures mean rclone is stuck.\n */\nconst AUTH_FAIL_RE =\n /invalid_client|couldn'?t fetch token|invalid_grant|InvalidAuthenticationToken/i;\n/**\n * `itemNotFound` = OneDrive/SharePoint Graph 404 on upload: transient (indexing lag,\n * self-heals on respawn) vs permanent (update-session invalidated — fixed in _buildRcloneArgs,\n * not this threshold). Counted per-object; escalates at stuck threshold. See connectors/CLAUDE.md.\n */\nconst ITEM_NOT_FOUND_RE = /itemNotFound/i;\n\n/**\n * rclone's poisoned-VFS-cache signature. A container SIGKILLed mid-write leaves\n * the persistent `--vfs-cache-mode full` write-back cache (`vfs` + `vfsMeta`)\n * inconsistent — entries reference backing files that no longer exist. On the\n * next spawn rclone replays that backlog on every boot, fails to reload, and\n * never attaches the FUSE mountpoint (the readiness probe times out). The two\n * phrasings rclone emits are \"failed to reload item\" and \"failed to add virtual\n * dir entry\"; matching either flags the failure as cache-poisoning so spawn can\n * quarantine the cache and retry once on a clean rebuild from the remote.\n */\nconst CACHE_POISON_RE = /failed to reload item|failed to add virtual dir entry/i;\n\n/**\n * Thrown by {@link RcloneProcessManager.spawnOnce} when a mount-readiness\n * failure was accompanied by the {@link CACHE_POISON_RE} signature, so\n * {@link RcloneProcessManager.spawn} knows the failure is a recoverable\n * poisoned cache (quarantine + single retry) rather than a connectivity/token\n * fault. Its `message` is the full mount-failure detail (including the stderr\n * tail), so surfacing it directly when recovery declines loses no diagnostics.\n */\nexport class CachePoisonedMountError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CachePoisonedMountError\";\n }\n}\n\n/**\n * @internal\n * True when an rclone log line carries the poisoned-VFS-cache signature\n * ({@link CACHE_POISON_RE}). Exported for tests; not part of the public API.\n */\nexport function _isCachePoisonLine(line: string): boolean {\n return CACHE_POISON_RE.test(line);\n}\n\n/**\n * Move a poisoned rclone VFS cache aside so the next spawn rebuilds a clean one\n * from the authoritative remote. Moves `<cacheDir>/vfs` + `<cacheDir>/vfsMeta`\n * (whichever exist) into `<cacheDir>/.corrupt-<ISO>` — a move-aside, never a\n * delete, so any (junk) un-uploaded bytes stay recoverable for forensics. The\n * quarantine dir is nested inside `cacheDir` (not a sibling) so it lives within\n * the per-session cache dir the platform removes wholesale on session close —\n * bounding its lifetime to the session — and rclone only reads its own\n * `vfs`/`vfsMeta` subdirs, so the dotted sibling is inert to the live mount.\n * (A bounded retain-N/reap-after-M GC of repeated resets within one long-lived\n * session is a follow-up; session-close cleanup covers the common case.)\n *\n * Returns the quarantine dir path when anything was moved, else `null` (nothing\n * to quarantine — the failure was not a poisoned cache). `nowMs` is injected for\n * deterministic test timestamps. Exported for tests; not part of the public API.\n */\nexport async function quarantineCacheDir(cacheDir: string, nowMs: number): Promise<string | null> {\n const stamp = new Date(nowMs).toISOString().replace(/[:.]/g, \"-\");\n const quarantineDir = path.join(cacheDir, `.corrupt-${stamp}`);\n // Create the destination parent BEFORE any rename so an ENOENT from rename\n // unambiguously means \"src is missing\" (not \"dst dir absent\"). An empty dir\n // (nothing moved) is cleaned up below.\n await mkdir(quarantineDir, { recursive: true });\n let moved = 0;\n for (const sub of [\"vfs\", \"vfsMeta\"] as const) {\n const src = path.join(cacheDir, sub);\n const dst = path.join(quarantineDir, sub);\n try {\n await rename(src, dst);\n } catch (err) {\n const code = (err as { code?: string } | null)?.code;\n if (code === \"ENOENT\") continue; // this cache sub doesn't exist — skip\n if (code === \"EXDEV\") {\n // Cross-device rename — fall back to copy + rm. Clean up a partial dst if\n // the copy fails, so a retry never sees a half-written quarantine (and\n // src stays put → move-aside semantics hold).\n try {\n await cp(src, dst, { recursive: true });\n } catch (cpErr) {\n await rm(dst, { recursive: true, force: true }).catch(() => undefined);\n throw cpErr;\n }\n await rm(src, { recursive: true, force: true });\n } else {\n throw err;\n }\n }\n moved += 1;\n }\n if (moved === 0) {\n // No cache subdir existed — drop the empty quarantine dir we made.\n await rm(quarantineDir, { recursive: true, force: true }).catch(() => undefined);\n return null;\n }\n return quarantineDir;\n}\n\n/**\n * @internal\n * Route a single rclone log line (JSON or raw) to the appropriate Logger\n * call. Exported for tests; not part of the public API. When `ctx` is\n * supplied, also tracks consecutive upload failures per object and invokes\n * `ctx.onUploadStuck` once the retry count for an object reaches the threshold.\n */\nexport function _routeRcloneLogLine(line: string, log: Logger, ctx?: RcloneLogRouteContext): void {\n const trimmed = line.trim();\n if (trimmed.length === 0) return;\n\n let parsed: RcloneJsonLine | null = null;\n try {\n const candidate = JSON.parse(trimmed);\n if (candidate && typeof candidate === \"object\") parsed = candidate as RcloneJsonLine;\n } catch {\n parsed = null;\n }\n\n if (!parsed) {\n if (ctx) {\n _trackUploadFailure(trimmed, undefined, ctx);\n if (AUTH_FAIL_RE.test(trimmed)) ctx.onAuthError?.();\n if (ITEM_NOT_FOUND_RE.test(trimmed)) _trackItemNotFound(undefined, trimmed, ctx);\n }\n log.info(trimmed);\n return;\n }\n\n const level = (parsed.level ?? \"INFO\").toUpperCase();\n const msg = parsed.msg ?? \"\";\n const data: Record<string, unknown> = {};\n if (parsed.object !== undefined) data.object = parsed.object;\n if (parsed.source !== undefined) data.source = parsed.source;\n\n if (ctx) {\n _trackUploadFailure(msg, parsed.object, ctx);\n const errText = typeof parsed.error === \"string\" ? parsed.error : \"\";\n if (AUTH_FAIL_RE.test(msg) || (errText && AUTH_FAIL_RE.test(errText))) ctx.onAuthError?.();\n if (ITEM_NOT_FOUND_RE.test(msg) || (errText && ITEM_NOT_FOUND_RE.test(errText))) {\n _trackItemNotFound(parsed.object, msg, ctx);\n }\n }\n\n switch (level) {\n case \"DEBUG\":\n log.debug(msg, data);\n break;\n case \"INFO\":\n case \"NOTICE\":\n log.info(msg, data);\n break;\n case \"WARNING\":\n log.warn(msg, data);\n break;\n case \"ERROR\":\n case \"CRITICAL\":\n case \"EMERGENCY\":\n case \"ALERT\":\n log.error(msg, parsed.error, data);\n break;\n default:\n log.info(msg, data);\n break;\n }\n}\n\n/**\n * @internal\n * Inspect one rclone message for an upload retry / success and update the\n * per-object alert state in `ctx`. Fires `onUploadStuck` once when an object's\n * retry count first reaches the threshold; a later success clears the alert so\n * a fresh failure run can re-trigger.\n */\nfunction _trackUploadFailure(\n msg: string,\n object: string | undefined,\n ctx: RcloneLogRouteContext,\n): void {\n const failMatch = UPLOAD_FAIL_RE.exec(msg);\n if (failMatch) {\n const tries = Number(failMatch[1]);\n const key = object ?? extractObjectFromMsg(msg) ?? \"(unknown)\";\n const threshold = ctx.stuckThreshold ?? DEFAULT_UPLOAD_STUCK_THRESHOLD;\n if (!ctx.alertedObjects) ctx.alertedObjects = new Set<string>();\n const alerted = ctx.alertedObjects;\n if (tries >= threshold && !alerted.has(key)) {\n alerted.add(key);\n ctx.onUploadStuck?.(key, tries);\n }\n return;\n }\n if (UPLOAD_OK_RE.test(msg)) {\n const key = object ?? extractObjectFromMsg(msg);\n if (key) {\n ctx.alertedObjects?.delete(key);\n ctx.itemNotFoundCounts?.delete(key);\n }\n }\n}\n\n/**\n * @internal\n * Track consecutive `itemNotFound` upload failures per object and surface via\n * `onUploadStuck` only once an object crosses the stuck threshold — the same gate\n * the retry-count path uses — rather than on the first occurrence, because\n * itemNotFound is often transient (see {@link ITEM_NOT_FOUND_RE}). A later upload\n * success clears the count (in {@link _trackUploadFailure}). Deduped against\n * `alertedObjects` so it fires at most once per stuck run, and shares that set\n * with the retry tracker so the two paths can't double-fire for one object.\n */\nfunction _trackItemNotFound(\n object: string | undefined,\n msg: string,\n ctx: RcloneLogRouteContext,\n): void {\n const key = object ?? extractObjectFromMsg(msg) ?? \"(unknown)\";\n if (!ctx.itemNotFoundCounts) ctx.itemNotFoundCounts = new Map<string, number>();\n if (!ctx.alertedObjects) ctx.alertedObjects = new Set<string>();\n const count = (ctx.itemNotFoundCounts.get(key) ?? 0) + 1;\n ctx.itemNotFoundCounts.set(key, count);\n const threshold = ctx.stuckThreshold ?? DEFAULT_UPLOAD_STUCK_THRESHOLD;\n if (count >= threshold && !ctx.alertedObjects.has(key)) {\n ctx.alertedObjects.add(key);\n ctx.onUploadStuck?.(key, count);\n }\n}\n\n/** Best-effort path extraction from a free-text rclone message. */\nfunction extractObjectFromMsg(msg: string): string | undefined {\n const m = /(?:^|\\s)([^\\s:]+\\/[^\\s:]+):/.exec(msg);\n return m?.[1];\n}\n\n/**\n * @internal\n * Build the `rclone mount` argv from a spawn config. Extracted from spawn() so\n * the flag wiring (notably `--vfs-write-back` and the conditional\n * `--ignore-size --ignore-checksum`) is unit-testable without actually\n * launching rclone. Exported for tests; not part of the public API.\n */\nexport function _buildRcloneArgs(\n config: RcloneSpawnConfig,\n io: { configPath: string; rcAddr: string },\n): string[] {\n const args = [\n \"mount\",\n config.remote,\n config.mountPoint,\n \"--config\",\n io.configPath,\n \"--cache-dir\",\n config.cacheDir,\n \"--vfs-cache-mode\",\n config.vfsCacheMode,\n \"--vfs-cache-max-size\",\n config.cacheMaxSize ?? \"5G\",\n \"--vfs-cache-max-age\",\n config.cacheMaxAge ?? \"168h\",\n \"--vfs-write-back\",\n config.vfsWriteBack ?? DEFAULT_VFS_WRITE_BACK,\n \"--vfs-cache-poll-interval\",\n \"60s\",\n \"--rc\",\n \"--rc-addr\",\n io.rcAddr,\n // loopback-only rc server — without no-auth, flush's POST /vfs/refresh 403s,\n // graceful stop fails, and the write-back cache is left dirty. Safe: nothing\n // external can reach 127.0.0.1:<port>.\n \"--rc-no-auth\",\n \"--log-level\",\n \"INFO\",\n \"--use-json-log\",\n \"--allow-other\",\n // The ro-tmpfs deferred-mount barrier is already mounted here; without this\n // rclone aborts with \"directory already mounted\". See mount-placeholder.ts.\n \"--allow-non-empty\",\n ];\n\n // Remotes that rewrite bytes on upload (SharePoint LF→CRLF) make the\n // post-transfer size/hash check fail and rclone rolls the upload back\n // forever. Both flags are needed: a byte change shifts size AND checksum.\n if (config.ignoreSizeCheck) {\n args.push(\"--ignore-size\", \"--ignore-checksum\");\n }\n\n // SharePoint invalidates rclone's resumable upload session on an in-place\n // UPDATE; a single-part PUT below 4Mi avoids it. Rationale + the ≥4Mi gap:\n // connectors/CLAUDE.md.\n if (config.driverName === \"sharepoint\") {\n args.push(\"--onedrive-upload-cutoff\", \"4Mi\");\n }\n\n return args;\n}\n\n/**\n * @internal\n * Split an rclone mount `remote` (`skaile-<id>:/base/path`) plus a\n * mount-relative path into the `{fs, remote}` pair rclone's `operations/stat`\n * rc command expects: `fs` is the backend root (`skaile-<id>:`) and `remote` is\n * the object path within it. Leading/trailing slashes are normalised away so\n * the join is stable regardless of how either side is slashed. Exported for\n * tests; not part of the public API.\n */\nexport function _operationsStatTarget(\n remote: string,\n relPath: string,\n): { fs: string; remote: string } {\n const colon = remote.indexOf(\":\");\n const fs = colon >= 0 ? remote.slice(0, colon + 1) : remote;\n const base = colon >= 0 ? remote.slice(colon + 1) : \"\";\n const joined = [base, relPath]\n .map((s) => s.replace(/^\\/+|\\/+$/g, \"\"))\n .filter((s) => s.length > 0)\n .join(\"/\");\n return { fs, remote: joined };\n}\n\n/**\n * Query rclone's `operations/stat` rc endpoint for the authoritative remote\n * size of `relPath` under `remote`. Returns the byte size, or `null` when the\n * object is missing, is a directory, the call fails, or the size is absent.\n *\n * Unlike a `statSync` on the FUSE mount, `operations/stat` resolves the object\n * against the backend directly, so it is not subject to the VFS cache's\n * non-truncated stale tail. Pass `fetchImpl` to test without a live rc server.\n */\nexport async function fetchAuthoritativeSize(\n rcAddr: string,\n remote: string,\n relPath: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<number | null> {\n const target = _operationsStatTarget(remote, relPath);\n try {\n const res = await fetchImpl(`http://${rcAddr}/operations/stat`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(target),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as { item?: { Size?: number; IsDir?: boolean } | null };\n const item = body.item;\n if (!item || item.IsDir === true) return null;\n return typeof item.Size === \"number\" && item.Size >= 0 ? item.Size : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Poll `dir` until its newest file mtime is at least `thresholdMs` in the past\n * (no write for that long), or `timeoutMs` elapses. Returns true if it went\n * quiescent, false on timeout. An empty/missing dir counts as quiescent.\n */\nexport async function awaitQuiescent(\n dir: string,\n opts: { thresholdMs: number; timeoutMs: number; pollMs: number },\n): Promise<boolean> {\n const deadline = Date.now() + opts.timeoutMs;\n for (;;) {\n const newest = await newestMtimeMs(dir);\n if (newest === null || Date.now() - newest >= opts.thresholdMs) return true;\n if (Date.now() >= deadline) return false;\n await sleep(opts.pollMs);\n }\n}\n\n/**\n * Resolve the rclone vfs content subtree (`<cacheDir>/vfs`) where cached file\n * data — and therefore agent writes — land, falling back to `cacheDir` itself\n * if that subtree doesn't exist yet. Keeps the stabilization gate off rclone's\n * `vfsMeta/` housekeeping tree.\n */\nasync function vfsContentDir(cacheDir: string): Promise<string> {\n const vfs = path.join(cacheDir, \"vfs\");\n try {\n return (await stat(vfs)).isDirectory() ? vfs : cacheDir;\n } catch {\n return cacheDir;\n }\n}\n\n/**\n * Recursively find the most recent file mtime (ms) under `dir`. Returns null if\n * the dir is missing or contains no files. Symlinks are skipped — rclone's\n * cache holds only regular files and dirs.\n */\nasync function newestMtimeMs(dir: string): Promise<number | null> {\n let newest: number | null = null;\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const e of entries) {\n const full = path.join(dir, String(e.name));\n if (e.isDirectory()) {\n const sub = await newestMtimeMs(full);\n if (sub !== null && (newest === null || sub > newest)) newest = sub;\n } else if (e.isFile()) {\n try {\n const s = await stat(full);\n if (newest === null || s.mtimeMs > newest) newest = s.mtimeMs;\n } catch {\n // ignore — file vanished between readdir and stat\n }\n }\n }\n } catch {\n return null;\n }\n return newest;\n}\n\n/**\n * @internal\n * Returns true if a FUSE mount is present at `mountPoint` in the given\n * /proc/self/mounts text. The fstype check (field 3, `fuse.*`) is essential:\n * the deferred-mount barrier leaves a `tmpfs` mounted at the same path, so a\n * path-only match would report the *barrier* as the confirmed mount and mask a\n * dead rclone process. Exported for tests; not part of the public API.\n */\nexport function _fuseMountPresent(procMountsText: string, mountPoint: string): boolean {\n const resolved = path.resolve(mountPoint);\n for (const raw of procMountsText.split(\"\\n\")) {\n if (raw.length === 0) continue;\n const fields = raw.split(/\\s+/);\n const mp = fields[1];\n const fstype = fields[2];\n if (!mp || !fstype) continue;\n // /proc/self/mounts encodes spaces as \\040; cheap decode.\n const decoded = mp.replace(/\\\\040/g, \" \");\n // User-space FUSE only (`fuse` or `fuse.<subtype>`); excludes the `fusectl`\n // kernel control fs. rclone mounts as `fuse.rclone`.\n if (decoded === resolved && (fstype === \"fuse\" || fstype.startsWith(\"fuse.\"))) return true;\n }\n return false;\n}\n\n/** Returns true if a FUSE mount (rclone) is live at `mountPoint`. */\nasync function isMountpoint(mountPoint: string): Promise<boolean> {\n try {\n const text = await readFile(\"/proc/self/mounts\", \"utf8\");\n return _fuseMountPresent(text, mountPoint);\n } catch {\n return false;\n }\n}\n\n/**\n * Poll `check` every `intervalMs` until it returns true or `timeoutMs`\n * elapses. Returns true on success, false on timeout.\n */\nasync function waitFor(\n check: () => Promise<boolean>,\n opts: { timeoutMs: number; intervalMs: number },\n): Promise<boolean> {\n const deadline = Date.now() + opts.timeoutMs;\n while (Date.now() < deadline) {\n if (await check()) return true;\n await sleep(opts.intervalMs);\n }\n return await check();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/** Wire a Readable to a per-line callback, buffering partial chunks. */\nfunction attachLineSplitter(stream: Readable, onLine: (line: string) => void): void {\n let buffer = \"\";\n stream.setEncoding(\"utf8\");\n stream.on(\"data\", (chunk: string) => {\n buffer += chunk;\n let idx = buffer.indexOf(\"\\n\");\n while (idx >= 0) {\n const line = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 1);\n if (line.length > 0) onLine(line);\n idx = buffer.indexOf(\"\\n\");\n }\n });\n stream.on(\"end\", () => {\n if (buffer.length > 0) {\n onLine(buffer);\n buffer = \"\";\n }\n });\n}\n\n/** Recursively sum file sizes under `dir`. Returns 0 if dir does not exist. */\nasync function dirSize(dir: string): Promise<number> {\n let total = 0;\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const e of entries) {\n const full = path.join(dir, String(e.name));\n if (e.isDirectory()) {\n total += await dirSize(full);\n } else if (e.isFile()) {\n try {\n const s = await stat(full);\n total += s.size;\n } catch {\n // ignore\n }\n }\n }\n } catch {\n return 0;\n }\n return total;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../asset-manager/src/install-agent.ts","../asset-manager/src/installer.ts"],"names":["parseYaml","basename","join","resolve","existsSync"],"mappings":"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","file":"chunk-4VPRAG35.js","sourcesContent":["/**\n * Agent installation — renders a GitAgent package (agent.yaml + SOUL.md + RULES.md)\n * into the framework-native format (`.claude/agents/<name>.md`, `.omp/agents/<name>/`,\n * `.codex/agents/<name>.toml`) and resolves abilities, contracts, fragments, and\n * prompt extensions from the workspace config along the way.\n *\n * System prompt phases (per agent):\n * 1. extends merge — inherit from parent agent.yaml if manifest.extends is set\n * 2. ability refs — read SKILL.md frontmatter from installed skills dir\n * 3. contract refs — locate CONTRACT.md files in the installed skills dir\n * 4. fragments — resolve framework fragments (agent-mode, handoff, etc.)\n * 5. prompt-extensions — load per-project markdown extensions from skaile.yaml\n *\n * Used by `installer.ts` (the asset-install path) and `skaile install`. Sub-agents\n * declared in `agent.yaml#requires` are installed flat (no nesting) in the same\n * deploy directory.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { basename, isAbsolute, join, relative, resolve } from \"node:path\";\nimport type { DriverTarget, SkWorkspaceConfig } from \"@skaile/workspaces/core\";\nimport { DRIVER_TARGETS } from \"@skaile/workspaces/core\";\nimport { parse as parseYaml } from \"yaml\";\nimport {\n type AbilityRef,\n type ConnectorRef,\n type ContractRef,\n type FragmentContext,\n loadPromptExtensions,\n resolveFragments,\n} from \"./fragments.js\";\nimport { type AgentManifest, type AgentRenderInput, renderAgentToFramework } from \"./renderers.js\";\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction readManifest(agentDir: string): AgentManifest | null {\n const yamlPath = join(agentDir, \"agent.yaml\");\n if (!existsSync(yamlPath)) return null;\n try {\n return parseYaml(readFileSync(yamlPath, \"utf-8\")) as AgentManifest;\n } catch {\n return null;\n }\n}\n\nfunction readFile(agentDir: string, name: string): string | null {\n const p = join(agentDir, name);\n if (!existsSync(p)) return null;\n try {\n return readFileSync(p, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/** Extract YAML frontmatter from a markdown file (content between first two --- delimiters). */\nfunction parseFrontmatter(content: string): Record<string, unknown> {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return {};\n try {\n return (parseYaml(match[1]!) as Record<string, unknown>) ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * Merge parent and child agent manifests.\n * Scalars: child wins. Arrays: parent + child, deduplicated.\n */\nfunction mergeManifests(parent: AgentManifest, child: AgentManifest): AgentManifest {\n const result: AgentManifest = { ...parent };\n for (const [k, val] of Object.entries(child) as [keyof AgentManifest, unknown][]) {\n if (val === undefined) continue;\n const parentVal = result[k as keyof AgentManifest];\n if (Array.isArray(val) && Array.isArray(parentVal)) {\n (result as Record<string, unknown>)[k] = [...new Set([...parentVal, ...val])];\n } else {\n (result as Record<string, unknown>)[k] = val;\n }\n }\n return result;\n}\n\n/**\n * Phase 1: inherit scalars/arrays from a parent agent when `manifest.extends` is set.\n * Returns the (possibly merged) manifest; pushes a warning when the parent is missing.\n */\nfunction applyExtendsMerge(\n manifest: AgentManifest,\n srcDir: string,\n warnings: string[],\n): AgentManifest {\n if (!manifest.extends) return manifest;\n const parentDir = resolve(srcDir, manifest.extends);\n const parentManifest = readManifest(parentDir);\n if (parentManifest) {\n return mergeManifests(parentManifest, manifest);\n }\n warnings.push(\n `extends: parent agent not found at \"${manifest.extends}\" (from ${srcDir}) — skipping inheritance`,\n );\n return manifest;\n}\n\n/** Phase 2: resolve ability refs — read description from installed SKILL.md files. */\nfunction resolveAbilityRefs(\n manifest: AgentManifest,\n workspaceRoot: string,\n skillsRelDir: string,\n): AbilityRef[] {\n const abilityRefs: AbilityRef[] = [];\n for (const name of manifest.abilities ?? []) {\n const skillMdPath = join(workspaceRoot, skillsRelDir, name, \"SKILL.md\");\n if (!existsSync(skillMdPath)) continue;\n try {\n const fm = parseFrontmatter(readFileSync(skillMdPath, \"utf-8\"));\n const desc = typeof fm.description === \"string\" ? fm.description : undefined;\n if (desc) abilityRefs.push({ name, description: desc });\n } catch {\n // skip unreadable SKILL.md\n }\n }\n return abilityRefs;\n}\n\n/** Phase 3: resolve contract refs — locate CONTRACT.md files in the skills dir. */\nfunction resolveContractRefs(\n manifest: AgentManifest,\n workspaceRoot: string,\n skillsRelDir: string,\n): ContractRef[] {\n const contractRefs: ContractRef[] = [];\n for (const name of manifest.contracts ?? []) {\n const contractAbsPath = join(workspaceRoot, skillsRelDir, name, \"CONTRACT.md\");\n if (!existsSync(contractAbsPath)) continue;\n contractRefs.push({ name, relativePath: relative(workspaceRoot, contractAbsPath) });\n }\n return contractRefs;\n}\n\n/** Phase 4: assemble the fragment context from the manifest, workspace config, and resolved refs. */\nfunction buildFragmentContext(\n manifest: AgentManifest,\n driverTarget: string,\n skillsRelDir: string,\n wsConfig: SkWorkspaceConfig | undefined,\n abilityRefs: AbilityRef[],\n contractRefs: ContractRef[],\n): FragmentContext {\n const subAgentNames = (manifest.requires ?? []).filter((r) => r.name).map((r) => r.name);\n\n const connectors: ConnectorRef[] = (wsConfig?.connectors ?? []).map((c) => ({\n id: c.id,\n driver: c.driver,\n access: c.access ?? \"read-write\",\n }));\n\n const agentsRelDir = DRIVER_TARGETS[driverTarget as DriverTarget]?.local.agent ?? \"\";\n\n return {\n framework: driverTarget,\n skillsDir: skillsRelDir,\n agentsDir: agentsRelDir,\n subAgents: subAgentNames,\n connectors,\n abilityRefs,\n contractRefs,\n };\n}\n\n// ── Core installation ─────────────────────────────────────────────────────────\n\n/**\n * Install a single GitAgent source directory using the appropriate renderer.\n *\n * When `includeSubAgents` is `true`, recursively installs `requires[]` entries as\n * separate flat agents in the same deploy directory (no nesting). Tracks visited\n * directories to prevent infinite loops in `requires[]` cycles.\n *\n * @param srcDir - Absolute path to the GitAgent source directory (contains `agent.yaml`).\n * @param agentDeployDir - Absolute path to the framework's agent deploy directory.\n * @param workspaceRoot - Absolute path to the workspace root.\n * @param driverTarget - Agent framework ID used to select the renderer.\n * @param skillsRelDir - Relative path to the installed skills dir (e.g. `\".claude/skills\"`).\n * @param nameOverride - Override name for the installed agent. Defaults to `manifest.name`.\n * @param includeSubAgents - When `true`, recursively install `requires[]` sub-agents.\n * @param visited - Set of resolved source paths already processed (cycle guard).\n * @param wsConfig - Workspace config from `skaile.yaml` (fragments, connectors, extensions).\n * @param log - Optional logger callback for progress messages.\n * @returns Object with `created` file paths and `warnings` list.\n * @docLink packages/asset-manager/concepts#install-agent\n */\nexport function installAgent(\n srcDir: string,\n agentDeployDir: string,\n workspaceRoot: string,\n driverTarget: string,\n /** Relative path to the installed skills dir (e.g. \".claude/skills\") */\n skillsRelDir: string,\n nameOverride: string | undefined,\n includeSubAgents: boolean,\n visited: Set<string>,\n wsConfig: SkWorkspaceConfig | undefined,\n log?: (msg: string) => void,\n): { created: string[]; warnings: string[] } {\n const created: string[] = [];\n const warnings: string[] = [];\n\n const realSrc = resolve(srcDir);\n if (visited.has(realSrc)) return { created, warnings };\n visited.add(realSrc);\n\n const initialManifest = readManifest(srcDir);\n if (!initialManifest) {\n warnings.push(`${srcDir} has no agent.yaml — skipping (not a valid GitAgent package)`);\n return { created, warnings };\n }\n\n // Phase 1: extends merge — inherit scalars/arrays from parent agent\n const manifest = applyExtendsMerge(initialManifest, srcDir, warnings);\n\n const agentName = nameOverride ?? manifest.name ?? basename(srcDir);\n\n log?.(`Installing git-agent: ${agentName} (${driverTarget})`);\n\n // Phase 2: resolve ability refs — read description from installed SKILL.md files\n const abilityRefs = resolveAbilityRefs(manifest, workspaceRoot, skillsRelDir);\n\n // Phase 3: resolve contract refs — locate CONTRACT.md files in the skills dir\n const contractRefs = resolveContractRefs(manifest, workspaceRoot, skillsRelDir);\n\n // Phase 4: build fragment context and resolve framework fragments + prompt extensions\n const fragmentCtx = buildFragmentContext(\n manifest,\n driverTarget,\n skillsRelDir,\n wsConfig,\n abilityRefs,\n contractRefs,\n );\n\n const frameworkFragments = resolveFragments(\n fragmentCtx,\n wsConfig?.agent?.fragments,\n workspaceRoot,\n );\n const promptExtensions = loadPromptExtensions(\n wsConfig?.agent?.[\"prompt-extensions\"],\n workspaceRoot,\n );\n\n const input: AgentRenderInput = {\n manifest,\n soul: readFile(srcDir, \"SOUL.md\"),\n rules: readFile(srcDir, \"RULES.md\"),\n duties: readFile(srcDir, \"DUTIES.md\"),\n agentName,\n agentDeployDir,\n workspaceRoot,\n abilityRefs,\n contractRefs,\n frameworkFragments,\n promptExtensions,\n };\n\n const result = renderAgentToFramework(input, driverTarget, log);\n created.push(...result.created);\n warnings.push(...result.warnings);\n\n // Recursively install sub-agents from requires[] as flat top-level agents\n if (includeSubAgents) {\n installSubAgents(manifest, agentName, srcDir, agentDeployDir, workspaceRoot, driverTarget, {\n skillsRelDir,\n includeSubAgents,\n visited,\n wsConfig,\n log,\n created,\n warnings,\n });\n }\n\n return { created, warnings };\n}\n\n/**\n * Recursively install `requires[]` entries as separate flat agents in the same deploy\n * directory. Appends rendered file paths and warnings into the shared `created`/`warnings`\n * arrays carried on `ctx`.\n */\nfunction installSubAgents(\n manifest: AgentManifest,\n agentName: string,\n srcDir: string,\n agentDeployDir: string,\n workspaceRoot: string,\n driverTarget: string,\n ctx: {\n skillsRelDir: string;\n includeSubAgents: boolean;\n visited: Set<string>;\n wsConfig: SkWorkspaceConfig | undefined;\n log?: (msg: string) => void;\n created: string[];\n warnings: string[];\n },\n): void {\n for (const req of manifest.requires ?? []) {\n if (!req.source || !req.name) continue;\n\n const subSrc = isAbsolute(req.source) ? req.source : resolve(srcDir, req.source);\n\n if (!existsSync(subSrc)) {\n ctx.warnings.push(`Sub-agent source not found: ${req.source} (from ${agentName})`);\n continue;\n }\n\n const sub = installAgent(\n subSrc,\n agentDeployDir,\n workspaceRoot,\n driverTarget,\n ctx.skillsRelDir,\n undefined, // use sub-agent's own name from its agent.yaml\n ctx.includeSubAgents,\n ctx.visited,\n ctx.wsConfig,\n ctx.log,\n );\n ctx.created.push(...sub.created);\n ctx.warnings.push(...sub.warnings);\n }\n}\n","/**\n * Asset deployment — symlink (local repos) or copy (remote repos) to framework dirs.\n */\n\nimport {\n cpSync,\n existsSync,\n lstatSync,\n mkdirSync,\n rmSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport type {\n AiComponent,\n CatalogEntry,\n DriverTarget,\n SourceDeclaration,\n} from \"@skaile/workspaces/core\";\nimport {\n applyPatch,\n computeHash,\n DRIVER_TARGETS,\n deployedBase,\n deployedDir,\n isDeployed,\n resolveSkWorkspaceConfig,\n} from \"@skaile/workspaces/core\";\nimport { installAgent } from \"./install-agent.js\";\nimport type { Log } from \"./renderers.js\";\n\nexport type { Log } from \"./renderers.js\";\n\nconst noop: Log = () => {};\n\n// ── Filesystem helpers ────────────────────────────────────────────────────────\n\nconst DIRECTORY_MANIFESTS = new Set([\"SKILL.md\", \"AGENT.md\", \"agent.yaml\", \"CONTRACT.md\"]);\n\nfunction clearDest(dest: string): void {\n try {\n const s = lstatSync(dest);\n if (s.isSymbolicLink()) unlinkSync(dest);\n else rmSync(dest, { recursive: true, force: true });\n } catch {}\n}\n\nfunction copyFromManifest(manifestPath: string, dest: string): void {\n const name = basename(manifestPath);\n const parentDir = dirname(manifestPath);\n clearDest(dest);\n\n if (DIRECTORY_MANIFESTS.has(name) || basename(parentDir) === basename(dest)) {\n cpSync(parentDir, dest, { recursive: true });\n } else {\n mkdirSync(dest, { recursive: true });\n cpSync(manifestPath, join(dest, name));\n }\n}\n\nfunction symlinkFromManifest(manifestPath: string, dest: string): void {\n const name = basename(manifestPath);\n const parentDir = dirname(manifestPath);\n clearDest(dest);\n mkdirSync(dirname(dest), { recursive: true });\n\n if (DIRECTORY_MANIFESTS.has(name) || basename(parentDir) === basename(dest)) {\n symlinkSync(resolve(parentDir), dest);\n } else {\n mkdirSync(dest, { recursive: true });\n symlinkSync(resolve(manifestPath), join(dest, name));\n }\n}\n\n// ── Deploy options ───────────────────────────────────────────────────────────\n\n/**\n * Options controlling where and how assets are deployed.\n *\n * @docLink packages/asset-manager/api-reference#installer\n */\nexport interface DeployOptions {\n /** Agent framework to target (determines framework-specific directory layout). Defaults to `\"claude-code\"`. */\n driverTarget?: DriverTarget;\n /** When `true`, deploy into the global Skaile cache rather than a project workspace. */\n global?: boolean;\n /** Absolute path to the workspace root. Defaults to `process.cwd()`. */\n cwd?: string;\n}\n\n// ── Deploy / remove ──────────────────────────────────────────────────────────\n\n/**\n * Deploy a single asset to the framework-specific directory.\n *\n * Uses symlinks for local-path repositories (fast, live-updating) and copies\n * for remote repositories (persists after repo wipes). Agents are rendered\n * via the enriched `installAgent` path which resolves abilities, contracts,\n * and framework fragments before writing the native agent file.\n *\n * @param entry - Catalog entry describing the asset to deploy.\n * @param repositories - Repository declarations from `skaile.yaml` (used to\n * determine whether the source is a local path or a remote clone).\n * @param opts - Deployment target options.\n * @param log - Optional logger callback for progress messages.\n * @returns `true` when the asset was deployed successfully.\n * @docLink packages/asset-manager/api-reference#installer\n */\nexport function deployAsset(\n entry: CatalogEntry,\n repositories: Record<string, SourceDeclaration>,\n opts: DeployOptions = {},\n log: Log = noop,\n): boolean {\n const driverTarget = opts.driverTarget ?? \"claude-code\";\n const globalInstall = opts.global ?? false;\n const cwd = opts.cwd;\n\n // Bundles are not deployed directly — their dependencies are.\n // MCP servers are configured in skaile.yaml, not deployed to driver target dirs.\n if (entry.kind === \"bundle\" || entry.kind === \"mcp-server\") return true;\n\n // Agents need framework-specific rendering via the enriched installAgent path\n if (entry.kind === \"agent\") {\n const workspaceRoot = cwd ?? process.cwd();\n const agentDeployDir = deployedBase(\n \"agent\" as AiComponent,\n driverTarget as DriverTarget,\n globalInstall,\n cwd,\n );\n const targetMap = DRIVER_TARGETS[driverTarget as DriverTarget];\n const skillsRelDir = targetMap?.local.skill ?? \"\";\n const wsConfig = resolveSkWorkspaceConfig(workspaceRoot);\n const name = basename(entry.source);\n const srcDir = DIRECTORY_MANIFESTS.has(name) ? dirname(entry.source) : entry.source;\n const result = installAgent(\n srcDir,\n agentDeployDir,\n workspaceRoot,\n driverTarget,\n skillsRelDir,\n entry.name,\n /* includeSubAgents */ true,\n new Set<string>(),\n wsConfig,\n log,\n );\n for (const w of result.warnings) log(` warn: ${w}`);\n if (result.created.length > 0) return true;\n // Fall through to raw deploy if renderer produces no files (unsupported framework, etc.)\n }\n\n const dest = deployedDir(entry.kind as AiComponent, entry.name, driverTarget, globalInstall, cwd);\n mkdirSync(dirname(dest), { recursive: true });\n\n // Determine if local or remote. Factory sources have a `path` (the bundled\n // dir under node_modules) but must be COPIED, not symlinked — the dir is\n // replaced on every package upgrade, so a symlink into it would dangle.\n const repoDecl = entry.publisher ? repositories[entry.publisher] : undefined;\n const isLocal = repoDecl?.path != null && repoDecl.factory !== true;\n\n if (isLocal) {\n symlinkFromManifest(entry.source, dest);\n log(` symlink ${entry.kind}:${entry.name}`);\n return true;\n } else {\n copyFromManifest(entry.source, dest);\n log(` copy ${entry.kind}:${entry.name}`);\n return true;\n }\n}\n\n/**\n * Deploy all resolved assets, applying patches where configured.\n *\n * Already-deployed assets are skipped unless their deployed manifest content differs\n * from the source. This handles copies (remote repos) that have gone stale after a\n * source update. Symlinked (local) repos always resolve to the live source, so their\n * hashes always match and they are never needlessly re-linked.\n *\n * @param resolved - Catalog entries to deploy (output of `resolveAll`).\n * @param repositories - Repository declarations from `skaile.yaml`.\n * @param patches - Map of `kind:name` → patch file path for patch application.\n * @param opts - Deployment target options.\n * @param log - Optional logger callback for progress messages.\n * @returns Array of asset refs (`kind:name`) that were newly deployed in this call.\n * @docLink packages/asset-manager/api-reference#installer\n */\nexport function deployAll(\n resolved: CatalogEntry[],\n repositories: Record<string, SourceDeclaration>,\n patches: Record<string, string>,\n opts: DeployOptions = {},\n log: Log = noop,\n): string[] {\n const deployed: string[] = [];\n const driverTarget = opts.driverTarget ?? \"claude-code\";\n const globalInstall = opts.global ?? false;\n const cwd = opts.cwd;\n\n for (const entry of resolved) {\n // Skip non-deployable asset kinds — bundles are resolved to their contents,\n // mcp-servers are wired at session startup, and mixin kinds (persona, ruleset,\n // knowledge) are resolved by the mixin-resolver at session creation time.\n if (\n entry.kind === \"bundle\" ||\n entry.kind === \"mcp-server\" ||\n entry.kind === \"persona\" ||\n entry.kind === \"ruleset\" ||\n entry.kind === \"knowledge\"\n )\n continue;\n\n const ref = `${entry.kind}:${entry.name}`;\n\n if (isDeployed(entry.kind as AiComponent, entry.name, driverTarget, globalInstall, cwd)) {\n // Compare the deployed manifest file against the source to detect stale copies.\n // For symlinks the deployed path resolves through to the source file, so hashes\n // always match — symlinked installs are never needlessly re-linked.\n const dest = deployedDir(\n entry.kind as AiComponent,\n entry.name,\n driverTarget,\n globalInstall,\n cwd,\n );\n const manifestName = basename(entry.source);\n const deployedManifest = join(dest, manifestName);\n try {\n const srcHash = computeHash(entry.source);\n const depHash = computeHash(deployedManifest);\n if (srcHash === depHash) {\n log(` already deployed: ${ref}`);\n continue;\n }\n log(` updating: ${ref} (content changed)`);\n // fall through to redeploy\n } catch {\n // Deployed manifest unreadable (e.g. agent rendered to a different path) — skip\n log(` already deployed: ${ref}`);\n continue;\n }\n }\n\n deployAsset(entry, repositories, opts, log);\n deployed.push(ref);\n\n // Apply patch if configured\n const patchFile = patches[ref];\n if (patchFile && existsSync(patchFile)) {\n const dest = deployedDir(\n entry.kind as AiComponent,\n entry.name,\n driverTarget,\n globalInstall,\n cwd,\n );\n if (applyPatch(dest, patchFile)) {\n log(` patched ${ref}`);\n } else {\n log(` patch failed for ${ref}`);\n }\n }\n }\n\n return deployed;\n}\n\n/**\n * Remove a deployed asset from the framework directory.\n *\n * Removes symlinks with `unlink`; removes copied directories with `rm -rf`.\n *\n * @param kind - Asset kind (`skill`, `agent`, `prompt`, `flow`, `contract`).\n * @param name - Asset name as registered in the catalog.\n * @param opts - Deployment target options (must match the options used at install time).\n * @returns `true` if the asset existed and was removed; `false` if it was not deployed.\n * @docLink packages/asset-manager/api-reference#installer\n */\nexport function removeAsset(kind: string, name: string, opts: DeployOptions = {}): boolean {\n const driverTarget = opts.driverTarget ?? \"claude-code\";\n const globalInstall = opts.global ?? false;\n const cwd = opts.cwd;\n\n const dest = deployedDir(kind as AiComponent, name, driverTarget, globalInstall, cwd);\n try {\n const s = lstatSync(dest);\n if (s.isSymbolicLink()) unlinkSync(dest);\n else rmSync(dest, { recursive: true, force: true });\n return true;\n } catch {\n return false;\n }\n}\n\n// ── Scaffold ─────────────────────────────────────────────────────────────────\n\nconst SKILL_TEMPLATE = `---\nname: \"{name}\"\ndescription: \"\"\nmetadata:\n version: \"0.1.0\"\n---\n\n# {name}\n\nSkill prompt goes here.\n`;\n\nconst BUNDLE_TEMPLATE = `name: {name}\ndescription: A curated set of assets\nversion: 0.1.0\ndependencies:\n - skill:example-skill\n`;\n\nconst FLOW_TEMPLATE = `id: \"{name}\"\nversion: \"0.1.0\"\nname: \"{name}\"\ndescription: Flow description\n\nglobals:\n approval_mode: checkpoint\n\nnodes: []\n`;\n\n/**\n * Create a minimal scaffold directory for a new asset.\n *\n * Writes the appropriate manifest file (`SKILL.md`, `AGENT.md`, `CONTRACT.md`,\n * `<name>.bundle.yaml`, `<name>.flow.yaml`, or `<name>.prompt.md`) inside a\n * new `<destDir>/<name>/` directory.\n *\n * @param name - Asset name (also used as the directory name).\n * @param kind - Asset kind: `skill` | `agent` | `bundle` | `flow` | `prompt` | `contract`.\n * @param destDir - Parent directory to create the asset in.\n * @returns `{ ok: true, path }` on success, `{ ok: false, path: errorMessage }` if the\n * directory already exists.\n * @docLink packages/asset-manager/api-reference#installer\n */\nexport function createScaffold(\n name: string,\n kind: string,\n destDir: string,\n): { ok: boolean; path: string } {\n const dest = join(destDir, name);\n if (existsSync(dest)) {\n return { ok: false, path: `Directory '${name}' already exists in ${destDir}` };\n }\n mkdirSync(dest, { recursive: true });\n\n if (kind === \"bundle\") {\n writeFileSync(\n join(dest, `${name}.bundle.yaml`),\n BUNDLE_TEMPLATE.replace(/\\{name\\}/g, name),\n \"utf8\",\n );\n } else if (kind === \"flow\") {\n writeFileSync(\n join(dest, `${name}.flow.yaml`),\n FLOW_TEMPLATE.replace(/\\{name\\}/g, name),\n \"utf8\",\n );\n } else if (kind === \"prompt\") {\n writeFileSync(\n join(dest, `${name}.prompt.md`),\n SKILL_TEMPLATE.replace(/\\{name\\}/g, name),\n \"utf8\",\n );\n } else if (kind === \"agent\") {\n writeFileSync(join(dest, \"AGENT.md\"), SKILL_TEMPLATE.replace(/\\{name\\}/g, name), \"utf8\");\n } else if (kind === \"contract\") {\n writeFileSync(join(dest, \"CONTRACT.md\"), SKILL_TEMPLATE.replace(/\\{name\\}/g, name), \"utf8\");\n } else {\n // Default: skill\n writeFileSync(join(dest, \"SKILL.md\"), SKILL_TEMPLATE.replace(/\\{name\\}/g, name), \"utf8\");\n }\n\n return { ok: true, path: dest };\n}\n"]}
|