@skaile/workspaces 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/{asset-feeds-JSHWTTJC.js → asset-feeds-CI76R7FI.js} +5 -5
- package/dist/{asset-feeds-JSHWTTJC.js.map → asset-feeds-CI76R7FI.js.map} +1 -1
- package/dist/asset-manager/index.js +5 -5
- package/dist/asset-manager/installer.js +4 -4
- package/dist/base-assets/connectors/deploy.js +5 -5
- package/dist/base-assets/connectors/devserver.js +5 -5
- package/dist/base-assets/connectors/flow/adapter.js +5 -5
- package/dist/base-assets/connectors/flow/run-flow.js +6 -6
- package/dist/base-assets/connectors/flow.js +5 -5
- package/dist/base-assets/connectors/git.js +5 -5
- package/dist/base-assets/connectors/gmail.js +5 -5
- package/dist/base-assets/connectors/googledrive.js +5 -5
- package/dist/base-assets/connectors/local.js +5 -5
- package/dist/base-assets/connectors/mattermost.js +5 -5
- package/dist/base-assets/connectors/memory.js +5 -5
- package/dist/base-assets/connectors/minio.js +5 -5
- package/dist/base-assets/connectors/postgres.js +5 -5
- package/dist/base-assets/connectors/redis.js +5 -5
- package/dist/base-assets/connectors/s3.js +5 -5
- package/dist/base-assets/connectors/sharepoint.js +5 -5
- package/dist/base-assets/connectors/sqlite.js +5 -5
- package/dist/base-assets/connectors/static-server.js +5 -5
- package/dist/base-assets/connectors/tunnel.js +5 -5
- package/dist/base-assets/connectors/webdav.js +5 -5
- package/dist/base-assets/connectors/xstate-store.js +5 -5
- package/dist/base-assets/connectors/xstate.js +5 -5
- package/dist/base-assets/connectors/yjs.js +5 -5
- package/dist/{chunk-2DKWQLFS.js → chunk-2WVQMRIE.js} +5 -5
- package/dist/{chunk-2DKWQLFS.js.map → chunk-2WVQMRIE.js.map} +1 -1
- package/dist/{chunk-VVS7MACX.js → chunk-5QNQLSBW.js} +193 -17
- package/dist/chunk-5QNQLSBW.js.map +1 -0
- package/dist/{chunk-4YG2AAFV.js → chunk-DEQ3OOTU.js} +6 -6
- package/dist/{chunk-4YG2AAFV.js.map → chunk-DEQ3OOTU.js.map} +1 -1
- package/dist/{chunk-R4FRSB47.js → chunk-DFUXWNTS.js} +3 -3
- package/dist/{chunk-R4FRSB47.js.map → chunk-DFUXWNTS.js.map} +1 -1
- package/dist/{chunk-FNP4OGGY.js → chunk-G4BR355S.js} +8 -8
- package/dist/{chunk-FNP4OGGY.js.map → chunk-G4BR355S.js.map} +1 -1
- package/dist/{chunk-LMDRMZ4F.js → chunk-H45ANMIU.js} +3 -3
- package/dist/{chunk-LMDRMZ4F.js.map → chunk-H45ANMIU.js.map} +1 -1
- package/dist/{chunk-KYYMP5PT.js → chunk-KFDTS7RX.js} +3 -3
- package/dist/{chunk-KYYMP5PT.js.map → chunk-KFDTS7RX.js.map} +1 -1
- package/dist/{chunk-BZGDESAG.js → chunk-RDH4SSMH.js} +2 -2
- package/dist/{chunk-BZGDESAG.js.map → chunk-RDH4SSMH.js.map} +1 -1
- package/dist/{chunk-2ACJB6JF.js → chunk-W5DFC35Z.js} +3 -3
- package/dist/{chunk-2ACJB6JF.js.map → chunk-W5DFC35Z.js.map} +1 -1
- package/dist/{chunk-IQYWI5OG.js → chunk-XAVM2BAJ.js} +4 -4
- package/dist/{chunk-IQYWI5OG.js.map → chunk-XAVM2BAJ.js.map} +1 -1
- package/dist/{chunk-RCPFXP3Y.js → chunk-XGWGLIHZ.js} +4 -4
- package/dist/{chunk-RCPFXP3Y.js.map → chunk-XGWGLIHZ.js.map} +1 -1
- package/dist/cli/index.js +16 -16
- package/dist/connectors/config.js +4 -4
- package/dist/connectors/index.js +5 -5
- package/dist/core/index.js +3 -3
- package/dist/core/runtime-assets.js +2 -2
- package/dist/core/src/index.d.ts +2 -2
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +54 -3
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/workspace-config.js +1 -1
- package/dist/{ensure-sources-LRT3TIWI.js → ensure-sources-IDVQ77NJ.js} +5 -5
- package/dist/{ensure-sources-LRT3TIWI.js.map → ensure-sources-IDVQ77NJ.js.map} +1 -1
- package/dist/runner/index.js +7 -7
- package/dist/sdk/asset-manager.js +5 -5
- package/dist/sdk/core.js +3 -3
- package/dist/sdk/index.js +7 -7
- package/dist/sdk/runner.js +7 -7
- package/dist/{setup-CJWJWYEO.js → setup-AIOLUTKV.js} +5 -5
- package/dist/{setup-CJWJWYEO.js.map → setup-AIOLUTKV.js.map} +1 -1
- package/dist/{store-client-H6BTDCA4.js → store-client-CYEH2GKC.js} +6 -6
- package/dist/{store-client-H6BTDCA4.js.map → store-client-CYEH2GKC.js.map} +1 -1
- package/dist/tui/index.js +7 -7
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-VVS7MACX.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../core/src/repo-manager.ts","../core/src/workspace-config.ts"],"names":["resolve","join","existsSync","mkdirSync","writeFileSync","stringify","homedir","parsePath","readFileSync","parse"],"mappings":"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","file":"chunk-VVS7MACX.js","sourcesContent":["/**\n * Repository operations — clone, pull, scan, resolve, link.\n *\n * Remote repos are cloned to a shared global cache (~/.skaile/repos/<name>/).\n * Projects reference the cache via symlinks at .skaile/repos/<name>/.\n * Local repos (path:) are used directly. Linked repos override remote URLs.\n *\n * Supports partial clone + sparse checkout for large repos.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n symlinkSync,\n lstatSync,\n writeFileSync,\n} from \"node:fs\";\nimport { resolve, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { parse, stringify } from \"yaml\";\nimport type { AssetRef, CatalogEntry } from \"./models.js\";\nimport { parseAssetRef } from \"./models.js\";\nimport type { RepositoryDeclaration } from \"./workspace-config.js\";\nimport { scanDirectory } from \"./manifest.js\";\n\n// ── Global cache ─────────────────────────────────────────────────────────────\n\n/**\n * Return the global shared repo cache directory (`~/.skaile/repos` by default).\n * Override with the `SKAILE_CACHE_DIR` environment variable.\n * @docLink packages/core/api-reference#get-global-cache-dir\n */\nexport function getGlobalCacheDir(): string {\n return process.env.SKAILE_CACHE_DIR ?? join(homedir(), \".skaile\", \"repos\");\n}\n\n// ── Git operations ───────────────────────────────────────────────────────────\n\n/**\n * Shared env for all git subprocess spawns.\n * GIT_TERMINAL_PROMPT=0 prevents git from opening /dev/tty to ask for\n * credentials when running inside a CLI spinner (which holds the terminal in\n * raw mode). Without this, git bypasses stdio: \"pipe\" and the process hangs\n * indefinitely waiting for input that can never arrive.\n */\nconst GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: \"0\" };\n\n/**\n * Clone a remote git repository using partial clone (treeless) with sparse checkout.\n * Falls back to a regular shallow clone if the server does not support partial clones.\n *\n * @param url - Remote git URL\n * @param branch - Branch to clone\n * @param dest - Local destination directory\n * @returns `true` on success, `false` on failure\n * @docLink packages/core/api-reference#clone-repo\n */\nexport function cloneRepo(url: string, branch: string, dest: string): boolean {\n mkdirSync(dest, { recursive: true });\n // Try partial clone first (requires git 2.25+ and server support)\n const r = spawnSync(\n \"git\",\n [\"clone\", \"--depth=1\", \"--filter=blob:none\", \"--sparse\", \"--branch\", branch, url, dest],\n { stdio: \"pipe\", env: GIT_ENV },\n );\n if (r.status === 0) {\n // Enable cone mode for sparse checkout\n spawnSync(\"git\", [\"-C\", dest, \"sparse-checkout\", \"init\", \"--cone\"], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n // Check out everything initially (for discovery)\n spawnSync(\"git\", [\"-C\", dest, \"sparse-checkout\", \"disable\"], { stdio: \"pipe\", env: GIT_ENV });\n return true;\n }\n // Fallback: regular shallow clone\n const fallback = spawnSync(\"git\", [\"clone\", \"--depth=1\", \"--branch\", branch, url, dest], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n return fallback.status === 0;\n}\n\n/**\n * Pull the latest commits for a cloned repository.\n * On shallow clone divergence, falls back to `git fetch --depth=1` + `git reset --hard`.\n *\n * @param dest - Local repo directory\n * @param branch - Branch to pull\n * @returns `true` on success, `false` on failure\n * @docLink packages/core/api-reference#pull-repo\n */\nexport function pullRepo(dest: string, branch: string): boolean {\n const r = spawnSync(\"git\", [\"-C\", dest, \"pull\", \"--depth=1\", \"--ff-only\"], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n if (r.status === 0) return true;\n // Shallow clones can diverge — force-sync via fetch + reset\n const fetch = spawnSync(\"git\", [\"-C\", dest, \"fetch\", \"--depth=1\", \"origin\", branch], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n if (fetch.status !== 0) return false;\n const reset = spawnSync(\"git\", [\"-C\", dest, \"reset\", \"--hard\", `origin/${branch}`], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n return reset.status === 0;\n}\n\n/**\n * Return the current HEAD commit SHA for a local repository.\n *\n * @param repoDir - Absolute path to the cloned repository\n * @returns Full commit SHA string, or `null` on failure\n * @docLink packages/core/api-reference#get-repo-commit\n */\nexport function getRepoCommit(repoDir: string): string | null {\n const r = spawnSync(\"git\", [\"-C\", repoDir, \"rev-parse\", \"HEAD\"], {\n encoding: \"utf8\",\n stdio: \"pipe\",\n });\n return r.status === 0 ? r.stdout.trim() : null;\n}\n\n/**\n * Check out a specific tag, branch, or commit SHA in a local repository.\n * Fetches the ref from `origin` first, then attempts `FETCH_HEAD` checkout.\n *\n * @param repoDir - Absolute path to the cloned repository\n * @param pin - Tag, branch name, or commit SHA\n * @returns `true` on success, `false` on failure\n * @docLink packages/core/api-reference#checkout-pin\n */\nexport function checkoutPin(repoDir: string, pin: string): boolean {\n // Fetch the ref first (works for tags, branches, and commits)\n spawnSync(\"git\", [\"-C\", repoDir, \"fetch\", \"--depth=1\", \"origin\", pin], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n const r = spawnSync(\"git\", [\"-C\", repoDir, \"checkout\", \"FETCH_HEAD\"], {\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n if (r.status === 0) return true;\n // Fallback: try direct checkout (for branches already fetched)\n const r2 = spawnSync(\"git\", [\"-C\", repoDir, \"checkout\", pin], { stdio: \"pipe\", env: GIT_ENV });\n return r2.status === 0;\n}\n\n// ── Link management ──────────────────────────────────────────────────────────\n\n/**\n * Map of repo name → local filesystem path for development overrides.\n * Stored in `.skaile/links.yaml`; used to redirect a named repo to a local clone.\n * @docLink packages/core/api-reference#link-config\n */\nexport interface LinkConfig {\n [repoName: string]: string; // repo name → local path\n}\n\n/** Path to the project-local links file. */\nfunction linksFile(projectDir: string): string {\n return join(projectDir, \".skaile\", \"links.yaml\");\n}\n\n/**\n * Read the dev-link map from `.skaile/links.yaml` in the project directory.\n * Returns an empty object when no links file exists.\n *\n * @param projectDir - Absolute path to the project root\n * @returns `LinkConfig` map (may be empty)\n * @docLink packages/core/api-reference#read-links\n */\nexport function readLinks(projectDir: string): LinkConfig {\n const file = linksFile(projectDir);\n if (!existsSync(file)) return {};\n try {\n return (parse(readFileSync(file, \"utf8\")) as LinkConfig) ?? {};\n } catch {\n return {};\n }\n}\n\n/**\n * Persist the dev-link map to `.skaile/links.yaml` in the project directory.\n *\n * @param projectDir - Absolute path to the project root\n * @param links - Updated `LinkConfig` to write\n * @docLink packages/core/api-reference#write-links\n */\nexport function writeLinks(projectDir: string, links: LinkConfig): void {\n const dir = join(projectDir, \".skaile\");\n mkdirSync(dir, { recursive: true });\n writeFileSync(linksFile(projectDir), stringify(links));\n}\n\n/**\n * Register a local filesystem path as a dev override for a named repository.\n * The path is stored in `.skaile/links.yaml` and takes priority over the remote URL at runtime.\n *\n * @param projectDir - Absolute path to the project root\n * @param repoName - Name of the repository to override\n * @param localPath - Local path (absolute or relative to `projectDir`) to use instead\n * @throws When the resolved path does not exist\n * @docLink packages/core/api-reference#link-repo\n */\nexport function linkRepo(projectDir: string, repoName: string, localPath: string): void {\n const resolved = resolve(projectDir, localPath);\n if (!existsSync(resolved)) {\n throw new Error(`Path not found: ${localPath} (resolved: ${resolved})`);\n }\n const links = readLinks(projectDir);\n links[repoName] = resolved;\n writeLinks(projectDir, links);\n}\n\n/**\n * Remove the dev-link override for a named repository, reverting it to the remote URL.\n *\n * @param projectDir - Absolute path to the project root\n * @param repoName - Name of the repository to unlink\n * @returns `true` if the link existed and was removed, `false` if no link was found\n * @docLink packages/core/api-reference#unlink-repo\n */\nexport function unlinkRepo(projectDir: string, repoName: string): boolean {\n const links = readLinks(projectDir);\n if (!links[repoName]) return false;\n delete links[repoName];\n writeLinks(projectDir, links);\n return true;\n}\n\n// ── Repo lifecycle ───────────────────────────────────────────────────────────\n\n/**\n * Ensure a repository is available locally, cloning or symlinking as needed.\n *\n * Resolution order:\n * 1. Linked override (`.skaile/links.yaml`) — highest priority\n * 2. Local path (`decl.path`) — direct filesystem reference\n * 3. Remote URL (`decl.url`) — cloned to the shared global cache, symlinked into `.skaile/repos/`\n *\n * Pin support: when `opts.pin` is provided, the tag/commit is checked out after clone.\n *\n * @param decl - Repository declaration from `skaile.yaml`\n * @param name - Logical repository name (cache key)\n * @param reposDir - Project-local repos directory (`.skaile/repos/`)\n * @param opts - Optional: `pin` for a specific commit/tag, `projectDir` for link lookup\n * @returns Absolute path to the local repository directory\n * @throws When the repository cannot be resolved or cloned\n * @docLink packages/core/api-reference#ensure-repo\n */\nexport function ensureRepo(\n decl: RepositoryDeclaration,\n name: string,\n reposDir: string,\n opts?: { pin?: string; projectDir?: string },\n): string {\n // 1. Check for linked override\n if (opts?.projectDir) {\n const links = readLinks(opts.projectDir);\n if (links[name]) {\n const linked = links[name];\n if (!existsSync(linked)) {\n throw new Error(\n `Linked path not found: ${linked}. Remove the .skaile/links.yaml entry to clear it.`,\n );\n }\n return linked;\n }\n }\n\n // 2. Local path\n if (decl.path) {\n const projectDir = opts?.projectDir ?? resolve(reposDir, \"..\");\n const resolved = resolve(projectDir, decl.path);\n if (!existsSync(resolved)) {\n throw new Error(`Local repository path not found: ${decl.path} (resolved: ${resolved})`);\n }\n return resolved;\n }\n\n // 3. Remote URL — clone to shared global cache\n if (decl.url) {\n const branch = decl.branch ?? \"main\";\n const globalCache = getGlobalCacheDir();\n const cacheDest = join(globalCache, name);\n\n // Clone or pull in global cache\n if (existsSync(join(cacheDest, \".git\"))) {\n if (!opts?.pin) pullRepo(cacheDest, branch);\n } else {\n if (!cloneRepo(decl.url, branch, cacheDest)) {\n throw new Error(`Failed to clone ${decl.url} (branch: ${branch})`);\n }\n }\n\n // Checkout pin if specified\n if (opts?.pin) {\n checkoutPin(cacheDest, opts.pin);\n }\n\n // Create symlink in project-local .skaile/repos/ → global cache\n const projectDest = join(reposDir, name);\n const projectExists = existsSync(projectDest);\n const isSymlink = projectExists && lstatSync(projectDest).isSymbolicLink();\n\n if (!projectExists) {\n mkdirSync(reposDir, { recursive: true });\n try {\n symlinkSync(cacheDest, projectDest);\n } catch {\n // Symlink failed (Windows?), just use cache dir directly\n return cacheDest;\n }\n } else if (!isSymlink) {\n // Stale real directory (legacy clone) — replace with symlink to global cache\n rmSync(projectDest, { recursive: true });\n try {\n symlinkSync(cacheDest, projectDest);\n } catch {\n // Symlink failed, fall through to return cacheDest\n }\n }\n\n return cacheDest;\n }\n\n throw new Error(`Repository \"${name}\" has neither url nor path`);\n}\n\n// ── Scanning ─────────────────────────────────────────────────────────────────\n\n/**\n * Scan a repository directory and return all discovered asset catalog entries.\n * Delegates to `scanDirectory` from `manifest.ts`.\n *\n * @param repoDir - Absolute path to the repository root\n * @param repoName - Repository name attached to each produced entry\n * @returns Array of `CatalogEntry` objects found in the repository\n * @docLink packages/core/api-reference#scan-repo\n */\nexport function scanRepo(repoDir: string, repoName: string): CatalogEntry[] {\n return scanDirectory(repoDir, repoName);\n}\n\n// ── Resolution ───────────────────────────────────────────────────────────────\n\n/**\n * Resolve a single asset reference to its `CatalogEntry` by scanning declared repositories.\n *\n * Search order:\n * 1. Explicit `@repository` qualifier on the ref — only that repo is searched.\n * 2. `opts.preferRepo` — searched first when set (repo affinity for transitive deps).\n * 3. All declared repos in declaration order.\n *\n * @param ref - Parsed asset reference to resolve\n * @param repositories - Repository declarations from `skaile.yaml`\n * @param reposDir - Project-local repos directory (`.skaile/repos/`)\n * @param opts - Optional: `projectDir` for link lookup, `preferRepo` for affinity\n * @returns Matching `CatalogEntry`, or `null` if not found in any repository\n * @docLink packages/core/api-reference#resolve-asset\n */\nexport function resolveAsset(\n ref: AssetRef,\n repositories: Record<string, RepositoryDeclaration>,\n reposDir: string,\n opts?: { projectDir?: string; preferRepo?: string },\n): CatalogEntry | null {\n let repoNames: string[];\n if (ref.repository) {\n // Explicit @repo qualifier — only search that repo\n repoNames = [ref.repository];\n } else if (opts?.preferRepo && opts.preferRepo in repositories) {\n // Repo affinity from parent — search preferred repo first, then others\n const rest = Object.keys(repositories).filter((n) => n !== opts.preferRepo);\n repoNames = [opts.preferRepo, ...rest];\n } else {\n repoNames = Object.keys(repositories);\n }\n\n for (const repoName of repoNames) {\n const decl = repositories[repoName];\n if (!decl) continue;\n\n const repoDir = resolveRepoDir(decl, repoName, reposDir, opts?.projectDir);\n if (!repoDir || !existsSync(repoDir)) continue;\n\n const entries = scanRepo(repoDir, repoName);\n const match = entries.find((e) => e.kind === ref.kind && e.name === ref.name);\n if (match) return match;\n }\n\n return null;\n}\n\n/** Resolve repo dir without cloning (for lookups). Checks links first. */\nfunction resolveRepoDir(\n decl: RepositoryDeclaration,\n name: string,\n reposDir: string,\n projectDir?: string,\n): string | null {\n // Check links\n if (projectDir) {\n const links = readLinks(projectDir);\n if (links[name]) {\n return existsSync(links[name]) ? links[name] : null;\n }\n }\n\n if (decl.path) {\n const base = projectDir ?? resolve(reposDir, \"..\");\n const resolved = resolve(base, decl.path);\n return existsSync(resolved) ? resolved : null;\n }\n\n // Check project-local symlink or global cache\n const projectDest = join(reposDir, name);\n if (existsSync(projectDest)) return projectDest;\n\n const globalDest = join(getGlobalCacheDir(), name);\n if (existsSync(join(globalDest, \".git\"))) return globalDest;\n\n return null;\n}\n\n/**\n * Collision record: the same `kind:name` was found in more than one repository.\n * Produced by `resolveAll` when multiple repos contain the same asset.\n * @docLink packages/core/api-reference#asset-collision\n */\nexport interface AssetCollision {\n /** \"kind:name\" key. */\n key: string;\n /** Repository the asset was resolved from. */\n resolvedFrom: string;\n /** Other repositories that also contain this asset. */\n shadowedIn: string[];\n}\n\n/**\n * Result of a full transitive dependency resolution via `resolveAll`.\n * @docLink packages/core/api-reference#resolve-result\n */\nexport interface ResolveResult {\n /** All resolved assets in leaf-first (dependency) order. */\n resolved: CatalogEntry[];\n /** Refs that could not be found in any repo. */\n missing: string[];\n /** Maps \"kind:name\" → resolved_by (\"direct\" or \"kind:name\" of parent). */\n resolvedBy: Map<string, string>;\n /** Assets that exist in multiple repos (resolved entry shadows others). */\n collisions: AssetCollision[];\n}\n\n/**\n * Resolve all dependencies (including transitive) from a list of asset ref strings.\n * Returns resolved assets in leaf-first order (dependencies before dependents).\n *\n * Repo affinity: transitive deps inherit the parent entry's repository as a\n * search preference, so bundled assets are found in their own repo first.\n * Explicit `@repo` qualifiers always take precedence over affinity.\n *\n * @param deps - Top-level asset ref strings to resolve (e.g. `[\"skill:use-exa\", \"agent:pi\"]`)\n * @param repositories - Repository declarations from `skaile.yaml`\n * @param reposDir - Project-local repos directory\n * @param opts - Optional: `projectDir` for link lookup\n * @returns `ResolveResult` with resolved entries, missing refs, provenance map, and collisions\n * @docLink packages/core/api-reference#resolve-all\n */\nexport function resolveAll(\n deps: string[],\n repositories: Record<string, RepositoryDeclaration>,\n reposDir: string,\n opts?: { projectDir?: string },\n): ResolveResult {\n const resolved: CatalogEntry[] = [];\n const seen = new Set<string>();\n const missing: string[] = [];\n const resolvedBy = new Map<string, string>();\n\n function visit(refStr: string, parent: string, parentRepo?: string): void {\n const ref = parseAssetRef(refStr);\n const key = `${ref.kind}:${ref.name}`;\n if (seen.has(key)) return;\n seen.add(key);\n\n // Pass repo affinity: explicit @repo on the ref wins, then parent's repo\n const preferRepo = ref.repository ?? parentRepo;\n const entry = resolveAsset(ref, repositories, reposDir, {\n ...opts,\n preferRepo,\n });\n if (!entry) {\n missing.push(refStr);\n return;\n }\n\n resolvedBy.set(key, parent);\n\n // Propagate entry's repository to transitive deps\n const entryRepo = entry.repository;\n\n // Resolve transitive deps (from requires field)\n for (const req of entry.requires) {\n visit(`${req.kind}:${req.name}`, key, entryRepo);\n }\n\n // Resolve bundle dependencies\n for (const dep of entry.dependencies) {\n visit(dep, key, entryRepo);\n }\n\n resolved.push(entry);\n }\n\n for (const dep of deps) {\n visit(dep, \"direct\");\n }\n\n // Detect collisions: check each resolved asset against other repos\n const collisions = detectCollisions(resolved, repositories, reposDir, opts?.projectDir);\n\n return { resolved, missing, resolvedBy, collisions };\n}\n\n/**\n * For each resolved asset, check whether other repos also contain the same\n * kind:name pair. Returns only actual collisions (2+ repos).\n */\nfunction detectCollisions(\n resolved: CatalogEntry[],\n repositories: Record<string, RepositoryDeclaration>,\n reposDir: string,\n projectDir?: string,\n): AssetCollision[] {\n const repoNames = Object.keys(repositories);\n if (repoNames.length < 2) return [];\n\n // Build per-repo catalog caches (avoids re-scanning)\n const repoEntries = new Map<string, CatalogEntry[]>();\n for (const repoName of repoNames) {\n const decl = repositories[repoName];\n if (!decl) continue;\n const repoDir = resolveRepoDir(decl, repoName, reposDir, projectDir);\n if (!repoDir || !existsSync(repoDir)) continue;\n repoEntries.set(repoName, scanRepo(repoDir, repoName));\n }\n\n const collisions: AssetCollision[] = [];\n for (const entry of resolved) {\n const key = `${entry.kind}:${entry.name}`;\n const shadowedIn: string[] = [];\n for (const [repoName, entries] of repoEntries) {\n if (repoName === entry.repository) continue;\n if (entries.some((e) => e.kind === entry.kind && e.name === entry.name)) {\n shadowedIn.push(repoName);\n }\n }\n if (shadowedIn.length > 0 && entry.repository) {\n collisions.push({ key, resolvedFrom: entry.repository, shadowedIn });\n }\n }\n return collisions;\n}\n\n// ── Status ───────────────────────────────────────────────────────────────────\n\n/**\n * Status summary for a repository — local HEAD, remote HEAD, and how far behind.\n * @docLink packages/core/api-reference#repo-status\n */\nexport interface RepoStatus {\n /** Logical name of the repository. */\n name: string;\n /** Whether the repo is local, remote (cloned), or linked (dev override). */\n kind: \"local\" | \"remote\" | \"linked\";\n /** Current local HEAD commit SHA. */\n localHead: string;\n /** Remote HEAD commit SHA (fetched during status check). */\n remoteHead: string;\n /** Number of commits the local clone is behind the remote. */\n behind: number;\n /** `true` when `behind === 0`. */\n upToDate: boolean;\n /** Absolute path the link points to (linked repos only). */\n linkedTo?: string;\n /** Human-readable error string when the status check failed. */\n error?: string;\n}\n\n/**\n * Check whether a repository clone is up to date with its remote.\n * Fetches the last 50 commits to compare local HEAD with `origin/<branch>`.\n *\n * @param decl - Repository declaration from `skaile.yaml`\n * @param name - Logical repository name\n * @param reposDir - Project-local repos directory\n * @param projectDir - Optional project root for link lookup\n * @returns `RepoStatus` describing the current state\n * @docLink packages/core/api-reference#check-repo-status\n */\nexport function checkRepoStatus(\n decl: RepositoryDeclaration,\n name: string,\n reposDir: string,\n projectDir?: string,\n): RepoStatus {\n // Check for linked override\n if (projectDir) {\n const links = readLinks(projectDir);\n if (links[name]) {\n return {\n name,\n kind: \"linked\",\n localHead: \"\",\n remoteHead: \"\",\n behind: 0,\n upToDate: true,\n linkedTo: links[name],\n };\n }\n }\n\n const base: RepoStatus = {\n name,\n kind: decl.path ? \"local\" : \"remote\",\n localHead: \"\",\n remoteHead: \"\",\n behind: 0,\n upToDate: true,\n };\n\n if (decl.path) return base;\n\n // Check global cache first, then project-local\n let dest = join(getGlobalCacheDir(), name);\n if (!existsSync(join(dest, \".git\"))) {\n dest = join(reposDir, name);\n }\n if (!existsSync(join(dest, \".git\"))) {\n return { ...base, error: \"Not cloned yet\" };\n }\n\n const branch = decl.branch ?? \"main\";\n\n const localHead = getRepoCommit(dest);\n if (!localHead) return { ...base, error: \"Failed to read local HEAD\" };\n base.localHead = localHead;\n\n const fetchR = spawnSync(\"git\", [\"-C\", dest, \"fetch\", \"--depth=50\", \"origin\", branch], {\n encoding: \"utf8\",\n stdio: \"pipe\",\n env: GIT_ENV,\n });\n if (fetchR.status !== 0) return { ...base, error: \"Fetch failed\" };\n\n const remoteR = spawnSync(\"git\", [\"-C\", dest, \"rev-parse\", `origin/${branch}`], {\n encoding: \"utf8\",\n stdio: \"pipe\",\n });\n if (remoteR.status !== 0) return { ...base, error: \"Failed to read remote HEAD\" };\n base.remoteHead = remoteR.stdout.trim();\n\n const countR = spawnSync(\n \"git\",\n [\"-C\", dest, \"rev-list\", \"--left-right\", \"--count\", `HEAD...origin/${branch}`],\n { encoding: \"utf8\", stdio: \"pipe\" },\n );\n if (countR.status === 0) {\n const parts = countR.stdout.trim().split(/\\s+/);\n base.behind = parseInt(parts[1] ?? \"0\", 10);\n }\n\n base.upToDate = base.behind === 0;\n return base;\n}\n","/**\n * Unified workspace configuration — `skaile.yaml` / `<name>.skaile.yaml`\n *\n * Single file combining AI resources, data connectors, agent behavior,\n * runtime defaults, and workspace layout.\n *\n * ── File naming ──────────────────────────────────────────────────────────\n *\n * skaile.yaml → canonical default workspace config\n * staging.skaile.yaml → alternative workspace config\n * *.skaile.yaml → glob pattern for named configs\n *\n * ── Stacking ─────────────────────────────────────────────────────────────\n *\n * Files stack across scope levels (same name must match):\n * ~/.skaile/skaile.yaml priority 10 (user)\n * /app/skaile.yaml priority 20 (app)\n * /project/skaile.yaml priority 30 (project)\n *\n * ── Relationship to other files ──────────────────────────────────────────\n *\n * .skaile/settings.json User-specific overrides (API keys, personal\n * model preferences). Gitignored. Overrides\n * workspace config defaults at runtime.\n *\n * workspace.yaml Scaffold template. Generates skaile.yaml\n * at `skaile init` time. Never read at runtime.\n *\n * agent.yaml Agent definition (identity). Referenced from\n * skaile.yaml via `agent.definition`.\n */\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, parse as parsePath, resolve } from \"node:path\";\nimport { parse, stringify } from \"yaml\";\nimport { fromMcpServerMd } from \"./manifest.js\";\nimport { type CatalogEntry, parseAssetRef } from \"./models.js\";\nimport { getGlobalCacheDir, resolveAsset } from \"./repo-manager.js\";\n\n// ── Agent config ──────────────────────────────────────────────────────────────\n\n/**\n * Named agent configuration profile. The \"default\" profile is the active one.\n * Personal overrides (apiKeys, model preference) live in .skaile/settings.json.\n * @docLink packages/core/workspace-config#agent-config-profile\n */\nexport interface AgentConfigProfile {\n /** Bridge driver to use: \"claude-sdk\", \"codex\", or \"omp\". */\n driver?: string;\n /** Default LLM provider: \"anthropic\", \"openai\", \"google\", etc. */\n provider?: string;\n /** Default model identifier. */\n model?: string;\n /** Thinking mode for Claude models. */\n thinking?: \"adaptive\" | \"enabled\" | \"disabled\";\n /** Reasoning effort level. */\n effort?: \"low\" | \"medium\" | \"high\" | string;\n /** Override framework install paths (rarely needed). */\n skills_dir?: string;\n agents_dir?: string;\n prompts_dir?: string;\n}\n\n// ── Startup ───────────────────────────────────────────────────────────────────\n\n/**\n * A startup directive — run on workspace launch.\n *\n * String form: \"agent:research-assistant\" — start the named agent\n * Object form: { \"system-prompt-override\": \"...\" } — replace system prompt\n * { \"system-prompt-append\": \"...\" } — append to system prompt\n * @docLink packages/core/workspace-config#startup-directive\n */\nexport type StartupDirective = string | Record<string, string>;\n\n// ── AI Resources ──────────────────────────────────────────────────────────────\n\n/**\n * An AI resource source with its own dependency list.\n * All declared dependencies are installed from this source's catalog.\n * @docLink packages/core/workspace-config#ai-resource-entry\n */\nexport interface AiResourceEntry {\n /** Source name (used as cache key and in CLI output). */\n name: string;\n /** Path to local directory or GitHub repo URL. */\n path: string;\n /** Git branch (default: main). */\n branch?: string;\n /** Skill/agent/package/flow refs to install from this source. Syntax: \"kind:name\". */\n dependencies?: string[];\n /** Auto-deploy to framework dirs on install. */\n auto_deploy?: boolean;\n}\n\n// ── Repository Declaration ────────────────────────────────────────────────────\n\n/**\n * Internal-only data shape used by the legacy asset install pipeline\n * (`repo-manager`, `lock`, `runtime-assets`). Carries the resolved URL or\n * path for an `ai_resources[]` entry. Not surfaced via the workspace config\n * schema — new sources are registered through `@skaile/library`.\n *\n * @docLink packages/core/workspace-config#repository-declaration\n */\nexport interface RepositoryDeclaration {\n /** GitHub or git URL (for remote repos). */\n url?: string;\n /** Local filesystem path (for local repos). */\n path?: string;\n /** Git branch (default: main). */\n branch?: string;\n /** Upstream URL for fork workflows. */\n upstream?: string;\n}\n\n// ── Source Entry ──────────────────────────────────────────────────────────────\n\n/**\n * A github source registered for this project — a third-party repo of AI\n * assets the project depends on. Bytes live under `~/.skaile/sources/<name>/`\n * (machine-global clone cache); this entry is the *per-project* declaration\n * that the project uses the source.\n *\n * Persisted under the `sources:` key in `skaile.yaml`.\n *\n * @docLink packages/core/workspace-config#source-entry\n */\nexport interface SourceEntry {\n /** Slug used as cache directory name (`~/.skaile/sources/<name>/`). */\n name: string;\n /** Git URL (ssh or https). */\n url: string;\n /** Git branch (default: main). */\n branch?: string;\n}\n\n// ── Mounts ──────────────────────────────────────────────────────────────────\n\n/**\n * A filesystem mount — projected storage backend.\n * @docLink packages/core/workspace-config#mount-declaration\n */\ninterface MountDeclaration {\n /** Unique identifier. Used as mount dir name. */\n id: string;\n /** Mount driver: \"local\", \"git\", \"s3\", \"webdav\", \"sharepoint\". */\n driver: string;\n /** What to mount: URL, bucket path, host filesystem path. */\n source: string;\n /** Workspace-relative mount point (default: .mounts/<id>). */\n target?: string;\n /** Access level enforced by the mount driver. */\n access?: \"read-only\" | \"read-write\";\n /** Credential reference: \"env:VAR_NAME\" or inline value. */\n auth?: string;\n /**\n * Whether to watch this mount for filesystem changes.\n * true = always watch, false = never watch, undefined = auto (watch if read-write).\n */\n watch?: boolean;\n /**\n * **Expert-only.** When `true`, the mount manager wires the resolved\n * credential into the workspace so the agent's interactive `git`/`curl`\n * tools can authenticate directly against the mount's host. Defaults to\n * `false` — agents have no credential exposure and rely on driver-managed\n * pulls/pushes. See `_devlog/specs/2026-05-05-git-credential-tiers.md`.\n */\n exposeAccessToken?: boolean;\n /**\n * Optional override for the access token TTL (seconds). When omitted, the\n * provider's natural TTL is used. Values above the provider's documented\n * maximum are silently capped.\n */\n accessTokenTTL?: number;\n /** Driver-specific configuration (branch, region, etc.). */\n options?: Record<string, unknown>;\n}\n\n// ── Connectors ────────────────────────────────────────────────────────────────\n\n/**\n * A data connector — tool-accessed backend the agent interacts with.\n * @docLink packages/core/workspace-config#connector-declaration\n */\nexport interface ConnectorDeclaration {\n /** Unique identifier. Used as tool namespace. */\n id: string;\n /** Connector adapter: \"postgres\", \"redis\", \"sqlite\", \"memory\", \"xstate\", \"xstate-store\", \"yjs\". */\n driver: string;\n /**\n * Access level enforced by ConnectorManager.\n * Optional in config — ConnectorManager defaults to \"read-only\" when absent.\n */\n access?: \"read-only\" | \"read-write\";\n /** Credential reference: \"env:VAR_NAME\" or inline value. */\n auth?: string;\n /** Adapter-specific configuration (dsn, host, etc.). */\n options?: Record<string, unknown>;\n\n // ── Extended fields (Plan A: first-level asset support) ──────────────────\n /** Semver range for future catalog versioning, e.g. \"^1.0.0\". */\n version?: string;\n /**\n * Run a health check (ping) when the connector is first connected.\n * Default: false. Set to true to surface connection errors early.\n */\n health_check?: boolean;\n /**\n * Inject this connector's skill description into the agent's system prompt.\n * Default: false.\n */\n expose_as_skill?: boolean;\n /** Tags for catalog browsing and skill routing. */\n tags?: string[];\n\n /**\n * Optional filesystem face — makes the connector \"mountable\".\n * When present, ConnectorManager allocates a mount directory and passes it\n * to the connector via `ConnectContext.mountTarget`.\n *\n * YAML key: `mount` (sub-block under a `connectors:` entry).\n * Replaces the legacy top-level `mounts:` key (hard cut — see Task 11).\n */\n mount?: {\n /** Source URL or path (repo URL, bucket name, host path). */\n source: string;\n /** Override mount target directory (default: `.mounts/<id>/`). */\n target?: string;\n /** Watch flag: omitted → watch read-write, skip read-only. */\n watch?: boolean;\n /** Expert-only: expose the resolved credential to the agent CLI. */\n exposeAccessToken?: boolean;\n /** Optional access-token TTL override (seconds). */\n accessTokenTTL?: number;\n };\n}\n\n// ── MCP Servers ──────────────────────────────────────────────────────────────\n\n/**\n * Reference to a Nix-built asset recipe.\n *\n * The `attr` field selects an attribute path in the platform's flake\n * (`/etc/skaile/flake/`), e.g. `mcps.excel`, `mcps.ppt`, `stacks.baseline`.\n * Resolution happens at session start (cold) and on `reconfigure_mcps`\n * (hot-add) via `nix path-info --offline`.\n *\n * @docLink packages/core/concepts#asset-recipe\n */\nexport interface AssetRecipe {\n /** Flake attribute path, e.g. `mcps.excel`. */\n attr: string;\n}\n\n/**\n * Validates an `AssetRecipe.attr` value against nix attribute path syntax.\n *\n * Nix attribute paths are dot-separated segments. Each segment must start with\n * a letter and contain only letters, digits, underscores, hyphens, and dots.\n * Characters like `#`, spaces, and nix expression fragments are explicitly\n * rejected — even though `spawnSync` array args prevent shell injection, nix\n * parses the combined `flakeRef#attr` string and invalid chars trigger\n * unintended evaluation paths.\n *\n * Deliberate restriction: leading digits per segment are not allowed even\n * though some nix attrs permit them, because they are rare in practice and\n * the restriction makes the validation straightforward to audit.\n *\n * @throws Error when `attr` is invalid\n */\nexport function validateAssetRecipeAttr(attr: string): void {\n if (typeof attr !== \"string\" || attr.length === 0) {\n throw new Error(\"AssetRecipe.attr must be a non-empty string\");\n }\n if (attr.length > 200) {\n throw new Error(`AssetRecipe.attr too long (${attr.length} chars, max 200)`);\n }\n const VALID_ATTR = /^[a-z][a-z0-9._-]*(?:\\.[a-z][a-z0-9._-]*)*$/i;\n if (!VALID_ATTR.test(attr)) {\n throw new Error(\n `AssetRecipe.attr \"${attr}\" contains invalid characters. ` +\n `Allowed: letters, digits, underscore, hyphen, dot. ` +\n `Each dot-segment must start with a letter.`,\n );\n }\n}\n\n/**\n * A declarative external MCP server — spawned or connected at session startup\n * and injected into the Claude SDK driver as a named `mcpServers` entry.\n *\n * Maps directly to the Claude Agent SDK's `McpServerConfig` union:\n * - `transport: \"stdio\"` (default) → `McpStdioServerConfig` — subprocess spawn\n * - `transport: \"sse\"` → `McpSSEServerConfig` — HTTP Server-Sent Events\n * - `transport: \"http\"` → `McpHttpServerConfig` — HTTP streaming\n *\n * The `id` becomes the key in the SDK's `mcpServers` record and also the MCP\n * tool prefix (e.g., `mcp__my-server__<tool-name>`).\n * @docLink packages/core/workspace-config#mcp-server-declaration\n */\nexport interface McpServerDeclaration {\n /** Unique identifier — used as the `mcpServers` record key and tool prefix. */\n id: string;\n /**\n * Transport type.\n * Default: `\"stdio\"` (subprocess).\n */\n transport?: \"stdio\" | \"sse\" | \"http\";\n /** For `\"stdio\"`: the command to execute (e.g. `\"npx\"`, `\"node\"`, `\"python\"`). */\n command?: string;\n /** For `\"stdio\"`: arguments passed to the command. */\n args?: string[];\n /** For `\"stdio\"`: environment variables injected into the subprocess. */\n env?: Record<string, string>;\n /** For `\"sse\"` and `\"http\"`: the server URL. */\n url?: string;\n /** For `\"sse\"` and `\"http\"`: HTTP headers (e.g. `Authorization`). */\n headers?: Record<string, string>;\n /** Short description of what this server provides (used in catalog). */\n description?: string;\n /** Tags for catalog browsing and discovery. */\n tags?: string[];\n /**\n * Optional Nix recipe binding. When present, the runner resolves the\n * recipe's `/nix/store` out-path before subprocess spawn and substitutes\n * `${recipe:<id>}` / `${recipe:<id>:<sub>}` / `${recipe:<id>:bin}` /\n * `${recipe:<id>:lib}` markers in `command`, `args`, and `env` values.\n * `<id>` matches this declaration's `id` field.\n */\n recipe?: AssetRecipe;\n}\n\n// ── Agent Configuration ──────────────────────────────────────────────────────\n\n/**\n * Platform-level context describing the environment the agent operates in.\n * Rendered by the runner into a \"## Platform\" section of the system prompt.\n */\nexport interface AgentContextConfig {\n /** Platform identifier (e.g. \"skaile\"). Controls the rendered header sentence. */\n platform?: string;\n /** Whether multiple users may interact in the same session. */\n multi_user?: boolean;\n /** Session persistence model. */\n session_model?: \"persistent\" | \"ephemeral\";\n}\n\nexport interface AgentConfig {\n /**\n * Agent definition reference. Resolved in order:\n * - Local path: \".skaile/agent\" or \"./my-agent\"\n * - Catalog reference: \"agent:<name>\" (resolved via asset manager catalog)\n * - Resource path: \"ai-assets://<domain>/agents/<name>\"\n */\n definition?: string;\n\n /**\n * Platform-level context (platform identifier, multi-user flag, session model).\n * Consumed by the runner to build the \"## Platform\" section of the system prompt.\n */\n context?: AgentContextConfig;\n\n /** Agent runtime constraints. */\n permissions?: AgentPermissions;\n\n /** Lifecycle hooks — shell commands run at specific points. */\n hooks?: AgentHooks;\n\n /** Named subagent definitions available for delegation. */\n subagents?: Record<string, SubagentConfig>;\n\n /**\n * Control which framework fragments are included in the rendered system prompt.\n * true (default) — include built-in fragment\n * false — omit this fragment\n * string — path to a custom markdown file (relative to project root)\n *\n * Fragment IDs: \"agent-mode\" | \"skill-discovery\" | \"connector-usage\" | \"handoff\"\n */\n fragments?: Record<string, boolean | string>;\n\n /**\n * Additional markdown files appended at the end of every rendered agent system\n * prompt in this workspace. Paths relative to the project root (skaile.yaml).\n *\n * YAML key: `prompt-extensions`\n */\n \"prompt-extensions\"?: string[];\n\n /**\n * Free-form user-authored agent prompt. Plain text or markdown — no length\n * cap, no template substitution. Prepended immediately after the platform\n * context section and before the environment section in the assembled\n * system prompt (see runner's {@link assembleSystemPrompt}).\n *\n * Written by the platform's wake-time yaml serializer from the combined\n * project-level + session-level prompts stored on `SkaileConfigData.agent.prompt`.\n * Standalone CLI / forge sessions may set this directly in `skaile.yaml`.\n *\n * Spec: `docs/superpowers/specs/2026-05-13-platform-agent-prompt-design.md`\n * @since 2026-05\n */\n prompt?: string;\n}\n\nexport interface AgentPermissions {\n /** Maximum agentic turns per query (default: 15). */\n max_turns?: number;\n /**\n * Permission mode for Claude SDK driver.\n * 'auto' = bypassPermissions (default for automated flows).\n * 'interactive' = prompt for each tool use.\n */\n permission_mode?: \"auto\" | \"interactive\";\n /** Glob patterns the agent may NOT write to. Stacking: union across scopes. */\n deny_write?: string[];\n /** Glob patterns the agent may NOT read. Stacking: union across scopes. */\n deny_read?: string[];\n}\n\nexport interface AgentHooks {\n /** Run before a flow starts (after resources are connected). */\n pre_flow?: HookEntry[];\n /** Run after a flow completes (before resources disconnect). */\n post_flow?: HookEntry[];\n /** Run before each flow node executes. */\n pre_node?: HookEntry[];\n /** Run after each flow node completes successfully. */\n post_node?: HookEntry[];\n}\n\nexport interface HookEntry {\n /** Human-readable hook name. */\n name: string;\n /** Shell command to execute. */\n run: string;\n /** Working directory relative to workspace root (default: workspace root). */\n cwd?: string;\n /** Timeout in seconds (default: 60). */\n timeout?: number;\n /** Continue flow if hook fails (default: false). */\n continue_on_error?: boolean;\n}\n\nexport interface SubagentConfig {\n /** What this subagent does. */\n description: string;\n /** System prompt for the subagent. */\n prompt: string;\n /** Tools this subagent may use (default: all). */\n tools?: string[];\n /** Tools this subagent may NOT use. */\n disallowed_tools?: string[];\n /** Model override. */\n model?: string;\n}\n\n// ── Workspace Layout ─────────────────────────────────────────────────────────\n\nexport interface WorkspaceLayoutConfig {\n /** Directories to ensure exist (created at scaffold time, verified at run time). */\n directories?: string[];\n\n /** Git configuration. */\n git?: GitConfig;\n\n /** Post-scaffold setup commands (run once after `skaile init`). */\n setup?: SetupEntry[];\n\n /** Container configuration (Docker). */\n container?: ContainerConfig;\n}\n\nexport interface GitConfig {\n /** Initialize a git repo at scaffold time (default: true). */\n init?: boolean;\n /** .gitignore entries. Stacking: concatenate + deduplicate. */\n ignore?: string[];\n}\n\nexport interface SetupEntry {\n /** Human-readable name. */\n name: string;\n /** Shell command to execute. */\n run: string;\n /** Working directory relative to workspace root. */\n cwd?: string;\n /** Continue if command fails (default: false). */\n continue_on_error?: boolean;\n}\n\nexport interface NixContainerConfig {\n /**\n * Nixpkgs package attribute names to include in the environment.\n * Example: [\"nodejs_22\", \"bun\", \"git\", \"python3\"]\n */\n packages?: string[];\n /**\n * Nixpkgs registry name used as a package prefix for `nix shell`.\n * MUST be a bare registry name like \"nixpkgs\" — not a channel path like\n * \"nixpkgs/nixos-24.11\" (which is not valid as a flake ref prefix).\n * Defaults to \"nixpkgs\".\n */\n channel?: string;\n /**\n * Path to a Nix file (shell.nix / flake.nix) relative to the project root.\n * When set, `packages` and `channel` are ignored — the file is the source of truth.\n */\n flake?: string;\n /**\n * Predefined named stack to resolve from the system stack registry (SKAILE_NIX_STACK_REGISTRY).\n * Overridden by `packages` if present.\n * Takes precedence over the parent `ContainerConfig.stack` field when nix mode is active.\n */\n stack?: string;\n}\n\nexport interface ContainerConfig {\n /** Enable Docker container generation. */\n enabled?: boolean;\n /** Base Docker image. */\n image?: string;\n /** System packages to install. */\n packages?: string[];\n /** Agent CLIs to install globally in the container. */\n agent_clis?: string[];\n /** Ports to expose. */\n ports?: string[];\n /** Environment variables to pass through. */\n env?: string[];\n /** Docker volume/bind mounts. */\n mounts?: Array<{ type: \"bind\" | \"volume\"; source: string; target: string }>;\n /** WebSocket port for IPC. */\n ws_port?: number;\n /**\n * Named system stack.\n * - Docker mode: resolved to an image tag via `dockerImageMap` (SKAILE_DOCKER_IMAGE_MAP).\n * - Nix mode: resolved to a package list via `nixStackRegistry` (SKAILE_NIX_STACK_REGISTRY).\n * Overridden by `nix.stack` if both are present.\n */\n stack?: string;\n /** Nix-specific environment configuration (nix session mode only). */\n nix?: NixContainerConfig;\n}\n\n// ── Top-level config ──────────────────────────────────────────────────────────\n\nexport interface SkWorkspaceConfig {\n /** Project name (defaults to directory basename). */\n name?: string;\n /** Project description. */\n description?: string;\n\n /**\n * Agent configuration profiles. The \"default\" profile provides runtime\n * defaults (framework, model, provider). Personal overrides live in\n * .skaile/settings.json and always take priority.\n *\n * YAML key: `agent-config` or `agent_config`\n */\n agent_config?: Record<string, AgentConfigProfile>;\n\n /**\n * Startup directives — executed when the workspace is launched.\n * Each item is either a string (\"agent:name\") or a map\n * ({ \"system-prompt-override\": \"...\" }).\n */\n startup?: StartupDirective[];\n\n /**\n * Internal-only — always `{}` on the merged config. Kept on the shape so\n * `repo-manager`, `lock`, and `runtime-assets` keep type-checking; their\n * `Record<string, RepositoryDeclaration>` arguments are built from\n * `ai_resources[]` entries inside the install pipeline.\n */\n repositories?: Record<string, RepositoryDeclaration>;\n\n /**\n * Asset dependencies using kind:name[@repo][#pin] syntax (new format).\n * Top-level flat list — repos and deps are separate concerns.\n *\n * YAML key: `dependencies`\n */\n dependencies?: string[];\n\n /**\n * Github sources this project depends on. Each entry names a clone under\n * `~/.skaile/sources/<name>/` (machine-global cache). `skaile init` and\n * `skaile install` clone any missing entries; `skaile source add/remove/sync`\n * are the CRUD surface.\n *\n * YAML key: `sources`\n */\n sources?: SourceEntry[];\n\n /**\n * Local patches applied during install (new format).\n * Maps \"kind:name\" → patch file path relative to project root.\n *\n * YAML key: `patches`\n */\n patches?: Record<string, string>;\n\n /**\n * AI resource sources, each with its own dependency list.\n * @deprecated Use `repositories` + `dependencies` instead.\n */\n ai_resources?: AiResourceEntry[];\n\n /**\n * @deprecated The top-level `mounts:` key is no longer supported as of Task 11.\n *\n * Move filesystem-projected storage backends under `connectors:` with a\n * `mount:` sub-block. See `docs/migration-mounts-to-connectors.md`.\n *\n * This field is kept on the type **only** so `config.ts` can detect a\n * present `mounts:` block and throw a migration error. It is never merged,\n * applied, or forwarded to any manager. `normalizeConfig` still populates it\n * when `mounts:` is present in the YAML so the detection check works.\n *\n * YAML key: `mounts` (rejected at runtime — do not use)\n */\n mounts?: MountDeclaration[];\n\n /**\n * Data connectors — tool-accessed backends.\n *\n * Each declaration's `driver` field is an *implicit* catalog ref\n * (`connector:<driver>`). The runtime resolves it through\n * `resolveRuntimeAssets()`, which scans every declared `repositories` entry\n * plus the implicit `@skaile/base-assets` repo for matching `CONNECTOR.md`\n * manifests. Drivers that do not match any catalog entry produce a\n * `missing_driver` warning at session startup.\n *\n * YAML key: `connectors`\n */\n connectors?: ConnectorDeclaration[];\n\n /**\n * External MCP servers — injected into the Claude SDK driver at session startup.\n * Supports stdio subprocess, SSE, and HTTP transports.\n *\n * YAML key: `mcp_servers`\n */\n mcp_servers?: McpServerDeclaration[];\n\n /** Agent behavior — definition reference, permissions, hooks, subagents. */\n agent?: AgentConfig;\n\n /** Workspace layout — directories, git, setup scripts, container. */\n workspace?: WorkspaceLayoutConfig;\n\n /**\n * Secret provisioning configuration.\n * Controls how connector credentials are resolved at runtime.\n *\n * YAML key: `secrets`\n */\n secrets?: SecretsConfig;\n\n /**\n * Telemetry configuration — passed through raw to the telemetry package.\n * Parsed by `resolveTelemetryConfig` in `@skaile/workspaces/telemetry`.\n *\n * YAML key: `telemetry`\n */\n telemetry?: Record<string, unknown>;\n\n /**\n * Session compaction settings -- controls when and how conversation\n * snapshots are created.\n *\n * YAML key: `compaction`\n */\n compaction?: CompactionConfig;\n}\n\nexport interface SecretsConfig {\n /**\n * How secrets are provided to the container.\n * \"env\" — read from process.env (default, for CLI/standalone)\n * \"provisioned\" — wait for secrets over transport bridge (platform containers)\n */\n provider?: \"env\" | \"provisioned\";\n /** Timeout in ms for waiting for provisioned secrets (default: 30000). */\n timeoutMs?: number;\n}\n\n// ── Compaction config ────────────────────────────────────────────────────────\n\nexport interface CompactionConfig {\n /** Enable managed compaction (default: true). */\n enabled?: boolean;\n /** Context fill percentage that triggers compaction (default: 80). */\n thresholdPercent?: number;\n /** Compact before hibernation for cheap restores (default: true). */\n compactOnHibernate?: boolean;\n /** Minimum ms between compactions to prevent thrashing (default: 120000). */\n minCooldownMs?: number;\n /** Enable manual compact command in expert mode (default: false). */\n manualCompactEnabled?: boolean;\n}\n\nexport const COMPACTION_DEFAULTS: Required<CompactionConfig> = {\n enabled: true,\n thresholdPercent: 80,\n compactOnHibernate: true,\n minCooldownMs: 120_000,\n manualCompactEnabled: false,\n};\n\n// ── Deprecated type aliases ───────────────────────────────────────────────────\n\n/** @deprecated Use AgentConfigProfile */\nexport interface RuntimeDefaults {\n framework?: string;\n driver?: string;\n provider?: string;\n model?: string;\n skills_dir?: string;\n agents_dir?: string;\n prompts_dir?: string;\n}\n\n/** @deprecated Use AiResourceEntry[] */\nexport interface AiResourcesConfig {\n sources?: AiResourceSource[];\n requires?: string[];\n auto_deploy?: boolean;\n}\n\n/** @deprecated Use AiResourceEntry */\nexport interface AiResourceSource {\n name: string;\n path: string;\n branch?: string;\n}\n\n// ── Config file info ──────────────────────────────────────────────────────────\n\nexport interface SkWorkspaceConfigFile {\n /** Absolute path to the config file. */\n path: string;\n /** Workspace name (extracted from filename). */\n name: string;\n /** Parsed config. */\n config: SkWorkspaceConfig;\n}\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\n/** Suffix for named workspace configs: `<name>.skaile.yaml` */\nexport const SKAILE_YAML_SUFFIX = \".skaile.yaml\";\n/** Filename for the default workspace config when no name is given. */\nexport const SKAILE_YAML_DEFAULT = \"skaile.yaml\";\n\n/** @deprecated Use SKAILE_YAML_SUFFIX */\nexport const SK_WORKSPACE_SUFFIX = SKAILE_YAML_SUFFIX;\n/** @deprecated Use SKAILE_YAML_DEFAULT */\nexport const SK_WORKSPACE_DEFAULT_NAME = \"default\";\n\n// ── Config I/O ────────────────────────────────────────────────────────────────\n\n/**\n * Return the canonical filename for a workspace config.\n * The default workspace resolves to `\"skaile.yaml\"`; named workspaces resolve to\n * `\"<name>.skaile.yaml\"`.\n *\n * @param name - Optional workspace name (omit or pass `\"default\"` for the primary config)\n * @returns Filename string (not a full path)\n * @docLink packages/core/workspace-config#workspace-config-filename\n */\nexport function workspaceConfigFilename(name?: string): string {\n if (!name || name === \"default\") return SKAILE_YAML_DEFAULT;\n return `${name}${SKAILE_YAML_SUFFIX}`;\n}\n\n/**\n * Return `true` if `filename` matches the workspace config naming convention\n * (`\"skaile.yaml\"` or any `\"*.skaile.yaml\"`).\n *\n * @param filename - Bare filename (no directory component)\n * @docLink packages/core/workspace-config#is-workspace-config-filename\n */\nexport function isWorkspaceConfigFilename(filename: string): boolean {\n return filename === SKAILE_YAML_DEFAULT || filename.endsWith(SKAILE_YAML_SUFFIX);\n}\n\n/**\n * Extract the workspace name from a config filename.\n * `\"skaile.yaml\"` → `\"default\"`, `\"staging.skaile.yaml\"` → `\"staging\"`.\n *\n * @param filename - Bare filename produced by `workspaceConfigFilename`\n * @returns Workspace name string\n * @docLink packages/core/workspace-config#workspace-name-from-filename\n */\nexport function workspaceNameFromFilename(filename: string): string {\n if (filename === SKAILE_YAML_DEFAULT) return \"default\";\n return filename.slice(0, -SKAILE_YAML_SUFFIX.length);\n}\n\n/**\n * Load a single workspace config file from `dir`.\n * When `name` is omitted and no `skaile.yaml` exists, falls back to the sole\n * `*.skaile.yaml` file in the directory if exactly one is present.\n *\n * @param dir - Directory to search for the config file\n * @param name - Optional workspace name (omit for the default `skaile.yaml`)\n * @returns Parsed config file info, or `null` if no matching file was found\n * @docLink packages/core/workspace-config#load-sk-workspace-config\n */\nexport function loadSkWorkspaceConfig(dir: string, name?: string): SkWorkspaceConfigFile | null {\n const resolvedDir = resolve(dir);\n const canonicalName = name && name !== \"default\" ? name : undefined;\n\n const filename = workspaceConfigFilename(canonicalName);\n const filePath = join(resolvedDir, filename);\n if (existsSync(filePath)) {\n return parseConfigFile(filePath, canonicalName ?? \"default\");\n }\n\n if (!canonicalName) {\n const found = listSkWorkspaceConfigs(resolvedDir);\n if (found.length === 1) return found[0]!;\n }\n\n return null;\n}\n\n/**\n * Serialize and write a workspace config to `dir`, creating the directory if needed.\n *\n * @param dir - Target directory (created recursively if absent)\n * @param config - Config object to serialize as YAML\n * @param name - Optional workspace name (omit for the default `skaile.yaml`)\n * @returns Absolute path of the written file\n * @docLink packages/core/workspace-config#save-sk-workspace-config\n */\nexport function saveSkWorkspaceConfig(\n dir: string,\n config: SkWorkspaceConfig,\n name?: string,\n): string {\n const resolvedDir = resolve(dir);\n const filename = workspaceConfigFilename(name);\n const filePath = join(resolvedDir, filename);\n\n if (!existsSync(resolvedDir)) {\n mkdirSync(resolvedDir, { recursive: true });\n }\n\n writeFileSync(filePath, stringify(config, { lineWidth: 120 }));\n return filePath;\n}\n\n/**\n * List all workspace config files present in `dir`, sorted alphabetically by name.\n * Returns an empty array when `dir` does not exist or is unreadable.\n *\n * @param dir - Directory to scan for `skaile.yaml` and `*.skaile.yaml` files\n * @returns Array of parsed config file descriptors\n * @docLink packages/core/workspace-config#list-sk-workspace-configs\n */\nexport function listSkWorkspaceConfigs(dir: string): SkWorkspaceConfigFile[] {\n const resolvedDir = resolve(dir);\n if (!existsSync(resolvedDir)) return [];\n\n const configs: SkWorkspaceConfigFile[] = [];\n try {\n for (const entry of readdirSync(resolvedDir)) {\n if (isWorkspaceConfigFilename(entry)) {\n const wsName = workspaceNameFromFilename(entry);\n const parsed = parseConfigFile(join(resolvedDir, entry), wsName);\n if (parsed) configs.push(parsed);\n }\n }\n } catch {\n /* unreadable dir */\n }\n\n return configs.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Resolve the effective workspace config by stacking configs across three scope levels:\n * user (`~/.skaile/`) < app (`opts.appDir`) < project (`projectDir`).\n *\n * Each level's config is merged with `mergeSkWorkspaceConfigs`, with higher-priority\n * scopes winning for scalars and unions applied for arrays (deny lists, directories, etc.).\n * Returns an empty object `{}` when no config files are found.\n *\n * @param projectDir - Root directory of the current project\n * @param opts - Optional overrides: `name` selects a named workspace (default: `\"default\"`),\n * `appDir` inserts an app-level config between user and project scopes\n * @returns Merged effective `SkWorkspaceConfig`\n * @docLink packages/core/workspace-config#resolve-sk-workspace-config\n */\nexport function resolveSkWorkspaceConfig(\n projectDir: string,\n opts?: { name?: string; appDir?: string },\n): SkWorkspaceConfig {\n const name = opts?.name ?? SK_WORKSPACE_DEFAULT_NAME;\n const configs: SkWorkspaceConfig[] = [];\n\n const userConfig = loadSkWorkspaceConfig(join(homedir(), \".skaile\"), name);\n if (userConfig) configs.push(userConfig.config);\n\n if (opts?.appDir) {\n const appConfig = loadSkWorkspaceConfig(opts.appDir, name);\n if (appConfig) configs.push(appConfig.config);\n }\n\n const projectConfig = loadSkWorkspaceConfig(projectDir, name);\n if (projectConfig) configs.push(projectConfig.config);\n\n if (configs.length > 0) return configs.reduce(mergeSkWorkspaceConfigs);\n\n return {};\n}\n\n/**\n * Walk upward from `startDir` looking for a `skaile.yaml` (or `*.skaile.yaml`).\n * Returns the directory containing the first match, or `undefined` if none found.\n *\n * Stops after 20 levels to avoid scanning all the way to `/`.\n *\n * @param startDir - Directory to start searching from (usually `process.cwd()`)\n * @returns Absolute path to the workspace root, or `undefined`\n * @docLink packages/core/workspace-config#find-workspace-root\n */\nexport function findWorkspaceRoot(startDir: string): string | undefined {\n let dir = resolve(startDir);\n const root = parsePath(dir).root; // filesystem root (e.g. \"/\" or \"C:\\\\\")\n let depth = 0;\n\n while (depth < 20) {\n if (existsSync(join(dir, SKAILE_YAML_DEFAULT))) return dir;\n // Check for named workspace configs (*.skaile.yaml)\n try {\n for (const entry of readdirSync(dir)) {\n if (entry.endsWith(SKAILE_YAML_SUFFIX)) return dir;\n }\n } catch {\n /* unreadable */\n }\n\n if (dir === root) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n depth++;\n }\n return undefined;\n}\n\n// ── Merge logic ───────────────────────────────────────────────────────────────\n\n/**\n * Deep-merge two workspace configs according to stacking rules.\n * `overlay` takes priority over `base` for scalar fields.\n * Arrays use concatenation + deduplication; deny lists always union.\n * Mounts and connectors are merged by `id` (overlay entry wins for same id).\n * Hooks are concatenated in order (base first, overlay appended).\n *\n * @param base - Lower-priority config (e.g. user or app scope)\n * @param overlay - Higher-priority config (e.g. project scope)\n * @returns Merged `SkWorkspaceConfig`\n * @docLink packages/core/workspace-config#merge-sk-workspace-configs\n */\nexport function mergeSkWorkspaceConfigs(\n base: SkWorkspaceConfig,\n overlay: SkWorkspaceConfig,\n): SkWorkspaceConfig {\n return {\n name: overlay.name ?? base.name,\n description: overlay.description ?? base.description,\n\n // agent_config: per-profile key, overlay profile wins\n agent_config: {\n ...(base.agent_config ?? {}),\n ...(overlay.agent_config ?? {}),\n },\n\n // startup: overlay wins (project-level only)\n startup: overlay.startup ?? base.startup,\n\n // ai_resources: dedupe by source name — overlay entry wins for same name\n ai_resources: dedupeByKey(\n [...(base.ai_resources ?? []), ...(overlay.ai_resources ?? [])],\n \"name\",\n ),\n\n // mounts: by id — overlay wins\n mounts: mergeById(base.mounts ?? [], overlay.mounts ?? []),\n\n // connectors: by id — overlay wins\n connectors: mergeById(base.connectors ?? [], overlay.connectors ?? []),\n\n // mcp_servers: by id — overlay wins\n mcp_servers: mergeById(base.mcp_servers ?? [], overlay.mcp_servers ?? []),\n\n agent: {\n definition: overlay.agent?.definition ?? base.agent?.definition,\n context: overlay.agent?.context ?? base.agent?.context,\n permissions: {\n ...base.agent?.permissions,\n ...stripUndefined(overlay.agent?.permissions),\n deny_write: dedupe([\n ...(base.agent?.permissions?.deny_write ?? []),\n ...(overlay.agent?.permissions?.deny_write ?? []),\n ]),\n deny_read: dedupe([\n ...(base.agent?.permissions?.deny_read ?? []),\n ...(overlay.agent?.permissions?.deny_read ?? []),\n ]),\n },\n subagents: {\n ...(base.agent?.subagents ?? {}),\n ...(overlay.agent?.subagents ?? {}),\n },\n hooks: {\n pre_flow: [\n ...(base.agent?.hooks?.pre_flow ?? []),\n ...(overlay.agent?.hooks?.pre_flow ?? []),\n ],\n post_flow: [\n ...(base.agent?.hooks?.post_flow ?? []),\n ...(overlay.agent?.hooks?.post_flow ?? []),\n ],\n pre_node: [\n ...(base.agent?.hooks?.pre_node ?? []),\n ...(overlay.agent?.hooks?.pre_node ?? []),\n ],\n post_node: [\n ...(base.agent?.hooks?.post_node ?? []),\n ...(overlay.agent?.hooks?.post_node ?? []),\n ],\n },\n },\n\n workspace: {\n directories: dedupe([\n ...(base.workspace?.directories ?? []),\n ...(overlay.workspace?.directories ?? []),\n ]),\n git: {\n init: overlay.workspace?.git?.init ?? base.workspace?.git?.init,\n ignore: dedupe([\n ...(base.workspace?.git?.ignore ?? []),\n ...(overlay.workspace?.git?.ignore ?? []),\n ]),\n },\n setup: overlay.workspace?.setup ?? base.workspace?.setup,\n container: overlay.workspace?.container ?? base.workspace?.container,\n },\n\n // secrets: overlay wins entirely\n secrets: overlay.secrets ?? base.secrets,\n\n // telemetry: overlay wins entirely (raw pass-through)\n telemetry: overlay.telemetry ?? base.telemetry,\n\n // repositories: always empty in merged output; the schema no longer\n // accepts this key. The internal install pipeline builds its own map\n // from `ai_resources[]` entries.\n repositories: {},\n\n // dependencies: concatenate and dedupe\n dependencies: dedupe([...(base.dependencies ?? []), ...(overlay.dependencies ?? [])]),\n\n // sources: dedupe by name — overlay entry wins for the same name\n sources: dedupeByKey([...(base.sources ?? []), ...(overlay.sources ?? [])], \"name\"),\n };\n}\n\n// ── Raw → canonical normalization ─────────────────────────────────────────────\n\n/** Scalar fields that identify a flat (un-profiled) agent-config block. */\nconst AGENT_PROFILE_FIELDS = [\n \"driver\",\n \"provider\",\n \"model\",\n \"thinking\",\n \"effort\",\n \"skills_dir\",\n \"agents_dir\",\n \"prompts_dir\",\n] as const;\n\n/**\n * Coerce a raw agent-config block into the canonical profile-map shape\n * (`{ default: {...}, … }`).\n *\n * Accepts two authoring shapes:\n * - **Profile map** (canonical): `{ default: { driver, model }, staging: {…} }`\n * - **Flat profile**: `{ driver, model, provider }` — emitted by clients that\n * serialize a runtime config object straight to YAML. Wrapped as the\n * `default` profile so `settingsFromWorkspaceConfig` finds it.\n *\n * A block is flat when any known profile field is present as a scalar; a profile\n * named e.g. `driver` carries an object value, so the scalar check disambiguates.\n */\nfunction normalizeAgentConfig(raw: Record<string, unknown>): Record<string, AgentConfigProfile> {\n const looksFlat = AGENT_PROFILE_FIELDS.some((f) => typeof raw[f] === \"string\");\n return looksFlat\n ? { default: raw as AgentConfigProfile }\n : (raw as Record<string, AgentConfigProfile>);\n}\n\n/**\n * Normalize a raw parsed YAML object into the canonical SkWorkspaceConfig shape.\n * Handles backward-compatible fields:\n * - `agent-config` (hyphen) / `agentConfig` (camelCase) → `agent_config`\n * - flat agent-config (`{ driver, model }`) → `{ default: { driver, model } }`\n * - `aiResources` (camelCase) → `ai_resources`\n * - `ai_resources` as object (old {sources, requires}) → AiResourceEntry[]\n * - `data_resources` → `connectors`\n * @docLink packages/core/workspace-config#normalize-config\n */\nexport function normalizeConfig(raw: Record<string, unknown>): SkWorkspaceConfig {\n const config: SkWorkspaceConfig = {};\n\n if (raw.name) config.name = String(raw.name);\n if (raw.description) config.description = String(raw.description);\n\n // agent_config: accept 'agent-config' (hyphen), 'agent_config' (underscore),\n // or 'agentConfig' (camelCase — emitted by clients that serialize a JS config\n // object straight to YAML). Both profile-map and flat shapes are accepted.\n const agentConfigRaw = raw[\"agent-config\"] ?? raw.agent_config ?? raw.agentConfig;\n if (agentConfigRaw && typeof agentConfigRaw === \"object\" && !Array.isArray(agentConfigRaw)) {\n config.agent_config = normalizeAgentConfig(agentConfigRaw as Record<string, unknown>);\n }\n\n // startup\n if (Array.isArray(raw.startup)) {\n config.startup = raw.startup as StartupDirective[];\n }\n\n // ai_resources: support both old object {sources, requires} and new array\n // [{name, path, dependencies}]; accept the camelCase `aiResources` alias too.\n const aiResRaw = raw.ai_resources ?? raw.aiResources;\n if (Array.isArray(aiResRaw)) {\n config.ai_resources = aiResRaw as AiResourceEntry[];\n } else if (aiResRaw && typeof aiResRaw === \"object\") {\n const old = aiResRaw as Record<string, unknown>;\n const sources = Array.isArray(old.sources) ? (old.sources as Record<string, unknown>[]) : [];\n const requires = Array.isArray(old.requires) ? (old.requires as string[]).filter(Boolean) : [];\n const autoDeploy = Boolean(old.auto_deploy ?? false);\n\n config.ai_resources = sources.map((s, i) => {\n const entry: AiResourceEntry = {\n name: String(s.name ?? \"\"),\n path: String(s.path ?? s.url ?? \"\"),\n };\n if (s.branch) entry.branch = String(s.branch);\n if (autoDeploy) entry.auto_deploy = true;\n // Attach global requires to first source\n if (i === 0 && requires.length > 0) entry.dependencies = requires;\n return entry;\n });\n }\n\n // mounts\n if (Array.isArray(raw.mounts)) {\n config.mounts = raw.mounts as MountDeclaration[];\n }\n\n // connectors (no data_resources fallback — clean break)\n if (Array.isArray(raw.connectors)) {\n config.connectors = raw.connectors as ConnectorDeclaration[];\n }\n\n // mcp_servers\n if (Array.isArray(raw.mcp_servers)) {\n config.mcp_servers = raw.mcp_servers as McpServerDeclaration[];\n }\n\n if (raw.agent) config.agent = raw.agent as AgentConfig;\n if (raw.workspace) config.workspace = raw.workspace as WorkspaceLayoutConfig;\n\n // secrets\n if (raw.secrets && typeof raw.secrets === \"object\") {\n config.secrets = raw.secrets as SecretsConfig;\n }\n\n // dependencies\n if (Array.isArray(raw.dependencies)) {\n config.dependencies = raw.dependencies.filter((d): d is string => typeof d === \"string\");\n }\n\n // sources\n if (Array.isArray(raw.sources)) {\n const entries: SourceEntry[] = [];\n for (const item of raw.sources) {\n if (!item || typeof item !== \"object\") continue;\n const s = item as Record<string, unknown>;\n const name = typeof s.name === \"string\" ? s.name : \"\";\n const url = typeof s.url === \"string\" ? s.url : \"\";\n if (!name || !url) continue;\n const entry: SourceEntry = { name, url };\n if (typeof s.branch === \"string\" && s.branch.length > 0) entry.branch = s.branch;\n entries.push(entry);\n }\n if (entries.length > 0) config.sources = entries;\n }\n\n // telemetry: pass through raw object — parsed by @skaile/workspaces/telemetry\n if (raw.telemetry && typeof raw.telemetry === \"object\" && !Array.isArray(raw.telemetry)) {\n config.telemetry = raw.telemetry as Record<string, unknown>;\n }\n\n return config;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction parseConfigFile(filePath: string, name: string): SkWorkspaceConfigFile | null {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = (parse(raw) as Record<string, unknown>) ?? {};\n } catch {\n return null;\n }\n const config = normalizeConfig(parsed);\n return { path: filePath, name, config };\n}\n\nfunction dedupe(arr: string[]): string[] {\n return [...new Set(arr)];\n}\n\nfunction dedupeByKey<T extends object>(arr: T[], key: string): T[] {\n const seen = new Set<string>();\n const result: T[] = [];\n for (let i = arr.length - 1; i >= 0; i--) {\n const val = String((arr[i] as any)[key] ?? \"\");\n if (!seen.has(val)) {\n seen.add(val);\n result.unshift(arr[i]!);\n }\n }\n return result;\n}\n\nfunction mergeById<T extends { id: string }>(base: T[], overlay: T[]): T[] {\n const map = new Map<string, T>();\n for (const r of base) map.set(r.id, r);\n for (const r of overlay) map.set(r.id, r);\n return [...map.values()];\n}\n\nfunction stripUndefined<T extends object>(obj?: T): Partial<T> {\n if (!obj) return {};\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n if (v !== undefined) result[k] = v;\n }\n return result as Partial<T>;\n}\n\n// ── MCP server loader ─────────────────────────────────────────────────────────\n\n/**\n * Build a `McpServerDeclaration` from a resolved `CatalogEntry` with `kind: \"mcp-server\"`.\n * Maps `metadata` fields (transport, command, args, env, url, headers) to declaration fields.\n * Returns `null` when the entry has no usable metadata (no command and no url).\n */\nfunction mcpDeclFromCatalogEntry(entry: CatalogEntry): McpServerDeclaration | null {\n const m = entry.metadata;\n if (!m) return null;\n\n const decl: McpServerDeclaration = { id: entry.name };\n if (m.transport) decl.transport = String(m.transport) as \"stdio\" | \"sse\" | \"http\";\n if (m.command) decl.command = String(m.command);\n if (Array.isArray(m.args)) decl.args = m.args.map(String);\n if (m.env && typeof m.env === \"object\") decl.env = m.env as Record<string, string>;\n if (m.url) decl.url = String(m.url);\n if (m.headers && typeof m.headers === \"object\") {\n decl.headers = m.headers as Record<string, string>;\n }\n if (entry.description) decl.description = entry.description;\n if (m.recipe && typeof m.recipe === \"object\" && !Array.isArray(m.recipe)) {\n const r = m.recipe as Record<string, unknown>;\n if (typeof r.attr === \"string\") {\n try {\n validateAssetRecipeAttr(r.attr);\n decl.recipe = { attr: r.attr };\n } catch (err) {\n // Invalid attr — skip the recipe field entirely (treat as if recipe was absent).\n // The MCP server may still be usable via a command/url without recipe substitution.\n console.warn(\n `[workspace-config] mcpDeclFromCatalogEntry: invalid recipe.attr for entry \"${entry.name}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n // Must have at least a command (stdio) or url (sse/http) to be useful\n if (!decl.command && !decl.url) return null;\n return decl;\n}\n\n/**\n * Merge two `McpServerDeclaration` objects field-by-field.\n * `overlay` values win for every non-undefined field; `base` provides defaults.\n */\nfunction mergeMcpDeclarations(\n base: McpServerDeclaration,\n overlay: McpServerDeclaration,\n): McpServerDeclaration {\n return {\n id: overlay.id,\n transport: overlay.transport ?? base.transport,\n command: overlay.command ?? base.command,\n args: overlay.args ?? base.args,\n env: overlay.env ? (base.env ? { ...base.env, ...overlay.env } : overlay.env) : base.env,\n url: overlay.url ?? base.url,\n headers: overlay.headers\n ? base.headers\n ? { ...base.headers, ...overlay.headers }\n : overlay.headers\n : base.headers,\n description: overlay.description ?? base.description,\n tags: overlay.tags ?? base.tags,\n recipe: overlay.recipe ?? base.recipe,\n };\n}\n\n/**\n * Scan `<projectDir>/.skaile/assets/mcp-server/<name>/MCP.md` for MCP servers\n * that the platform materializer has written to disk for a subscribed asset.\n *\n * For each immediate subdirectory containing an `MCP.md`, the manifest is parsed\n * via {@link fromMcpServerMd} and mapped to a declaration via\n * {@link mcpDeclFromCatalogEntry}. A sibling `.instance.json` (written by the\n * platform materializer) is folded into `decl.env`.\n *\n * **Env-fold precedence (lowest → highest):**\n * 1. `MCP.md` `env` defaults\n * 2. string-valued entries of `.instance.json` `config` (non-string config\n * values — objects/arrays/numbers — are skipped so env never contains\n * `[object Object]`)\n * 3. `.instance.json` `resolvedSecrets` (always folded, all keys)\n *\n * Folded secret *values* are never logged. A malformed `MCP.md` for one asset\n * is caught per-directory and skipped (warned without secret values) so one bad\n * asset never aborts the whole scan.\n *\n * @param projectDir - Workspace root containing `.skaile/assets/mcp-server/`\n * @returns Declarations for every materialized MCP asset (empty if the dir is absent)\n */\nfunction loadMaterializedMcpDeclarations(projectDir: string): McpServerDeclaration[] {\n const dir = join(projectDir, \".skaile/assets/mcp-server\");\n if (!existsSync(dir)) return [];\n\n const result: McpServerDeclaration[] = [];\n\n let subdirs: string[];\n try {\n subdirs = readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n return [];\n }\n\n for (const name of subdirs) {\n const subDir = join(dir, name);\n const mdPath = join(subDir, \"MCP.md\");\n if (!existsSync(mdPath)) continue;\n\n try {\n const entry = fromMcpServerMd(mdPath, name);\n const decl = mcpDeclFromCatalogEntry(entry);\n if (!decl) continue;\n\n decl.id = entry.name || name;\n\n const instancePath = join(subDir, \".instance.json\");\n if (existsSync(instancePath)) {\n // A malformed transient .instance.json must not nuke a valid MCP server:\n // catch parse errors here so the decl survives with its MCP.md env.\n try {\n const instance = JSON.parse(readFileSync(instancePath, \"utf8\")) as {\n config?: Record<string, unknown>;\n resolvedSecrets?: Record<string, unknown>;\n };\n\n const env: Record<string, string> = { ...(decl.env ?? {}) };\n\n // string-config < resolvedSecrets (folded after, so secrets win)\n if (instance.config && typeof instance.config === \"object\") {\n for (const [k, v] of Object.entries(instance.config)) {\n if (typeof v === \"string\") env[k] = v;\n }\n }\n if (instance.resolvedSecrets && typeof instance.resolvedSecrets === \"object\") {\n for (const [k, v] of Object.entries(instance.resolvedSecrets)) {\n // Guard like the config fold above — a non-string secret (serializer\n // bug) must not land in subprocess env as \"[object Object]\"/\"null\".\n if (typeof v === \"string\") env[k] = v;\n }\n }\n\n if (Object.keys(env).length > 0) decl.env = env;\n } catch (err) {\n // Never include secret values in the warning — only the failing path + message.\n console.warn(\n `[workspace-config] loadMaterializedMcpDeclarations: ignoring malformed \".instance.json\" for \"${name}\": ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n result.push(decl);\n } catch (err) {\n // Never include secret values in the warning — only the failing path + message.\n console.warn(\n `[workspace-config] loadMaterializedMcpDeclarations: failed to load \"${mdPath}\": ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n }\n\n return result;\n}\n\n/**\n * Load MCP server declarations by merging three sources:\n *\n * 1. **Catalog defaults** — `mcp-server:*` refs in the `dependencies` array\n * (or legacy `ai_resources[].dependencies`). Each ref is resolved from the\n * repository catalog; the `MCP.md` frontmatter provides default config\n * (transport, command, args, env, url, headers).\n *\n * 2. **Materialized assets** — MCP servers the platform materializer has written\n * to `<projectDir>/.skaile/assets/mcp-server/<name>/MCP.md` for subscribed\n * assets (see {@link loadMaterializedMcpDeclarations}). This scan ALWAYS runs,\n * so a subscribed asset on disk with no `dependencies:` and no `mcp_servers:`\n * entry is still picked up.\n *\n * 3. **Explicit declarations** — entries in the `mcp_servers` section of\n * `skaile.yaml`. These override the other two sources field-by-field when the\n * `id` matches.\n *\n * **Precedence (lowest → highest):** catalog-dep refs < materialized assets <\n * explicit `mcp_servers:`. A catalog-dep and a materialized asset with the same\n * id merge (materialized overlay onto catalog base) rather than double-counting.\n *\n * @param projectDir - Workspace root where `skaile.yaml` lives\n * @returns Unified array of `McpServerDeclaration` objects ready for the runner\n * @docLink packages/core/workspace-config#load-mcp-server-declarations\n */\nexport function loadMcpServerDeclarations(projectDir: string): McpServerDeclaration[] {\n const config = resolveSkWorkspaceConfig(projectDir);\n const explicit = config.mcp_servers ?? [];\n\n // Materialized scan always runs — the primary use case is a subscribed asset\n // on disk with no dependencies: and no mcp_servers: entry.\n const materialized = loadMaterializedMcpDeclarations(projectDir);\n\n // Collect all mcp-server refs from both dependency formats\n const mcpRefStrings: string[] = [];\n\n // New format: top-level dependencies\n for (const dep of config.dependencies ?? []) {\n const ref = parseAssetRef(dep);\n if (ref.kind === \"mcp-server\") mcpRefStrings.push(dep);\n }\n\n // Legacy format: ai_resources[].dependencies\n for (const res of config.ai_resources ?? []) {\n for (const dep of res.dependencies ?? []) {\n const ref = parseAssetRef(dep);\n if (ref.kind === \"mcp-server\") mcpRefStrings.push(dep);\n }\n }\n\n // Resolve catalog entries\n const repositories = config.repositories ?? {};\n\n // Also build repositories from legacy ai_resources for backward compat\n const allRepos = { ...repositories };\n for (const res of config.ai_resources ?? []) {\n if (res.name && res.path && !(res.name in allRepos)) {\n allRepos[res.name] = {\n url: res.path.startsWith(\"/\") ? undefined : res.path,\n path: res.path.startsWith(\"/\") ? res.path : undefined,\n branch: res.branch,\n };\n }\n }\n\n const reposDir = getGlobalCacheDir();\n // byId tracks the current merged decl per id so later, higher-precedence\n // sources overlay onto it instead of double-counting.\n const byId = new Map<string, McpServerDeclaration>();\n const order: string[] = [];\n\n const upsert = (decl: McpServerDeclaration) => {\n const existing = byId.get(decl.id);\n if (existing) {\n byId.set(decl.id, mergeMcpDeclarations(existing, decl));\n } else {\n byId.set(decl.id, decl);\n order.push(decl.id);\n }\n };\n\n // Source 1 (lowest): catalog-dep refs\n const seen = new Set<string>();\n for (const refStr of mcpRefStrings) {\n const ref = parseAssetRef(refStr);\n if (seen.has(ref.name)) continue;\n seen.add(ref.name);\n\n const entry = resolveAsset(ref, allRepos, reposDir, { projectDir });\n if (!entry) continue;\n\n const catalogDecl = mcpDeclFromCatalogEntry(entry);\n if (!catalogDecl) continue;\n\n upsert(catalogDecl);\n }\n\n // Source 2: materialized assets — overlay onto matching catalog base.\n for (const decl of materialized) {\n upsert(decl);\n }\n\n // Source 3 (highest): explicit mcp_servers: — overlay field-by-field.\n for (const decl of explicit) {\n upsert(decl);\n }\n\n return order.map((id) => byId.get(id) as McpServerDeclaration);\n}\n\n// ── Agent definition resolver ──────────────────────────────────────────────────\n\n/**\n * Walk upward from `from` (max 8 levels) until a directory containing\n * `ai-assets/` is found. Returns the absolute path to that `ai-assets/`\n * directory, or undefined if none found.\n */\nfunction findAiAssetsDir(from: string): string | undefined {\n let dir = resolve(from);\n for (let i = 0; i < 8; i++) {\n const candidate = join(dir, \"ai-assets\");\n if (existsSync(candidate)) return candidate;\n const resolved = resolve(dir, \"..\");\n if (resolved === dir) break;\n dir = resolved;\n }\n return undefined;\n}\n\n/**\n * Resolve the `agent.definition` field from `skaile.yaml` in `projectDir`\n * to an absolute filesystem path.\n *\n * Resolution rules:\n * - Absent or empty → undefined\n * - Relative/absolute local path → resolve(projectDir, definition)\n * - `ai-assets://<rest>` → walk up for ai-assets/, join with <rest>\n * - `agent:<name>` catalog refs → resolved via repository scanning\n *\n * Used by the runner to determine agentDir without requiring --agent-dir.\n * @docLink packages/core/workspace-config#resolve-agent-dir\n */\nexport function resolveAgentDir(projectDir: string): string | undefined {\n const config = resolveSkWorkspaceConfig(projectDir);\n const definition = config.agent?.definition;\n if (!definition) return undefined;\n\n // ai-assets:// URI\n if (definition.startsWith(\"ai-assets://\")) {\n const relPath = definition.slice(\"ai-assets://\".length);\n const aiAssetsDir = findAiAssetsDir(projectDir);\n if (!aiAssetsDir) return undefined;\n return join(aiAssetsDir, relPath);\n }\n\n // Catalog reference — resolve via repository scanning\n if (definition.startsWith(\"agent:\")) {\n const ref = parseAssetRef(definition);\n const repositories = config.repositories ?? {};\n const reposDir = getGlobalCacheDir();\n const entry = resolveAsset(ref, repositories, reposDir, { projectDir });\n if (!entry) return undefined;\n return dirname(entry.source);\n }\n\n // Local path (relative or absolute)\n return resolve(projectDir, definition);\n}\n"]}
|