zidane 8.2.2 → 8.2.3
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/dist/chat/pure.d.ts +2 -2
- package/dist/chat/pure.js +6 -6
- package/dist/chat.d.ts +2 -2
- package/dist/chat.js +9 -9
- package/dist/{client-core-BdD20sOv.d.ts → client-core-EEEX_u6D.d.ts} +3 -3
- package/dist/{client-core-BdD20sOv.d.ts.map → client-core-EEEX_u6D.d.ts.map} +1 -1
- package/dist/{connection-loop-DTk82YVl.d.ts → connection-loop-CpgfUmuw.d.ts} +3 -3
- package/dist/{connection-loop-DTk82YVl.d.ts.map → connection-loop-CpgfUmuw.d.ts.map} +1 -1
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-BICXFGiJ.js → dispatcher-Bv9-c6I2.js} +10 -10
- package/dist/{dispatcher-BICXFGiJ.js.map → dispatcher-Bv9-c6I2.js.map} +1 -1
- package/dist/{engine-QCX3GV-i.js → engine-XmoPPB6U.js} +4 -4
- package/dist/{engine-QCX3GV-i.js.map → engine-XmoPPB6U.js.map} +1 -1
- package/dist/{executor-B8GoXaaE.js → executor-BhthPE1q.js} +3 -3
- package/dist/{executor-B8GoXaaE.js.map → executor-BhthPE1q.js.map} +1 -1
- package/dist/{extensions-BeH3D-bq.js → extensions-BgBwogRW.js} +2 -2
- package/dist/{extensions-BeH3D-bq.js.map → extensions-BgBwogRW.js.map} +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{host-scoped-settings-CCnaBkCV.js → host-scoped-settings-C-Nmb6vr.js} +2 -2
- package/dist/{host-scoped-settings-CCnaBkCV.js.map → host-scoped-settings-C-Nmb6vr.js.map} +1 -1
- package/dist/{host-signals-DI9JQvR9.js → host-signals-BFudPyCT.js} +5 -5
- package/dist/{host-signals-DI9JQvR9.js.map → host-signals-BFudPyCT.js.map} +1 -1
- package/dist/{index-BkNeiJYI.d.ts → index-AqRZ3gEz.d.ts} +2 -2
- package/dist/{index-BkNeiJYI.d.ts.map → index-AqRZ3gEz.d.ts.map} +1 -1
- package/dist/{index-lcuvhQfF.d.ts → index-CDS7YdUC.d.ts} +4 -4
- package/dist/{index-lcuvhQfF.d.ts.map → index-CDS7YdUC.d.ts.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/ipc/remote.d.ts +4 -4
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.d.ts +4 -4
- package/dist/ipc.js +7 -7
- package/dist/{links-CN5JFFde.js → links-rFaWqS2Y.js} +9 -9
- package/dist/{links-CN5JFFde.js.map → links-rFaWqS2Y.js.map} +1 -1
- package/dist/{mcp-allowlist-BQ5MvhHi.js → mcp-allowlist-CLXweyxk.js} +14 -3
- package/dist/mcp-allowlist-CLXweyxk.js.map +1 -0
- package/dist/{oauth-TVPPye84.js → oauth-7_48zR7n.js} +75 -19
- package/dist/oauth-7_48zR7n.js.map +1 -0
- package/dist/{registry-PNi9rsGi.js → registry-eourRLY2.js} +2 -2
- package/dist/{registry-PNi9rsGi.js.map → registry-eourRLY2.js.map} +1 -1
- package/dist/{remote-hosts-b6Luwdhu.js → remote-hosts-DY2J07ut.js} +4 -4
- package/dist/{remote-hosts-b6Luwdhu.js.map → remote-hosts-DY2J07ut.js.map} +1 -1
- package/dist/{secret-shapes-CEoGmfEE.js → secret-shapes-BjW4l6U0.js} +8 -3
- package/dist/{secret-shapes-CEoGmfEE.js.map → secret-shapes-BjW4l6U0.js.map} +1 -1
- package/dist/{settings-keys-DssjmqAV.js → settings-keys-CPdmkTz7.js} +3 -3
- package/dist/{settings-keys-DssjmqAV.js.map → settings-keys-CPdmkTz7.js.map} +1 -1
- package/dist/{shell-path-BUFwqU_A.js → shell-path-B8b3EOtK.js} +3 -3
- package/dist/{shell-path-BUFwqU_A.js.map → shell-path-B8b3EOtK.js.map} +1 -1
- package/dist/store-L01W0gGI.js.map +1 -1
- package/dist/{todo-edits-H77ROt6X.js → todo-edits-BERpCRPj.js} +3 -3
- package/dist/{todo-edits-H77ROt6X.js.map → todo-edits-BERpCRPj.js.map} +1 -1
- package/dist/{transcript-anchors-s-yxh0jt.js → transcript-anchors-jHrg-r-H.js} +6 -6
- package/dist/{transcript-anchors-s-yxh0jt.js.map → transcript-anchors-jHrg-r-H.js.map} +1 -1
- package/dist/{transcript-reconcile-DeFLIQ14.js → transcript-reconcile-CPdrNbbR.js} +2 -2
- package/dist/{transcript-reconcile-DeFLIQ14.js.map → transcript-reconcile-CPdrNbbR.js.map} +1 -1
- package/dist/tui.d.ts +5 -5
- package/dist/tui.js +14 -14
- package/dist/{turn-operations-BbGJ-KSt.d.ts → turn-operations-DuGtKuc_.d.ts} +9 -2
- package/dist/turn-operations-DuGtKuc_.d.ts.map +1 -0
- package/dist/{url-CLl0u4Z8.js → url-D8KZ7Edw.js} +2 -2
- package/dist/{url-CLl0u4Z8.js.map → url-D8KZ7Edw.js.map} +1 -1
- package/dist/{version-v77Y4A3C.js → version-bd3DQJkc.js} +2 -2
- package/dist/{version-v77Y4A3C.js.map → version-bd3DQJkc.js.map} +1 -1
- package/dist/{workspace-exec-stream-kqARO8iC.js → workspace-exec-stream-CyfYgqAh.js} +4 -4
- package/dist/{workspace-exec-stream-kqARO8iC.js.map → workspace-exec-stream-CyfYgqAh.js.map} +1 -1
- package/dist/{ws-BD9FN98u.js → ws-CURQ2igk.js} +5 -5
- package/dist/{ws-BD9FN98u.js.map → ws-CURQ2igk.js.map} +1 -1
- package/dist/{ws-client-D7eb2UbH.js → ws-client-BVljYbdb.js} +3 -3
- package/dist/{ws-client-D7eb2UbH.js.map → ws-client-BVljYbdb.js.map} +1 -1
- package/package.json +1 -1
- package/dist/mcp-allowlist-BQ5MvhHi.js.map +0 -1
- package/dist/oauth-TVPPye84.js.map +0 -1
- package/dist/turn-operations-BbGJ-KSt.d.ts.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { i as writeJsonFileAtomic, t as OWNER_ONLY } from "./atomic-write-Ijgf2Mhc.js";
|
|
2
2
|
import { t as projectUserPaths } from "./project-user-paths-DWqZyUgb.js";
|
|
3
|
-
import { O as DEFAULT_SETTINGS, P as settingsFromStored } from "./secret-shapes-
|
|
4
|
-
import { N as readProjects, _ as parseMcpsFile, d as userSystemMdPath, o as settingsToWire } from "./host-scoped-settings-
|
|
3
|
+
import { O as DEFAULT_SETTINGS, P as settingsFromStored } from "./secret-shapes-BjW4l6U0.js";
|
|
4
|
+
import { N as readProjects, _ as parseMcpsFile, d as userSystemMdPath, o as settingsToWire } from "./host-scoped-settings-C-Nmb6vr.js";
|
|
5
5
|
import { d as loadState } from "./store-L01W0gGI.js";
|
|
6
6
|
import { s as readProviderCredential } from "./credentials-B9DfBJP9.js";
|
|
7
|
-
import { n as hashValue, r as isRecord, t as isSyncableSetting } from "./settings-keys-
|
|
7
|
+
import { n as hashValue, r as isRecord, t as isSyncableSetting } from "./settings-keys-CPdmkTz7.js";
|
|
8
8
|
import { i as SYNC_MODES, n as SYNC_CATEGORIES, s as fieldCategory } from "./types-B4oqzENY.js";
|
|
9
9
|
import { existsSync, lstatSync, readFileSync, readdirSync, statSync, watch } from "node:fs";
|
|
10
10
|
import { basename, dirname, join, relative, sep } from "node:path";
|
|
@@ -721,4 +721,4 @@ function syncLocalInfo(sources) {
|
|
|
721
721
|
//#endregion
|
|
722
722
|
export { createSyncEngine as t };
|
|
723
723
|
|
|
724
|
-
//# sourceMappingURL=engine-
|
|
724
|
+
//# sourceMappingURL=engine-XmoPPB6U.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-QCX3GV-i.js","names":[],"sources":["../src/chat/sync/collect.ts","../src/chat/sync/local.ts","../src/chat/sync/pusher.ts","../src/chat/sync/watchers.ts","../src/chat/sync/engine.ts"],"sourcesContent":["/**\n * This computer's state for each sync category, read from disk as a\n * `sync.push` payload (`./types` `SyncPayloads`): what the user set here,\n * never what a server session put in a window.\n *\n * - settings: `state.json`'s settings over the defaults, syncable keys only;\n * - safelists: `projects.json`;\n * - files: the user-scope `SYSTEM.md`, and the user-scope skills\n * (`~/.agents/skills`, `~/.<prefix>/skills`; the first of a name wins),\n * bounded like the server bounds them (a skill over them is left out);\n * - mcps: the user-scope `mcps.json` files (the first of a name wins);\n * - extensions: user-scope extensions installed from a source (their\n * `.install.json`); the others are listed as not syncable;\n * - keys: the stored API keys of the providers opted in.\n */\nimport type { ProviderDescriptor } from '../providers'\nimport type { SyncCategory, SyncFile, SyncPayloads } from './types'\nimport { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs'\nimport { join, relative, sep } from 'node:path'\nimport { readProviderCredential } from '../credentials'\nimport { parseMcpsFile } from '../mcps-discovery'\nimport { projectUserPaths } from '../project-user-paths'\nimport { readProjects } from '../safe-mode'\nimport { DEFAULT_SETTINGS, settingsFromStored } from '../settings-defaults'\nimport { loadState } from '../store'\nimport { userSystemMdPath } from '../system-md'\nimport { isSyncableSetting, settingsToWire } from './settings-keys'\n\nexport interface SyncSources {\n /** The user dir (`projects.json`, `credentials.json`). */\n dataDir: string\n /** This computer's `state.json`. */\n statePath: string\n home: string\n prefix: string\n providers: () => Readonly<Record<string, ProviderDescriptor>>\n}\n\nconst MAX_FILE_BYTES = 1024 * 1024\nconst MAX_SKILL_BYTES = 4 * 1024 * 1024\nconst MAX_SKILL_FILES = 200\nconst MAX_DEPTH = 8\n/** Not part of a skill: version control and installed dependencies. */\nconst SKIPPED_DIRS = new Set(['.git', 'node_modules'])\n\nfunction userPaths(sources: SyncSources, subPath: string): string[] {\n return projectUserPaths({ subPath, cwd: sources.home, home: sources.home, prefix: sources.prefix }).filter(p => p.source === 'user').map(p => p.path)\n}\n\n/** Every file and folder a category reads: what the watchers watch. */\nexport function syncWatchTargets(sources: SyncSources): { category: SyncCategory, path: string, recursive: boolean }[] {\n return [\n { category: 'settings', path: sources.statePath, recursive: false },\n { category: 'safelists', path: join(sources.dataDir, 'projects.json'), recursive: false },\n { category: 'files', path: userSystemMdPath({ home: sources.home, prefix: sources.prefix }), recursive: false },\n ...userPaths(sources, 'skills').map(path => ({ category: 'files' as const, path, recursive: true })),\n ...userPaths(sources, 'mcps.json').map(path => ({ category: 'mcps' as const, path, recursive: false })),\n ...userPaths(sources, 'extensions').map(path => ({ category: 'extensions' as const, path, recursive: true })),\n { category: 'keys', path: join(sources.dataDir, 'credentials.json'), recursive: false },\n ]\n}\n\nfunction settingsPayload(sources: SyncSources): SyncPayloads['settings'] {\n const stored = settingsFromStored(loadState(sources.statePath).settings ?? {})\n const merged = { ...DEFAULT_SETTINGS, ...stored } as Record<string, unknown>\n return { values: settingsToWire(Object.fromEntries(Object.entries(merged).filter(([key]) => key in DEFAULT_SETTINGS && isSyncableSetting(key)))) }\n}\n\nfunction safelistsPayload(sources: SyncSources): SyncPayloads['safelists'] {\n const projects = readProjects(sources.dataDir)\n return { projects: Object.fromEntries(Object.entries(projects).flatMap(([path, entry]) => (Array.isArray(entry?.safelist) ? [[path, [...entry.safelist]]] : []))) }\n}\n\n/** A skill folder's files, or null when it is over the bounds (or not a plain folder). */\nfunction skillFiles(dir: string): SyncFile[] | null {\n const files: SyncFile[] = []\n let total = 0\n const walk = (at: string, depth: number): boolean => {\n if (depth > MAX_DEPTH)\n return false\n for (const name of readdirSync(at).sort()) {\n const path = join(at, name)\n const stat = lstatSync(path)\n if (stat.isDirectory()) {\n if (SKIPPED_DIRS.has(name))\n continue\n if (!walk(path, depth + 1))\n return false\n }\n else if (stat.isFile()) {\n if (stat.size > MAX_FILE_BYTES || files.length >= MAX_SKILL_FILES)\n return false\n total += stat.size\n if (total > MAX_SKILL_BYTES)\n return false\n files.push({ path: relative(dir, path).split(sep).join('/'), data: readFileSync(path).toString('base64') })\n }\n // Links and anything else: not copied.\n }\n return true\n }\n try {\n return walk(dir, 1) && files.length > 0 ? files : null\n }\n catch {\n return null\n }\n}\n\n/** The user-scope skills: name → folder, the first root of a name winning (as discovery does). */\nexport function userSkillDirs(sources: SyncSources): Map<string, string> {\n const found = new Map<string, string>()\n for (const root of userPaths(sources, 'skills')) {\n let names: string[]\n try {\n names = readdirSync(root).sort()\n }\n catch {\n continue\n }\n for (const name of names) {\n const dir = join(root, name)\n if (!found.has(name) && !name.startsWith('.') && existsSync(join(dir, 'SKILL.md')) && lstatSync(dir).isDirectory())\n found.set(name, dir)\n }\n }\n return found\n}\n\nfunction filesPayload(sources: SyncSources): SyncPayloads['files'] {\n const mdPath = userSystemMdPath({ home: sources.home, prefix: sources.prefix })\n const systemMd = existsSync(mdPath) ? readFileSync(mdPath, 'utf8') : null\n const skills: SyncPayloads['files']['skills'] = []\n for (const [name, dir] of userSkillDirs(sources)) {\n const files = skillFiles(dir)\n if (files)\n skills.push({ name, files })\n }\n return { systemMd, skills }\n}\n\nfunction mcpsPayload(sources: SyncSources): SyncPayloads['mcps'] {\n const servers = new Map<string, Record<string, unknown>>()\n for (const path of userPaths(sources, 'mcps.json')) {\n if (!existsSync(path))\n continue\n try {\n for (const server of parseMcpsFile(readFileSync(path, 'utf8'))) {\n if (!servers.has(server.name))\n servers.set(server.name, server as unknown as Record<string, unknown>)\n }\n }\n catch {\n // A file discovery can't read either: nothing to sync from it.\n }\n }\n return { servers: [...servers.values()] }\n}\n\n/** User-scope extensions: those with a source (syncable) and the local ones (not). */\nexport function userExtensions(sources: SyncSources): { syncable: SyncPayloads['extensions']['extensions'], local: string[] } {\n const syncable: SyncPayloads['extensions']['extensions'] = []\n const local: string[] = []\n const seen = new Set<string>()\n for (const root of userPaths(sources, 'extensions')) {\n let names: string[]\n try {\n names = readdirSync(root).sort()\n }\n catch {\n continue\n }\n for (const name of names) {\n const dir = join(root, name)\n if (name.startsWith('.') || seen.has(name) || !lstatSync(dir).isDirectory())\n continue\n seen.add(name)\n // `.install.json` (`src/extensions/install.ts`): the spec an install replays.\n let provenance: { spec?: unknown, extension?: unknown } | null = null\n try {\n provenance = JSON.parse(readFileSync(join(dir, '.install.json'), 'utf8'))\n }\n catch {}\n if (provenance && typeof provenance.spec === 'string' && provenance.spec.trim() !== '')\n syncable.push({ name, spec: provenance.spec, ...(typeof provenance.extension === 'string' ? { extension: provenance.extension } : {}) })\n else\n local.push(name)\n }\n }\n return { syncable, local }\n}\n\n/** Providers with an API key stored here: what the keys category can offer. */\nexport function storedApiKeyProviders(sources: SyncSources): { key: string, label: string }[] {\n return Object.values(sources.providers()).flatMap((descriptor) => {\n const credential = readProviderCredential(sources.dataDir, descriptor)\n return credential?.kind === 'apikey' && credential.value ? [{ key: descriptor.key, label: descriptor.label }] : []\n })\n}\n\nfunction keysPayload(sources: SyncSources, optedIn: readonly string[]): SyncPayloads['keys'] {\n const providers = sources.providers()\n return {\n keys: optedIn.flatMap((provider) => {\n const descriptor = providers[provider]\n const credential = descriptor ? readProviderCredential(sources.dataDir, descriptor) : undefined\n return credential?.kind === 'apikey' && credential.value ? [{ provider, key: credential.value }] : []\n }),\n }\n}\n\nexport function collectSyncPayload(category: SyncCategory, sources: SyncSources, optedInKeys: readonly string[] = []): SyncPayloads[SyncCategory] {\n switch (category) {\n case 'settings': return settingsPayload(sources)\n case 'safelists': return safelistsPayload(sources)\n case 'files': return filesPayload(sources)\n case 'mcps': return mcpsPayload(sources)\n case 'extensions': return { extensions: userExtensions(sources).syncable }\n case 'keys': return keysPayload(sources, optedInKeys)\n }\n}\n","/**\n * This computer's side of settings sync, on disk:\n *\n * - `<dataDir>/device.json` (0600): the device id servers know this computer\n * by (random, made once) and its name (the host name).\n * - `<dataDir>/hosts-sync.json` (0600), next to `hosts.json`: per saved\n * server (by host id), the mode, the categories, the API keys opted in,\n * the categories still to push (the offline queue: one entry per category,\n * the newest value wins, so at most six) and the outcome of the last push.\n */\nimport type { SyncCategory, SyncMode, SyncPushResult } from './types'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { hostname } from 'node:os'\nimport { join } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { isRecord } from './hash'\nimport { SYNC_CATEGORIES, SYNC_MODES } from './types'\n\nexport interface DeviceIdentity {\n id: string\n name: string\n}\n\n/** Saved sync settings for one server, kept in `hosts-sync.json`. */\nexport interface ServerSyncConfig {\n /** Whether and how this computer syncs to the server. */\n mode: SyncMode\n /** Categories sent to the server. */\n categories: SyncCategory[]\n /** Providers whose stored API key goes to this server. */\n keys: string[]\n /** Categories changed here and not pushed yet (offline queue). */\n pending: SyncCategory[]\n /** Per category, a hash of what was last pushed (a restart finds what changed meanwhile). */\n sent: Partial<Record<SyncCategory, string>>\n /** Time of the last successful push in epoch ms. */\n lastSyncAt?: number\n /** Message of the last failed push. */\n lastError?: string\n /** What the last push of each category did there. */\n results: Partial<Record<SyncCategory, SyncPushResult>>\n}\n\ninterface SyncConfigFile {\n version: 1\n servers: Record<string, ServerSyncConfig>\n}\n\nexport const DEFAULT_SERVER_SYNC: Readonly<ServerSyncConfig> = { mode: 'off', categories: ['settings'], keys: [], pending: [], sent: {}, results: {} }\n\nexport function hostsSyncPath(dataDir: string): string {\n return join(dataDir, 'hosts-sync.json')\n}\n\nexport function deviceIdentityPath(dataDir: string): string {\n return join(dataDir, 'device.json')\n}\n\nfunction readJson(path: string): unknown {\n if (!existsSync(path))\n return undefined\n try {\n return JSON.parse(readFileSync(path, 'utf8'))\n }\n catch {\n return undefined\n }\n}\n\n/** This computer's device id and name, made on first use. */\nexport function readDeviceIdentity(dataDir: string, name?: string): DeviceIdentity {\n const raw = readJson(deviceIdentityPath(dataDir))\n if (isRecord(raw) && typeof raw.id === 'string' && raw.id !== '')\n return { id: raw.id, name: name ?? (typeof raw.name === 'string' && raw.name ? raw.name : hostname()) }\n const identity = { id: randomUUID(), name: name ?? hostname() }\n writeJsonFileAtomic(deviceIdentityPath(dataDir), identity, OWNER_ONLY)\n return identity\n}\n\nfunction categoriesOf(value: unknown): SyncCategory[] {\n return Array.isArray(value) ? SYNC_CATEGORIES.filter(c => value.includes(c)) : []\n}\n\nfunction serverConfigOf(raw: unknown): ServerSyncConfig {\n if (!isRecord(raw))\n return { ...DEFAULT_SERVER_SYNC }\n return {\n mode: SYNC_MODES.includes(raw.mode as SyncMode) ? raw.mode as SyncMode : 'off',\n categories: categoriesOf(raw.categories),\n keys: Array.isArray(raw.keys) ? raw.keys.filter((k): k is string => typeof k === 'string') : [],\n pending: categoriesOf(raw.pending),\n sent: isRecord(raw.sent) ? Object.fromEntries(Object.entries(raw.sent).filter(([c, h]) => SYNC_CATEGORIES.includes(c as SyncCategory) && typeof h === 'string')) : {},\n ...(typeof raw.lastSyncAt === 'number' ? { lastSyncAt: raw.lastSyncAt } : {}),\n ...(typeof raw.lastError === 'string' ? { lastError: raw.lastError } : {}),\n results: isRecord(raw.results) ? raw.results as ServerSyncConfig['results'] : {},\n }\n}\n\nexport function readSyncConfigs(dataDir: string): Record<string, ServerSyncConfig> {\n const raw = readJson(hostsSyncPath(dataDir))\n if (!isRecord(raw) || !isRecord(raw.servers))\n return {}\n return Object.fromEntries(Object.entries(raw.servers).map(([key, value]) => [key, serverConfigOf(value)]))\n}\n\nexport function writeSyncConfigs(dataDir: string, servers: Record<string, ServerSyncConfig>): void {\n const file: SyncConfigFile = { version: 1, servers }\n writeJsonFileAtomic(hostsSyncPath(dataDir), file, OWNER_ONLY)\n}\n","/**\n * The push side of settings sync (`./engine`): per server, its config (read\n * from and saved to `hosts-sync.json`), its connection, what it said last\n * (`sync.status`, a conflicting source), and the queue flush: claim, then\n * push each pending category's snapshot, one flush at a time per server.\n */\nimport type { SyncSources } from './collect'\nimport type { SyncClient } from './engine'\nimport type { DeviceIdentity, ServerSyncConfig } from './local'\nimport type { SyncCategory, SyncStatus } from './types'\nimport { collectSyncPayload } from './collect'\nimport { hashValue } from './hash'\nimport { DEFAULT_SERVER_SYNC, readSyncConfigs, writeSyncConfigs } from './local'\nimport { SYNC_CATEGORIES } from './types'\n\nconst errorText = (err: unknown): string => (err instanceof Error ? err.message : String(err))\n\nexport function createSyncPusher({ sources, device, emit }: { sources: SyncSources, device: DeviceIdentity, emit: () => void }) {\n const configs = readSyncConfigs(sources.dataDir)\n const clients = new Map<string, SyncClient>()\n const statuses = new Map<string, SyncStatus>()\n const conflicts = new Map<string, string>()\n const flushing = new Map<string, Promise<void>>()\n const again = new Set<string>()\n let stopped = false\n\n const configOf = (key: string): ServerSyncConfig => configs[key] ?? { ...DEFAULT_SERVER_SYNC, categories: [...DEFAULT_SERVER_SYNC.categories] }\n const save = (key: string, config: ServerSyncConfig): void => {\n configs[key] = config\n writeSyncConfigs(sources.dataDir, configs)\n emit()\n }\n const fail = (key: string, err: unknown): void => save(key, { ...configOf(key), lastError: errorText(err) })\n\n /** Categories whose snapshot here differs from what was last pushed to the server. */\n const changedCategories = (config: ServerSyncConfig, only?: SyncCategory): SyncCategory[] =>\n config.categories.filter((category) => {\n if (only && category !== only)\n return false\n try {\n return hashValue(collectSyncPayload(category, sources, config.keys)) !== config.sent[category]\n }\n catch {\n return true\n }\n })\n\n const queue = (key: string, categories: readonly SyncCategory[]): void => {\n const config = configOf(key)\n const pending = SYNC_CATEGORIES.filter(c => config.pending.includes(c) || categories.includes(c))\n if (pending.length !== config.pending.length)\n save(key, { ...config, pending })\n }\n\n async function claim(key: string, client: SyncClient, takeover: boolean): Promise<boolean> {\n const config = configOf(key)\n const result = await client.request('sync.claim', { deviceId: device.id, deviceName: device.name, categories: config.categories, keys: config.keys, ...(takeover ? { takeover: true } : {}) })\n statuses.set(key, result.status)\n if (result.claimed)\n conflicts.delete(key)\n else\n conflicts.set(key, result.status.source?.deviceName ?? 'another device')\n return result.claimed\n }\n\n async function flushOnce(key: string, takeover: boolean): Promise<void> {\n const client = clients.get(key)\n let config = configOf(key)\n if (!client || !client.hello.sync || config.mode === 'off' || (config.pending.length === 0 && !takeover) || stopped)\n return\n try {\n if (!(await claim(key, client, takeover)))\n return\n for (const category of [...configOf(key).pending]) {\n config = configOf(key)\n if (!config.categories.includes(category)) {\n save(key, { ...config, pending: config.pending.filter(c => c !== category) })\n continue\n }\n const payload = collectSyncPayload(category, sources, config.keys)\n const result = await client.request('sync.push', { deviceId: device.id, category, payload })\n config = configOf(key)\n const { lastError: _dropped, ...rest } = config\n save(key, {\n ...rest,\n pending: config.pending.filter(c => c !== category),\n sent: { ...config.sent, [category]: hashValue(payload) },\n results: { ...config.results, [category]: result },\n lastSyncAt: Date.now(),\n })\n }\n statuses.set(key, await client.request('sync.status', {}))\n }\n catch (err) {\n fail(key, err)\n }\n }\n\n /** Push the queue if the server is connected and this device is its source; `takeover` claims it first. */\n function flush(key: string, takeover = false): Promise<void> {\n const running = flushing.get(key)\n if (running && !takeover) {\n again.add(key)\n return running\n }\n const run = (async () => {\n if (running)\n await running\n await flushOnce(key, takeover)\n // A change while pushing: once more (`flushOnce` stops on its own once stopped).\n while (again.delete(key))\n await flushOnce(key, false)\n })().finally(() => {\n if (flushing.get(key) === run)\n flushing.delete(key)\n emit()\n })\n flushing.set(key, run)\n emit()\n return run\n }\n\n /** Read the server's record: who syncs there now. */\n async function refresh(key: string): Promise<void> {\n const client = clients.get(key)\n if (!client?.hello.sync)\n return\n try {\n const status = await client.request('sync.status', {})\n statuses.set(key, status)\n if (!status.source || status.source.deviceId === device.id)\n conflicts.delete(key)\n else if (configOf(key).mode !== 'off')\n conflicts.set(key, status.source.deviceName)\n }\n catch {}\n emit()\n }\n\n /** This device stops being the server's source (the server keeps what it has). */\n async function release(key: string): Promise<void> {\n const client = clients.get(key)\n conflicts.delete(key)\n if (!client?.hello.sync)\n return\n await client.request('sync.release', { deviceId: device.id }).catch(() => undefined)\n const status = await client.request('sync.status', {}).catch(() => null)\n if (status)\n statuses.set(key, status)\n }\n\n function forget(key: string): void {\n clients.delete(key)\n statuses.delete(key)\n conflicts.delete(key)\n if (configs[key]) {\n delete configs[key]\n writeSyncConfigs(sources.dataDir, configs)\n }\n }\n\n return {\n configs,\n clients,\n statuses,\n conflicts,\n flushing,\n configOf,\n save,\n fail,\n changedCategories,\n queue,\n claim,\n flush,\n refresh,\n release,\n forget,\n stop: () => {\n stopped = true\n clients.clear()\n },\n }\n}\n","/**\n * File watchers for settings sync (`./engine`): on each file and folder a\n * category reads (`syncWatchTargets`), or the folder it would appear in.\n * Events are debounced into one check of the categories they touched; the\n * watchers are rebuilt after each check (a folder created since, such as the\n * first skill, is then watched too).\n */\nimport type { SyncSources } from './collect'\nimport type { SyncCategory } from './types'\nimport { existsSync, statSync, watch } from 'node:fs'\nimport { basename, dirname } from 'node:path'\nimport { syncWatchTargets } from './collect'\n\nexport interface SyncWatchers {\n /** Start (or restart) the watchers when `active`, else close them. */\n refresh: (active: boolean) => void\n /** Report a change (a watcher, or the app's own settings stream). */\n schedule: (category?: SyncCategory) => void\n count: () => number\n close: () => void\n}\n\nexport function createSyncWatchers({ sources, debounceMs, check }: {\n sources: SyncSources\n debounceMs: number\n /** After the debounce: the categories that changed (`all`: unknown which), then the watchers are refreshed by the caller. */\n check: (which: readonly (SyncCategory | 'all')[]) => void\n}): SyncWatchers {\n let watchers: { close: () => void }[] = []\n let timer: ReturnType<typeof setTimeout> | null = null\n let closed = false\n const dirty = new Set<SyncCategory | 'all'>()\n\n const closeAll = (): void => {\n for (const w of watchers)\n w.close()\n watchers = []\n }\n\n const schedule = (category?: SyncCategory): void => {\n if (closed)\n return\n dirty.add(category ?? 'all')\n if (timer)\n return\n timer = setTimeout(() => {\n timer = null\n const which = [...dirty]\n dirty.clear()\n check(which)\n }, debounceMs)\n }\n\n return {\n schedule,\n refresh(active) {\n closeAll()\n if (closed || !active)\n return\n for (const target of syncWatchTargets(sources)) {\n const isDir = existsSync(target.path) && statSync(target.path).isDirectory()\n const at = isDir ? target.path : dirname(target.path)\n if (!existsSync(at))\n continue\n const name = basename(target.path)\n try {\n // A file's folder: only that file's events.\n watchers.push(watch(at, { recursive: isDir && target.recursive, persistent: false }, (_event, changed) => {\n if (isDir || changed === null || String(changed) === name)\n schedule(target.category)\n }))\n }\n catch {\n // A folder that can't be watched: the app's own reports still find its changes.\n }\n }\n },\n count: () => watchers.length,\n close() {\n closed = true\n if (timer)\n clearTimeout(timer)\n timer = null\n closeAll()\n },\n }\n}\n","/**\n * Settings sync, the client side shared by the TUI and the GUI main process:\n * for each saved server, push this computer's categories to it\n * (`sync.claim`, `sync.push`), now (Import once) or as they change (Keep in\n * sync). Loaded by each app behind its `remoteHosts` gate only, with the\n * saved hosts; nothing here dials: the app hands over each server's\n * connection (`connected` / `disconnected`).\n *\n * Change detection: file watchers on what each category reads\n * (`syncWatchTargets`), only while some server keeps in sync, plus the\n * app's own reports (`notifyLocalChange`: its settings stream). Either one\n * schedules a check (debounced): a category whose snapshot hashes\n * differently from what was last pushed is queued (`pending`, persisted in\n * `hosts-sync.json`), and the queue flushes when the server is connected.\n * Offline, it waits; the newest value wins, there being one source.\n */\nimport type { ProviderDescriptor } from '../providers'\nimport type { DeviceIdentity, ServerSyncConfig } from './local'\nimport type { SyncCategory, SyncClaimResult, SyncPayload, SyncPayloads, SyncPushResult, SyncStatus } from './types'\nimport { collectSyncPayload, storedApiKeyProviders, userExtensions } from './collect'\nimport { hashValue } from './hash'\nimport { readDeviceIdentity } from './local'\nimport { createSyncPusher } from './pusher'\nimport { fieldCategory, SYNC_CATEGORIES } from './types'\nimport { createSyncWatchers } from './watchers'\n\n/** The part of a host connection sync uses (an `IpcClient` is one). */\nexport interface SyncClient {\n /** Sends a sync RPC to the server and resolves with its reply. */\n request: ((method: 'sync.status', params: Record<string, never>) => Promise<SyncStatus>)\n & ((method: 'sync.claim', params: { deviceId: string, deviceName: string, takeover?: boolean, categories?: SyncCategory[], keys?: string[] }) => Promise<SyncClaimResult>)\n & ((method: 'sync.push', params: { deviceId: string, category: SyncCategory, payload: SyncPayload }) => Promise<SyncPushResult>)\n & ((method: 'sync.reset', params: { field: string }) => Promise<{ reset: boolean }>)\n & ((method: 'sync.release', params: { deviceId: string }) => Promise<{ released: boolean }>)\n /** What the server announced when it connected. `sync` is set when it supports settings sync. */\n hello: { sync?: boolean }\n}\n\n/** Options for {@link createSyncEngine}. */\nexport interface SyncEngineOptions {\n /** Directory holding the sync state files and the device identity. */\n dataDir: string\n /** Path of the file holding the app's saved settings. */\n statePath: string\n /** User home directory, where user-scope files and skills are read from. */\n home: string\n /** Storage prefix, such as `.zidane`. */\n prefix: string\n /** Returns the provider descriptors used to list API keys that can be opted in. */\n providers: () => Readonly<Record<string, ProviderDescriptor>>\n /** Default: this computer's host name. */\n deviceName?: string\n /** Wait after a change before checking (a save is often several writes). Default 500 ms. */\n debounceMs?: number\n /** File watchers (default on); off, only `notifyLocalChange` finds changes. */\n watch?: boolean\n}\n\n/** What a UI shows for one server. */\nexport interface SyncView {\n /** Saved sync settings for the server. */\n config: ServerSyncConfig\n /** Whether a connection to the server is open. */\n connected: boolean\n /** The server takes sync (`ipc.hello.sync`); false for an older server. */\n supported: boolean\n /** The server's record, when read. */\n status: SyncStatus | null\n /** Another device syncs to this server: its name. */\n conflict: string | null\n /** A push or refresh is running. */\n busy: boolean\n}\n\n/** Pushes this computer's settings to saved servers and tracks the state each one reports. Servers are identified by key. */\nexport interface SyncEngine {\n /** Identity of this computer. */\n device: DeviceIdentity\n /** Returns what a UI shows for the server. */\n view: (key: string) => SyncView\n /** Change the mode, categories or opted-in keys; pushes what that calls for. */\n configure: (key: string, patch: Partial<Pick<ServerSyncConfig, 'mode' | 'categories' | 'keys'>>) => Promise<void>\n /** Push every selected category now (whatever the mode, but off). */\n pushAll: (key: string) => Promise<void>\n /** Become the source of a server another device syncs to, then push. */\n takeOver: (key: string) => Promise<void>\n /** Drop an override on the server (the next push writes the field again). */\n reset: (key: string, field: string) => Promise<void>\n /** Read the server's record again. */\n refresh: (key: string) => Promise<void>\n /** Reports that a connection to the server opened. Reads its record and pushes what its mode calls for. */\n connected: (key: string, client: SyncClient) => void\n /** Reports that the connection to the server closed. */\n disconnected: (key: string) => void\n /** A server's `sync:changed` signal. */\n serverChanged: (key: string) => void\n /** The server was removed here: forget its sync config (the server keeps what it has). */\n removed: (key: string) => void\n /** This computer changed something (the app's settings stream): check, push if it differs. */\n notifyLocalChange: (category?: SyncCategory) => void\n /** What this computer has that the UIs mention: API keys to opt in, extensions that can't sync, stdio MCP servers. */\n localInfo: () => SyncLocalInfo\n /** File watchers are running (some server keeps in sync). */\n watching: () => boolean\n /** Calls `listener` when any view changes. Returns a function that removes it. */\n subscribe: (listener: () => void) => () => void\n /** Stops the file watchers and pending pushes. */\n stop: () => void\n}\n\n/** What this computer has that sync UIs mention. */\nexport interface SyncLocalInfo {\n /** Providers with an API key that can be opted in, with display labels. */\n keyProviders: { key: string, label: string }[]\n /** Names of extensions that cannot sync because they are not installed from npm or GitHub. */\n localExtensions: string[]\n /** Names of stdio MCP servers, whose commands may be missing on the server. */\n stdioMcps: string[]\n}\n\n/**\n * Engines CREATED in this process so far: monotonic (never decremented when\n * one stops), not a live count. The containment tests compare it before and\n * after a mount to prove an engine did, or did not, start.\n */\nlet engines = 0\nexport function syncEngineCount(): number {\n return engines\n}\n\n/**\n * Creates a sync engine for this computer. Starts file watchers once a server is set to keep in sync.\n *\n * @param options - Paths, providers and timing for the engine.\n */\nexport function createSyncEngine(options: SyncEngineOptions): SyncEngine {\n engines++\n const sources = { dataDir: options.dataDir, statePath: options.statePath, home: options.home, prefix: options.prefix, providers: options.providers }\n const device = readDeviceIdentity(options.dataDir, options.deviceName)\n const listeners = new Set<() => void>()\n const emit = (): void => {\n for (const listener of [...listeners]) {\n try {\n listener()\n }\n catch {}\n }\n }\n const pusher = createSyncPusher({ sources, device, emit })\n const { configOf, save, queue, flush, clients, statuses, conflicts } = pusher\n const keeping = (): string[] => Object.entries(pusher.configs).filter(([, c]) => c.mode === 'keep').map(([key]) => key)\n\n const watchers = createSyncWatchers({\n sources,\n debounceMs: options.debounceMs ?? 500,\n // Each server that keeps in sync: queue what changed, push it.\n check: (which) => {\n for (const key of keeping()) {\n const config = configOf(key)\n const changed = which.includes('all') ? pusher.changedCategories(config) : which.flatMap(c => pusher.changedCategories(config, c as SyncCategory))\n if (changed.length > 0) {\n queue(key, changed)\n void flush(key)\n }\n }\n refreshWatchers()\n },\n })\n function refreshWatchers(): void {\n watchers.refresh(options.watch !== false && keeping().length > 0)\n emit()\n }\n\n /** A config patch applied: what it turns on gets pushed (all of it when a mode starts). */\n async function apply(key: string, before: ServerSyncConfig, next: ServerSyncConfig, patch: Partial<ServerSyncConfig>): Promise<void> {\n if (next.mode === 'off') {\n const turnedOff = before.mode !== 'off'\n save(key, turnedOff ? { ...next, pending: [], sent: {} } : next)\n if (turnedOff) {\n refreshWatchers()\n // The server keeps what it has; it stops naming this device as its source.\n await pusher.release(key)\n emit()\n }\n return\n }\n const fresh = before.mode === 'off' || patch.mode === 'once'\n const added = next.categories.filter(c => !before.categories.includes(c))\n const keysChanged = patch.keys !== undefined && hashValue(before.keys) !== hashValue(next.keys)\n const toPush = fresh ? next.categories : [...added, ...(keysChanged && next.categories.includes('keys') ? ['keys' as const] : [])]\n next.pending = SYNC_CATEGORIES.filter(c => next.categories.includes(c) && (next.pending.includes(c) || toPush.includes(c)))\n if (fresh)\n next.sent = {}\n save(key, next)\n refreshWatchers()\n // New categories or keys with nothing queued: claim again, the server checks pushes against them.\n const client = clients.get(key)\n if (client?.hello.sync && next.pending.length === 0 && (added.length > 0 || keysChanged)) {\n await pusher.claim(key, client, false).catch(err => pusher.fail(key, err))\n emit()\n }\n await flush(key)\n }\n\n const engine: SyncEngine = {\n device,\n\n view: key => ({\n config: configOf(key),\n connected: clients.has(key),\n supported: clients.get(key)?.hello.sync === true,\n status: statuses.get(key) ?? null,\n conflict: conflicts.get(key) ?? null,\n busy: pusher.flushing.has(key),\n }),\n\n configure(key, patch) {\n const before = configOf(key)\n const next: ServerSyncConfig = {\n ...before,\n ...(patch.mode ? { mode: patch.mode } : {}),\n ...(patch.categories ? { categories: SYNC_CATEGORIES.filter(c => patch.categories!.includes(c)) } : {}),\n ...(patch.keys ? { keys: [...new Set(patch.keys)] } : {}),\n }\n return apply(key, before, next, patch)\n },\n\n async pushAll(key) {\n const config = configOf(key)\n if (config.mode === 'off')\n return\n save(key, { ...config, pending: [...config.categories], sent: {} })\n await flush(key)\n },\n\n async takeOver(key) {\n const config = configOf(key)\n if (config.mode === 'off')\n return\n save(key, { ...config, pending: [...config.categories], sent: {} })\n await flush(key, true)\n },\n\n async reset(key, field) {\n const client = clients.get(key)\n if (!client)\n throw new Error('The server is not connected.')\n await client.request('sync.reset', { field })\n await pusher.refresh(key)\n // That field is sync's again: send its category.\n const category = fieldCategory(field)\n const config = configOf(key)\n if (category && config.categories.includes(category) && config.mode !== 'off') {\n save(key, { ...config, sent: { ...config.sent, [category]: '' } })\n queue(key, [category])\n await flush(key)\n }\n },\n\n refresh: key => pusher.refresh(key),\n\n connected(key, client) {\n clients.set(key, client)\n emit()\n if (!client.hello.sync)\n return\n const config = configOf(key)\n // Keep in sync: what changed here while away (or while this app was closed) joins the queue.\n if (config.mode === 'keep') {\n const changed = pusher.changedCategories(config)\n if (changed.length > 0)\n queue(key, changed)\n }\n void pusher.refresh(key).then(() => flush(key))\n },\n\n disconnected(key) {\n clients.delete(key)\n emit()\n },\n\n serverChanged: (key) => {\n const before = statuses.get(key)\n void pusher.refresh(key).then(() => {\n // An override reset there (from any window): its category is sync's again, push it.\n const after = statuses.get(key)\n const config = configOf(key)\n if (!before || !after || after.source?.deviceId !== device.id || config.mode === 'off')\n return\n const back = Object.keys(before.overrides).filter(field => !after.overrides[field]).map(fieldCategory).filter((c): c is SyncCategory => c !== undefined && config.categories.includes(c))\n if (back.length === 0)\n return\n save(key, { ...config, sent: Object.fromEntries(Object.entries(config.sent).filter(([c]) => !back.includes(c as SyncCategory))) })\n queue(key, back)\n void flush(key)\n })\n },\n\n removed(key) {\n if (configOf(key).mode !== 'off')\n void pusher.release(key)\n pusher.forget(key)\n refreshWatchers()\n },\n\n notifyLocalChange(category) {\n if (keeping().length > 0)\n watchers.schedule(category)\n },\n\n localInfo: () => syncLocalInfo(sources),\n\n watching: () => watchers.count() > 0,\n\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n\n stop() {\n watchers.close()\n pusher.stop()\n listeners.clear()\n },\n }\n\n refreshWatchers()\n return engine\n}\n\nfunction syncLocalInfo(sources: Parameters<typeof storedApiKeyProviders>[0]): SyncLocalInfo {\n const read = <T>(fn: () => T, fallback: T): T => {\n try {\n return fn()\n }\n catch {\n return fallback\n }\n }\n return {\n keyProviders: read(() => storedApiKeyProviders(sources), []),\n localExtensions: read(() => userExtensions(sources).local, []),\n stdioMcps: read(() => (collectSyncPayload('mcps', sources) as SyncPayloads['mcps']).servers.filter(s => typeof s.command === 'string' && s.command !== '').map(s => String(s.name)), []),\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"engine-XmoPPB6U.js","names":[],"sources":["../src/chat/sync/collect.ts","../src/chat/sync/local.ts","../src/chat/sync/pusher.ts","../src/chat/sync/watchers.ts","../src/chat/sync/engine.ts"],"sourcesContent":["/**\n * This computer's state for each sync category, read from disk as a\n * `sync.push` payload (`./types` `SyncPayloads`): what the user set here,\n * never what a server session put in a window.\n *\n * - settings: `state.json`'s settings over the defaults, syncable keys only;\n * - safelists: `projects.json`;\n * - files: the user-scope `SYSTEM.md`, and the user-scope skills\n * (`~/.agents/skills`, `~/.<prefix>/skills`; the first of a name wins),\n * bounded like the server bounds them (a skill over them is left out);\n * - mcps: the user-scope `mcps.json` files (the first of a name wins);\n * - extensions: user-scope extensions installed from a source (their\n * `.install.json`); the others are listed as not syncable;\n * - keys: the stored API keys of the providers opted in.\n */\nimport type { ProviderDescriptor } from '../providers'\nimport type { SyncCategory, SyncFile, SyncPayloads } from './types'\nimport { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs'\nimport { join, relative, sep } from 'node:path'\nimport { readProviderCredential } from '../credentials'\nimport { parseMcpsFile } from '../mcps-discovery'\nimport { projectUserPaths } from '../project-user-paths'\nimport { readProjects } from '../safe-mode'\nimport { DEFAULT_SETTINGS, settingsFromStored } from '../settings-defaults'\nimport { loadState } from '../store'\nimport { userSystemMdPath } from '../system-md'\nimport { isSyncableSetting, settingsToWire } from './settings-keys'\n\nexport interface SyncSources {\n /** The user dir (`projects.json`, `credentials.json`). */\n dataDir: string\n /** This computer's `state.json`. */\n statePath: string\n home: string\n prefix: string\n providers: () => Readonly<Record<string, ProviderDescriptor>>\n}\n\nconst MAX_FILE_BYTES = 1024 * 1024\nconst MAX_SKILL_BYTES = 4 * 1024 * 1024\nconst MAX_SKILL_FILES = 200\nconst MAX_DEPTH = 8\n/** Not part of a skill: version control and installed dependencies. */\nconst SKIPPED_DIRS = new Set(['.git', 'node_modules'])\n\nfunction userPaths(sources: SyncSources, subPath: string): string[] {\n return projectUserPaths({ subPath, cwd: sources.home, home: sources.home, prefix: sources.prefix }).filter(p => p.source === 'user').map(p => p.path)\n}\n\n/** Every file and folder a category reads: what the watchers watch. */\nexport function syncWatchTargets(sources: SyncSources): { category: SyncCategory, path: string, recursive: boolean }[] {\n return [\n { category: 'settings', path: sources.statePath, recursive: false },\n { category: 'safelists', path: join(sources.dataDir, 'projects.json'), recursive: false },\n { category: 'files', path: userSystemMdPath({ home: sources.home, prefix: sources.prefix }), recursive: false },\n ...userPaths(sources, 'skills').map(path => ({ category: 'files' as const, path, recursive: true })),\n ...userPaths(sources, 'mcps.json').map(path => ({ category: 'mcps' as const, path, recursive: false })),\n ...userPaths(sources, 'extensions').map(path => ({ category: 'extensions' as const, path, recursive: true })),\n { category: 'keys', path: join(sources.dataDir, 'credentials.json'), recursive: false },\n ]\n}\n\nfunction settingsPayload(sources: SyncSources): SyncPayloads['settings'] {\n const stored = settingsFromStored(loadState(sources.statePath).settings ?? {})\n const merged = { ...DEFAULT_SETTINGS, ...stored } as Record<string, unknown>\n return { values: settingsToWire(Object.fromEntries(Object.entries(merged).filter(([key]) => key in DEFAULT_SETTINGS && isSyncableSetting(key)))) }\n}\n\nfunction safelistsPayload(sources: SyncSources): SyncPayloads['safelists'] {\n const projects = readProjects(sources.dataDir)\n return { projects: Object.fromEntries(Object.entries(projects).flatMap(([path, entry]) => (Array.isArray(entry?.safelist) ? [[path, [...entry.safelist]]] : []))) }\n}\n\n/** A skill folder's files, or null when it is over the bounds (or not a plain folder). */\nfunction skillFiles(dir: string): SyncFile[] | null {\n const files: SyncFile[] = []\n let total = 0\n const walk = (at: string, depth: number): boolean => {\n if (depth > MAX_DEPTH)\n return false\n for (const name of readdirSync(at).sort()) {\n const path = join(at, name)\n const stat = lstatSync(path)\n if (stat.isDirectory()) {\n if (SKIPPED_DIRS.has(name))\n continue\n if (!walk(path, depth + 1))\n return false\n }\n else if (stat.isFile()) {\n if (stat.size > MAX_FILE_BYTES || files.length >= MAX_SKILL_FILES)\n return false\n total += stat.size\n if (total > MAX_SKILL_BYTES)\n return false\n files.push({ path: relative(dir, path).split(sep).join('/'), data: readFileSync(path).toString('base64') })\n }\n // Links and anything else: not copied.\n }\n return true\n }\n try {\n return walk(dir, 1) && files.length > 0 ? files : null\n }\n catch {\n return null\n }\n}\n\n/** The user-scope skills: name → folder, the first root of a name winning (as discovery does). */\nexport function userSkillDirs(sources: SyncSources): Map<string, string> {\n const found = new Map<string, string>()\n for (const root of userPaths(sources, 'skills')) {\n let names: string[]\n try {\n names = readdirSync(root).sort()\n }\n catch {\n continue\n }\n for (const name of names) {\n const dir = join(root, name)\n if (!found.has(name) && !name.startsWith('.') && existsSync(join(dir, 'SKILL.md')) && lstatSync(dir).isDirectory())\n found.set(name, dir)\n }\n }\n return found\n}\n\nfunction filesPayload(sources: SyncSources): SyncPayloads['files'] {\n const mdPath = userSystemMdPath({ home: sources.home, prefix: sources.prefix })\n const systemMd = existsSync(mdPath) ? readFileSync(mdPath, 'utf8') : null\n const skills: SyncPayloads['files']['skills'] = []\n for (const [name, dir] of userSkillDirs(sources)) {\n const files = skillFiles(dir)\n if (files)\n skills.push({ name, files })\n }\n return { systemMd, skills }\n}\n\nfunction mcpsPayload(sources: SyncSources): SyncPayloads['mcps'] {\n const servers = new Map<string, Record<string, unknown>>()\n for (const path of userPaths(sources, 'mcps.json')) {\n if (!existsSync(path))\n continue\n try {\n for (const server of parseMcpsFile(readFileSync(path, 'utf8'))) {\n if (!servers.has(server.name))\n servers.set(server.name, server as unknown as Record<string, unknown>)\n }\n }\n catch {\n // A file discovery can't read either: nothing to sync from it.\n }\n }\n return { servers: [...servers.values()] }\n}\n\n/** User-scope extensions: those with a source (syncable) and the local ones (not). */\nexport function userExtensions(sources: SyncSources): { syncable: SyncPayloads['extensions']['extensions'], local: string[] } {\n const syncable: SyncPayloads['extensions']['extensions'] = []\n const local: string[] = []\n const seen = new Set<string>()\n for (const root of userPaths(sources, 'extensions')) {\n let names: string[]\n try {\n names = readdirSync(root).sort()\n }\n catch {\n continue\n }\n for (const name of names) {\n const dir = join(root, name)\n if (name.startsWith('.') || seen.has(name) || !lstatSync(dir).isDirectory())\n continue\n seen.add(name)\n // `.install.json` (`src/extensions/install.ts`): the spec an install replays.\n let provenance: { spec?: unknown, extension?: unknown } | null = null\n try {\n provenance = JSON.parse(readFileSync(join(dir, '.install.json'), 'utf8'))\n }\n catch {}\n if (provenance && typeof provenance.spec === 'string' && provenance.spec.trim() !== '')\n syncable.push({ name, spec: provenance.spec, ...(typeof provenance.extension === 'string' ? { extension: provenance.extension } : {}) })\n else\n local.push(name)\n }\n }\n return { syncable, local }\n}\n\n/** Providers with an API key stored here: what the keys category can offer. */\nexport function storedApiKeyProviders(sources: SyncSources): { key: string, label: string }[] {\n return Object.values(sources.providers()).flatMap((descriptor) => {\n const credential = readProviderCredential(sources.dataDir, descriptor)\n return credential?.kind === 'apikey' && credential.value ? [{ key: descriptor.key, label: descriptor.label }] : []\n })\n}\n\nfunction keysPayload(sources: SyncSources, optedIn: readonly string[]): SyncPayloads['keys'] {\n const providers = sources.providers()\n return {\n keys: optedIn.flatMap((provider) => {\n const descriptor = providers[provider]\n const credential = descriptor ? readProviderCredential(sources.dataDir, descriptor) : undefined\n return credential?.kind === 'apikey' && credential.value ? [{ provider, key: credential.value }] : []\n }),\n }\n}\n\nexport function collectSyncPayload(category: SyncCategory, sources: SyncSources, optedInKeys: readonly string[] = []): SyncPayloads[SyncCategory] {\n switch (category) {\n case 'settings': return settingsPayload(sources)\n case 'safelists': return safelistsPayload(sources)\n case 'files': return filesPayload(sources)\n case 'mcps': return mcpsPayload(sources)\n case 'extensions': return { extensions: userExtensions(sources).syncable }\n case 'keys': return keysPayload(sources, optedInKeys)\n }\n}\n","/**\n * This computer's side of settings sync, on disk:\n *\n * - `<dataDir>/device.json` (0600): the device id servers know this computer\n * by (random, made once) and its name (the host name).\n * - `<dataDir>/hosts-sync.json` (0600), next to `hosts.json`: per saved\n * server (by host id), the mode, the categories, the API keys opted in,\n * the categories still to push (the offline queue: one entry per category,\n * the newest value wins, so at most six) and the outcome of the last push.\n */\nimport type { SyncCategory, SyncMode, SyncPushResult } from './types'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { hostname } from 'node:os'\nimport { join } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { isRecord } from './hash'\nimport { SYNC_CATEGORIES, SYNC_MODES } from './types'\n\nexport interface DeviceIdentity {\n id: string\n name: string\n}\n\n/** Saved sync settings for one server, kept in `hosts-sync.json`. */\nexport interface ServerSyncConfig {\n /** Whether and how this computer syncs to the server. */\n mode: SyncMode\n /** Categories sent to the server. */\n categories: SyncCategory[]\n /** Providers whose stored API key goes to this server. */\n keys: string[]\n /** Categories changed here and not pushed yet (offline queue). */\n pending: SyncCategory[]\n /** Per category, a hash of what was last pushed (a restart finds what changed meanwhile). */\n sent: Partial<Record<SyncCategory, string>>\n /** Time of the last successful push in epoch ms. */\n lastSyncAt?: number\n /** Message of the last failed push. */\n lastError?: string\n /** What the last push of each category did there. */\n results: Partial<Record<SyncCategory, SyncPushResult>>\n}\n\ninterface SyncConfigFile {\n version: 1\n servers: Record<string, ServerSyncConfig>\n}\n\nexport const DEFAULT_SERVER_SYNC: Readonly<ServerSyncConfig> = { mode: 'off', categories: ['settings'], keys: [], pending: [], sent: {}, results: {} }\n\nexport function hostsSyncPath(dataDir: string): string {\n return join(dataDir, 'hosts-sync.json')\n}\n\nexport function deviceIdentityPath(dataDir: string): string {\n return join(dataDir, 'device.json')\n}\n\nfunction readJson(path: string): unknown {\n if (!existsSync(path))\n return undefined\n try {\n return JSON.parse(readFileSync(path, 'utf8'))\n }\n catch {\n return undefined\n }\n}\n\n/** This computer's device id and name, made on first use. */\nexport function readDeviceIdentity(dataDir: string, name?: string): DeviceIdentity {\n const raw = readJson(deviceIdentityPath(dataDir))\n if (isRecord(raw) && typeof raw.id === 'string' && raw.id !== '')\n return { id: raw.id, name: name ?? (typeof raw.name === 'string' && raw.name ? raw.name : hostname()) }\n const identity = { id: randomUUID(), name: name ?? hostname() }\n writeJsonFileAtomic(deviceIdentityPath(dataDir), identity, OWNER_ONLY)\n return identity\n}\n\nfunction categoriesOf(value: unknown): SyncCategory[] {\n return Array.isArray(value) ? SYNC_CATEGORIES.filter(c => value.includes(c)) : []\n}\n\nfunction serverConfigOf(raw: unknown): ServerSyncConfig {\n if (!isRecord(raw))\n return { ...DEFAULT_SERVER_SYNC }\n return {\n mode: SYNC_MODES.includes(raw.mode as SyncMode) ? raw.mode as SyncMode : 'off',\n categories: categoriesOf(raw.categories),\n keys: Array.isArray(raw.keys) ? raw.keys.filter((k): k is string => typeof k === 'string') : [],\n pending: categoriesOf(raw.pending),\n sent: isRecord(raw.sent) ? Object.fromEntries(Object.entries(raw.sent).filter(([c, h]) => SYNC_CATEGORIES.includes(c as SyncCategory) && typeof h === 'string')) : {},\n ...(typeof raw.lastSyncAt === 'number' ? { lastSyncAt: raw.lastSyncAt } : {}),\n ...(typeof raw.lastError === 'string' ? { lastError: raw.lastError } : {}),\n results: isRecord(raw.results) ? raw.results as ServerSyncConfig['results'] : {},\n }\n}\n\nexport function readSyncConfigs(dataDir: string): Record<string, ServerSyncConfig> {\n const raw = readJson(hostsSyncPath(dataDir))\n if (!isRecord(raw) || !isRecord(raw.servers))\n return {}\n return Object.fromEntries(Object.entries(raw.servers).map(([key, value]) => [key, serverConfigOf(value)]))\n}\n\nexport function writeSyncConfigs(dataDir: string, servers: Record<string, ServerSyncConfig>): void {\n const file: SyncConfigFile = { version: 1, servers }\n writeJsonFileAtomic(hostsSyncPath(dataDir), file, OWNER_ONLY)\n}\n","/**\n * The push side of settings sync (`./engine`): per server, its config (read\n * from and saved to `hosts-sync.json`), its connection, what it said last\n * (`sync.status`, a conflicting source), and the queue flush: claim, then\n * push each pending category's snapshot, one flush at a time per server.\n */\nimport type { SyncSources } from './collect'\nimport type { SyncClient } from './engine'\nimport type { DeviceIdentity, ServerSyncConfig } from './local'\nimport type { SyncCategory, SyncStatus } from './types'\nimport { collectSyncPayload } from './collect'\nimport { hashValue } from './hash'\nimport { DEFAULT_SERVER_SYNC, readSyncConfigs, writeSyncConfigs } from './local'\nimport { SYNC_CATEGORIES } from './types'\n\nconst errorText = (err: unknown): string => (err instanceof Error ? err.message : String(err))\n\nexport function createSyncPusher({ sources, device, emit }: { sources: SyncSources, device: DeviceIdentity, emit: () => void }) {\n const configs = readSyncConfigs(sources.dataDir)\n const clients = new Map<string, SyncClient>()\n const statuses = new Map<string, SyncStatus>()\n const conflicts = new Map<string, string>()\n const flushing = new Map<string, Promise<void>>()\n const again = new Set<string>()\n let stopped = false\n\n const configOf = (key: string): ServerSyncConfig => configs[key] ?? { ...DEFAULT_SERVER_SYNC, categories: [...DEFAULT_SERVER_SYNC.categories] }\n const save = (key: string, config: ServerSyncConfig): void => {\n configs[key] = config\n writeSyncConfigs(sources.dataDir, configs)\n emit()\n }\n const fail = (key: string, err: unknown): void => save(key, { ...configOf(key), lastError: errorText(err) })\n\n /** Categories whose snapshot here differs from what was last pushed to the server. */\n const changedCategories = (config: ServerSyncConfig, only?: SyncCategory): SyncCategory[] =>\n config.categories.filter((category) => {\n if (only && category !== only)\n return false\n try {\n return hashValue(collectSyncPayload(category, sources, config.keys)) !== config.sent[category]\n }\n catch {\n return true\n }\n })\n\n const queue = (key: string, categories: readonly SyncCategory[]): void => {\n const config = configOf(key)\n const pending = SYNC_CATEGORIES.filter(c => config.pending.includes(c) || categories.includes(c))\n if (pending.length !== config.pending.length)\n save(key, { ...config, pending })\n }\n\n async function claim(key: string, client: SyncClient, takeover: boolean): Promise<boolean> {\n const config = configOf(key)\n const result = await client.request('sync.claim', { deviceId: device.id, deviceName: device.name, categories: config.categories, keys: config.keys, ...(takeover ? { takeover: true } : {}) })\n statuses.set(key, result.status)\n if (result.claimed)\n conflicts.delete(key)\n else\n conflicts.set(key, result.status.source?.deviceName ?? 'another device')\n return result.claimed\n }\n\n async function flushOnce(key: string, takeover: boolean): Promise<void> {\n const client = clients.get(key)\n let config = configOf(key)\n if (!client || !client.hello.sync || config.mode === 'off' || (config.pending.length === 0 && !takeover) || stopped)\n return\n try {\n if (!(await claim(key, client, takeover)))\n return\n for (const category of [...configOf(key).pending]) {\n config = configOf(key)\n if (!config.categories.includes(category)) {\n save(key, { ...config, pending: config.pending.filter(c => c !== category) })\n continue\n }\n const payload = collectSyncPayload(category, sources, config.keys)\n const result = await client.request('sync.push', { deviceId: device.id, category, payload })\n config = configOf(key)\n const { lastError: _dropped, ...rest } = config\n save(key, {\n ...rest,\n pending: config.pending.filter(c => c !== category),\n sent: { ...config.sent, [category]: hashValue(payload) },\n results: { ...config.results, [category]: result },\n lastSyncAt: Date.now(),\n })\n }\n statuses.set(key, await client.request('sync.status', {}))\n }\n catch (err) {\n fail(key, err)\n }\n }\n\n /** Push the queue if the server is connected and this device is its source; `takeover` claims it first. */\n function flush(key: string, takeover = false): Promise<void> {\n const running = flushing.get(key)\n if (running && !takeover) {\n again.add(key)\n return running\n }\n const run = (async () => {\n if (running)\n await running\n await flushOnce(key, takeover)\n // A change while pushing: once more (`flushOnce` stops on its own once stopped).\n while (again.delete(key))\n await flushOnce(key, false)\n })().finally(() => {\n if (flushing.get(key) === run)\n flushing.delete(key)\n emit()\n })\n flushing.set(key, run)\n emit()\n return run\n }\n\n /** Read the server's record: who syncs there now. */\n async function refresh(key: string): Promise<void> {\n const client = clients.get(key)\n if (!client?.hello.sync)\n return\n try {\n const status = await client.request('sync.status', {})\n statuses.set(key, status)\n if (!status.source || status.source.deviceId === device.id)\n conflicts.delete(key)\n else if (configOf(key).mode !== 'off')\n conflicts.set(key, status.source.deviceName)\n }\n catch {}\n emit()\n }\n\n /** This device stops being the server's source (the server keeps what it has). */\n async function release(key: string): Promise<void> {\n const client = clients.get(key)\n conflicts.delete(key)\n if (!client?.hello.sync)\n return\n await client.request('sync.release', { deviceId: device.id }).catch(() => undefined)\n const status = await client.request('sync.status', {}).catch(() => null)\n if (status)\n statuses.set(key, status)\n }\n\n function forget(key: string): void {\n clients.delete(key)\n statuses.delete(key)\n conflicts.delete(key)\n if (configs[key]) {\n delete configs[key]\n writeSyncConfigs(sources.dataDir, configs)\n }\n }\n\n return {\n configs,\n clients,\n statuses,\n conflicts,\n flushing,\n configOf,\n save,\n fail,\n changedCategories,\n queue,\n claim,\n flush,\n refresh,\n release,\n forget,\n stop: () => {\n stopped = true\n clients.clear()\n },\n }\n}\n","/**\n * File watchers for settings sync (`./engine`): on each file and folder a\n * category reads (`syncWatchTargets`), or the folder it would appear in.\n * Events are debounced into one check of the categories they touched; the\n * watchers are rebuilt after each check (a folder created since, such as the\n * first skill, is then watched too).\n */\nimport type { SyncSources } from './collect'\nimport type { SyncCategory } from './types'\nimport { existsSync, statSync, watch } from 'node:fs'\nimport { basename, dirname } from 'node:path'\nimport { syncWatchTargets } from './collect'\n\nexport interface SyncWatchers {\n /** Start (or restart) the watchers when `active`, else close them. */\n refresh: (active: boolean) => void\n /** Report a change (a watcher, or the app's own settings stream). */\n schedule: (category?: SyncCategory) => void\n count: () => number\n close: () => void\n}\n\nexport function createSyncWatchers({ sources, debounceMs, check }: {\n sources: SyncSources\n debounceMs: number\n /** After the debounce: the categories that changed (`all`: unknown which), then the watchers are refreshed by the caller. */\n check: (which: readonly (SyncCategory | 'all')[]) => void\n}): SyncWatchers {\n let watchers: { close: () => void }[] = []\n let timer: ReturnType<typeof setTimeout> | null = null\n let closed = false\n const dirty = new Set<SyncCategory | 'all'>()\n\n const closeAll = (): void => {\n for (const w of watchers)\n w.close()\n watchers = []\n }\n\n const schedule = (category?: SyncCategory): void => {\n if (closed)\n return\n dirty.add(category ?? 'all')\n if (timer)\n return\n timer = setTimeout(() => {\n timer = null\n const which = [...dirty]\n dirty.clear()\n check(which)\n }, debounceMs)\n }\n\n return {\n schedule,\n refresh(active) {\n closeAll()\n if (closed || !active)\n return\n for (const target of syncWatchTargets(sources)) {\n const isDir = existsSync(target.path) && statSync(target.path).isDirectory()\n const at = isDir ? target.path : dirname(target.path)\n if (!existsSync(at))\n continue\n const name = basename(target.path)\n try {\n // A file's folder: only that file's events.\n watchers.push(watch(at, { recursive: isDir && target.recursive, persistent: false }, (_event, changed) => {\n if (isDir || changed === null || String(changed) === name)\n schedule(target.category)\n }))\n }\n catch {\n // A folder that can't be watched: the app's own reports still find its changes.\n }\n }\n },\n count: () => watchers.length,\n close() {\n closed = true\n if (timer)\n clearTimeout(timer)\n timer = null\n closeAll()\n },\n }\n}\n","/**\n * Settings sync, the client side shared by the TUI and the GUI main process:\n * for each saved server, push this computer's categories to it\n * (`sync.claim`, `sync.push`), now (Import once) or as they change (Keep in\n * sync). Loaded by each app behind its `remoteHosts` gate only, with the\n * saved hosts; nothing here dials: the app hands over each server's\n * connection (`connected` / `disconnected`).\n *\n * Change detection: file watchers on what each category reads\n * (`syncWatchTargets`), only while some server keeps in sync, plus the\n * app's own reports (`notifyLocalChange`: its settings stream). Either one\n * schedules a check (debounced): a category whose snapshot hashes\n * differently from what was last pushed is queued (`pending`, persisted in\n * `hosts-sync.json`), and the queue flushes when the server is connected.\n * Offline, it waits; the newest value wins, there being one source.\n */\nimport type { ProviderDescriptor } from '../providers'\nimport type { DeviceIdentity, ServerSyncConfig } from './local'\nimport type { SyncCategory, SyncClaimResult, SyncPayload, SyncPayloads, SyncPushResult, SyncStatus } from './types'\nimport { collectSyncPayload, storedApiKeyProviders, userExtensions } from './collect'\nimport { hashValue } from './hash'\nimport { readDeviceIdentity } from './local'\nimport { createSyncPusher } from './pusher'\nimport { fieldCategory, SYNC_CATEGORIES } from './types'\nimport { createSyncWatchers } from './watchers'\n\n/** The part of a host connection sync uses (an `IpcClient` is one). */\nexport interface SyncClient {\n /** Sends a sync RPC to the server and resolves with its reply. */\n request: ((method: 'sync.status', params: Record<string, never>) => Promise<SyncStatus>)\n & ((method: 'sync.claim', params: { deviceId: string, deviceName: string, takeover?: boolean, categories?: SyncCategory[], keys?: string[] }) => Promise<SyncClaimResult>)\n & ((method: 'sync.push', params: { deviceId: string, category: SyncCategory, payload: SyncPayload }) => Promise<SyncPushResult>)\n & ((method: 'sync.reset', params: { field: string }) => Promise<{ reset: boolean }>)\n & ((method: 'sync.release', params: { deviceId: string }) => Promise<{ released: boolean }>)\n /** What the server announced when it connected. `sync` is set when it supports settings sync. */\n hello: { sync?: boolean }\n}\n\n/** Options for {@link createSyncEngine}. */\nexport interface SyncEngineOptions {\n /** Directory holding the sync state files and the device identity. */\n dataDir: string\n /** Path of the file holding the app's saved settings. */\n statePath: string\n /** User home directory, where user-scope files and skills are read from. */\n home: string\n /** Storage prefix, such as `.zidane`. */\n prefix: string\n /** Returns the provider descriptors used to list API keys that can be opted in. */\n providers: () => Readonly<Record<string, ProviderDescriptor>>\n /** Default: this computer's host name. */\n deviceName?: string\n /** Wait after a change before checking (a save is often several writes). Default 500 ms. */\n debounceMs?: number\n /** File watchers (default on); off, only `notifyLocalChange` finds changes. */\n watch?: boolean\n}\n\n/** What a UI shows for one server. */\nexport interface SyncView {\n /** Saved sync settings for the server. */\n config: ServerSyncConfig\n /** Whether a connection to the server is open. */\n connected: boolean\n /** The server takes sync (`ipc.hello.sync`); false for an older server. */\n supported: boolean\n /** The server's record, when read. */\n status: SyncStatus | null\n /** Another device syncs to this server: its name. */\n conflict: string | null\n /** A push or refresh is running. */\n busy: boolean\n}\n\n/** Pushes this computer's settings to saved servers and tracks the state each one reports. Servers are identified by key. */\nexport interface SyncEngine {\n /** Identity of this computer. */\n device: DeviceIdentity\n /** Returns what a UI shows for the server. */\n view: (key: string) => SyncView\n /** Change the mode, categories or opted-in keys; pushes what that calls for. */\n configure: (key: string, patch: Partial<Pick<ServerSyncConfig, 'mode' | 'categories' | 'keys'>>) => Promise<void>\n /** Push every selected category now (whatever the mode, but off). */\n pushAll: (key: string) => Promise<void>\n /** Become the source of a server another device syncs to, then push. */\n takeOver: (key: string) => Promise<void>\n /** Drop an override on the server (the next push writes the field again). */\n reset: (key: string, field: string) => Promise<void>\n /** Read the server's record again. */\n refresh: (key: string) => Promise<void>\n /** Reports that a connection to the server opened. Reads its record and pushes what its mode calls for. */\n connected: (key: string, client: SyncClient) => void\n /** Reports that the connection to the server closed. */\n disconnected: (key: string) => void\n /** A server's `sync:changed` signal. */\n serverChanged: (key: string) => void\n /** The server was removed here: forget its sync config (the server keeps what it has). */\n removed: (key: string) => void\n /** This computer changed something (the app's settings stream): check, push if it differs. */\n notifyLocalChange: (category?: SyncCategory) => void\n /** What this computer has that the UIs mention: API keys to opt in, extensions that can't sync, stdio MCP servers. */\n localInfo: () => SyncLocalInfo\n /** File watchers are running (some server keeps in sync). */\n watching: () => boolean\n /** Calls `listener` when any view changes. Returns a function that removes it. */\n subscribe: (listener: () => void) => () => void\n /** Stops the file watchers and pending pushes. */\n stop: () => void\n}\n\n/** What this computer has that sync UIs mention. */\nexport interface SyncLocalInfo {\n /** Providers with an API key that can be opted in, with display labels. */\n keyProviders: { key: string, label: string }[]\n /** Names of extensions that cannot sync because they are not installed from npm or GitHub. */\n localExtensions: string[]\n /** Names of stdio MCP servers, whose commands may be missing on the server. */\n stdioMcps: string[]\n}\n\n/**\n * Engines CREATED in this process so far: monotonic (never decremented when\n * one stops), not a live count. The containment tests compare it before and\n * after a mount to prove an engine did, or did not, start.\n */\nlet engines = 0\nexport function syncEngineCount(): number {\n return engines\n}\n\n/**\n * Creates a sync engine for this computer. Starts file watchers once a server is set to keep in sync.\n *\n * @param options - Paths, providers and timing for the engine.\n */\nexport function createSyncEngine(options: SyncEngineOptions): SyncEngine {\n engines++\n const sources = { dataDir: options.dataDir, statePath: options.statePath, home: options.home, prefix: options.prefix, providers: options.providers }\n const device = readDeviceIdentity(options.dataDir, options.deviceName)\n const listeners = new Set<() => void>()\n const emit = (): void => {\n for (const listener of [...listeners]) {\n try {\n listener()\n }\n catch {}\n }\n }\n const pusher = createSyncPusher({ sources, device, emit })\n const { configOf, save, queue, flush, clients, statuses, conflicts } = pusher\n const keeping = (): string[] => Object.entries(pusher.configs).filter(([, c]) => c.mode === 'keep').map(([key]) => key)\n\n const watchers = createSyncWatchers({\n sources,\n debounceMs: options.debounceMs ?? 500,\n // Each server that keeps in sync: queue what changed, push it.\n check: (which) => {\n for (const key of keeping()) {\n const config = configOf(key)\n const changed = which.includes('all') ? pusher.changedCategories(config) : which.flatMap(c => pusher.changedCategories(config, c as SyncCategory))\n if (changed.length > 0) {\n queue(key, changed)\n void flush(key)\n }\n }\n refreshWatchers()\n },\n })\n function refreshWatchers(): void {\n watchers.refresh(options.watch !== false && keeping().length > 0)\n emit()\n }\n\n /** A config patch applied: what it turns on gets pushed (all of it when a mode starts). */\n async function apply(key: string, before: ServerSyncConfig, next: ServerSyncConfig, patch: Partial<ServerSyncConfig>): Promise<void> {\n if (next.mode === 'off') {\n const turnedOff = before.mode !== 'off'\n save(key, turnedOff ? { ...next, pending: [], sent: {} } : next)\n if (turnedOff) {\n refreshWatchers()\n // The server keeps what it has; it stops naming this device as its source.\n await pusher.release(key)\n emit()\n }\n return\n }\n const fresh = before.mode === 'off' || patch.mode === 'once'\n const added = next.categories.filter(c => !before.categories.includes(c))\n const keysChanged = patch.keys !== undefined && hashValue(before.keys) !== hashValue(next.keys)\n const toPush = fresh ? next.categories : [...added, ...(keysChanged && next.categories.includes('keys') ? ['keys' as const] : [])]\n next.pending = SYNC_CATEGORIES.filter(c => next.categories.includes(c) && (next.pending.includes(c) || toPush.includes(c)))\n if (fresh)\n next.sent = {}\n save(key, next)\n refreshWatchers()\n // New categories or keys with nothing queued: claim again, the server checks pushes against them.\n const client = clients.get(key)\n if (client?.hello.sync && next.pending.length === 0 && (added.length > 0 || keysChanged)) {\n await pusher.claim(key, client, false).catch(err => pusher.fail(key, err))\n emit()\n }\n await flush(key)\n }\n\n const engine: SyncEngine = {\n device,\n\n view: key => ({\n config: configOf(key),\n connected: clients.has(key),\n supported: clients.get(key)?.hello.sync === true,\n status: statuses.get(key) ?? null,\n conflict: conflicts.get(key) ?? null,\n busy: pusher.flushing.has(key),\n }),\n\n configure(key, patch) {\n const before = configOf(key)\n const next: ServerSyncConfig = {\n ...before,\n ...(patch.mode ? { mode: patch.mode } : {}),\n ...(patch.categories ? { categories: SYNC_CATEGORIES.filter(c => patch.categories!.includes(c)) } : {}),\n ...(patch.keys ? { keys: [...new Set(patch.keys)] } : {}),\n }\n return apply(key, before, next, patch)\n },\n\n async pushAll(key) {\n const config = configOf(key)\n if (config.mode === 'off')\n return\n save(key, { ...config, pending: [...config.categories], sent: {} })\n await flush(key)\n },\n\n async takeOver(key) {\n const config = configOf(key)\n if (config.mode === 'off')\n return\n save(key, { ...config, pending: [...config.categories], sent: {} })\n await flush(key, true)\n },\n\n async reset(key, field) {\n const client = clients.get(key)\n if (!client)\n throw new Error('The server is not connected.')\n await client.request('sync.reset', { field })\n await pusher.refresh(key)\n // That field is sync's again: send its category.\n const category = fieldCategory(field)\n const config = configOf(key)\n if (category && config.categories.includes(category) && config.mode !== 'off') {\n save(key, { ...config, sent: { ...config.sent, [category]: '' } })\n queue(key, [category])\n await flush(key)\n }\n },\n\n refresh: key => pusher.refresh(key),\n\n connected(key, client) {\n clients.set(key, client)\n emit()\n if (!client.hello.sync)\n return\n const config = configOf(key)\n // Keep in sync: what changed here while away (or while this app was closed) joins the queue.\n if (config.mode === 'keep') {\n const changed = pusher.changedCategories(config)\n if (changed.length > 0)\n queue(key, changed)\n }\n void pusher.refresh(key).then(() => flush(key))\n },\n\n disconnected(key) {\n clients.delete(key)\n emit()\n },\n\n serverChanged: (key) => {\n const before = statuses.get(key)\n void pusher.refresh(key).then(() => {\n // An override reset there (from any window): its category is sync's again, push it.\n const after = statuses.get(key)\n const config = configOf(key)\n if (!before || !after || after.source?.deviceId !== device.id || config.mode === 'off')\n return\n const back = Object.keys(before.overrides).filter(field => !after.overrides[field]).map(fieldCategory).filter((c): c is SyncCategory => c !== undefined && config.categories.includes(c))\n if (back.length === 0)\n return\n save(key, { ...config, sent: Object.fromEntries(Object.entries(config.sent).filter(([c]) => !back.includes(c as SyncCategory))) })\n queue(key, back)\n void flush(key)\n })\n },\n\n removed(key) {\n if (configOf(key).mode !== 'off')\n void pusher.release(key)\n pusher.forget(key)\n refreshWatchers()\n },\n\n notifyLocalChange(category) {\n if (keeping().length > 0)\n watchers.schedule(category)\n },\n\n localInfo: () => syncLocalInfo(sources),\n\n watching: () => watchers.count() > 0,\n\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n\n stop() {\n watchers.close()\n pusher.stop()\n listeners.clear()\n },\n }\n\n refreshWatchers()\n return engine\n}\n\nfunction syncLocalInfo(sources: Parameters<typeof storedApiKeyProviders>[0]): SyncLocalInfo {\n const read = <T>(fn: () => T, fallback: T): T => {\n try {\n return fn()\n }\n catch {\n return fallback\n }\n }\n return {\n keyProviders: read(() => storedApiKeyProviders(sources), []),\n localExtensions: read(() => userExtensions(sources).local, []),\n stdioMcps: read(() => (collectSyncPayload('mcps', sources) as SyncPayloads['mcps']).servers.filter(s => typeof s.command === 'string' && s.command !== '').map(s => String(s.name)), []),\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as createProcessContext } from "./contexts-Bw06j9eP.js";
|
|
2
2
|
import { t as resolveStorageDirs } from "./xdg-CJS70jqe.js";
|
|
3
3
|
import { _ as workspacePath } from "./environment-B4asakh7.js";
|
|
4
|
-
import { Dt as teardownWorktree, Et as prepareWorktree, M as createWorkspaceConfinement, N as isInside, _ as sandboxUnreadableDirs, g as resolveSandboxForRoots } from "./oauth-
|
|
5
|
-
import { rt as MACHINE_STREAM_CHUNK_BYTES } from "./mcp-allowlist-
|
|
4
|
+
import { Dt as teardownWorktree, Et as prepareWorktree, M as createWorkspaceConfinement, N as isInside, _ as sandboxUnreadableDirs, g as resolveSandboxForRoots } from "./oauth-7_48zR7n.js";
|
|
5
|
+
import { rt as MACHINE_STREAM_CHUNK_BYTES } from "./mcp-allowlist-CLXweyxk.js";
|
|
6
6
|
import { Buffer } from "node:buffer";
|
|
7
7
|
import { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
8
8
|
import { isAbsolute, join, resolve } from "node:path";
|
|
@@ -618,4 +618,4 @@ function createMachineExecutor(options) {
|
|
|
618
618
|
//#endregion
|
|
619
619
|
export { createMachineExecutor, shareableRoot };
|
|
620
620
|
|
|
621
|
-
//# sourceMappingURL=executor-
|
|
621
|
+
//# sourceMappingURL=executor-BhthPE1q.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor-B8GoXaaE.js","names":[],"sources":["../src/ipc/machine/params.ts","../src/ipc/machine/streams.ts","../src/ipc/machine/task-logs.ts","../src/ipc/machine/terminals.ts","../src/ipc/machine/executor.ts"],"sourcesContent":["/**\n * Shape checks for what a host sends a machine. The host is not trusted: a\n * malformed request is refused before anything runs.\n */\nimport type { MachineHandleRef } from '../../chat/machine-protocol'\n\nexport type Params = Record<string, unknown>\n\nexport function paramsOf(value: unknown): Params {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error('Invalid params: expected an object.')\n return value as Params\n}\n\nexport function str(params: Params, key: string): string {\n const value = params[key]\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optStr(params: Params, key: string): string | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optNum(params: Params, key: string): number | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isFinite(value))\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function num(params: Params, key: string): number {\n const value = optNum(params, key)\n if (value === undefined)\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function optEnv(params: Params, key: string): Record<string, string> | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (!value || typeof value !== 'object' || Array.isArray(value) || Object.values(value).some(v => typeof v !== 'string'))\n throw new Error(`Invalid params: \"${key}\" must map names to strings.`)\n return value as Record<string, string>\n}\n\nexport function handleRef(params: Params): MachineHandleRef {\n const handle = params.handle as Partial<MachineHandleRef> | undefined\n if (!handle || typeof handle.id !== 'string' || typeof handle.cwd !== 'string' || handle.id.length > 200)\n throw new Error('Invalid params: \"handle\" must be { id, cwd }.')\n return { id: handle.id, cwd: handle.cwd }\n}\n","/**\n * Live processes a machine runs for its host (`exec.stream`, `docs/MACHINES.md`):\n * `execStream` of its process context, its stdout / stderr sent as\n * `exec.stream.data` notifications (chunks of at most\n * `MACHINE_STREAM_CHUNK_BYTES`), then one `exec.stream.exit` once both are\n * drained. Bounded (`MACHINE_MAX_STREAMS`); a lost host link kills them all:\n * a stream carries a live protocol (a stdio MCP server), output it can't\n * deliver would desynchronize it.\n */\nimport type { ExecutionContext, ExecutionHandle, StreamHandle } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { MACHINE_MAX_STREAMS, MACHINE_STREAM_CHUNK_BYTES } from '../../chat/machine-protocol'\n\nexport interface MachineStreams {\n start: (context: ExecutionContext, handle: ExecutionHandle, input: { callId: string, command: string, cwd?: string, env?: Record<string, string> }) => Promise<{ pid: number }>\n write: (callId: string, data: string) => Promise<void>\n /** `exec.cancel` of a stream: `false` when no stream has this id. */\n kill: (callId: string) => boolean\n /** The host link dropped. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineStreams(options: {\n send: (method: 'exec.stream.data' | 'exec.stream.exit', params: Record<string, unknown>) => boolean\n}): MachineStreams {\n const streams = new Map<string, StreamHandle>()\n\n async function pump(callId: string, name: 'stdout' | 'stderr', source: AsyncIterable<Uint8Array> | undefined): Promise<void> {\n if (!source)\n return\n for await (const chunk of source) {\n for (let at = 0; at < chunk.byteLength; at += MACHINE_STREAM_CHUNK_BYTES) {\n const data = Buffer.from(chunk.subarray(at, at + MACHINE_STREAM_CHUNK_BYTES)).toString('base64')\n if (!options.send('exec.stream.data', { callId, stream: name, data }))\n void streams.get(callId)?.kill()\n }\n }\n }\n\n const kill = (callId: string): boolean => {\n const stream = streams.get(callId)\n if (!stream)\n return false\n void stream.kill().catch(() => undefined)\n return true\n }\n\n return {\n async start(context, handle, { callId, command, cwd, env }) {\n if (!context.execStream)\n throw new Error('This machine cannot stream processes.')\n if (streams.has(callId))\n throw new Error(`A stream \"${callId}\" already runs.`)\n if (streams.size >= MACHINE_MAX_STREAMS)\n throw new Error(`This machine already runs ${MACHINE_MAX_STREAMS} live processes.`)\n const stream = await context.execStream(handle, command, { ...(cwd ? { cwd } : {}), ...(env ? { env } : {}) })\n streams.set(callId, stream)\n void Promise.all([pump(callId, 'stdout', stream.stdout), pump(callId, 'stderr', stream.stderr), stream.exited])\n .catch(() => undefined)\n .then(async () => {\n const code = await stream.exited\n streams.delete(callId)\n options.send('exec.stream.exit', { callId, code })\n })\n return { pid: stream.pid }\n },\n async write(callId, data) {\n const stream = streams.get(callId)\n if (!stream)\n throw new Error(`No live process \"${callId}\" on this machine.`)\n const bytes = Buffer.from(data, 'base64')\n if (bytes.byteLength > MACHINE_STREAM_CHUNK_BYTES)\n throw new Error(`exec.stream.write: at most ${MACHINE_STREAM_CHUNK_BYTES} bytes per call.`)\n await stream.write(bytes)\n },\n kill,\n linkLost() {\n for (const callId of streams.keys())\n kill(callId)\n },\n async closeAll() {\n const all = [...streams.values()]\n streams.clear()\n await Promise.all(all.map(stream => stream.kill().catch(() => undefined)))\n },\n }\n}\n","/**\n * The machine's background-task logs (`<data dir>/tasks/`): the one place in\n * its data dir the host may read, and only the logs of tasks this machine\n * started. A command run for the host can reach that folder (no sandbox, or\n * a sandbox that allows the data dir's parent), so a log path is never\n * trusted as a path: it is opened without following a symlink, must be a\n * regular file, and its real path must be the same file inside the tasks\n * dir. Otherwise `ln -sf ~/.zidane/credentials.json <log>` would make the\n * (unsandboxed) machine process read anything for the host.\n */\nimport { Buffer } from 'node:buffer'\nimport { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isInside } from '../../chat/workspace-confinement'\n\nconst NO_FOLLOW = constants.O_NOFOLLOW ?? 0\n\nexport interface TaskLogs {\n /** The folder a handle's task logs go in: made owner-only, refused when it is not a real folder in the tasks dir. */\n outputDir: (handleId: string) => string\n add: (path: string) => void\n has: (path: string) => boolean\n count: () => number\n read: (path: string, binary: boolean) => string\n size: (path: string) => number\n}\n\n/** `path` made (or kept) an owner-only real folder; a symlink there is refused, never followed. */\nfunction ownerOnlyDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: 0o700 })\n const stat = lstatSync(path)\n if (!stat.isDirectory() || stat.isSymbolicLink())\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n chmodSync(path, 0o700)\n}\n\nexport function createTaskLogs(dataDir: string): TaskLogs {\n const dir = join(dataDir, 'tasks')\n ownerOnlyDir(dir)\n const realDir = realpathSync.native(dir)\n const known = new Set<string>()\n const refused = (path: string): Error => new Error(`${path} is not a task log of this machine.`)\n\n /** An fd on the log at `path`, checked as the module header says; the caller closes it. */\n const open = (path: string): number => {\n let fd: number\n try {\n fd = openSync(path, constants.O_RDONLY | NO_FOLLOW)\n }\n catch {\n throw refused(path)\n }\n try {\n const opened = fstatSync(fd)\n const real = realpathSync.native(path)\n const named = statSync(real)\n if (!opened.isFile() || !isInside(realDir, real) || named.ino !== opened.ino || named.dev !== opened.dev)\n throw refused(path)\n return fd\n }\n catch {\n closeSync(fd)\n throw refused(path)\n }\n }\n\n const withLog = <T>(path: string, fn: (fd: number) => T): T => {\n const fd = open(path)\n try {\n return fn(fd)\n }\n finally {\n closeSync(fd)\n }\n }\n\n return {\n outputDir(handleId) {\n const path = join(dir, Buffer.from(handleId).toString('hex').slice(0, 64))\n ownerOnlyDir(path)\n if (!isInside(realDir, realpathSync.native(path)))\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n return path\n },\n add: path => void known.add(path),\n has: path => known.has(path),\n count: () => known.size,\n read: (path, binary) => withLog(path, fd => (binary ? readFileSync(fd).toString('base64') : readFileSync(fd, 'utf8'))),\n size: path => withLog(path, fd => fstatSync(fd).size),\n }\n}\n","/**\n * PTYs a machine runs for its host. They outlive the host link for a grace\n * period, buffering their output (bounded), so a host that reconnects\n * reattaches with the backlog; past the grace they are killed.\n */\nimport type { ExecutionContext, ExecutionHandle, TerminalProcess } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\n\nexport const MACHINE_MAX_TERMINALS = 16\nexport const MACHINE_TERMINAL_BACKLOG_BYTES = 256 * 1024\nexport const MACHINE_TERMINAL_GRACE_MS = 5 * 60 * 1000\n\ninterface Entry {\n process: TerminalProcess\n backlog: Buffer[]\n backlogBytes: number\n /** Bytes produced since it opened. */\n total: number\n graceTimer?: ReturnType<typeof setTimeout>\n}\n\nexport interface MachineTerminals {\n open: (context: ExecutionContext, handle: ExecutionHandle, options: { cols: number, rows: number, cwd?: string }) => Promise<string>\n attach: (terminalId: string) => { attached: boolean, backlog: string, total: number }\n write: (terminalId: string, data: string) => void\n resize: (terminalId: string, cols: number, rows: number) => void\n kill: (terminalId: string) => Promise<void>\n /** The host link dropped: start every terminal's grace period. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineTerminals(options: {\n /** Live output to the host; `false` when the link is down. */\n send: (method: 'terminal.data' | 'terminal.exit', params: Record<string, unknown>) => boolean\n graceMs?: number\n}): MachineTerminals {\n const terminals = new Map<string, Entry>()\n const graceMs = options.graceMs ?? MACHINE_TERMINAL_GRACE_MS\n\n const entry = (terminalId: string): Entry => {\n const found = terminals.get(terminalId)\n if (!found)\n throw new Error(`No terminal \"${terminalId}\" on this machine.`)\n return found\n }\n\n const remember = (e: Entry, data: Uint8Array): void => {\n e.backlog.push(Buffer.from(data))\n e.backlogBytes += data.byteLength\n e.total += data.byteLength\n while (e.backlogBytes > MACHINE_TERMINAL_BACKLOG_BYTES && e.backlog.length > 1)\n e.backlogBytes -= e.backlog.shift()!.byteLength\n }\n\n const kill = async (terminalId: string): Promise<void> => {\n const e = terminals.get(terminalId)\n if (!e)\n return\n terminals.delete(terminalId)\n clearTimeout(e.graceTimer)\n await e.process.kill().catch(() => undefined)\n }\n\n return {\n async open(context, handle, { cols, rows, cwd }) {\n if (!context.openTerminal)\n throw new Error('This machine has no terminal support (it needs Bun).')\n if (terminals.size >= MACHINE_MAX_TERMINALS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TERMINALS} terminals.`)\n const holder: { id?: string } = {}\n const pending: Uint8Array[] = []\n const process = await context.openTerminal(handle, {\n cols,\n rows,\n ...(cwd ? { cwd } : {}),\n onData: (data) => {\n const e = holder.id ? terminals.get(holder.id) : undefined\n if (!e) {\n pending.push(data)\n return\n }\n remember(e, data)\n options.send('terminal.data', { terminalId: holder.id, data: Buffer.from(data).toString('base64') })\n },\n })\n holder.id = process.id\n const e: Entry = { process, backlog: [], backlogBytes: 0, total: 0 }\n terminals.set(process.id, e)\n for (const data of pending)\n remember(e, data)\n void process.exited.then((code) => {\n if (terminals.get(process.id) !== e)\n return\n terminals.delete(process.id)\n clearTimeout(e.graceTimer)\n options.send('terminal.exit', { terminalId: process.id, code })\n })\n return process.id\n },\n attach(terminalId) {\n const e = terminals.get(terminalId)\n if (!e)\n return { attached: false, backlog: '', total: 0 }\n clearTimeout(e.graceTimer)\n e.graceTimer = undefined\n return { attached: true, backlog: Buffer.concat(e.backlog).toString('base64'), total: e.total }\n },\n write: (terminalId, data) => entry(terminalId).process.write(Buffer.from(data, 'base64')),\n resize: (terminalId, cols, rows) => entry(terminalId).process.resize(cols, rows),\n kill,\n linkLost() {\n for (const [id, e] of terminals) {\n clearTimeout(e.graceTimer)\n e.graceTimer = setTimeout(() => void kill(id), graceMs)\n e.graceTimer.unref?.()\n }\n },\n async closeAll() {\n await Promise.all([...terminals.keys()].map(kill))\n },\n }\n}\n","/**\n * What a machine runs for its host (`docs/MACHINES.md` § Machine side): the\n * machine protocol's host→machine methods, served from one `process`\n * execution context, behind a guard that never trusts the host. Every handle\n * cwd, command cwd and file path resolves against the handle's cwd and must\n * real-path into a declared root (symlinks followed), never into the\n * machine's data dir; the one exception is reading a log file of a\n * background task this machine started (`./task-logs.ts`: opened without\n * following symlinks, checked to be that file).\n *\n * Transport-free: the agent (`./agent.ts`) feeds it requests and gives it a\n * `notify` toward the host, which is `false` while the link is down (task\n * exits are then queued until {@link MachineExecutor.linkUp}).\n */\nimport type { MachineRoot } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { WorkspaceConfinement } from '../../chat/workspace-confinement'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo } from '../../contexts/types'\nimport type { Params } from './params'\nimport { Buffer } from 'node:buffer'\nimport { mkdirSync, realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { workspacePath } from '../../chat/environment'\nimport { prepareWorktree, teardownWorktree } from '../../chat/environments'\nimport { resolveSandboxForRoots, sandboxUnreadableDirs } from '../../chat/sandbox-settings'\nimport { createWorkspaceConfinement, isInside } from '../../chat/workspace-confinement'\nimport { resolveStorageDirs } from '../../chat/xdg'\nimport { createProcessContext } from '../../contexts/process'\nimport { handleRef, num, optEnv, optNum, optStr, paramsOf, str } from './params'\nimport { createMachineStreams } from './streams'\nimport { createTaskLogs } from './task-logs'\nimport { createMachineTerminals } from './terminals'\n\nexport const MACHINE_MAX_TASKS = 64\nexport const MACHINE_TASK_OUTPUT_BYTES = 8 * 1024 * 1024\nconst MAX_PENDING_EXITS = 256\nconst GLOB_CHARS = /[*?[\\]{}]/\n\nexport interface MachineExecutorOptions {\n roots: readonly MachineRoot[]\n /** The machine's own data dir: never reachable by file ops. */\n dataDir: string\n /** A notification to the host; `false` when the link is down. */\n notify: (method: string, params: Record<string, unknown>) => boolean\n /** Terminals' grace after the link drops. */\n terminalGraceMs?: number\n /**\n * The machine user's own `sandbox*` settings (`docs/MACHINES.md` §\n * Sandbox): applied to every command this machine runs, whatever the host.\n */\n sandbox?: LooseSandboxSettings\n /**\n * The machine user's zidane data dir: private to file operations (with the\n * rest of {@link machinePrivateDirs}) and its credential files hidden from\n * sandboxed commands.\n */\n credentialsDataDir?: string\n}\n\n/**\n * What file operations never reach, whatever the roots (`docs/MACHINES.md` §\n * Security model): zidane's own folders as this process resolves them (data,\n * config, state, cache: credentials, tokens, extensions, plugins, skills,\n * mcps.json, SYSTEM.md, the machine's data, sync files), the default\n * `~/.zidane`, the given data dir (a server's `--data-dir`), and the\n * credential folders the sandbox hides (`~/.ssh`, `~/.aws`, …).\n */\nexport function machinePrivateDirs(zidaneDataDir?: string): string[] {\n const storage = resolveStorageDirs()\n return [...new Set([\n ...(zidaneDataDir ? [zidaneDataDir] : []),\n storage.dataDir,\n storage.configDir,\n storage.stateDir,\n storage.cacheDir,\n join(homedir(), '.zidane'),\n ...sandboxUnreadableDirs(zidaneDataDir),\n ])]\n}\n\nexport interface MachineExecutor {\n /** Serve one host request; throws (the agent turns it into a JSON-RPC error). */\n handle: (method: string, params: unknown) => Promise<unknown>\n /** The host link is (back) up: re-send what was queued. */\n linkUp: () => void\n /** The host link dropped: terminals start their grace. */\n linkLost: () => void\n close: () => Promise<void>\n /** The OS sandbox the machine applies, and why it can't when it is on but unavailable. */\n sandbox: { on: boolean, warning?: string }\n}\n\n/** The static directory of a glob (`/a/b/**\\/*.ts` → `/a/b`). */\nfunction globBase(path: string): string {\n const segments = path.split('/')\n const index = segments.findIndex(s => GLOB_CHARS.test(s))\n return index < 0 ? path : segments.slice(0, index).join('/') || '/'\n}\n\n/**\n * A folder a user offers to share (`zidane machine share --root`, a share\n * link): its real path must exist and not be, or be inside, a private\n * folder (a root there would lend what {@link machinePrivateDirs} keeps out).\n * Returns the real path.\n */\nexport function shareableRoot(root: string, zidaneDataDir?: string): string {\n let real: string\n try {\n real = realpathSync.native(root)\n }\n catch {\n throw new Error(`${root} does not exist.`)\n }\n const hidden = machinePrivateDirs(zidaneDataDir).map(realPathOr).find(dir => isInside(dir, real))\n if (hidden)\n throw new Error(`${root} is inside ${hidden} (zidane's own data or credentials): share a folder outside it.`)\n return real\n}\n\nfunction realPathOr(path: string): string {\n try {\n return realpathSync.native(path)\n }\n catch {\n return path\n }\n}\n\nexport function machineConfinement(roots: readonly MachineRoot[], dataDir: string, privateDirs: readonly string[] = []): WorkspaceConfinement {\n // Worktrees made in the data dir's `worktrees/` are workspace content; nothing else there is.\n const worktrees = join(dataDir, 'worktrees')\n mkdirSync(worktrees, { recursive: true })\n return createWorkspaceConfinement([...roots.map(root => root.path), worktrees], {\n dataDir,\n privateDirs,\n names: { roots: 'the machine\\'s roots', dataDir: 'the machine\\'s data dir, which the host can\\'t reach' },\n })\n}\n\n/**\n * A listing's entries whose real path is reachable: a traversal can follow a\n * symlinked folder out of the roots, or walk into a private one, from a base\n * that passed the check.\n */\nfunction reachableEntries<T>(confinement: WorkspaceConfinement, base: string, entries: readonly T[]): T[] {\n return entries.filter((entry) => {\n const path = typeof entry === 'string' ? entry : (entry as { path?: unknown }).path\n if (typeof path !== 'string')\n return false\n try {\n confinement.checkPath(isAbsolute(path) ? path : resolve(base, path))\n return true\n }\n catch {\n return false\n }\n })\n}\n\n/** `fs.list`: a path or glob under the handle's cwd, no `..` in a pattern, only reachable entries back. */\nasync function listReachable(context: ExecutionContext, confinement: WorkspaceConfinement, handle: ExecutionHandle, params: Params): Promise<unknown[]> {\n const pattern = str(params, 'path')\n if (GLOB_CHARS.test(pattern) && pattern.split(/[/\\\\]/).includes('..'))\n throw new Error(`\"${pattern}\": a pattern can't climb with \"..\".`)\n const path = workspacePath(handle.cwd, pattern)\n confinement.checkPath(globBase(path))\n const raw = params.options && typeof params.options === 'object' ? params.options as Record<string, unknown> : {}\n const listOptions = {\n ...(typeof raw.glob === 'boolean' ? { glob: raw.glob } : {}),\n ...(typeof raw.limit === 'number' ? { limit: raw.limit } : {}),\n ...(typeof raw.metadata === 'boolean' ? { metadata: raw.metadata } : {}),\n ...(typeof raw.gitignore === 'boolean' ? { gitignore: raw.gitignore } : {}),\n }\n return reachableEntries(confinement, globBase(path), await context.listFiles(handle, path, listOptions))\n}\n\n/** One process context for every handle, under the machine user's own sandbox when it is on. */\nfunction sandboxedContext(options: MachineExecutorOptions, confinement: WorkspaceConfinement): { sandbox: ReturnType<typeof resolveSandboxForRoots>, context: ExecutionContext } {\n const sandbox = resolveSandboxForRoots(options.sandbox ?? { sandbox: false }, confinement.roots, {\n ...(options.credentialsDataDir ? { dataDir: options.credentialsDataDir } : {}),\n // Not the task logs: the machine process writes them, and a command able to write there could swap one for a symlink.\n })\n return { sandbox, context: createProcessContext({ cwd: confinement.roots[0]!, ...(sandbox.isolation ? { isolation: sandbox.isolation } : {}) }) }\n}\n\nexport function createMachineExecutor(options: MachineExecutorOptions): MachineExecutor {\n const confinement = machineConfinement(options.roots, options.dataDir, machinePrivateDirs(options.credentialsDataDir))\n const { sandbox, context } = sandboxedContext(options, confinement)\n const handles = new Map<string, ExecutionHandle>()\n const calls = new Map<string, AbortController>()\n const taskLogs = createTaskLogs(options.dataDir)\n const pendingExits: Array<Record<string, unknown>> = []\n const terminals = createMachineTerminals({ send: options.notify, ...(options.terminalGraceMs !== undefined ? { graceMs: options.terminalGraceMs } : {}) })\n const streams = createMachineStreams({ send: options.notify })\n\n /** A handle's cwd, checked on every call (not only at spawn): the host names it each time. */\n async function handleFor(params: Params): Promise<ExecutionHandle> {\n const ref = handleRef(params)\n const cwd = confinement.resolveFolder(ref.cwd)\n const existing = handles.get(ref.id)\n if (existing && existing.cwd === cwd)\n return existing\n const handle = await context.spawn({ cwd })\n handles.set(ref.id, handle)\n // The id now names another folder: the old handle (and its tasks) would otherwise live on unreachable.\n if (existing)\n await context.destroy(existing).catch(() => undefined)\n return handle\n }\n\n /** `path` resolved like the context resolves it, then confined. */\n function checked(handle: ExecutionHandle, path: string): string {\n const absolute = workspacePath(handle.cwd, path)\n confinement.checkPath(absolute)\n return absolute\n }\n\n /** A log of a task this machine started, by its path (never through the context: see `./task-logs.ts`). */\n const taskLog = (handle: ExecutionHandle, path: string): string | undefined => {\n const absolute = workspacePath(handle.cwd, path)\n return taskLogs.has(absolute) ? absolute : undefined\n }\n\n const cwdOption = (handle: ExecutionHandle, params: Params): { cwd?: string } => {\n const cwd = optStr(params, 'cwd')\n return cwd === undefined ? {} : { cwd: confinement.resolveFolder(workspacePath(handle.cwd, cwd)) }\n }\n\n const sendExit = (exit: Record<string, unknown>): void => {\n if (options.notify('task.exit', exit))\n return\n pendingExits.push(exit)\n if (pendingExits.length > MAX_PENDING_EXITS)\n pendingExits.shift()\n }\n\n const methods: Record<string, (params: Params) => Promise<unknown>> = {\n 'machine.ping': async () => ({ ok: true }),\n 'exec.spawn': async (params) => {\n const handle = await handleFor(params)\n return { id: handleRef(params).id, cwd: handle.cwd }\n },\n 'exec.run': async (params) => {\n const handle = await handleFor(params)\n const callId = str(params, 'callId')\n // A second call under one id would take over its cancel: the first could no longer be stopped.\n if (calls.has(callId))\n throw new Error(`A call \"${callId}\" is already running.`)\n const controller = new AbortController()\n calls.set(callId, controller)\n try {\n const env = optEnv(params, 'env')\n const timeout = optNum(params, 'timeout')\n return await context.exec(handle, str(params, 'command'), { ...cwdOption(handle, params), ...(env ? { env } : {}), ...(timeout !== undefined ? { timeout } : {}), signal: controller.signal })\n }\n finally {\n calls.delete(callId)\n }\n },\n 'exec.cancel': async (params) => {\n const callId = str(params, 'callId')\n const controller = calls.get(callId)\n controller?.abort()\n return { cancelled: controller !== undefined || streams.kill(callId) }\n },\n 'exec.stream': async (params) => {\n const handle = await handleFor(params)\n const env = optEnv(params, 'env')\n return streams.start(context, handle, { callId: str(params, 'callId'), command: str(params, 'command'), ...cwdOption(handle, params), ...(env ? { env } : {}) })\n },\n 'exec.stream.write': async (params) => {\n await streams.write(str(params, 'callId'), str(params, 'data'))\n return { ok: true }\n },\n 'exec.destroy': async (params) => {\n const ref = handleRef(params)\n const handle = handles.get(ref.id)\n handles.delete(ref.id)\n if (handle)\n await context.destroy(handle)\n return { ok: true }\n },\n 'fs.read': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n if (log)\n return { content: taskLogs.read(log, params.binary === true) }\n const path = checked(handle, str(params, 'path'))\n if (params.binary === true)\n return { content: Buffer.from(await context.readFileBinary!(handle, path)).toString('base64') }\n return { content: await context.readFile(handle, path) }\n },\n 'fs.write': async (params) => {\n const handle = await handleFor(params)\n await context.writeFile(handle, checked(handle, str(params, 'path')), Buffer.from(str(params, 'content'), 'base64'))\n return { ok: true }\n },\n 'fs.list': async params => ({ entries: await listReachable(context, confinement, await handleFor(params), params) }),\n 'fs.size': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n return { size: log ? taskLogs.size(log) : await context.fileSize!(handle, checked(handle, str(params, 'path'))) }\n },\n 'bg.start': async (params) => {\n const handle = await handleFor(params)\n const running = (await context.listBackground!(handle)).filter(t => t.status === 'running').length\n if (taskLogs.count() >= MACHINE_MAX_TASKS * 4 || running >= MACHINE_MAX_TASKS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TASKS} background tasks.`)\n const env = optEnv(params, 'env')\n const cap = optNum(params, 'maxOutputBytes')\n const task = await context.execBackground!(handle, str(params, 'command'), {\n ...cwdOption(handle, params),\n ...(env ? { env } : {}),\n outputDir: taskLogs.outputDir(handleRef(params).id),\n maxOutputBytes: Math.min(cap && cap > 0 ? cap : MACHINE_TASK_OUTPUT_BYTES, MACHINE_TASK_OUTPUT_BYTES),\n onExit: (info: TaskExitInfo) => sendExit({ taskId: info.taskId, exit: { ...info } }),\n })\n taskLogs.add(task.outputPath)\n return { taskId: task.taskId, pid: task.pid, outputPath: task.outputPath }\n },\n 'bg.list': async params => ({ tasks: await context.listBackground!(await handleFor(params)) }),\n 'bg.kill': async params => ({ exit: await context.killBackground!(await handleFor(params), str(params, 'taskId')) }),\n 'bg.wait': async (params) => {\n const timeoutMs = optNum(params, 'timeoutMs')\n return { exit: await context.waitBackground!(await handleFor(params), str(params, 'taskId'), timeoutMs !== undefined ? { timeoutMs } : {}) }\n },\n 'terminal.open': async (params) => {\n const handle = await handleFor(params)\n const terminalId = await terminals.open(context, handle, { cols: num(params, 'cols'), rows: num(params, 'rows'), ...cwdOption(handle, params) })\n return { terminalId }\n },\n 'terminal.attach': async params => terminals.attach(str(params, 'terminalId')),\n 'terminal.write': async (params) => {\n terminals.write(str(params, 'terminalId'), str(params, 'data'))\n return { ok: true }\n },\n 'terminal.resize': async (params) => {\n terminals.resize(str(params, 'terminalId'), num(params, 'cols'), num(params, 'rows'))\n return { ok: true }\n },\n 'terminal.kill': async (params) => {\n await terminals.kill(str(params, 'terminalId'))\n return { ok: true }\n },\n // The host stops viewing; the PTY keeps running (as after a lost link, without the grace).\n 'terminal.detach': async () => ({ ok: true }),\n 'env.checkFolder': async params => ({ cwd: confinement.resolveFolder(str(params, 'cwd')) }),\n 'env.prepareWorktree': async (params) => {\n const cwd = confinement.resolveFolder(str(params, 'cwd'))\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n const base = optStr(params, 'base')\n const prepared = await prepareWorktree({ cwd, environment: { kind: 'worktree', state: 'provisioning', branch: str(params, 'branch'), ...(base ? { base } : {}) }, config }, options.dataDir)\n const ref = prepared.environment?.ref as { path: string, repoRoot: string }\n confinement.resolveFolder(ref.path)\n return { cwd: prepared.cwd ?? ref.path, branch: prepared.environment?.branch, base: prepared.environment?.base, ref }\n },\n 'env.teardownWorktree': async (params) => {\n const ref = (params.ref ?? {}) as { path?: unknown, repoRoot?: unknown }\n if (typeof ref.path !== 'string' || typeof ref.repoRoot !== 'string')\n throw new Error('Invalid params: \"ref\" must be { path, repoRoot }.')\n confinement.checkPath(ref.path)\n confinement.resolveFolder(ref.repoRoot)\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n return teardownWorktree({ path: ref.path, repoRoot: ref.repoRoot }, optStr(params, 'branch'), config)\n },\n }\n\n return {\n async handle(method, raw) {\n if (!Object.hasOwn(methods, method))\n throw new Error(`Unknown machine method \"${method}\".`)\n return methods[method]!(paramsOf(raw))\n },\n linkUp() {\n while (pendingExits.length > 0) {\n if (!options.notify('task.exit', pendingExits[0]!))\n return\n pendingExits.shift()\n }\n },\n sandbox: { on: sandbox.isolation !== undefined, ...(sandbox.warning ? { warning: sandbox.warning } : {}) },\n linkLost: () => {\n terminals.linkLost()\n streams.linkLost()\n },\n async close() {\n for (const controller of calls.values())\n controller.abort()\n await streams.closeAll()\n await terminals.closeAll()\n await Promise.all([...handles.values()].map(handle => context.destroy(handle).catch(() => undefined)))\n handles.clear()\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"executor-BhthPE1q.js","names":[],"sources":["../src/ipc/machine/params.ts","../src/ipc/machine/streams.ts","../src/ipc/machine/task-logs.ts","../src/ipc/machine/terminals.ts","../src/ipc/machine/executor.ts"],"sourcesContent":["/**\n * Shape checks for what a host sends a machine. The host is not trusted: a\n * malformed request is refused before anything runs.\n */\nimport type { MachineHandleRef } from '../../chat/machine-protocol'\n\nexport type Params = Record<string, unknown>\n\nexport function paramsOf(value: unknown): Params {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error('Invalid params: expected an object.')\n return value as Params\n}\n\nexport function str(params: Params, key: string): string {\n const value = params[key]\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optStr(params: Params, key: string): string | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optNum(params: Params, key: string): number | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isFinite(value))\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function num(params: Params, key: string): number {\n const value = optNum(params, key)\n if (value === undefined)\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function optEnv(params: Params, key: string): Record<string, string> | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (!value || typeof value !== 'object' || Array.isArray(value) || Object.values(value).some(v => typeof v !== 'string'))\n throw new Error(`Invalid params: \"${key}\" must map names to strings.`)\n return value as Record<string, string>\n}\n\nexport function handleRef(params: Params): MachineHandleRef {\n const handle = params.handle as Partial<MachineHandleRef> | undefined\n if (!handle || typeof handle.id !== 'string' || typeof handle.cwd !== 'string' || handle.id.length > 200)\n throw new Error('Invalid params: \"handle\" must be { id, cwd }.')\n return { id: handle.id, cwd: handle.cwd }\n}\n","/**\n * Live processes a machine runs for its host (`exec.stream`, `docs/MACHINES.md`):\n * `execStream` of its process context, its stdout / stderr sent as\n * `exec.stream.data` notifications (chunks of at most\n * `MACHINE_STREAM_CHUNK_BYTES`), then one `exec.stream.exit` once both are\n * drained. Bounded (`MACHINE_MAX_STREAMS`); a lost host link kills them all:\n * a stream carries a live protocol (a stdio MCP server), output it can't\n * deliver would desynchronize it.\n */\nimport type { ExecutionContext, ExecutionHandle, StreamHandle } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { MACHINE_MAX_STREAMS, MACHINE_STREAM_CHUNK_BYTES } from '../../chat/machine-protocol'\n\nexport interface MachineStreams {\n start: (context: ExecutionContext, handle: ExecutionHandle, input: { callId: string, command: string, cwd?: string, env?: Record<string, string> }) => Promise<{ pid: number }>\n write: (callId: string, data: string) => Promise<void>\n /** `exec.cancel` of a stream: `false` when no stream has this id. */\n kill: (callId: string) => boolean\n /** The host link dropped. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineStreams(options: {\n send: (method: 'exec.stream.data' | 'exec.stream.exit', params: Record<string, unknown>) => boolean\n}): MachineStreams {\n const streams = new Map<string, StreamHandle>()\n\n async function pump(callId: string, name: 'stdout' | 'stderr', source: AsyncIterable<Uint8Array> | undefined): Promise<void> {\n if (!source)\n return\n for await (const chunk of source) {\n for (let at = 0; at < chunk.byteLength; at += MACHINE_STREAM_CHUNK_BYTES) {\n const data = Buffer.from(chunk.subarray(at, at + MACHINE_STREAM_CHUNK_BYTES)).toString('base64')\n if (!options.send('exec.stream.data', { callId, stream: name, data }))\n void streams.get(callId)?.kill()\n }\n }\n }\n\n const kill = (callId: string): boolean => {\n const stream = streams.get(callId)\n if (!stream)\n return false\n void stream.kill().catch(() => undefined)\n return true\n }\n\n return {\n async start(context, handle, { callId, command, cwd, env }) {\n if (!context.execStream)\n throw new Error('This machine cannot stream processes.')\n if (streams.has(callId))\n throw new Error(`A stream \"${callId}\" already runs.`)\n if (streams.size >= MACHINE_MAX_STREAMS)\n throw new Error(`This machine already runs ${MACHINE_MAX_STREAMS} live processes.`)\n const stream = await context.execStream(handle, command, { ...(cwd ? { cwd } : {}), ...(env ? { env } : {}) })\n streams.set(callId, stream)\n void Promise.all([pump(callId, 'stdout', stream.stdout), pump(callId, 'stderr', stream.stderr), stream.exited])\n .catch(() => undefined)\n .then(async () => {\n const code = await stream.exited\n streams.delete(callId)\n options.send('exec.stream.exit', { callId, code })\n })\n return { pid: stream.pid }\n },\n async write(callId, data) {\n const stream = streams.get(callId)\n if (!stream)\n throw new Error(`No live process \"${callId}\" on this machine.`)\n const bytes = Buffer.from(data, 'base64')\n if (bytes.byteLength > MACHINE_STREAM_CHUNK_BYTES)\n throw new Error(`exec.stream.write: at most ${MACHINE_STREAM_CHUNK_BYTES} bytes per call.`)\n await stream.write(bytes)\n },\n kill,\n linkLost() {\n for (const callId of streams.keys())\n kill(callId)\n },\n async closeAll() {\n const all = [...streams.values()]\n streams.clear()\n await Promise.all(all.map(stream => stream.kill().catch(() => undefined)))\n },\n }\n}\n","/**\n * The machine's background-task logs (`<data dir>/tasks/`): the one place in\n * its data dir the host may read, and only the logs of tasks this machine\n * started. A command run for the host can reach that folder (no sandbox, or\n * a sandbox that allows the data dir's parent), so a log path is never\n * trusted as a path: it is opened without following a symlink, must be a\n * regular file, and its real path must be the same file inside the tasks\n * dir. Otherwise `ln -sf ~/.zidane/credentials.json <log>` would make the\n * (unsandboxed) machine process read anything for the host.\n */\nimport { Buffer } from 'node:buffer'\nimport { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isInside } from '../../chat/workspace-confinement'\n\nconst NO_FOLLOW = constants.O_NOFOLLOW ?? 0\n\nexport interface TaskLogs {\n /** The folder a handle's task logs go in: made owner-only, refused when it is not a real folder in the tasks dir. */\n outputDir: (handleId: string) => string\n add: (path: string) => void\n has: (path: string) => boolean\n count: () => number\n read: (path: string, binary: boolean) => string\n size: (path: string) => number\n}\n\n/** `path` made (or kept) an owner-only real folder; a symlink there is refused, never followed. */\nfunction ownerOnlyDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: 0o700 })\n const stat = lstatSync(path)\n if (!stat.isDirectory() || stat.isSymbolicLink())\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n chmodSync(path, 0o700)\n}\n\nexport function createTaskLogs(dataDir: string): TaskLogs {\n const dir = join(dataDir, 'tasks')\n ownerOnlyDir(dir)\n const realDir = realpathSync.native(dir)\n const known = new Set<string>()\n const refused = (path: string): Error => new Error(`${path} is not a task log of this machine.`)\n\n /** An fd on the log at `path`, checked as the module header says; the caller closes it. */\n const open = (path: string): number => {\n let fd: number\n try {\n fd = openSync(path, constants.O_RDONLY | NO_FOLLOW)\n }\n catch {\n throw refused(path)\n }\n try {\n const opened = fstatSync(fd)\n const real = realpathSync.native(path)\n const named = statSync(real)\n if (!opened.isFile() || !isInside(realDir, real) || named.ino !== opened.ino || named.dev !== opened.dev)\n throw refused(path)\n return fd\n }\n catch {\n closeSync(fd)\n throw refused(path)\n }\n }\n\n const withLog = <T>(path: string, fn: (fd: number) => T): T => {\n const fd = open(path)\n try {\n return fn(fd)\n }\n finally {\n closeSync(fd)\n }\n }\n\n return {\n outputDir(handleId) {\n const path = join(dir, Buffer.from(handleId).toString('hex').slice(0, 64))\n ownerOnlyDir(path)\n if (!isInside(realDir, realpathSync.native(path)))\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n return path\n },\n add: path => void known.add(path),\n has: path => known.has(path),\n count: () => known.size,\n read: (path, binary) => withLog(path, fd => (binary ? readFileSync(fd).toString('base64') : readFileSync(fd, 'utf8'))),\n size: path => withLog(path, fd => fstatSync(fd).size),\n }\n}\n","/**\n * PTYs a machine runs for its host. They outlive the host link for a grace\n * period, buffering their output (bounded), so a host that reconnects\n * reattaches with the backlog; past the grace they are killed.\n */\nimport type { ExecutionContext, ExecutionHandle, TerminalProcess } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\n\nexport const MACHINE_MAX_TERMINALS = 16\nexport const MACHINE_TERMINAL_BACKLOG_BYTES = 256 * 1024\nexport const MACHINE_TERMINAL_GRACE_MS = 5 * 60 * 1000\n\ninterface Entry {\n process: TerminalProcess\n backlog: Buffer[]\n backlogBytes: number\n /** Bytes produced since it opened. */\n total: number\n graceTimer?: ReturnType<typeof setTimeout>\n}\n\nexport interface MachineTerminals {\n open: (context: ExecutionContext, handle: ExecutionHandle, options: { cols: number, rows: number, cwd?: string }) => Promise<string>\n attach: (terminalId: string) => { attached: boolean, backlog: string, total: number }\n write: (terminalId: string, data: string) => void\n resize: (terminalId: string, cols: number, rows: number) => void\n kill: (terminalId: string) => Promise<void>\n /** The host link dropped: start every terminal's grace period. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineTerminals(options: {\n /** Live output to the host; `false` when the link is down. */\n send: (method: 'terminal.data' | 'terminal.exit', params: Record<string, unknown>) => boolean\n graceMs?: number\n}): MachineTerminals {\n const terminals = new Map<string, Entry>()\n const graceMs = options.graceMs ?? MACHINE_TERMINAL_GRACE_MS\n\n const entry = (terminalId: string): Entry => {\n const found = terminals.get(terminalId)\n if (!found)\n throw new Error(`No terminal \"${terminalId}\" on this machine.`)\n return found\n }\n\n const remember = (e: Entry, data: Uint8Array): void => {\n e.backlog.push(Buffer.from(data))\n e.backlogBytes += data.byteLength\n e.total += data.byteLength\n while (e.backlogBytes > MACHINE_TERMINAL_BACKLOG_BYTES && e.backlog.length > 1)\n e.backlogBytes -= e.backlog.shift()!.byteLength\n }\n\n const kill = async (terminalId: string): Promise<void> => {\n const e = terminals.get(terminalId)\n if (!e)\n return\n terminals.delete(terminalId)\n clearTimeout(e.graceTimer)\n await e.process.kill().catch(() => undefined)\n }\n\n return {\n async open(context, handle, { cols, rows, cwd }) {\n if (!context.openTerminal)\n throw new Error('This machine has no terminal support (it needs Bun).')\n if (terminals.size >= MACHINE_MAX_TERMINALS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TERMINALS} terminals.`)\n const holder: { id?: string } = {}\n const pending: Uint8Array[] = []\n const process = await context.openTerminal(handle, {\n cols,\n rows,\n ...(cwd ? { cwd } : {}),\n onData: (data) => {\n const e = holder.id ? terminals.get(holder.id) : undefined\n if (!e) {\n pending.push(data)\n return\n }\n remember(e, data)\n options.send('terminal.data', { terminalId: holder.id, data: Buffer.from(data).toString('base64') })\n },\n })\n holder.id = process.id\n const e: Entry = { process, backlog: [], backlogBytes: 0, total: 0 }\n terminals.set(process.id, e)\n for (const data of pending)\n remember(e, data)\n void process.exited.then((code) => {\n if (terminals.get(process.id) !== e)\n return\n terminals.delete(process.id)\n clearTimeout(e.graceTimer)\n options.send('terminal.exit', { terminalId: process.id, code })\n })\n return process.id\n },\n attach(terminalId) {\n const e = terminals.get(terminalId)\n if (!e)\n return { attached: false, backlog: '', total: 0 }\n clearTimeout(e.graceTimer)\n e.graceTimer = undefined\n return { attached: true, backlog: Buffer.concat(e.backlog).toString('base64'), total: e.total }\n },\n write: (terminalId, data) => entry(terminalId).process.write(Buffer.from(data, 'base64')),\n resize: (terminalId, cols, rows) => entry(terminalId).process.resize(cols, rows),\n kill,\n linkLost() {\n for (const [id, e] of terminals) {\n clearTimeout(e.graceTimer)\n e.graceTimer = setTimeout(() => void kill(id), graceMs)\n e.graceTimer.unref?.()\n }\n },\n async closeAll() {\n await Promise.all([...terminals.keys()].map(kill))\n },\n }\n}\n","/**\n * What a machine runs for its host (`docs/MACHINES.md` § Machine side): the\n * machine protocol's host→machine methods, served from one `process`\n * execution context, behind a guard that never trusts the host. Every handle\n * cwd, command cwd and file path resolves against the handle's cwd and must\n * real-path into a declared root (symlinks followed), never into the\n * machine's data dir; the one exception is reading a log file of a\n * background task this machine started (`./task-logs.ts`: opened without\n * following symlinks, checked to be that file).\n *\n * Transport-free: the agent (`./agent.ts`) feeds it requests and gives it a\n * `notify` toward the host, which is `false` while the link is down (task\n * exits are then queued until {@link MachineExecutor.linkUp}).\n */\nimport type { MachineRoot } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { WorkspaceConfinement } from '../../chat/workspace-confinement'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo } from '../../contexts/types'\nimport type { Params } from './params'\nimport { Buffer } from 'node:buffer'\nimport { mkdirSync, realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { workspacePath } from '../../chat/environment'\nimport { prepareWorktree, teardownWorktree } from '../../chat/environments'\nimport { resolveSandboxForRoots, sandboxUnreadableDirs } from '../../chat/sandbox-settings'\nimport { createWorkspaceConfinement, isInside } from '../../chat/workspace-confinement'\nimport { resolveStorageDirs } from '../../chat/xdg'\nimport { createProcessContext } from '../../contexts/process'\nimport { handleRef, num, optEnv, optNum, optStr, paramsOf, str } from './params'\nimport { createMachineStreams } from './streams'\nimport { createTaskLogs } from './task-logs'\nimport { createMachineTerminals } from './terminals'\n\nexport const MACHINE_MAX_TASKS = 64\nexport const MACHINE_TASK_OUTPUT_BYTES = 8 * 1024 * 1024\nconst MAX_PENDING_EXITS = 256\nconst GLOB_CHARS = /[*?[\\]{}]/\n\nexport interface MachineExecutorOptions {\n roots: readonly MachineRoot[]\n /** The machine's own data dir: never reachable by file ops. */\n dataDir: string\n /** A notification to the host; `false` when the link is down. */\n notify: (method: string, params: Record<string, unknown>) => boolean\n /** Terminals' grace after the link drops. */\n terminalGraceMs?: number\n /**\n * The machine user's own `sandbox*` settings (`docs/MACHINES.md` §\n * Sandbox): applied to every command this machine runs, whatever the host.\n */\n sandbox?: LooseSandboxSettings\n /**\n * The machine user's zidane data dir: private to file operations (with the\n * rest of {@link machinePrivateDirs}) and its credential files hidden from\n * sandboxed commands.\n */\n credentialsDataDir?: string\n}\n\n/**\n * What file operations never reach, whatever the roots (`docs/MACHINES.md` §\n * Security model): zidane's own folders as this process resolves them (data,\n * config, state, cache: credentials, tokens, extensions, plugins, skills,\n * mcps.json, SYSTEM.md, the machine's data, sync files), the default\n * `~/.zidane`, the given data dir (a server's `--data-dir`), and the\n * credential folders the sandbox hides (`~/.ssh`, `~/.aws`, …).\n */\nexport function machinePrivateDirs(zidaneDataDir?: string): string[] {\n const storage = resolveStorageDirs()\n return [...new Set([\n ...(zidaneDataDir ? [zidaneDataDir] : []),\n storage.dataDir,\n storage.configDir,\n storage.stateDir,\n storage.cacheDir,\n join(homedir(), '.zidane'),\n ...sandboxUnreadableDirs(zidaneDataDir),\n ])]\n}\n\nexport interface MachineExecutor {\n /** Serve one host request; throws (the agent turns it into a JSON-RPC error). */\n handle: (method: string, params: unknown) => Promise<unknown>\n /** The host link is (back) up: re-send what was queued. */\n linkUp: () => void\n /** The host link dropped: terminals start their grace. */\n linkLost: () => void\n close: () => Promise<void>\n /** The OS sandbox the machine applies, and why it can't when it is on but unavailable. */\n sandbox: { on: boolean, warning?: string }\n}\n\n/** The static directory of a glob (`/a/b/**\\/*.ts` → `/a/b`). */\nfunction globBase(path: string): string {\n const segments = path.split('/')\n const index = segments.findIndex(s => GLOB_CHARS.test(s))\n return index < 0 ? path : segments.slice(0, index).join('/') || '/'\n}\n\n/**\n * A folder a user offers to share (`zidane machine share --root`, a share\n * link): its real path must exist and not be, or be inside, a private\n * folder (a root there would lend what {@link machinePrivateDirs} keeps out).\n * Returns the real path.\n */\nexport function shareableRoot(root: string, zidaneDataDir?: string): string {\n let real: string\n try {\n real = realpathSync.native(root)\n }\n catch {\n throw new Error(`${root} does not exist.`)\n }\n const hidden = machinePrivateDirs(zidaneDataDir).map(realPathOr).find(dir => isInside(dir, real))\n if (hidden)\n throw new Error(`${root} is inside ${hidden} (zidane's own data or credentials): share a folder outside it.`)\n return real\n}\n\nfunction realPathOr(path: string): string {\n try {\n return realpathSync.native(path)\n }\n catch {\n return path\n }\n}\n\nexport function machineConfinement(roots: readonly MachineRoot[], dataDir: string, privateDirs: readonly string[] = []): WorkspaceConfinement {\n // Worktrees made in the data dir's `worktrees/` are workspace content; nothing else there is.\n const worktrees = join(dataDir, 'worktrees')\n mkdirSync(worktrees, { recursive: true })\n return createWorkspaceConfinement([...roots.map(root => root.path), worktrees], {\n dataDir,\n privateDirs,\n names: { roots: 'the machine\\'s roots', dataDir: 'the machine\\'s data dir, which the host can\\'t reach' },\n })\n}\n\n/**\n * A listing's entries whose real path is reachable: a traversal can follow a\n * symlinked folder out of the roots, or walk into a private one, from a base\n * that passed the check.\n */\nfunction reachableEntries<T>(confinement: WorkspaceConfinement, base: string, entries: readonly T[]): T[] {\n return entries.filter((entry) => {\n const path = typeof entry === 'string' ? entry : (entry as { path?: unknown }).path\n if (typeof path !== 'string')\n return false\n try {\n confinement.checkPath(isAbsolute(path) ? path : resolve(base, path))\n return true\n }\n catch {\n return false\n }\n })\n}\n\n/** `fs.list`: a path or glob under the handle's cwd, no `..` in a pattern, only reachable entries back. */\nasync function listReachable(context: ExecutionContext, confinement: WorkspaceConfinement, handle: ExecutionHandle, params: Params): Promise<unknown[]> {\n const pattern = str(params, 'path')\n if (GLOB_CHARS.test(pattern) && pattern.split(/[/\\\\]/).includes('..'))\n throw new Error(`\"${pattern}\": a pattern can't climb with \"..\".`)\n const path = workspacePath(handle.cwd, pattern)\n confinement.checkPath(globBase(path))\n const raw = params.options && typeof params.options === 'object' ? params.options as Record<string, unknown> : {}\n const listOptions = {\n ...(typeof raw.glob === 'boolean' ? { glob: raw.glob } : {}),\n ...(typeof raw.limit === 'number' ? { limit: raw.limit } : {}),\n ...(typeof raw.metadata === 'boolean' ? { metadata: raw.metadata } : {}),\n ...(typeof raw.gitignore === 'boolean' ? { gitignore: raw.gitignore } : {}),\n }\n return reachableEntries(confinement, globBase(path), await context.listFiles(handle, path, listOptions))\n}\n\n/** One process context for every handle, under the machine user's own sandbox when it is on. */\nfunction sandboxedContext(options: MachineExecutorOptions, confinement: WorkspaceConfinement): { sandbox: ReturnType<typeof resolveSandboxForRoots>, context: ExecutionContext } {\n const sandbox = resolveSandboxForRoots(options.sandbox ?? { sandbox: false }, confinement.roots, {\n ...(options.credentialsDataDir ? { dataDir: options.credentialsDataDir } : {}),\n // Not the task logs: the machine process writes them, and a command able to write there could swap one for a symlink.\n })\n return { sandbox, context: createProcessContext({ cwd: confinement.roots[0]!, ...(sandbox.isolation ? { isolation: sandbox.isolation } : {}) }) }\n}\n\nexport function createMachineExecutor(options: MachineExecutorOptions): MachineExecutor {\n const confinement = machineConfinement(options.roots, options.dataDir, machinePrivateDirs(options.credentialsDataDir))\n const { sandbox, context } = sandboxedContext(options, confinement)\n const handles = new Map<string, ExecutionHandle>()\n const calls = new Map<string, AbortController>()\n const taskLogs = createTaskLogs(options.dataDir)\n const pendingExits: Array<Record<string, unknown>> = []\n const terminals = createMachineTerminals({ send: options.notify, ...(options.terminalGraceMs !== undefined ? { graceMs: options.terminalGraceMs } : {}) })\n const streams = createMachineStreams({ send: options.notify })\n\n /** A handle's cwd, checked on every call (not only at spawn): the host names it each time. */\n async function handleFor(params: Params): Promise<ExecutionHandle> {\n const ref = handleRef(params)\n const cwd = confinement.resolveFolder(ref.cwd)\n const existing = handles.get(ref.id)\n if (existing && existing.cwd === cwd)\n return existing\n const handle = await context.spawn({ cwd })\n handles.set(ref.id, handle)\n // The id now names another folder: the old handle (and its tasks) would otherwise live on unreachable.\n if (existing)\n await context.destroy(existing).catch(() => undefined)\n return handle\n }\n\n /** `path` resolved like the context resolves it, then confined. */\n function checked(handle: ExecutionHandle, path: string): string {\n const absolute = workspacePath(handle.cwd, path)\n confinement.checkPath(absolute)\n return absolute\n }\n\n /** A log of a task this machine started, by its path (never through the context: see `./task-logs.ts`). */\n const taskLog = (handle: ExecutionHandle, path: string): string | undefined => {\n const absolute = workspacePath(handle.cwd, path)\n return taskLogs.has(absolute) ? absolute : undefined\n }\n\n const cwdOption = (handle: ExecutionHandle, params: Params): { cwd?: string } => {\n const cwd = optStr(params, 'cwd')\n return cwd === undefined ? {} : { cwd: confinement.resolveFolder(workspacePath(handle.cwd, cwd)) }\n }\n\n const sendExit = (exit: Record<string, unknown>): void => {\n if (options.notify('task.exit', exit))\n return\n pendingExits.push(exit)\n if (pendingExits.length > MAX_PENDING_EXITS)\n pendingExits.shift()\n }\n\n const methods: Record<string, (params: Params) => Promise<unknown>> = {\n 'machine.ping': async () => ({ ok: true }),\n 'exec.spawn': async (params) => {\n const handle = await handleFor(params)\n return { id: handleRef(params).id, cwd: handle.cwd }\n },\n 'exec.run': async (params) => {\n const handle = await handleFor(params)\n const callId = str(params, 'callId')\n // A second call under one id would take over its cancel: the first could no longer be stopped.\n if (calls.has(callId))\n throw new Error(`A call \"${callId}\" is already running.`)\n const controller = new AbortController()\n calls.set(callId, controller)\n try {\n const env = optEnv(params, 'env')\n const timeout = optNum(params, 'timeout')\n return await context.exec(handle, str(params, 'command'), { ...cwdOption(handle, params), ...(env ? { env } : {}), ...(timeout !== undefined ? { timeout } : {}), signal: controller.signal })\n }\n finally {\n calls.delete(callId)\n }\n },\n 'exec.cancel': async (params) => {\n const callId = str(params, 'callId')\n const controller = calls.get(callId)\n controller?.abort()\n return { cancelled: controller !== undefined || streams.kill(callId) }\n },\n 'exec.stream': async (params) => {\n const handle = await handleFor(params)\n const env = optEnv(params, 'env')\n return streams.start(context, handle, { callId: str(params, 'callId'), command: str(params, 'command'), ...cwdOption(handle, params), ...(env ? { env } : {}) })\n },\n 'exec.stream.write': async (params) => {\n await streams.write(str(params, 'callId'), str(params, 'data'))\n return { ok: true }\n },\n 'exec.destroy': async (params) => {\n const ref = handleRef(params)\n const handle = handles.get(ref.id)\n handles.delete(ref.id)\n if (handle)\n await context.destroy(handle)\n return { ok: true }\n },\n 'fs.read': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n if (log)\n return { content: taskLogs.read(log, params.binary === true) }\n const path = checked(handle, str(params, 'path'))\n if (params.binary === true)\n return { content: Buffer.from(await context.readFileBinary!(handle, path)).toString('base64') }\n return { content: await context.readFile(handle, path) }\n },\n 'fs.write': async (params) => {\n const handle = await handleFor(params)\n await context.writeFile(handle, checked(handle, str(params, 'path')), Buffer.from(str(params, 'content'), 'base64'))\n return { ok: true }\n },\n 'fs.list': async params => ({ entries: await listReachable(context, confinement, await handleFor(params), params) }),\n 'fs.size': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n return { size: log ? taskLogs.size(log) : await context.fileSize!(handle, checked(handle, str(params, 'path'))) }\n },\n 'bg.start': async (params) => {\n const handle = await handleFor(params)\n const running = (await context.listBackground!(handle)).filter(t => t.status === 'running').length\n if (taskLogs.count() >= MACHINE_MAX_TASKS * 4 || running >= MACHINE_MAX_TASKS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TASKS} background tasks.`)\n const env = optEnv(params, 'env')\n const cap = optNum(params, 'maxOutputBytes')\n const task = await context.execBackground!(handle, str(params, 'command'), {\n ...cwdOption(handle, params),\n ...(env ? { env } : {}),\n outputDir: taskLogs.outputDir(handleRef(params).id),\n maxOutputBytes: Math.min(cap && cap > 0 ? cap : MACHINE_TASK_OUTPUT_BYTES, MACHINE_TASK_OUTPUT_BYTES),\n onExit: (info: TaskExitInfo) => sendExit({ taskId: info.taskId, exit: { ...info } }),\n })\n taskLogs.add(task.outputPath)\n return { taskId: task.taskId, pid: task.pid, outputPath: task.outputPath }\n },\n 'bg.list': async params => ({ tasks: await context.listBackground!(await handleFor(params)) }),\n 'bg.kill': async params => ({ exit: await context.killBackground!(await handleFor(params), str(params, 'taskId')) }),\n 'bg.wait': async (params) => {\n const timeoutMs = optNum(params, 'timeoutMs')\n return { exit: await context.waitBackground!(await handleFor(params), str(params, 'taskId'), timeoutMs !== undefined ? { timeoutMs } : {}) }\n },\n 'terminal.open': async (params) => {\n const handle = await handleFor(params)\n const terminalId = await terminals.open(context, handle, { cols: num(params, 'cols'), rows: num(params, 'rows'), ...cwdOption(handle, params) })\n return { terminalId }\n },\n 'terminal.attach': async params => terminals.attach(str(params, 'terminalId')),\n 'terminal.write': async (params) => {\n terminals.write(str(params, 'terminalId'), str(params, 'data'))\n return { ok: true }\n },\n 'terminal.resize': async (params) => {\n terminals.resize(str(params, 'terminalId'), num(params, 'cols'), num(params, 'rows'))\n return { ok: true }\n },\n 'terminal.kill': async (params) => {\n await terminals.kill(str(params, 'terminalId'))\n return { ok: true }\n },\n // The host stops viewing; the PTY keeps running (as after a lost link, without the grace).\n 'terminal.detach': async () => ({ ok: true }),\n 'env.checkFolder': async params => ({ cwd: confinement.resolveFolder(str(params, 'cwd')) }),\n 'env.prepareWorktree': async (params) => {\n const cwd = confinement.resolveFolder(str(params, 'cwd'))\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n const base = optStr(params, 'base')\n const prepared = await prepareWorktree({ cwd, environment: { kind: 'worktree', state: 'provisioning', branch: str(params, 'branch'), ...(base ? { base } : {}) }, config }, options.dataDir)\n const ref = prepared.environment?.ref as { path: string, repoRoot: string }\n confinement.resolveFolder(ref.path)\n return { cwd: prepared.cwd ?? ref.path, branch: prepared.environment?.branch, base: prepared.environment?.base, ref }\n },\n 'env.teardownWorktree': async (params) => {\n const ref = (params.ref ?? {}) as { path?: unknown, repoRoot?: unknown }\n if (typeof ref.path !== 'string' || typeof ref.repoRoot !== 'string')\n throw new Error('Invalid params: \"ref\" must be { path, repoRoot }.')\n confinement.checkPath(ref.path)\n confinement.resolveFolder(ref.repoRoot)\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n return teardownWorktree({ path: ref.path, repoRoot: ref.repoRoot }, optStr(params, 'branch'), config)\n },\n }\n\n return {\n async handle(method, raw) {\n if (!Object.hasOwn(methods, method))\n throw new Error(`Unknown machine method \"${method}\".`)\n return methods[method]!(paramsOf(raw))\n },\n linkUp() {\n while (pendingExits.length > 0) {\n if (!options.notify('task.exit', pendingExits[0]!))\n return\n pendingExits.shift()\n }\n },\n sandbox: { on: sandbox.isolation !== undefined, ...(sandbox.warning ? { warning: sandbox.warning } : {}) },\n linkLost: () => {\n terminals.linkLost()\n streams.linkLost()\n },\n async close() {\n for (const controller of calls.values())\n controller.abort()\n await streams.closeAll()\n await terminals.closeAll()\n await Promise.all([...handles.values()].map(handle => context.destroy(handle).catch(() => undefined)))\n handles.clear()\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { p as createArtifactDetectHook } from "./builtin-artifact-kinds-BmorPkgz
|
|
|
8
8
|
import { _ as parseInstallSource, d as InstallSourceError, g as lastLine, h as fetchInstallSource, m as defaultWhich, p as defaultExec, v as resolveNpmVersion, y as resolveSubdirRoot } from "./skills-DxT9Cnkt.js";
|
|
9
9
|
import { c as compileReferencePattern, g as parseBindingSpecs, h as parseBindingSpec, n as isExtensionPanelScope, p as bindingAlternatives } from "./panels-B_DfAx68.js";
|
|
10
10
|
import { r as createLogger, t as consoleSink } from "./logger-RZVCk9Ow.js";
|
|
11
|
-
import { t as ZIDANE_VERSION } from "./version-
|
|
11
|
+
import { t as ZIDANE_VERSION } from "./version-bd3DQJkc.js";
|
|
12
12
|
import { t as resolveStorageDirs } from "./xdg-CJS70jqe.js";
|
|
13
13
|
import { a as getOAuthProvider, c as registerOAuthProvider, l as unregisterOAuthProvider, t as BUILTIN_OAUTH_PROVIDER_IDS } from "./oauth-registry-DbsGvj6u.js";
|
|
14
14
|
import { d as isReservedCredKey } from "./cred-keys-C0KaSRp7.js";
|
|
@@ -4487,4 +4487,4 @@ function createExtensionPromptBridge() {
|
|
|
4487
4487
|
//#endregion
|
|
4488
4488
|
export { sanitizeExtensionConfigActionPatch as $, keybindingsPath as A, discoverExtensions as B, DEFAULT_KEYBINDINGS as C, ensureKeybindingsFile as D, KEYBINDING_KEY_COL_WIDTH as E, readKeybindingsRaw as F, registerExtensionHostModules as G, isExtensionDefinition as H, resolveExtensionKeybindings as I, coerceExtensionConfigInput as J, defineExtension as K, stripJsonComments as L, mergeKeybindings as M, normalizeBindingValue as N, formatBindingForDisplay as O, readKeybindings as P, resolveExtensionConfigValue as Q, ENTRY_CANDIDATES as R, createWorkspaceSurface as S, KEYBINDING_DEF_BY_ACTION as T, parseExtensionScanPathEnv as U, inlineLoadedExtension as V, scanExtensionDirectories as W, isValidExtensionConfigValue as X, isValidExtensionConfigItem as Y, resolveExtensionConfig as Z, createMcpSurface as _, listExtensionCandidates as a, createArtifactsSurface as b, removeInstalledExtension as c, buildExtensionRegistry as d, toWireConfigSchema as et, disposeExtensionRegistry as f, partitionExtensionCatalog as g, mergeContributions as h, installExtensionFromSpec as i, matchesBinding as j, groupBindings as k, updateInstalledExtension as l, filterRegistryPlugins as m, ExtensionInstallError as n, createExtensionBus as nt, parseExtensionInstallSource as o, filterExtensionRegistry as p, clampExtensionConfigNumber as q, fetchExtensionSource as r, serializedPayloadBytes as rt, readExtensionInstallProvenance as s, createExtensionPromptBridge as t, EXTENSION_BUS_MAX_PAYLOAD_BYTES as tt, discoverAndBuildExtensionRegistry as u, MAX_COMPOSER_BADGES as v, KEYBINDING_DEFS as w, createExtensionHostRuntimeBridge as x, createExtensionHud as y, defaultExtensionScanPaths as z };
|
|
4489
4489
|
|
|
4490
|
-
//# sourceMappingURL=extensions-
|
|
4490
|
+
//# sourceMappingURL=extensions-BgBwogRW.js.map
|