zidane 8.2.4 → 8.2.5
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.js +3 -3
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-Dclv6HXn.js → dispatcher-D_9_QFO3.js} +7 -7
- package/dist/{dispatcher-Dclv6HXn.js.map → dispatcher-D_9_QFO3.js.map} +1 -1
- package/dist/{engine-C_U6kDfA.js → engine-BsWBWgTB.js} +2 -2
- package/dist/{engine-C_U6kDfA.js.map → engine-BsWBWgTB.js.map} +1 -1
- package/dist/{executor-BFaR2nfc.js → executor-BSesPPcU.js} +2 -2
- package/dist/{executor-BFaR2nfc.js.map → executor-BSesPPcU.js.map} +1 -1
- package/dist/{extensions-DIbpUj5R.js → extensions-BJof-2mi.js} +2 -2
- package/dist/{extensions-DIbpUj5R.js.map → extensions-BJof-2mi.js.map} +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{host-signals-CQ2jZR-2.js → host-signals-CUKPZZxC.js} +5 -5
- package/dist/{host-signals-CQ2jZR-2.js.map → host-signals-CUKPZZxC.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.js +6 -6
- package/dist/{links-D5itfH8P.js → links-Bto-5dVu.js} +6 -6
- package/dist/{links-D5itfH8P.js.map → links-Bto-5dVu.js.map} +1 -1
- package/dist/{oauth-Ck3wQX4Q.js → oauth-BwPiX0hL.js} +2 -2
- package/dist/{oauth-Ck3wQX4Q.js.map → oauth-BwPiX0hL.js.map} +1 -1
- package/dist/{remote-hosts-BkOwRszu.js → remote-hosts-DcCh7fqp.js} +4 -4
- package/dist/{remote-hosts-BkOwRszu.js.map → remote-hosts-DcCh7fqp.js.map} +1 -1
- package/dist/{settings-keys-QoGJ5n3e.js → settings-keys-CnrJgT1T.js} +2 -2
- package/dist/{settings-keys-QoGJ5n3e.js.map → settings-keys-CnrJgT1T.js.map} +1 -1
- package/dist/{shell-path-BXXtRmEA.js → shell-path-rJDa0OMv.js} +3 -3
- package/dist/{shell-path-BXXtRmEA.js.map → shell-path-rJDa0OMv.js.map} +1 -1
- package/dist/{transcript-anchors-D8jWLpe5.js → transcript-anchors-BcFLh3ZA.js} +3 -3
- package/dist/{transcript-anchors-D8jWLpe5.js.map → transcript-anchors-BcFLh3ZA.js.map} +1 -1
- package/dist/tui.js +8 -8
- package/dist/{version-DDRBX7K6.js → version-DOvIuU8M.js} +2 -2
- package/dist/{version-DDRBX7K6.js.map → version-DOvIuU8M.js.map} +1 -1
- package/dist/{workspace-exec-stream-iHv9cooF.js → workspace-exec-stream-Bzxczzu2.js} +4 -4
- package/dist/{workspace-exec-stream-iHv9cooF.js.map → workspace-exec-stream-Bzxczzu2.js.map} +1 -1
- package/dist/{ws-B2HB87nz.js → ws-CrD-4Mx6.js} +3 -3
- package/dist/{ws-B2HB87nz.js.map → ws-CrD-4Mx6.js.map} +1 -1
- package/dist/{ws-client-DPC9ZJHr.js → ws-client-Dond8vT3.js} +2 -2
- package/dist/{ws-client-DPC9ZJHr.js.map → ws-client-Dond8vT3.js.map} +1 -1
- package/package.json +1 -1
package/dist/extensions.js
CHANGED
|
@@ -2,5 +2,5 @@ import { i as composeExtensionPreset, r as buildExtensionPreset } from "./debug-
|
|
|
2
2
|
import { a as commitKind, c as pullRequestKind, d as resolveArtifactKind, f as sessionBadges, i as branchKind, l as refreshArtifact, n as BUILTIN_ARTIFACT_KINDS, o as fileKind, p as createArtifactDetectHook, r as artifactKindLabel, s as parseShortstat, u as renderArtifactRow } from "./builtin-artifact-kinds-BmorPkgz.js";
|
|
3
3
|
import { C as viewForRead, N as clockTime, S as viewForIssueRead, _ as parseGithubRefKey, a as GITHUB_ISSUE_PROVIDER_ID, b as pullMeta, c as fetchGithubPullRequest, d as githubPullReferenceProvider, f as githubPullUrl, g as isPullFresh, h as githubRefKey, i as BUILTIN_REFERENCE_PROVIDERS, l as githubIssueReferenceProvider, m as githubRateLimitText, n as EMPTY_EXTENSION_REGISTRY, o as GITHUB_PULL_COLORS, p as githubPullView, r as isBadgeColor, s as GITHUB_PULL_PROVIDER_ID, u as githubIssueView, v as pullChecks, x as pullStateLook, y as pullFromMeta, z as githubTokenSource } from "./row-fields-F0tyvIgg.js";
|
|
4
4
|
import { C as mergeBadgeMenu, D as sessionBadgeTarget, E as runBadgeAction, S as extensionBadgeActions, T as normalizeBadgeTarget, _ as artifactBadgeTarget, a as panelBadgeText, b as builtinBadgeActions, c as compileReferencePattern, d as referenceProviderWires, f as referenceProviders, i as normalizePanelLoadContext, l as createReferenceResolver, n as isExtensionPanelScope, o as panelShowsIn, r as normalizePanelContent, s as resolvePanelLoadContext, t as PANEL_CONTENT_LIMITS, u as findReferences, v as badgeMenu, w as normalizeBadgeEffect, x as builtinBadgeEffect, y as badgePromptText } from "./panels-B_DfAx68.js";
|
|
5
|
-
import { $ as sanitizeExtensionConfigActionPatch, B as discoverExtensions, G as registerExtensionHostModules, H as isExtensionDefinition, J as coerceExtensionConfigInput, K as defineExtension, Q as resolveExtensionConfigValue, R as ENTRY_CANDIDATES, S as createWorkspaceSurface, U as parseExtensionScanPathEnv, V as inlineLoadedExtension, W as scanExtensionDirectories, X as isValidExtensionConfigValue, Y as isValidExtensionConfigItem, Z as resolveExtensionConfig, _ as createMcpSurface, a as listExtensionCandidates, b as createArtifactsSurface, c as removeInstalledExtension, d as buildExtensionRegistry, et as toWireConfigSchema, f as disposeExtensionRegistry, g as partitionExtensionCatalog, h as mergeContributions, i as installExtensionFromSpec, l as updateInstalledExtension, m as filterRegistryPlugins, n as ExtensionInstallError, nt as createExtensionBus, o as parseExtensionInstallSource, p as filterExtensionRegistry, q as clampExtensionConfigNumber, r as fetchExtensionSource, rt as serializedPayloadBytes, s as readExtensionInstallProvenance, t as createExtensionPromptBridge, tt as EXTENSION_BUS_MAX_PAYLOAD_BYTES, u as discoverAndBuildExtensionRegistry, v as MAX_COMPOSER_BADGES, x as createExtensionHostRuntimeBridge, y as createExtensionHud, z as defaultExtensionScanPaths } from "./extensions-
|
|
5
|
+
import { $ as sanitizeExtensionConfigActionPatch, B as discoverExtensions, G as registerExtensionHostModules, H as isExtensionDefinition, J as coerceExtensionConfigInput, K as defineExtension, Q as resolveExtensionConfigValue, R as ENTRY_CANDIDATES, S as createWorkspaceSurface, U as parseExtensionScanPathEnv, V as inlineLoadedExtension, W as scanExtensionDirectories, X as isValidExtensionConfigValue, Y as isValidExtensionConfigItem, Z as resolveExtensionConfig, _ as createMcpSurface, a as listExtensionCandidates, b as createArtifactsSurface, c as removeInstalledExtension, d as buildExtensionRegistry, et as toWireConfigSchema, f as disposeExtensionRegistry, g as partitionExtensionCatalog, h as mergeContributions, i as installExtensionFromSpec, l as updateInstalledExtension, m as filterRegistryPlugins, n as ExtensionInstallError, nt as createExtensionBus, o as parseExtensionInstallSource, p as filterExtensionRegistry, q as clampExtensionConfigNumber, r as fetchExtensionSource, rt as serializedPayloadBytes, s as readExtensionInstallProvenance, t as createExtensionPromptBridge, tt as EXTENSION_BUS_MAX_PAYLOAD_BYTES, u as discoverAndBuildExtensionRegistry, v as MAX_COMPOSER_BADGES, x as createExtensionHostRuntimeBridge, y as createExtensionHud, z as defaultExtensionScanPaths } from "./extensions-BJof-2mi.js";
|
|
6
6
|
export { BUILTIN_ARTIFACT_KINDS, BUILTIN_REFERENCE_PROVIDERS, EMPTY_EXTENSION_REGISTRY, ENTRY_CANDIDATES, EXTENSION_BUS_MAX_PAYLOAD_BYTES, ExtensionInstallError, GITHUB_ISSUE_PROVIDER_ID, GITHUB_PULL_COLORS, GITHUB_PULL_PROVIDER_ID, MAX_COMPOSER_BADGES, PANEL_CONTENT_LIMITS, artifactBadgeTarget, artifactKindLabel, badgeMenu, badgePromptText, branchKind, buildExtensionPreset, buildExtensionRegistry, builtinBadgeActions, builtinBadgeEffect, clampExtensionConfigNumber, clockTime, coerceExtensionConfigInput, commitKind, compileReferencePattern, composeExtensionPreset, createArtifactDetectHook, createArtifactsSurface, createExtensionBus, createExtensionHostRuntimeBridge, createExtensionHud, createExtensionPromptBridge, createMcpSurface, createReferenceResolver, createWorkspaceSurface, defaultExtensionScanPaths, defineExtension, discoverAndBuildExtensionRegistry, discoverExtensions, disposeExtensionRegistry, extensionBadgeActions, fetchExtensionSource, fetchGithubPullRequest, fileKind, filterExtensionRegistry, filterRegistryPlugins, findReferences, githubIssueReferenceProvider, githubIssueView, githubPullReferenceProvider, githubPullUrl, githubPullView, githubRateLimitText, githubRefKey, githubTokenSource, inlineLoadedExtension, installExtensionFromSpec, isBadgeColor, isExtensionDefinition, isExtensionPanelScope, isPullFresh, isValidExtensionConfigItem, isValidExtensionConfigValue, listExtensionCandidates, mergeBadgeMenu, mergeContributions, normalizeBadgeEffect, normalizeBadgeTarget, normalizePanelContent, normalizePanelLoadContext, panelBadgeText, panelShowsIn, parseExtensionInstallSource, parseExtensionScanPathEnv, parseGithubRefKey, parseShortstat, partitionExtensionCatalog, pullChecks, pullFromMeta, pullMeta, pullRequestKind, pullStateLook, readExtensionInstallProvenance, referenceProviderWires, referenceProviders, refreshArtifact, registerExtensionHostModules, removeInstalledExtension, renderArtifactRow, resolveArtifactKind, resolveExtensionConfig, resolveExtensionConfigValue, resolvePanelLoadContext, runBadgeAction, sanitizeExtensionConfigActionPatch, scanExtensionDirectories, serializedPayloadBytes, sessionBadgeTarget, sessionBadges, toWireConfigSchema, updateInstalledExtension, viewForIssueRead, viewForRead };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as JsonRpcConnectionClosedError } from "./json-rpc-G0rBfEar.js";
|
|
2
|
-
import { l as defaultSocketPath, p as selfDaemonSpawnCommand, u as ensureDaemonRunning } from "./settings-keys-
|
|
3
|
-
import { h as connectOrSpawnDaemon, m as connectIpcClient } from "./dispatcher-
|
|
2
|
+
import { l as defaultSocketPath, p as selfDaemonSpawnCommand, u as ensureDaemonRunning } from "./settings-keys-CnrJgT1T.js";
|
|
3
|
+
import { h as connectOrSpawnDaemon, m as connectIpcClient } from "./dispatcher-D_9_QFO3.js";
|
|
4
4
|
//#region src/tui/runtime/transport.ts
|
|
5
5
|
/** The shared daemon over its socket; spawns one when none is listening. */
|
|
6
6
|
function socketTransport(options = {}) {
|
|
@@ -41,7 +41,7 @@ function wsTransport(options) {
|
|
|
41
41
|
return {
|
|
42
42
|
async connect(connectOptions = {}) {
|
|
43
43
|
connectOptions.signal?.throwIfAborted();
|
|
44
|
-
const { connectWsClient } = await import("./ws-client-
|
|
44
|
+
const { connectWsClient } = await import("./ws-client-Dond8vT3.js").then((n) => n.i);
|
|
45
45
|
connectOptions.signal?.throwIfAborted();
|
|
46
46
|
return connectWsClient({
|
|
47
47
|
url: options.url,
|
|
@@ -53,7 +53,7 @@ function wsTransport(options) {
|
|
|
53
53
|
});
|
|
54
54
|
},
|
|
55
55
|
async classify(err) {
|
|
56
|
-
const { classifyWsFailure } = await import("./ws-
|
|
56
|
+
const { classifyWsFailure } = await import("./ws-CrD-4Mx6.js").then((n) => n.i);
|
|
57
57
|
return classifyWsFailure(err);
|
|
58
58
|
}
|
|
59
59
|
};
|
|
@@ -121,4 +121,4 @@ function hostSignalHandlers(sinks) {
|
|
|
121
121
|
//#endregion
|
|
122
122
|
export { wsTransport as i, lazyInProcessTransport as n, socketTransport as r, hostSignalHandlers as t };
|
|
123
123
|
|
|
124
|
-
//# sourceMappingURL=host-signals-
|
|
124
|
+
//# sourceMappingURL=host-signals-CUKPZZxC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-signals-CQ2jZR-2.js","names":[],"sources":["../src/tui/runtime/transport.ts","../src/tui/host/host-signals.ts"],"sourcesContent":["/**\n * How a window reaches its chat host: the shared daemon over its unix\n * socket (spawned on demand), a host running in the window's own process,\n * or a remote server over a WebSocket.\n * Everything above the transport (`connectHostSession`, the presence\n * watcher) speaks `IpcClient` and cannot tell which one it got.\n */\nimport type { IpcClient } from '../../ipc/client'\nimport type { HostFailureKind } from '../../ipc/hosts/connection-loop'\nimport type { InProcessHost } from '../../ipc/memory'\nimport { JsonRpcConnectionClosedError } from '../../acp/json-rpc'\nimport { connectIpcClient, connectOrSpawnDaemon } from '../../ipc/client'\nimport { defaultSocketPath, ensureDaemonRunning, selfDaemonSpawnCommand } from '../../ipc/daemon/lifecycle'\n\nexport interface HostConnectOptions {\n appVersion?: string\n /** The connection dropped (daemon exit, socket error, host shutdown). Not called for `close()`. */\n onClose?: () => void\n /**\n * A watcher that must never retire a mismatched daemon (the presence\n * client): it connects to whatever is running and degrades instead.\n * Session controllers are active: a stale daemon is drained and respawned.\n * Meaningless in-process, where client and host are one build.\n */\n passive?: boolean\n /** Give up before connecting once aborted (the attempt was superseded). */\n signal?: AbortSignal\n}\n\nexport interface HostTransport {\n connect: (options?: HostConnectOptions) => Promise<IpcClient>\n /**\n * How a failed `connect` is handled (`../../ipc/hosts/connection-loop`):\n * a server's refusal for good, another protocol version, or \"retry\".\n * Absent: always retry (This computer's daemon).\n */\n classify?: (err: unknown) => Promise<HostFailureKind>\n}\n\n/** The shared daemon over its socket; spawns one when none is listening. */\nexport function socketTransport(options: { socketPath?: string, spawnCommand?: string[] } = {}): HostTransport {\n // Resolved once: a window keeps talking to the daemon it started with,\n // even if the environment that named it changes before a reconnect.\n const socketPath = { socketPath: options.socketPath ?? defaultSocketPath() }\n return {\n async connect(connectOptions = {}) {\n const spawnCommand = options.spawnCommand ?? selfDaemonSpawnCommand()\n const common = {\n ...(connectOptions.appVersion ? { appVersion: connectOptions.appVersion } : {}),\n ...(connectOptions.onClose ? { onClose: connectOptions.onClose } : {}),\n }\n if (connectOptions.passive) {\n const path = await ensureDaemonRunning({ ...socketPath, spawnCommand })\n connectOptions.signal?.throwIfAborted()\n return connectIpcClient({ ...common, socketPath: path, drainOnMismatch: false })\n }\n connectOptions.signal?.throwIfAborted()\n return connectOrSpawnDaemon({ ...common, ...socketPath, spawnCommand })\n },\n }\n}\n\n/**\n * A remote host over a WebSocket (`zidane-server`). Nothing to spawn and\n * nothing to drain: `passive` changes nothing, a version mismatch is the\n * server's to resolve. The WebSocket client loads on the first connect, so\n * a window that never goes remote never loads it.\n */\nexport function wsTransport(options: { url: string, token?: string, expectHostId?: string }): HostTransport {\n return {\n async connect(connectOptions = {}) {\n connectOptions.signal?.throwIfAborted()\n const { connectWsClient } = await import('../../ipc/transports/ws-client')\n connectOptions.signal?.throwIfAborted()\n return connectWsClient({\n url: options.url,\n ...(options.token ? { token: options.token } : {}),\n ...(options.expectHostId ? { expectHostId: options.expectHostId } : {}),\n ...(connectOptions.appVersion ? { appVersion: connectOptions.appVersion } : {}),\n ...(connectOptions.onClose ? { onClose: connectOptions.onClose } : {}),\n ...(connectOptions.signal ? { signal: connectOptions.signal } : {}),\n })\n },\n async classify(err) {\n const { classifyWsFailure } = await import('../../ipc/hosts/ws')\n return classifyWsFailure(err)\n },\n }\n}\n\n/** A host in this process (see `startInProcessHost`). */\nexport function inProcessTransport(host: InProcessHost): HostTransport {\n return {\n async connect(options = {}) {\n options.signal?.throwIfAborted()\n return host.connect({\n ...(options.appVersion ? { appVersion: options.appVersion } : {}),\n ...(options.onClose ? { onClose: options.onClose } : {}),\n })\n },\n }\n}\n\nexport interface LazyInProcessTransport extends HostTransport {\n /** The host, once a connect started it. */\n started: () => InProcessHost | null\n /**\n * Shut the host down if it started (runs abort, clients' `onClose` fires)\n * and refuse later connects. Idempotent.\n */\n close: () => Promise<void>\n}\n\n/**\n * A host in this process, started by the first connect (a window that never\n * opens a session never builds one). A failed start is retried by the next.\n */\nexport function lazyInProcessTransport(start: () => Promise<InProcessHost>): LazyInProcessTransport {\n let starting: Promise<InProcessHost> | null = null\n let host: InProcessHost | null = null\n let closed = false\n const ensure = (): Promise<InProcessHost> => {\n starting ??= start().then(\n (started) => {\n host = started\n return started\n },\n (err: unknown) => {\n starting = null\n throw err\n },\n )\n return starting\n }\n return {\n async connect(options = {}) {\n if (closed)\n throw new JsonRpcConnectionClosedError()\n const started = await ensure()\n // Closed while starting: the close below shuts it down.\n if (closed)\n throw new JsonRpcConnectionClosedError()\n return inProcessTransport(started).connect(options)\n },\n started: () => host,\n async close() {\n closed = true\n const pending = starting\n if (!pending)\n return\n const started = await pending.catch(() => null)\n await started?.close()\n },\n }\n}\n","/**\n * What the window takes from a directory host's app-lifetime connection\n * (the shared connection loop's callbacks): its presence rows\n * (`presence.list` on connect, then `presence:changed`; none while it is\n * down) and its session changes (`sessions:changed`, which a host sends\n * every connection, watching a session or not). No WebSocket import.\n */\nimport type { HostSignal, IpcClient, SessionPresence } from '../../ipc/index'\n\nexport interface HostSignalSinks {\n onPresence?: (key: string, rows: readonly SessionPresence[]) => void\n /** Connected (also after a reconnect): the list should refresh. */\n onConnected?: (key: string) => void\n onSessionsChanged?: (key: string) => void\n}\n\nexport function hostSignalHandlers(sinks: HostSignalSinks): {\n onSignal: (key: string, signal: HostSignal) => void\n onConnected: (key: string, client: IpcClient) => void\n onDisconnected: (key: string) => void\n} {\n const { onPresence, onConnected, onSessionsChanged } = sinks\n return {\n onSignal: (key, signal) => {\n if (signal.kind === 'presence:changed')\n onPresence?.(key, signal.sessions)\n else if (signal.kind === 'sessions:changed')\n onSessionsChanged?.(key)\n },\n onConnected: (key, client) => {\n onConnected?.(key)\n if (onPresence)\n void client.request('presence.list', {}).then(rows => onPresence(key, rows), () => undefined)\n },\n onDisconnected: key => onPresence?.(key, []),\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"host-signals-CUKPZZxC.js","names":[],"sources":["../src/tui/runtime/transport.ts","../src/tui/host/host-signals.ts"],"sourcesContent":["/**\n * How a window reaches its chat host: the shared daemon over its unix\n * socket (spawned on demand), a host running in the window's own process,\n * or a remote server over a WebSocket.\n * Everything above the transport (`connectHostSession`, the presence\n * watcher) speaks `IpcClient` and cannot tell which one it got.\n */\nimport type { IpcClient } from '../../ipc/client'\nimport type { HostFailureKind } from '../../ipc/hosts/connection-loop'\nimport type { InProcessHost } from '../../ipc/memory'\nimport { JsonRpcConnectionClosedError } from '../../acp/json-rpc'\nimport { connectIpcClient, connectOrSpawnDaemon } from '../../ipc/client'\nimport { defaultSocketPath, ensureDaemonRunning, selfDaemonSpawnCommand } from '../../ipc/daemon/lifecycle'\n\nexport interface HostConnectOptions {\n appVersion?: string\n /** The connection dropped (daemon exit, socket error, host shutdown). Not called for `close()`. */\n onClose?: () => void\n /**\n * A watcher that must never retire a mismatched daemon (the presence\n * client): it connects to whatever is running and degrades instead.\n * Session controllers are active: a stale daemon is drained and respawned.\n * Meaningless in-process, where client and host are one build.\n */\n passive?: boolean\n /** Give up before connecting once aborted (the attempt was superseded). */\n signal?: AbortSignal\n}\n\nexport interface HostTransport {\n connect: (options?: HostConnectOptions) => Promise<IpcClient>\n /**\n * How a failed `connect` is handled (`../../ipc/hosts/connection-loop`):\n * a server's refusal for good, another protocol version, or \"retry\".\n * Absent: always retry (This computer's daemon).\n */\n classify?: (err: unknown) => Promise<HostFailureKind>\n}\n\n/** The shared daemon over its socket; spawns one when none is listening. */\nexport function socketTransport(options: { socketPath?: string, spawnCommand?: string[] } = {}): HostTransport {\n // Resolved once: a window keeps talking to the daemon it started with,\n // even if the environment that named it changes before a reconnect.\n const socketPath = { socketPath: options.socketPath ?? defaultSocketPath() }\n return {\n async connect(connectOptions = {}) {\n const spawnCommand = options.spawnCommand ?? selfDaemonSpawnCommand()\n const common = {\n ...(connectOptions.appVersion ? { appVersion: connectOptions.appVersion } : {}),\n ...(connectOptions.onClose ? { onClose: connectOptions.onClose } : {}),\n }\n if (connectOptions.passive) {\n const path = await ensureDaemonRunning({ ...socketPath, spawnCommand })\n connectOptions.signal?.throwIfAborted()\n return connectIpcClient({ ...common, socketPath: path, drainOnMismatch: false })\n }\n connectOptions.signal?.throwIfAborted()\n return connectOrSpawnDaemon({ ...common, ...socketPath, spawnCommand })\n },\n }\n}\n\n/**\n * A remote host over a WebSocket (`zidane-server`). Nothing to spawn and\n * nothing to drain: `passive` changes nothing, a version mismatch is the\n * server's to resolve. The WebSocket client loads on the first connect, so\n * a window that never goes remote never loads it.\n */\nexport function wsTransport(options: { url: string, token?: string, expectHostId?: string }): HostTransport {\n return {\n async connect(connectOptions = {}) {\n connectOptions.signal?.throwIfAborted()\n const { connectWsClient } = await import('../../ipc/transports/ws-client')\n connectOptions.signal?.throwIfAborted()\n return connectWsClient({\n url: options.url,\n ...(options.token ? { token: options.token } : {}),\n ...(options.expectHostId ? { expectHostId: options.expectHostId } : {}),\n ...(connectOptions.appVersion ? { appVersion: connectOptions.appVersion } : {}),\n ...(connectOptions.onClose ? { onClose: connectOptions.onClose } : {}),\n ...(connectOptions.signal ? { signal: connectOptions.signal } : {}),\n })\n },\n async classify(err) {\n const { classifyWsFailure } = await import('../../ipc/hosts/ws')\n return classifyWsFailure(err)\n },\n }\n}\n\n/** A host in this process (see `startInProcessHost`). */\nexport function inProcessTransport(host: InProcessHost): HostTransport {\n return {\n async connect(options = {}) {\n options.signal?.throwIfAborted()\n return host.connect({\n ...(options.appVersion ? { appVersion: options.appVersion } : {}),\n ...(options.onClose ? { onClose: options.onClose } : {}),\n })\n },\n }\n}\n\nexport interface LazyInProcessTransport extends HostTransport {\n /** The host, once a connect started it. */\n started: () => InProcessHost | null\n /**\n * Shut the host down if it started (runs abort, clients' `onClose` fires)\n * and refuse later connects. Idempotent.\n */\n close: () => Promise<void>\n}\n\n/**\n * A host in this process, started by the first connect (a window that never\n * opens a session never builds one). A failed start is retried by the next.\n */\nexport function lazyInProcessTransport(start: () => Promise<InProcessHost>): LazyInProcessTransport {\n let starting: Promise<InProcessHost> | null = null\n let host: InProcessHost | null = null\n let closed = false\n const ensure = (): Promise<InProcessHost> => {\n starting ??= start().then(\n (started) => {\n host = started\n return started\n },\n (err: unknown) => {\n starting = null\n throw err\n },\n )\n return starting\n }\n return {\n async connect(options = {}) {\n if (closed)\n throw new JsonRpcConnectionClosedError()\n const started = await ensure()\n // Closed while starting: the close below shuts it down.\n if (closed)\n throw new JsonRpcConnectionClosedError()\n return inProcessTransport(started).connect(options)\n },\n started: () => host,\n async close() {\n closed = true\n const pending = starting\n if (!pending)\n return\n const started = await pending.catch(() => null)\n await started?.close()\n },\n }\n}\n","/**\n * What the window takes from a directory host's app-lifetime connection\n * (the shared connection loop's callbacks): its presence rows\n * (`presence.list` on connect, then `presence:changed`; none while it is\n * down) and its session changes (`sessions:changed`, which a host sends\n * every connection, watching a session or not). No WebSocket import.\n */\nimport type { HostSignal, IpcClient, SessionPresence } from '../../ipc/index'\n\nexport interface HostSignalSinks {\n onPresence?: (key: string, rows: readonly SessionPresence[]) => void\n /** Connected (also after a reconnect): the list should refresh. */\n onConnected?: (key: string) => void\n onSessionsChanged?: (key: string) => void\n}\n\nexport function hostSignalHandlers(sinks: HostSignalSinks): {\n onSignal: (key: string, signal: HostSignal) => void\n onConnected: (key: string, client: IpcClient) => void\n onDisconnected: (key: string) => void\n} {\n const { onPresence, onConnected, onSessionsChanged } = sinks\n return {\n onSignal: (key, signal) => {\n if (signal.kind === 'presence:changed')\n onPresence?.(key, signal.sessions)\n else if (signal.kind === 'sessions:changed')\n onSessionsChanged?.(key)\n },\n onConnected: (key, client) => {\n onConnected?.(key)\n if (onPresence)\n void client.request('presence.list', {}).then(rows => onPresence(key, rows), () => undefined)\n },\n onDisconnected: key => onPresence?.(key, []),\n }\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -41,7 +41,7 @@ import { t as createRunSummaryCollector } from "./run-summary-2d26oMyQ.js";
|
|
|
41
41
|
import { c as listSkillCandidates, l as parseSkillInstallSpec, o as SkillInstallError, s as installSkillFromSpec, t as defineSkill, u as readSkillProvenance } from "./skills-DxT9Cnkt.js";
|
|
42
42
|
import { _ as readSkillEditMarker, a as sectionDigest, b as withZidaneSkillEditSkill, c as EXTENSION_EDIT_METADATA_KEY, d as ZIDANE_SKILL_EDIT_SKILL_NAME, f as buildZidaneExtensionSkill, g as extensionScaffold, h as extensionDirForCwd, i as latestSystemSnapshot, l as SKILL_EDIT_METADATA_KEY, m as editSessionMetadata, n as announcedDigest, o as sectionDigests, p as buildZidaneSkillEditSkill, r as catalogChangeNotes, s as systemSnapshotTurn, t as FROZEN_PROMPT_SECTION_KINDS, u as ZIDANE_EXTENSION_SKILL_NAME, v as resolveExtensionDocsDir, y as withZidaneExtensionSkill } from "./system-freeze-Um9ZJiPo.js";
|
|
43
43
|
import { E as runBadgeAction, S as extensionBadgeActions, T as normalizeBadgeTarget, c as compileReferencePattern, d as referenceProviderWires, l as createReferenceResolver, u as findReferences, v as badgeMenu } from "./panels-B_DfAx68.js";
|
|
44
|
-
import { $ as sanitizeExtensionConfigActionPatch, B as discoverExtensions, G as registerExtensionHostModules, H as isExtensionDefinition, J as coerceExtensionConfigInput, K as defineExtension, Q as resolveExtensionConfigValue, R as ENTRY_CANDIDATES, S as createWorkspaceSurface, U as parseExtensionScanPathEnv, V as inlineLoadedExtension, W as scanExtensionDirectories, X as isValidExtensionConfigValue, Y as isValidExtensionConfigItem, Z as resolveExtensionConfig, _ as createMcpSurface, a as listExtensionCandidates, b as createArtifactsSurface, c as removeInstalledExtension, d as buildExtensionRegistry, et as toWireConfigSchema, f as disposeExtensionRegistry, g as partitionExtensionCatalog, h as mergeContributions, i as installExtensionFromSpec, l as updateInstalledExtension, n as ExtensionInstallError, nt as createExtensionBus, o as parseExtensionInstallSource, p as filterExtensionRegistry, q as clampExtensionConfigNumber, r as fetchExtensionSource, s as readExtensionInstallProvenance, t as createExtensionPromptBridge, tt as EXTENSION_BUS_MAX_PAYLOAD_BYTES, u as discoverAndBuildExtensionRegistry, v as MAX_COMPOSER_BADGES, x as createExtensionHostRuntimeBridge, y as createExtensionHud, z as defaultExtensionScanPaths } from "./extensions-
|
|
44
|
+
import { $ as sanitizeExtensionConfigActionPatch, B as discoverExtensions, G as registerExtensionHostModules, H as isExtensionDefinition, J as coerceExtensionConfigInput, K as defineExtension, Q as resolveExtensionConfigValue, R as ENTRY_CANDIDATES, S as createWorkspaceSurface, U as parseExtensionScanPathEnv, V as inlineLoadedExtension, W as scanExtensionDirectories, X as isValidExtensionConfigValue, Y as isValidExtensionConfigItem, Z as resolveExtensionConfig, _ as createMcpSurface, a as listExtensionCandidates, b as createArtifactsSurface, c as removeInstalledExtension, d as buildExtensionRegistry, et as toWireConfigSchema, f as disposeExtensionRegistry, g as partitionExtensionCatalog, h as mergeContributions, i as installExtensionFromSpec, l as updateInstalledExtension, n as ExtensionInstallError, nt as createExtensionBus, o as parseExtensionInstallSource, p as filterExtensionRegistry, q as clampExtensionConfigNumber, r as fetchExtensionSource, s as readExtensionInstallProvenance, t as createExtensionPromptBridge, tt as EXTENSION_BUS_MAX_PAYLOAD_BYTES, u as discoverAndBuildExtensionRegistry, v as MAX_COMPOSER_BADGES, x as createExtensionHostRuntimeBridge, y as createExtensionHud, z as defaultExtensionScanPaths } from "./extensions-BJof-2mi.js";
|
|
45
45
|
import { r as formatLogLine } from "./logs-view-DF7ArI6t.js";
|
|
46
46
|
import { a as createRingBufferSink, i as createLoggingHooks, o as fanoutSink, r as createLogger, s as jsonSink, t as consoleSink } from "./logger-RZVCk9Ow.js";
|
|
47
47
|
import { a as getOAuthProvider, c as registerOAuthProvider, i as getOAuthApiKey, o as refreshAnthropicToken, s as refreshOpenAICodexToken } from "./oauth-registry-DbsGvj6u.js";
|
package/dist/ipc/remote.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as createSyncEngine } from "../engine-
|
|
1
|
+
import { t as createSyncEngine } from "../engine-BsWBWgTB.js";
|
|
2
2
|
import { t as keepHostConnected } from "../connection-loop-DSCehV3W.js";
|
|
3
|
-
import { a as hostCaBundle, n as HostBusyError, o as trustSystemCertificates, r as connectWsClient, t as HostAuthError } from "../ws-client-
|
|
4
|
-
import { a as MissingHostTokenError, c as createWsHostRegistry, l as probeWsHost, n as probeUnsavedWsHost, o as startSavedHosts, r as startWsSavedHosts, s as HOST_PROBE_TIMEOUT_MS, t as classifyWsFailure } from "../ws-
|
|
3
|
+
import { a as hostCaBundle, n as HostBusyError, o as trustSystemCertificates, r as connectWsClient, t as HostAuthError } from "../ws-client-Dond8vT3.js";
|
|
4
|
+
import { a as MissingHostTokenError, c as createWsHostRegistry, l as probeWsHost, n as probeUnsavedWsHost, o as startSavedHosts, r as startWsSavedHosts, s as HOST_PROBE_TIMEOUT_MS, t as classifyWsFailure } from "../ws-CrD-4Mx6.js";
|
|
5
5
|
export { HOST_PROBE_TIMEOUT_MS, HostAuthError, HostBusyError, MissingHostTokenError, classifyWsFailure, connectWsClient, createSyncEngine, createWsHostRegistry, hostCaBundle, keepHostConnected, probeUnsavedWsHost, probeWsHost, startSavedHosts, startWsSavedHosts, trustSystemCertificates };
|
package/dist/ipc.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { a as projectRootOf } from "./project-root-BOgUA6n5.js";
|
|
2
2
|
import { t as resolveStorageDirs } from "./xdg-CJS70jqe.js";
|
|
3
|
-
import { Mt as readFileSafe, Nt as resolveCwdPath, Pt as serializePreview, en as EditOutcomeLedger, h as createInteractionHub, jt as extractEditPayloadForGate, m as createChatHost, nn as createApprovalHub, rn as createMemoryApprovalsStore, tn as runCompaction } from "./oauth-
|
|
3
|
+
import { Mt as readFileSafe, Nt as resolveCwdPath, Pt as serializePreview, en as EditOutcomeLedger, h as createInteractionHub, jt as extractEditPayloadForGate, m as createChatHost, nn as createApprovalHub, rn as createMemoryApprovalsStore, tn as runCompaction } from "./oauth-BwPiX0hL.js";
|
|
4
4
|
import { it as MachineErrorCode, nt as MACHINE_PROTOCOL_VERSION } from "./mcp-allowlist-BbnTBKNN.js";
|
|
5
|
-
import { c as daemonSocketName, f as probeSocket, i as IpcVersionMismatchError, l as defaultSocketPath, p as selfDaemonSpawnCommand, s as IPC_BUILD_ID, u as ensureDaemonRunning } from "./settings-keys-
|
|
5
|
+
import { c as daemonSocketName, f as probeSocket, i as IpcVersionMismatchError, l as defaultSocketPath, p as selfDaemonSpawnCommand, s as IPC_BUILD_ID, u as ensureDaemonRunning } from "./settings-keys-CnrJgT1T.js";
|
|
6
6
|
import { c as SESSION_TURNS_PAGE, d as loadAllEvents, f as loadEventsPage, i as LOAD_EVENTS_PAGE_TURNS, l as SIGNAL_SEQ_FIELD, m as loadSessionDocument, n as IpcErrorCode, o as REDACTED, r as LOAD_EVENTS_MAX_PAGE_TURNS, s as SESSION_TURNS_MAX_PAGE, t as IPC_PROTOCOL_VERSION, u as hostRefOf } from "./protocol-Do_i6Ras.js";
|
|
7
|
-
import { a as historyWorkerUrl, c as createWorkerRpcClient, d as createDaemonEnvironment, f as createFileApprovalsStore, h as connectOrSpawnDaemon, i as createTranscriptHistoryWorker, l as createMachineHandlers, m as connectIpcClient, n as HISTORY_WORKER_KILL_SWITCH, o as WorkerRequestError, p as createHostEnvironment, r as createHostTranscriptPager, s as WorkerUnavailableError, u as createMachineLinkHandlers } from "./dispatcher-
|
|
7
|
+
import { a as historyWorkerUrl, c as createWorkerRpcClient, d as createDaemonEnvironment, f as createFileApprovalsStore, h as connectOrSpawnDaemon, i as createTranscriptHistoryWorker, l as createMachineHandlers, m as connectIpcClient, n as HISTORY_WORKER_KILL_SWITCH, o as WorkerRequestError, p as createHostEnvironment, r as createHostTranscriptPager, s as WorkerUnavailableError, u as createMachineLinkHandlers } from "./dispatcher-D_9_QFO3.js";
|
|
8
8
|
import { i as exchangeBoundaries, n as createTranscriptReplayCache, o as transcriptPage, r as WHOLE_RUN_PAGES, s as turnCutPoints } from "./transcript-cache-CdHKtx9y.js";
|
|
9
|
-
import { a as startIpcDaemon, i as shellPathAsync, n as mergePath, r as shellPath, t as fixPath } from "./shell-path-
|
|
9
|
+
import { a as startIpcDaemon, i as shellPathAsync, n as mergePath, r as shellPath, t as fixPath } from "./shell-path-rJDa0OMv.js";
|
|
10
10
|
import { t as serveWorkerRpc } from "./rpc-serve-CIV6Cv_c.js";
|
|
11
|
-
import { n as runRemoteOAuth, r as startInProcessHost, t as runWorkspaceExecStream } from "./workspace-exec-stream-
|
|
11
|
+
import { n as runRemoteOAuth, r as startInProcessHost, t as runWorkspaceExecStream } from "./workspace-exec-stream-Bzxczzu2.js";
|
|
12
12
|
import process from "node:process";
|
|
13
13
|
import { createInterface } from "node:readline";
|
|
14
14
|
//#region src/ipc/attach.ts
|
|
@@ -39,7 +39,7 @@ async function runAttach(options = {}) {
|
|
|
39
39
|
failRun?.(/* @__PURE__ */ new Error(`${what} connection lost`));
|
|
40
40
|
};
|
|
41
41
|
const appVersion = options.appVersion ? { appVersion: options.appVersion } : {};
|
|
42
|
-
const client = options.host ? await (await import("./ws-client-
|
|
42
|
+
const client = options.host ? await (await import("./ws-client-Dond8vT3.js").then((n) => n.i)).connectWsClient({
|
|
43
43
|
url: options.host.url,
|
|
44
44
|
...options.host.token ? { token: options.host.token } : {},
|
|
45
45
|
...appVersion,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { i as writeJsonFileAtomic, t as OWNER_ONLY } from "./atomic-write-Ijgf2Mhc.js";
|
|
2
|
-
import { t as ZIDANE_VERSION } from "./version-
|
|
2
|
+
import { t as ZIDANE_VERSION } from "./version-DOvIuU8M.js";
|
|
3
3
|
import { n as JsonRpcRemoteError, t as JsonRpcConnectionClosedError } from "./json-rpc-G0rBfEar.js";
|
|
4
|
-
import { kt as MachineLinkLostError } from "./oauth-
|
|
4
|
+
import { kt as MachineLinkLostError } from "./oauth-BwPiX0hL.js";
|
|
5
5
|
import { at as isValidMachineName, it as MachineErrorCode, ot as machineCredentialKey } from "./mcp-allowlist-BbnTBKNN.js";
|
|
6
6
|
import { _ as writeCredentialEntry, a as readCredentialEntry } from "./credentials-DxOQmset.js";
|
|
7
7
|
import { t as HostIdentityError } from "./connection-BaHd3T-D.js";
|
|
8
|
-
import { i as IpcVersionMismatchError } from "./settings-keys-
|
|
8
|
+
import { i as IpcVersionMismatchError } from "./settings-keys-CnrJgT1T.js";
|
|
9
9
|
import { t as keepHostConnected } from "./connection-loop-DSCehV3W.js";
|
|
10
10
|
import { n as displayHostUrl } from "./url-D4vG7lzO.js";
|
|
11
11
|
import { t as createHostRegistry } from "./registry-DxPP_tAt.js";
|
|
12
|
-
import { r as connectWsClient, t as HostAuthError } from "./ws-client-
|
|
13
|
-
import { createMachineExecutor, shareableRoot } from "./executor-
|
|
12
|
+
import { r as connectWsClient, t as HostAuthError } from "./ws-client-Dond8vT3.js";
|
|
13
|
+
import { createMachineExecutor, shareableRoot } from "./executor-BSesPPcU.js";
|
|
14
14
|
import { n as machineIdentity } from "./identity-CwfO8K-t.js";
|
|
15
15
|
import { closeSync, existsSync, linkSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, rmSync, statSync, utimesSync, writeSync } from "node:fs";
|
|
16
16
|
import { isAbsolute, join } from "node:path";
|
|
@@ -601,4 +601,4 @@ function startMachineLinks(options) {
|
|
|
601
601
|
//#endregion
|
|
602
602
|
export { startMachineLinks };
|
|
603
603
|
|
|
604
|
-
//# sourceMappingURL=links-
|
|
604
|
+
//# sourceMappingURL=links-Bto-5dVu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"links-D5itfH8P.js","names":[],"sources":["../src/ipc/machine/agent.ts","../src/ipc/machine/reverse.ts","../src/ipc/machine/share-lock.ts","../src/ipc/machine/links.ts"],"sourcesContent":["/**\n * The machine agent (`docs/MACHINES.md` § Machine side): dials its host with\n * a machine-scoped token, registers, and serves the host's execution\n * requests through the confined executor (`./executor.ts`) until stopped.\n * Reconnects with the hosts' connection loop (backoff; a refused token, a\n * different host at the URL, or a refused registration stop it for good).\n *\n * The CLI (`./cli.ts`, `zidane machine share`) runs it in the foreground;\n * `./links.ts` starts it from the local daemon / in-process host.\n */\nimport type { HostConnectionStatus } from '../../chat/hosts/connection'\nimport type { MachineRegisterParams, MachineRegisterResult, MachineRoot } from '../../chat/machine-protocol'\nimport type { IpcClient } from '../transports/client-core'\nimport type { MachineExecutorOptions } from './executor'\nimport { mkdirSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { writeJsonFileAtomic } from '../../atomic-write'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { isValidMachineName, MACHINE_PROTOCOL_VERSION, MachineErrorCode } from '../../chat/machine-protocol'\nimport { ZIDANE_VERSION } from '../../version'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { IpcVersionMismatchError } from '../transports/client-core'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\nimport { createMachineExecutor, shareableRoot } from './executor'\nimport { machineIdentity } from './identity'\n\nexport { machineIdentity } from './identity'\n\nexport interface MachineAgentOptions {\n /** `ws://` / `wss://` URL of the host. */\n hostUrl: string\n /** A `machine`-scoped token of that host. */\n token: string\n /** Display name, and the suffix of its environment kinds (`local@<name>`). */\n name: string\n /** Folders the host may use; absolute, existing. */\n roots: ReadonlyArray<string | MachineRoot>\n /** This machine's data dir: its id, the host it pinned, task logs. Never reachable by the host's file ops. */\n dataDir: string\n appVersion?: string\n /** Every status change (`connected`, `reconnecting`, `auth-refused`, …) and why it failed. */\n onStatus?: (status: HostConnectionStatus, detail?: string) => void\n /** Backoff bounds and heartbeat (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n terminalGraceMs?: number\n /** This machine user's `sandbox*` settings: every command the host sends runs under them (`docs/MACHINES.md` § Sandbox). */\n sandbox?: MachineExecutorOptions['sandbox']\n /** This machine user's zidane data dir: never shared (a root can't be in it, file ops never reach it), and its credential files are hidden from sandboxed commands. */\n credentialsDataDir?: string\n}\n\nexport interface MachineAgent {\n machineId: string\n status: () => HostConnectionStatus\n /** Reconnect now (after a fix on the host side). */\n retry: () => void\n stop: () => Promise<void>\n}\n\n/** A registration the host refused for good (its name taken, another protocol). */\nclass MachineRegisterError extends Error {\n constructor(message: string, readonly forGood: boolean) {\n super(message)\n this.name = 'MachineRegisterError'\n }\n}\n\nfunction normalizeRoots(roots: MachineAgentOptions['roots'], zidaneDataDir: string | undefined): MachineRoot[] {\n if (roots.length === 0)\n throw new Error('Share at least one folder (--root).')\n return roots.map((root) => {\n const entry = typeof root === 'string' ? { path: root } : root\n const real = shareableRoot(entry.path, zidaneDataDir)\n if (!statSync(real).isDirectory())\n throw new Error(`Root ${entry.path} is not a folder.`)\n return { path: real, ...(entry.label ? { label: entry.label } : {}) }\n })\n}\n\n/** The host id this machine pinned for `url` (the first host that answered there). */\nfunction pinnedHosts(dataDir: string): { get: (url: string) => string | undefined, set: (url: string, hostId: string) => void } {\n const file = join(dataDir, 'machine-hosts.json')\n const read = (): Record<string, string> => {\n try {\n return JSON.parse(readFileSync(file, 'utf8')) as Record<string, string>\n }\n catch {\n return {}\n }\n }\n return {\n get: url => read()[url],\n set: (url, hostId) => writeJsonFileAtomic(file, { ...read(), [url]: hostId }, { ensureDir: true, mode: 0o600 }),\n }\n}\n\nexport function startMachineAgent(options: MachineAgentOptions): MachineAgent {\n if (!isValidMachineName(options.name))\n throw new Error(`\"${options.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n mkdirSync(options.dataDir, { recursive: true, mode: 0o700 })\n const dataDir = realpathSync.native(options.dataDir)\n const roots = normalizeRoots(options.roots, options.credentialsDataDir)\n const machineId = machineIdentity(dataDir)\n const pins = pinnedHosts(dataDir)\n const url = options.hostUrl\n let client: IpcClient | null = null\n let status: HostConnectionStatus = 'connecting'\n\n const executor = createMachineExecutor({\n roots,\n dataDir,\n ...(options.terminalGraceMs !== undefined ? { terminalGraceMs: options.terminalGraceMs } : {}),\n ...(options.sandbox ? { sandbox: options.sandbox } : {}),\n ...(options.credentialsDataDir ? { credentialsDataDir: options.credentialsDataDir } : {}),\n notify: (method, params) => {\n if (!client)\n return false\n try {\n (client.notify as unknown as (m: string, p: unknown) => void)(method, params)\n return true\n }\n catch {\n return false\n }\n },\n })\n\n const register: MachineRegisterParams = {\n machineId,\n name: options.name,\n roots,\n capabilities: { shell: true, terminals: typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined', background: true, worktrees: true, stream: true, sandboxed: executor.sandbox.on },\n version: options.appVersion ?? ZIDANE_VERSION,\n protocolVersion: MACHINE_PROTOCOL_VERSION,\n }\n\n const loop = keepHostConnected({\n minDelayMs: options.minDelayMs ?? 1000,\n maxDelayMs: options.maxDelayMs ?? 30_000,\n async connect({ signal, onClose }) {\n const expectHostId = pins.get(url)\n const connected = await connectWsClient({\n url,\n token: options.token,\n signal,\n onClose,\n appVersion: register.version,\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n ...(expectHostId ? { expectHostId } : {}),\n serve: {\n request: (method, params) => executor.handle(method, params),\n notification: (method, params) => void executor.handle(method, params).catch(() => undefined),\n },\n })\n try {\n await (connected.request as unknown as (m: string, p: unknown) => Promise<MachineRegisterResult>)('machine.register', register)\n }\n catch (err) {\n connected.close()\n const code = err instanceof JsonRpcRemoteError ? err.code : undefined\n throw new MachineRegisterError(`${displayHostUrl(url)} refused this machine: ${(err as Error).message}`, code === MachineErrorCode.NameTaken || code === MachineErrorCode.VersionSkew || code === MachineErrorCode.IdBound)\n }\n if (!expectHostId && connected.hello.hostId)\n pins.set(url, connected.hello.hostId)\n return connected\n },\n classify: (err) => {\n if (err instanceof HostIdentityError)\n return 'identity'\n if (err instanceof HostAuthError || (err instanceof MachineRegisterError && err.forGood))\n return 'auth'\n return err instanceof IpcVersionMismatchError ? 'protocol' : 'retry'\n },\n update: (patch) => {\n if (patch.client !== undefined)\n client = patch.client\n if (patch.status) {\n status = patch.status\n options.onStatus?.(patch.status, patch.error)\n }\n },\n onConnected: () => executor.linkUp(),\n onDisconnected: () => executor.linkLost(),\n })\n\n return {\n machineId,\n status: () => status,\n retry: () => loop.retry(),\n async stop() {\n loop.stop()\n await executor.close()\n },\n }\n}\n","/**\n * A saved server used as a machine of this local host (`local@<server>`,\n * `docs/MACHINES.md` § Reverse direction). A local host has no listener, so\n * it dials the server as a client (its saved client token), asks it to lend\n * itself (`machine.attach`), and registers it in its own machine registry\n * with a connection that sends each host→machine request as `machine.call`.\n * The server's notifications come back as `machine:notification` signals.\n * Reconnects with the hosts' connection loop; a refused token, another host\n * at the URL, or a server that does not lend itself stop it for good.\n */\nimport type { AttachedMachine, MachineConnection, MachineRegistry } from '../../chat/host/machines'\nimport type { MachineLinkState } from '../../chat/machine-protocol'\nimport type { JsonValue } from '../../types'\nimport type { IpcClient } from '../transports/client-core'\nimport { JsonRpcConnectionClosedError, JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { MachineLinkLostError } from '../../chat/host/machines'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { MachineErrorCode } from '../../chat/machine-protocol'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\n\nexport interface ServerMachineOptions {\n machines: MachineRegistry\n url: string\n /** The saved server's client token. */\n token: string\n /** The saved server's host id: another host at the URL is refused. */\n expectHostId: string\n /** This host's id (the server keys its executor by it, so tasks survive a reconnect). */\n localHostId: string\n appVersion?: string\n onState: (state: MachineLinkState, detail?: string, machineName?: string) => void\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n}\n\nexport interface ServerMachine {\n retry: () => void\n stop: () => void\n}\n\n/** The server refused to lend itself (`allowAsMachine` off, a name taken here): for good. A busy server is retried. */\nclass AttachRefusedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AttachRefusedError'\n }\n}\n\nfunction connectionOver(client: IpcClient): MachineConnection {\n return {\n async request(method, params) {\n try {\n return await client.request('machine.call', { method, params: (params ?? {}) as JsonValue })\n }\n catch (err) {\n if (err instanceof JsonRpcConnectionClosedError)\n throw new MachineLinkLostError()\n throw err instanceof JsonRpcRemoteError ? new Error(err.message) : err\n }\n },\n notify: (method, params) => client.notify('machine.call', { method, params: (params ?? {}) as JsonValue }),\n close: () => client.close(),\n }\n}\n\nexport function startServerMachine(options: ServerMachineOptions): ServerMachine {\n let attached: AttachedMachine | undefined\n const where = displayHostUrl(options.url)\n\n const detach = (): void => {\n attached?.closed()\n attached = undefined\n }\n\n const loop = keepHostConnected({\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n async connect({ signal, onClose }) {\n const client = await connectWsClient({\n url: options.url,\n token: options.token,\n expectHostId: options.expectHostId,\n signal,\n onClose,\n ...(options.appVersion ? { appVersion: options.appVersion } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n })\n // Subscribed before attaching: the server re-sends queued task exits while it answers `machine.attach`.\n const early: Array<{ method: string, params: unknown }> = []\n let current: AttachedMachine | undefined\n client.onSignal((s) => {\n if (s.kind !== 'machine:notification')\n return\n if (current)\n current.notification(s.method, s.params)\n else if (early.length < 1024)\n early.push({ method: s.method, params: s.params })\n })\n try {\n const params = await client.request('machine.attach', { hostId: options.localHostId })\n detach()\n current = options.machines.attach(params, connectionOver(client))\n attached = current\n for (const { method, params: p } of early.splice(0))\n current.notification(method, p)\n options.onState('connected', undefined, params.name)\n }\n catch (err) {\n client.close()\n // No room there now (a capacity limit) or the link dropped: the loop retries with backoff.\n if (err instanceof JsonRpcConnectionClosedError || (err instanceof JsonRpcRemoteError && err.code === MachineErrorCode.Busy))\n throw new Error(`${where} can't lend itself right now: ${(err as Error).message}`)\n throw new AttachRefusedError(`${where} refused to be a machine: ${(err as Error).message}`)\n }\n return client\n },\n classify: err => (err instanceof HostIdentityError ? 'identity' : err instanceof HostAuthError || err instanceof AttachRefusedError ? 'auth' : 'retry'),\n update: (patch) => {\n if (!patch.status || patch.status === 'connected')\n return\n options.onState(patch.status === 'auth-refused' && patch.error?.includes('refused to be a machine') ? 'refused' : patch.status, patch.error)\n },\n onDisconnected: detach,\n })\n\n return {\n retry: () => loop.retry(),\n stop() {\n loop.stop()\n detach()\n },\n }\n}\n","/**\n * `machine-links.lock`: which process runs this computer's shares (one\n * machine id, one connection; two processes sharing it would keep replacing\n * each other's). Exclusive by construction, not by a read-then-write:\n *\n * - taking a free lock is an exclusive create (`wx`): one contender wins;\n * - the record names its holder (`pid`) and a per-process `nonce`; the\n * holder touches the file on every check, so a holder is stale when its\n * pid is gone OR the file went untouched for {@link STALE_MS} (a reused\n * pid never touches it);\n * - a stale lock is moved aside (an atomic rename to a name of our own),\n * checked to be the very record judged stale, then the exclusive create\n * runs again; a live lock moved aside by mistake is put back without\n * clobbering (`link`, which fails if the name is taken);\n * - a holder re-reads the record on every check: another nonce there means\n * it lost the lock, and the caller stops its shares;\n * - release removes the file only when it still carries this nonce.\n */\nimport { randomBytes } from 'node:crypto'\nimport { closeSync, linkSync, openSync, readFileSync, renameSync, rmSync, statSync, utimesSync, writeSync } from 'node:fs'\nimport process from 'node:process'\n\n/** A holder that has not touched its lock for this long is gone (its pid may be reused). */\nexport const SHARE_LOCK_STALE_MS = 30_000\n\ninterface LockRecord {\n pid: number\n nonce: string\n}\n\nexport interface ShareLock {\n /** Hold the lock (taking it when free or stale); `false` when another live process holds it. */\n acquire: () => boolean\n /** Whether this process held it at the last {@link acquire}. */\n held: () => boolean\n /** Remove the lock when this process still holds it; whether it did. */\n release: () => boolean\n}\n\nexport interface ShareLockOptions {\n /** Test seams. */\n pid?: number\n alive?: (pid: number) => boolean\n now?: () => number\n staleMs?: number\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n }\n catch (err) {\n return (err as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\nfunction readRecord(file: string): { record?: LockRecord, mtimeMs: number } | undefined {\n try {\n const mtimeMs = statSync(file).mtimeMs\n const raw = JSON.parse(readFileSync(file, 'utf8')) as Partial<LockRecord>\n return { mtimeMs, ...(typeof raw.pid === 'number' && typeof raw.nonce === 'string' ? { record: { pid: raw.pid, nonce: raw.nonce } } : {}) }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT')\n return undefined\n // Unreadable or half-written: judged by its age alone.\n try {\n return { mtimeMs: statSync(file).mtimeMs }\n }\n catch {\n return undefined\n }\n }\n}\n\nexport function createShareLock(file: string, options: ShareLockOptions = {}): ShareLock {\n const pid = options.pid ?? process.pid\n const alive = options.alive ?? processAlive\n const now = options.now ?? Date.now\n const staleMs = options.staleMs ?? SHARE_LOCK_STALE_MS\n const nonce = randomBytes(12).toString('hex')\n let holding = false\n\n const create = (): boolean => {\n let fd: number\n try {\n fd = openSync(file, 'wx', 0o600)\n }\n catch {\n return false\n }\n try {\n writeSync(fd, JSON.stringify({ pid, nonce }))\n }\n finally {\n closeSync(fd)\n }\n return true\n }\n\n const ours = (): boolean => readRecord(file)?.record?.nonce === nonce\n\n const stale = (found: { record?: LockRecord, mtimeMs: number }): boolean =>\n now() - found.mtimeMs > staleMs || (found.record !== undefined && !alive(found.record.pid))\n\n /** Move a stale lock aside; `true` when the record moved is the one judged stale. */\n const evict = (judged: { record?: LockRecord, mtimeMs: number }): boolean => {\n const aside = `${file}.${nonce}.stale`\n try {\n renameSync(file, aside)\n }\n catch {\n return false\n }\n const moved = readRecord(aside)\n const same = moved?.record?.nonce === judged.record?.nonce && moved?.mtimeMs === judged.mtimeMs\n if (!same) {\n // A live lock taken meanwhile: put it back, never over a newer one.\n try {\n linkSync(aside, file)\n }\n catch {\n // Someone holds the name again; that holder's own check settles it.\n }\n }\n rmSync(aside, { force: true })\n return same\n }\n\n return {\n acquire() {\n if (holding) {\n if (ours()) {\n try {\n const at = new Date(now())\n utimesSync(file, at, at)\n }\n catch {\n // The touch is best effort; the record still names this process.\n }\n return true\n }\n holding = false\n }\n if (create()) {\n holding = true\n return true\n }\n const found = readRecord(file)\n if (found && !stale(found))\n return false\n if (found && !evict(found))\n return false\n holding = create()\n return holding\n },\n held: () => holding,\n release() {\n const mine = holding && ours()\n if (mine)\n rmSync(file, { force: true })\n holding = false\n return mine\n },\n }\n}\n","/**\n * A local host's machine links (`docs/MACHINES.md` § Client UI), loaded only\n * behind remote hosts:\n *\n * - **Shares**: this computer lent to a saved server (a machine agent in\n * this process, with the machine token stored under `machine:<hostId>`).\n * One process runs them for the whole computer: the holder of\n * `machine-links.lock` (the daemon, or the first window's in-process\n * host; exclusive, `./share-lock.ts`). Two processes sharing one computer\n * under one machine id would keep replacing each other's connection, so a\n * process that finds it lost the lock stops its shares at once.\n * - **Uses**: a saved server lent to THIS host (`local@<server>`), over its\n * own client connection. Per host process: each host has its own machine\n * registry, so each attaches under its own instance id.\n *\n * The wanted links live in `<dataDir>/machine-links.json` (any process writes\n * it); every process re-reads it every {@link POLL_MS}, the holder applies the\n * shares and publishes their state in `machine-links-status.json`. Tokens\n * are never in either file.\n */\nimport type { MachineRegistry } from '../../chat/host/machines'\nimport type { HostEntry } from '../../chat/hosts/types'\nimport type { MachineLinksStatus, MachineLinkState, MachineShareStatus, MachineUseStatus } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { MachineAgent } from './agent'\nimport type { ServerMachine } from './reverse'\nimport { randomBytes } from 'node:crypto'\nimport { existsSync, readFileSync, rmSync } from 'node:fs'\nimport { isAbsolute, join } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { readCredentialEntry, writeCredentialEntry } from '../../chat/credentials'\nimport { createHostRegistry } from '../../chat/hosts'\nimport { isValidMachineName, machineCredentialKey } from '../../chat/machine-protocol'\nimport { startMachineAgent } from './agent'\nimport { shareableRoot } from './executor'\nimport { startServerMachine } from './reverse'\nimport { createShareLock } from './share-lock'\n\nconst POLL_MS = 2000\nconst CONFIG_FILE = 'machine-links.json'\nconst STATUS_FILE = 'machine-links-status.json'\nconst LOCK_FILE = 'machine-links.lock'\nconst MAX_ROOTS = 32\n\ninterface ShareConfig {\n hostId: string\n name: string\n roots: string[]\n}\n\ninterface LinksConfig {\n version: 1\n shares: ShareConfig[]\n uses: string[]\n}\n\nexport interface MachineLinksOptions {\n /** The host's data dir: saved hosts, credentials, these files. */\n dataDir: string\n machines: MachineRegistry\n /** This host's id (`ipc.hello`). */\n hostId: string | undefined\n /** This user's settings: a share applies their `sandbox*` to what it runs (`docs/MACHINES.md` § Sandbox). */\n settings?: () => LooseSandboxSettings\n /** Every status change, for `machine:links`. */\n onChange: (status: MachineLinksStatus) => void\n appVersion?: string\n /** Connection pacing (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n pollMs?: number\n}\n\nexport interface MachineLinks {\n status: () => MachineLinksStatus\n startShare: (input: { hostId: string, name: string, roots: string[], token?: string }) => MachineLinksStatus\n stopShare: (hostId: string) => MachineLinksStatus\n setUse: (hostId: string, enabled: boolean) => MachineLinksStatus\n /** Stop everything (remote hosts turned off, or the host closes); the wanted links stay saved. */\n close: () => Promise<void>\n}\n\nfunction readJson<T>(file: string, fallback: T): T {\n try {\n return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) as T : fallback\n }\n catch {\n return fallback\n }\n}\n\nfunction readConfig(file: string): LinksConfig {\n const raw = readJson<Partial<LinksConfig>>(file, {})\n const shares = Array.isArray(raw.shares)\n ? raw.shares.filter((s): s is ShareConfig => !!s && typeof s.hostId === 'string' && typeof s.name === 'string' && Array.isArray(s.roots) && s.roots.every(r => typeof r === 'string'))\n : []\n const uses = Array.isArray(raw.uses) ? raw.uses.filter((u): u is string => typeof u === 'string') : []\n return { version: 1, shares, uses }\n}\n\n/**\n * A share's name and roots, as a client sent them: every root absolute,\n * existing, and not (by its real path) zidane's data dir, inside it, or a\n * credentials folder (`./executor`'s `shareableRoot`).\n */\nexport function checkShareInput(input: { name: string, roots: string[] }, zidaneDataDir: string): void {\n if (!isValidMachineName(input.name))\n throw new Error(`\"${input.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n if (!Array.isArray(input.roots) || input.roots.length === 0)\n throw new Error('Share at least one folder.')\n if (input.roots.length > MAX_ROOTS)\n throw new Error(`Share at most ${MAX_ROOTS} folders.`)\n for (const root of input.roots) {\n if (typeof root !== 'string' || !isAbsolute(root))\n throw new Error(`${String(root)} is not an absolute folder path.`)\n shareableRoot(root, zidaneDataDir)\n }\n}\n\nexport function startMachineLinks(options: MachineLinksOptions): MachineLinks {\n const { dataDir, machines } = options\n const configFile = join(dataDir, CONFIG_FILE)\n const statusFile = join(dataDir, STATUS_FILE)\n const lock = createShareLock(join(dataDir, LOCK_FILE))\n // Reading entries and tokens needs no probe: nothing is dialed here but the links themselves.\n const hosts = createHostRegistry({ dataDir, probe: async () => ({ ok: false, error: 'unreachable', message: 'not probed here' }) })\n const instance = `${(options.hostId ?? 'local').slice(0, 40)}-${randomBytes(4).toString('hex')}`\n const pacing = {\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n }\n\n const shares = new Map<string, { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus }>()\n const uses = new Map<string, { link?: ServerMachine, status: MachineUseStatus }>()\n let holder = false\n let closed = false\n let lastPublished = ''\n\n const ownStatus = (): MachineLinksStatus => ({ shares: [...shares.values()].map(s => s.status), uses: [...uses.values()].map(u => u.status) })\n\n /** Shares as the holder reports them (another process may run them). */\n const status = (): MachineLinksStatus => {\n const own = ownStatus()\n if (holder)\n return own\n const config = readConfig(configFile)\n const published = readJson<Partial<MachineLinksStatus>>(statusFile, {})\n const known = new Map((published.shares ?? []).map(s => [s.hostId, s]))\n return {\n shares: config.shares.map(s => known.get(s.hostId) ?? { hostId: s.hostId, name: s.name, roots: s.roots, state: 'connecting' as const, detail: 'waiting for the zidane process that shares this computer' }),\n uses: own.uses,\n }\n }\n\n const publish = (): void => {\n if (closed)\n return\n const snapshot = status()\n const text = JSON.stringify(snapshot)\n if (holder) {\n try {\n writeJsonFileAtomic(statusFile, { shares: snapshot.shares }, OWNER_ONLY)\n }\n catch {\n // Best effort: other processes show \"waiting\" until it lands.\n }\n }\n if (text === lastPublished)\n return\n lastPublished = text\n options.onChange(snapshot)\n }\n\n const entry = (hostId: string): HostEntry => {\n const found = hosts.get(hostId)\n if (!found)\n throw new Error(`No saved server \"${hostId}\": add it on the Hosts page first.`)\n return found\n }\n\n function runShare(config: ShareConfig): void {\n const status: MachineShareStatus = { hostId: config.hostId, name: config.name, roots: config.roots, state: 'connecting' }\n const share: { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus } = { config, status }\n shares.set(config.hostId, share)\n const set = (state: MachineLinkState, detail?: string): void => {\n share.status = { ...status, state, ...(detail && state !== 'connected' ? { detail } : {}) }\n publish()\n }\n try {\n const server = entry(config.hostId)\n const cred = readCredentialEntry(dataDir, machineCredentialKey(config.hostId))\n const token = cred?.kind === 'apikey' ? cred.value : undefined\n if (!token)\n throw new Error(`No machine token saved for ${server.name}.`)\n share.agent = startMachineAgent({ hostUrl: server.url, token, name: config.name, roots: config.roots, dataDir: join(dataDir, 'machine'), credentialsDataDir: dataDir, ...(options.settings ? { sandbox: options.settings() } : {}), ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onStatus: (state, detail) => set(state, detail) })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n function runUse(hostId: string): void {\n const use: { link?: ServerMachine, status: MachineUseStatus } = { status: { hostId, state: 'connecting' } }\n uses.set(hostId, use)\n const set = (state: MachineLinkState, detail?: string, machineName?: string): void => {\n use.status = { hostId, state, ...(detail && state !== 'connected' ? { detail } : {}), ...(machineName ?? use.status.machineName ? { machineName: machineName ?? use.status.machineName } : {}) }\n publish()\n }\n try {\n const server = entry(hostId)\n const token = hosts.token(hostId)\n if (!token)\n throw new Error(`No token saved for ${server.name}: add it again.`)\n use.link = startServerMachine({ machines, url: server.url, token, expectHostId: hostId, localHostId: instance, ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onState: set })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n const stopShare = async (hostId: string): Promise<void> => {\n const share = shares.get(hostId)\n shares.delete(hostId)\n await share?.agent?.stop()\n }\n\n /** Bring the running links in line with the saved config. */\n function reconcile(): void {\n if (closed)\n return\n const config = readConfig(configFile)\n holder = lock.acquire()\n if (!holder) {\n // Lost the lock (or never had it): another process runs this computer's shares, never two.\n for (const hostId of [...shares.keys()])\n void stopShare(hostId)\n }\n else {\n const wanted = new Map(config.shares.map(s => [s.hostId, s]))\n for (const [hostId, share] of shares) {\n const want = wanted.get(hostId)\n if (!want || JSON.stringify(want) !== JSON.stringify(share.config))\n void stopShare(hostId)\n }\n for (const share of config.shares) {\n if (!shares.has(share.hostId))\n runShare(share)\n }\n }\n const wantedUses = new Set(config.uses)\n for (const [hostId, use] of uses) {\n if (!wantedUses.has(hostId)) {\n use.link?.stop()\n uses.delete(hostId)\n }\n }\n for (const hostId of config.uses) {\n if (!uses.has(hostId))\n runUse(hostId)\n }\n publish()\n }\n\n const writeConfig = (mutate: (config: LinksConfig) => void): MachineLinksStatus => {\n const config = readConfig(configFile)\n mutate(config)\n writeJsonFileAtomic(configFile, config, OWNER_ONLY)\n reconcile()\n return status()\n }\n\n reconcile()\n const timer = setInterval(reconcile, options.pollMs ?? POLL_MS)\n timer.unref?.()\n\n return {\n status,\n startShare(input) {\n checkShareInput(input, dataDir)\n const server = entry(input.hostId)\n const token = input.token?.trim()\n if (token)\n writeCredentialEntry(dataDir, machineCredentialKey(input.hostId), { kind: 'apikey', value: token })\n else if (readCredentialEntry(dataDir, machineCredentialKey(input.hostId))?.kind !== 'apikey')\n throw new Error(`No machine token for ${server.name}: create one there (zidane server token create --scope machine) or let this window create it.`)\n return writeConfig((config) => {\n config.shares = [...config.shares.filter(s => s.hostId !== input.hostId), { hostId: input.hostId, name: input.name, roots: [...input.roots] }]\n })\n },\n stopShare(hostId) {\n return writeConfig((config) => {\n config.shares = config.shares.filter(s => s.hostId !== hostId)\n })\n },\n setUse(hostId, enabled) {\n if (enabled) {\n const server = entry(hostId)\n if (!hosts.token(hostId))\n throw new Error(`No token saved for ${server.name}: add it again.`)\n }\n return writeConfig((config) => {\n config.uses = enabled ? [...new Set([...config.uses, hostId])] : config.uses.filter(u => u !== hostId)\n })\n },\n async close() {\n if (closed)\n return\n closed = true\n clearInterval(timer)\n for (const use of uses.values())\n use.link?.stop()\n uses.clear()\n await Promise.all([...shares.keys()].map(stopShare))\n // Only the holder's own files: a process that lost the lock leaves the new holder's alone.\n if (lock.release())\n rmSync(statusFile, { force: true })\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"links-Bto-5dVu.js","names":[],"sources":["../src/ipc/machine/agent.ts","../src/ipc/machine/reverse.ts","../src/ipc/machine/share-lock.ts","../src/ipc/machine/links.ts"],"sourcesContent":["/**\n * The machine agent (`docs/MACHINES.md` § Machine side): dials its host with\n * a machine-scoped token, registers, and serves the host's execution\n * requests through the confined executor (`./executor.ts`) until stopped.\n * Reconnects with the hosts' connection loop (backoff; a refused token, a\n * different host at the URL, or a refused registration stop it for good).\n *\n * The CLI (`./cli.ts`, `zidane machine share`) runs it in the foreground;\n * `./links.ts` starts it from the local daemon / in-process host.\n */\nimport type { HostConnectionStatus } from '../../chat/hosts/connection'\nimport type { MachineRegisterParams, MachineRegisterResult, MachineRoot } from '../../chat/machine-protocol'\nimport type { IpcClient } from '../transports/client-core'\nimport type { MachineExecutorOptions } from './executor'\nimport { mkdirSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { writeJsonFileAtomic } from '../../atomic-write'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { isValidMachineName, MACHINE_PROTOCOL_VERSION, MachineErrorCode } from '../../chat/machine-protocol'\nimport { ZIDANE_VERSION } from '../../version'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { IpcVersionMismatchError } from '../transports/client-core'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\nimport { createMachineExecutor, shareableRoot } from './executor'\nimport { machineIdentity } from './identity'\n\nexport { machineIdentity } from './identity'\n\nexport interface MachineAgentOptions {\n /** `ws://` / `wss://` URL of the host. */\n hostUrl: string\n /** A `machine`-scoped token of that host. */\n token: string\n /** Display name, and the suffix of its environment kinds (`local@<name>`). */\n name: string\n /** Folders the host may use; absolute, existing. */\n roots: ReadonlyArray<string | MachineRoot>\n /** This machine's data dir: its id, the host it pinned, task logs. Never reachable by the host's file ops. */\n dataDir: string\n appVersion?: string\n /** Every status change (`connected`, `reconnecting`, `auth-refused`, …) and why it failed. */\n onStatus?: (status: HostConnectionStatus, detail?: string) => void\n /** Backoff bounds and heartbeat (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n terminalGraceMs?: number\n /** This machine user's `sandbox*` settings: every command the host sends runs under them (`docs/MACHINES.md` § Sandbox). */\n sandbox?: MachineExecutorOptions['sandbox']\n /** This machine user's zidane data dir: never shared (a root can't be in it, file ops never reach it), and its credential files are hidden from sandboxed commands. */\n credentialsDataDir?: string\n}\n\nexport interface MachineAgent {\n machineId: string\n status: () => HostConnectionStatus\n /** Reconnect now (after a fix on the host side). */\n retry: () => void\n stop: () => Promise<void>\n}\n\n/** A registration the host refused for good (its name taken, another protocol). */\nclass MachineRegisterError extends Error {\n constructor(message: string, readonly forGood: boolean) {\n super(message)\n this.name = 'MachineRegisterError'\n }\n}\n\nfunction normalizeRoots(roots: MachineAgentOptions['roots'], zidaneDataDir: string | undefined): MachineRoot[] {\n if (roots.length === 0)\n throw new Error('Share at least one folder (--root).')\n return roots.map((root) => {\n const entry = typeof root === 'string' ? { path: root } : root\n const real = shareableRoot(entry.path, zidaneDataDir)\n if (!statSync(real).isDirectory())\n throw new Error(`Root ${entry.path} is not a folder.`)\n return { path: real, ...(entry.label ? { label: entry.label } : {}) }\n })\n}\n\n/** The host id this machine pinned for `url` (the first host that answered there). */\nfunction pinnedHosts(dataDir: string): { get: (url: string) => string | undefined, set: (url: string, hostId: string) => void } {\n const file = join(dataDir, 'machine-hosts.json')\n const read = (): Record<string, string> => {\n try {\n return JSON.parse(readFileSync(file, 'utf8')) as Record<string, string>\n }\n catch {\n return {}\n }\n }\n return {\n get: url => read()[url],\n set: (url, hostId) => writeJsonFileAtomic(file, { ...read(), [url]: hostId }, { ensureDir: true, mode: 0o600 }),\n }\n}\n\nexport function startMachineAgent(options: MachineAgentOptions): MachineAgent {\n if (!isValidMachineName(options.name))\n throw new Error(`\"${options.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n mkdirSync(options.dataDir, { recursive: true, mode: 0o700 })\n const dataDir = realpathSync.native(options.dataDir)\n const roots = normalizeRoots(options.roots, options.credentialsDataDir)\n const machineId = machineIdentity(dataDir)\n const pins = pinnedHosts(dataDir)\n const url = options.hostUrl\n let client: IpcClient | null = null\n let status: HostConnectionStatus = 'connecting'\n\n const executor = createMachineExecutor({\n roots,\n dataDir,\n ...(options.terminalGraceMs !== undefined ? { terminalGraceMs: options.terminalGraceMs } : {}),\n ...(options.sandbox ? { sandbox: options.sandbox } : {}),\n ...(options.credentialsDataDir ? { credentialsDataDir: options.credentialsDataDir } : {}),\n notify: (method, params) => {\n if (!client)\n return false\n try {\n (client.notify as unknown as (m: string, p: unknown) => void)(method, params)\n return true\n }\n catch {\n return false\n }\n },\n })\n\n const register: MachineRegisterParams = {\n machineId,\n name: options.name,\n roots,\n capabilities: { shell: true, terminals: typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined', background: true, worktrees: true, stream: true, sandboxed: executor.sandbox.on },\n version: options.appVersion ?? ZIDANE_VERSION,\n protocolVersion: MACHINE_PROTOCOL_VERSION,\n }\n\n const loop = keepHostConnected({\n minDelayMs: options.minDelayMs ?? 1000,\n maxDelayMs: options.maxDelayMs ?? 30_000,\n async connect({ signal, onClose }) {\n const expectHostId = pins.get(url)\n const connected = await connectWsClient({\n url,\n token: options.token,\n signal,\n onClose,\n appVersion: register.version,\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n ...(expectHostId ? { expectHostId } : {}),\n serve: {\n request: (method, params) => executor.handle(method, params),\n notification: (method, params) => void executor.handle(method, params).catch(() => undefined),\n },\n })\n try {\n await (connected.request as unknown as (m: string, p: unknown) => Promise<MachineRegisterResult>)('machine.register', register)\n }\n catch (err) {\n connected.close()\n const code = err instanceof JsonRpcRemoteError ? err.code : undefined\n throw new MachineRegisterError(`${displayHostUrl(url)} refused this machine: ${(err as Error).message}`, code === MachineErrorCode.NameTaken || code === MachineErrorCode.VersionSkew || code === MachineErrorCode.IdBound)\n }\n if (!expectHostId && connected.hello.hostId)\n pins.set(url, connected.hello.hostId)\n return connected\n },\n classify: (err) => {\n if (err instanceof HostIdentityError)\n return 'identity'\n if (err instanceof HostAuthError || (err instanceof MachineRegisterError && err.forGood))\n return 'auth'\n return err instanceof IpcVersionMismatchError ? 'protocol' : 'retry'\n },\n update: (patch) => {\n if (patch.client !== undefined)\n client = patch.client\n if (patch.status) {\n status = patch.status\n options.onStatus?.(patch.status, patch.error)\n }\n },\n onConnected: () => executor.linkUp(),\n onDisconnected: () => executor.linkLost(),\n })\n\n return {\n machineId,\n status: () => status,\n retry: () => loop.retry(),\n async stop() {\n loop.stop()\n await executor.close()\n },\n }\n}\n","/**\n * A saved server used as a machine of this local host (`local@<server>`,\n * `docs/MACHINES.md` § Reverse direction). A local host has no listener, so\n * it dials the server as a client (its saved client token), asks it to lend\n * itself (`machine.attach`), and registers it in its own machine registry\n * with a connection that sends each host→machine request as `machine.call`.\n * The server's notifications come back as `machine:notification` signals.\n * Reconnects with the hosts' connection loop; a refused token, another host\n * at the URL, or a server that does not lend itself stop it for good.\n */\nimport type { AttachedMachine, MachineConnection, MachineRegistry } from '../../chat/host/machines'\nimport type { MachineLinkState } from '../../chat/machine-protocol'\nimport type { JsonValue } from '../../types'\nimport type { IpcClient } from '../transports/client-core'\nimport { JsonRpcConnectionClosedError, JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { MachineLinkLostError } from '../../chat/host/machines'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { MachineErrorCode } from '../../chat/machine-protocol'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\n\nexport interface ServerMachineOptions {\n machines: MachineRegistry\n url: string\n /** The saved server's client token. */\n token: string\n /** The saved server's host id: another host at the URL is refused. */\n expectHostId: string\n /** This host's id (the server keys its executor by it, so tasks survive a reconnect). */\n localHostId: string\n appVersion?: string\n onState: (state: MachineLinkState, detail?: string, machineName?: string) => void\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n}\n\nexport interface ServerMachine {\n retry: () => void\n stop: () => void\n}\n\n/** The server refused to lend itself (`allowAsMachine` off, a name taken here): for good. A busy server is retried. */\nclass AttachRefusedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AttachRefusedError'\n }\n}\n\nfunction connectionOver(client: IpcClient): MachineConnection {\n return {\n async request(method, params) {\n try {\n return await client.request('machine.call', { method, params: (params ?? {}) as JsonValue })\n }\n catch (err) {\n if (err instanceof JsonRpcConnectionClosedError)\n throw new MachineLinkLostError()\n throw err instanceof JsonRpcRemoteError ? new Error(err.message) : err\n }\n },\n notify: (method, params) => client.notify('machine.call', { method, params: (params ?? {}) as JsonValue }),\n close: () => client.close(),\n }\n}\n\nexport function startServerMachine(options: ServerMachineOptions): ServerMachine {\n let attached: AttachedMachine | undefined\n const where = displayHostUrl(options.url)\n\n const detach = (): void => {\n attached?.closed()\n attached = undefined\n }\n\n const loop = keepHostConnected({\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n async connect({ signal, onClose }) {\n const client = await connectWsClient({\n url: options.url,\n token: options.token,\n expectHostId: options.expectHostId,\n signal,\n onClose,\n ...(options.appVersion ? { appVersion: options.appVersion } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n })\n // Subscribed before attaching: the server re-sends queued task exits while it answers `machine.attach`.\n const early: Array<{ method: string, params: unknown }> = []\n let current: AttachedMachine | undefined\n client.onSignal((s) => {\n if (s.kind !== 'machine:notification')\n return\n if (current)\n current.notification(s.method, s.params)\n else if (early.length < 1024)\n early.push({ method: s.method, params: s.params })\n })\n try {\n const params = await client.request('machine.attach', { hostId: options.localHostId })\n detach()\n current = options.machines.attach(params, connectionOver(client))\n attached = current\n for (const { method, params: p } of early.splice(0))\n current.notification(method, p)\n options.onState('connected', undefined, params.name)\n }\n catch (err) {\n client.close()\n // No room there now (a capacity limit) or the link dropped: the loop retries with backoff.\n if (err instanceof JsonRpcConnectionClosedError || (err instanceof JsonRpcRemoteError && err.code === MachineErrorCode.Busy))\n throw new Error(`${where} can't lend itself right now: ${(err as Error).message}`)\n throw new AttachRefusedError(`${where} refused to be a machine: ${(err as Error).message}`)\n }\n return client\n },\n classify: err => (err instanceof HostIdentityError ? 'identity' : err instanceof HostAuthError || err instanceof AttachRefusedError ? 'auth' : 'retry'),\n update: (patch) => {\n if (!patch.status || patch.status === 'connected')\n return\n options.onState(patch.status === 'auth-refused' && patch.error?.includes('refused to be a machine') ? 'refused' : patch.status, patch.error)\n },\n onDisconnected: detach,\n })\n\n return {\n retry: () => loop.retry(),\n stop() {\n loop.stop()\n detach()\n },\n }\n}\n","/**\n * `machine-links.lock`: which process runs this computer's shares (one\n * machine id, one connection; two processes sharing it would keep replacing\n * each other's). Exclusive by construction, not by a read-then-write:\n *\n * - taking a free lock is an exclusive create (`wx`): one contender wins;\n * - the record names its holder (`pid`) and a per-process `nonce`; the\n * holder touches the file on every check, so a holder is stale when its\n * pid is gone OR the file went untouched for {@link STALE_MS} (a reused\n * pid never touches it);\n * - a stale lock is moved aside (an atomic rename to a name of our own),\n * checked to be the very record judged stale, then the exclusive create\n * runs again; a live lock moved aside by mistake is put back without\n * clobbering (`link`, which fails if the name is taken);\n * - a holder re-reads the record on every check: another nonce there means\n * it lost the lock, and the caller stops its shares;\n * - release removes the file only when it still carries this nonce.\n */\nimport { randomBytes } from 'node:crypto'\nimport { closeSync, linkSync, openSync, readFileSync, renameSync, rmSync, statSync, utimesSync, writeSync } from 'node:fs'\nimport process from 'node:process'\n\n/** A holder that has not touched its lock for this long is gone (its pid may be reused). */\nexport const SHARE_LOCK_STALE_MS = 30_000\n\ninterface LockRecord {\n pid: number\n nonce: string\n}\n\nexport interface ShareLock {\n /** Hold the lock (taking it when free or stale); `false` when another live process holds it. */\n acquire: () => boolean\n /** Whether this process held it at the last {@link acquire}. */\n held: () => boolean\n /** Remove the lock when this process still holds it; whether it did. */\n release: () => boolean\n}\n\nexport interface ShareLockOptions {\n /** Test seams. */\n pid?: number\n alive?: (pid: number) => boolean\n now?: () => number\n staleMs?: number\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n }\n catch (err) {\n return (err as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\nfunction readRecord(file: string): { record?: LockRecord, mtimeMs: number } | undefined {\n try {\n const mtimeMs = statSync(file).mtimeMs\n const raw = JSON.parse(readFileSync(file, 'utf8')) as Partial<LockRecord>\n return { mtimeMs, ...(typeof raw.pid === 'number' && typeof raw.nonce === 'string' ? { record: { pid: raw.pid, nonce: raw.nonce } } : {}) }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT')\n return undefined\n // Unreadable or half-written: judged by its age alone.\n try {\n return { mtimeMs: statSync(file).mtimeMs }\n }\n catch {\n return undefined\n }\n }\n}\n\nexport function createShareLock(file: string, options: ShareLockOptions = {}): ShareLock {\n const pid = options.pid ?? process.pid\n const alive = options.alive ?? processAlive\n const now = options.now ?? Date.now\n const staleMs = options.staleMs ?? SHARE_LOCK_STALE_MS\n const nonce = randomBytes(12).toString('hex')\n let holding = false\n\n const create = (): boolean => {\n let fd: number\n try {\n fd = openSync(file, 'wx', 0o600)\n }\n catch {\n return false\n }\n try {\n writeSync(fd, JSON.stringify({ pid, nonce }))\n }\n finally {\n closeSync(fd)\n }\n return true\n }\n\n const ours = (): boolean => readRecord(file)?.record?.nonce === nonce\n\n const stale = (found: { record?: LockRecord, mtimeMs: number }): boolean =>\n now() - found.mtimeMs > staleMs || (found.record !== undefined && !alive(found.record.pid))\n\n /** Move a stale lock aside; `true` when the record moved is the one judged stale. */\n const evict = (judged: { record?: LockRecord, mtimeMs: number }): boolean => {\n const aside = `${file}.${nonce}.stale`\n try {\n renameSync(file, aside)\n }\n catch {\n return false\n }\n const moved = readRecord(aside)\n const same = moved?.record?.nonce === judged.record?.nonce && moved?.mtimeMs === judged.mtimeMs\n if (!same) {\n // A live lock taken meanwhile: put it back, never over a newer one.\n try {\n linkSync(aside, file)\n }\n catch {\n // Someone holds the name again; that holder's own check settles it.\n }\n }\n rmSync(aside, { force: true })\n return same\n }\n\n return {\n acquire() {\n if (holding) {\n if (ours()) {\n try {\n const at = new Date(now())\n utimesSync(file, at, at)\n }\n catch {\n // The touch is best effort; the record still names this process.\n }\n return true\n }\n holding = false\n }\n if (create()) {\n holding = true\n return true\n }\n const found = readRecord(file)\n if (found && !stale(found))\n return false\n if (found && !evict(found))\n return false\n holding = create()\n return holding\n },\n held: () => holding,\n release() {\n const mine = holding && ours()\n if (mine)\n rmSync(file, { force: true })\n holding = false\n return mine\n },\n }\n}\n","/**\n * A local host's machine links (`docs/MACHINES.md` § Client UI), loaded only\n * behind remote hosts:\n *\n * - **Shares**: this computer lent to a saved server (a machine agent in\n * this process, with the machine token stored under `machine:<hostId>`).\n * One process runs them for the whole computer: the holder of\n * `machine-links.lock` (the daemon, or the first window's in-process\n * host; exclusive, `./share-lock.ts`). Two processes sharing one computer\n * under one machine id would keep replacing each other's connection, so a\n * process that finds it lost the lock stops its shares at once.\n * - **Uses**: a saved server lent to THIS host (`local@<server>`), over its\n * own client connection. Per host process: each host has its own machine\n * registry, so each attaches under its own instance id.\n *\n * The wanted links live in `<dataDir>/machine-links.json` (any process writes\n * it); every process re-reads it every {@link POLL_MS}, the holder applies the\n * shares and publishes their state in `machine-links-status.json`. Tokens\n * are never in either file.\n */\nimport type { MachineRegistry } from '../../chat/host/machines'\nimport type { HostEntry } from '../../chat/hosts/types'\nimport type { MachineLinksStatus, MachineLinkState, MachineShareStatus, MachineUseStatus } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { MachineAgent } from './agent'\nimport type { ServerMachine } from './reverse'\nimport { randomBytes } from 'node:crypto'\nimport { existsSync, readFileSync, rmSync } from 'node:fs'\nimport { isAbsolute, join } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { readCredentialEntry, writeCredentialEntry } from '../../chat/credentials'\nimport { createHostRegistry } from '../../chat/hosts'\nimport { isValidMachineName, machineCredentialKey } from '../../chat/machine-protocol'\nimport { startMachineAgent } from './agent'\nimport { shareableRoot } from './executor'\nimport { startServerMachine } from './reverse'\nimport { createShareLock } from './share-lock'\n\nconst POLL_MS = 2000\nconst CONFIG_FILE = 'machine-links.json'\nconst STATUS_FILE = 'machine-links-status.json'\nconst LOCK_FILE = 'machine-links.lock'\nconst MAX_ROOTS = 32\n\ninterface ShareConfig {\n hostId: string\n name: string\n roots: string[]\n}\n\ninterface LinksConfig {\n version: 1\n shares: ShareConfig[]\n uses: string[]\n}\n\nexport interface MachineLinksOptions {\n /** The host's data dir: saved hosts, credentials, these files. */\n dataDir: string\n machines: MachineRegistry\n /** This host's id (`ipc.hello`). */\n hostId: string | undefined\n /** This user's settings: a share applies their `sandbox*` to what it runs (`docs/MACHINES.md` § Sandbox). */\n settings?: () => LooseSandboxSettings\n /** Every status change, for `machine:links`. */\n onChange: (status: MachineLinksStatus) => void\n appVersion?: string\n /** Connection pacing (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n pollMs?: number\n}\n\nexport interface MachineLinks {\n status: () => MachineLinksStatus\n startShare: (input: { hostId: string, name: string, roots: string[], token?: string }) => MachineLinksStatus\n stopShare: (hostId: string) => MachineLinksStatus\n setUse: (hostId: string, enabled: boolean) => MachineLinksStatus\n /** Stop everything (remote hosts turned off, or the host closes); the wanted links stay saved. */\n close: () => Promise<void>\n}\n\nfunction readJson<T>(file: string, fallback: T): T {\n try {\n return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) as T : fallback\n }\n catch {\n return fallback\n }\n}\n\nfunction readConfig(file: string): LinksConfig {\n const raw = readJson<Partial<LinksConfig>>(file, {})\n const shares = Array.isArray(raw.shares)\n ? raw.shares.filter((s): s is ShareConfig => !!s && typeof s.hostId === 'string' && typeof s.name === 'string' && Array.isArray(s.roots) && s.roots.every(r => typeof r === 'string'))\n : []\n const uses = Array.isArray(raw.uses) ? raw.uses.filter((u): u is string => typeof u === 'string') : []\n return { version: 1, shares, uses }\n}\n\n/**\n * A share's name and roots, as a client sent them: every root absolute,\n * existing, and not (by its real path) zidane's data dir, inside it, or a\n * credentials folder (`./executor`'s `shareableRoot`).\n */\nexport function checkShareInput(input: { name: string, roots: string[] }, zidaneDataDir: string): void {\n if (!isValidMachineName(input.name))\n throw new Error(`\"${input.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n if (!Array.isArray(input.roots) || input.roots.length === 0)\n throw new Error('Share at least one folder.')\n if (input.roots.length > MAX_ROOTS)\n throw new Error(`Share at most ${MAX_ROOTS} folders.`)\n for (const root of input.roots) {\n if (typeof root !== 'string' || !isAbsolute(root))\n throw new Error(`${String(root)} is not an absolute folder path.`)\n shareableRoot(root, zidaneDataDir)\n }\n}\n\nexport function startMachineLinks(options: MachineLinksOptions): MachineLinks {\n const { dataDir, machines } = options\n const configFile = join(dataDir, CONFIG_FILE)\n const statusFile = join(dataDir, STATUS_FILE)\n const lock = createShareLock(join(dataDir, LOCK_FILE))\n // Reading entries and tokens needs no probe: nothing is dialed here but the links themselves.\n const hosts = createHostRegistry({ dataDir, probe: async () => ({ ok: false, error: 'unreachable', message: 'not probed here' }) })\n const instance = `${(options.hostId ?? 'local').slice(0, 40)}-${randomBytes(4).toString('hex')}`\n const pacing = {\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n }\n\n const shares = new Map<string, { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus }>()\n const uses = new Map<string, { link?: ServerMachine, status: MachineUseStatus }>()\n let holder = false\n let closed = false\n let lastPublished = ''\n\n const ownStatus = (): MachineLinksStatus => ({ shares: [...shares.values()].map(s => s.status), uses: [...uses.values()].map(u => u.status) })\n\n /** Shares as the holder reports them (another process may run them). */\n const status = (): MachineLinksStatus => {\n const own = ownStatus()\n if (holder)\n return own\n const config = readConfig(configFile)\n const published = readJson<Partial<MachineLinksStatus>>(statusFile, {})\n const known = new Map((published.shares ?? []).map(s => [s.hostId, s]))\n return {\n shares: config.shares.map(s => known.get(s.hostId) ?? { hostId: s.hostId, name: s.name, roots: s.roots, state: 'connecting' as const, detail: 'waiting for the zidane process that shares this computer' }),\n uses: own.uses,\n }\n }\n\n const publish = (): void => {\n if (closed)\n return\n const snapshot = status()\n const text = JSON.stringify(snapshot)\n if (holder) {\n try {\n writeJsonFileAtomic(statusFile, { shares: snapshot.shares }, OWNER_ONLY)\n }\n catch {\n // Best effort: other processes show \"waiting\" until it lands.\n }\n }\n if (text === lastPublished)\n return\n lastPublished = text\n options.onChange(snapshot)\n }\n\n const entry = (hostId: string): HostEntry => {\n const found = hosts.get(hostId)\n if (!found)\n throw new Error(`No saved server \"${hostId}\": add it on the Hosts page first.`)\n return found\n }\n\n function runShare(config: ShareConfig): void {\n const status: MachineShareStatus = { hostId: config.hostId, name: config.name, roots: config.roots, state: 'connecting' }\n const share: { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus } = { config, status }\n shares.set(config.hostId, share)\n const set = (state: MachineLinkState, detail?: string): void => {\n share.status = { ...status, state, ...(detail && state !== 'connected' ? { detail } : {}) }\n publish()\n }\n try {\n const server = entry(config.hostId)\n const cred = readCredentialEntry(dataDir, machineCredentialKey(config.hostId))\n const token = cred?.kind === 'apikey' ? cred.value : undefined\n if (!token)\n throw new Error(`No machine token saved for ${server.name}.`)\n share.agent = startMachineAgent({ hostUrl: server.url, token, name: config.name, roots: config.roots, dataDir: join(dataDir, 'machine'), credentialsDataDir: dataDir, ...(options.settings ? { sandbox: options.settings() } : {}), ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onStatus: (state, detail) => set(state, detail) })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n function runUse(hostId: string): void {\n const use: { link?: ServerMachine, status: MachineUseStatus } = { status: { hostId, state: 'connecting' } }\n uses.set(hostId, use)\n const set = (state: MachineLinkState, detail?: string, machineName?: string): void => {\n use.status = { hostId, state, ...(detail && state !== 'connected' ? { detail } : {}), ...(machineName ?? use.status.machineName ? { machineName: machineName ?? use.status.machineName } : {}) }\n publish()\n }\n try {\n const server = entry(hostId)\n const token = hosts.token(hostId)\n if (!token)\n throw new Error(`No token saved for ${server.name}: add it again.`)\n use.link = startServerMachine({ machines, url: server.url, token, expectHostId: hostId, localHostId: instance, ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onState: set })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n const stopShare = async (hostId: string): Promise<void> => {\n const share = shares.get(hostId)\n shares.delete(hostId)\n await share?.agent?.stop()\n }\n\n /** Bring the running links in line with the saved config. */\n function reconcile(): void {\n if (closed)\n return\n const config = readConfig(configFile)\n holder = lock.acquire()\n if (!holder) {\n // Lost the lock (or never had it): another process runs this computer's shares, never two.\n for (const hostId of [...shares.keys()])\n void stopShare(hostId)\n }\n else {\n const wanted = new Map(config.shares.map(s => [s.hostId, s]))\n for (const [hostId, share] of shares) {\n const want = wanted.get(hostId)\n if (!want || JSON.stringify(want) !== JSON.stringify(share.config))\n void stopShare(hostId)\n }\n for (const share of config.shares) {\n if (!shares.has(share.hostId))\n runShare(share)\n }\n }\n const wantedUses = new Set(config.uses)\n for (const [hostId, use] of uses) {\n if (!wantedUses.has(hostId)) {\n use.link?.stop()\n uses.delete(hostId)\n }\n }\n for (const hostId of config.uses) {\n if (!uses.has(hostId))\n runUse(hostId)\n }\n publish()\n }\n\n const writeConfig = (mutate: (config: LinksConfig) => void): MachineLinksStatus => {\n const config = readConfig(configFile)\n mutate(config)\n writeJsonFileAtomic(configFile, config, OWNER_ONLY)\n reconcile()\n return status()\n }\n\n reconcile()\n const timer = setInterval(reconcile, options.pollMs ?? POLL_MS)\n timer.unref?.()\n\n return {\n status,\n startShare(input) {\n checkShareInput(input, dataDir)\n const server = entry(input.hostId)\n const token = input.token?.trim()\n if (token)\n writeCredentialEntry(dataDir, machineCredentialKey(input.hostId), { kind: 'apikey', value: token })\n else if (readCredentialEntry(dataDir, machineCredentialKey(input.hostId))?.kind !== 'apikey')\n throw new Error(`No machine token for ${server.name}: create one there (zidane server token create --scope machine) or let this window create it.`)\n return writeConfig((config) => {\n config.shares = [...config.shares.filter(s => s.hostId !== input.hostId), { hostId: input.hostId, name: input.name, roots: [...input.roots] }]\n })\n },\n stopShare(hostId) {\n return writeConfig((config) => {\n config.shares = config.shares.filter(s => s.hostId !== hostId)\n })\n },\n setUse(hostId, enabled) {\n if (enabled) {\n const server = entry(hostId)\n if (!hosts.token(hostId))\n throw new Error(`No token saved for ${server.name}: add it again.`)\n }\n return writeConfig((config) => {\n config.uses = enabled ? [...new Set([...config.uses, hostId])] : config.uses.filter(u => u !== hostId)\n })\n },\n async close() {\n if (closed)\n return\n closed = true\n clearInterval(timer)\n for (const use of uses.values())\n use.link?.stop()\n uses.clear()\n await Promise.all([...shares.keys()].map(stopShare))\n // Only the holder's own files: a process that lost the lock leaves the new holder's alone.\n if (lock.release())\n rmSync(statusFile, { force: true })\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -32,7 +32,7 @@ import { t as projectUserPaths } from "./project-user-paths-DWqZyUgb.js";
|
|
|
32
32
|
import { F as createGithubClient, L as githubClient, N as clockTime, P as configureGithubClient, n as EMPTY_EXTENSION_REGISTRY } from "./row-fields-F0tyvIgg.js";
|
|
33
33
|
import { r as artifacts_default } from "./presets-C4hkykN-.js";
|
|
34
34
|
import { _ as readSkillEditMarker, a as sectionDigest, b as withZidaneSkillEditSkill, c as EXTENSION_EDIT_METADATA_KEY, d as ZIDANE_SKILL_EDIT_SKILL_NAME, h as extensionDirForCwd, i as latestSystemSnapshot, l as SKILL_EDIT_METADATA_KEY, n as announcedDigest, o as sectionDigests, r as catalogChangeNotes, s as systemSnapshotTurn, u as ZIDANE_EXTENSION_SKILL_NAME, y as withZidaneExtensionSkill } from "./system-freeze-Um9ZJiPo.js";
|
|
35
|
-
import { F as readKeybindingsRaw, I as resolveExtensionKeybindings, M as mergeKeybindings, m as filterRegistryPlugins } from "./extensions-
|
|
35
|
+
import { F as readKeybindingsRaw, I as resolveExtensionKeybindings, M as mergeKeybindings, m as filterRegistryPlugins } from "./extensions-BJof-2mi.js";
|
|
36
36
|
import { r as createLogger, t as consoleSink } from "./logger-RZVCk9Ow.js";
|
|
37
37
|
import { t as resolveStorageDirs } from "./xdg-CJS70jqe.js";
|
|
38
38
|
import { n as defaultPluginDataRoot, r as loadAgentPlugin } from "./plugins-DXef5Hbf.js";
|
|
@@ -16553,4 +16553,4 @@ async function runOAuthLogin(descriptor, options) {
|
|
|
16553
16553
|
//#endregion
|
|
16554
16554
|
export { createAutomaticInteractionResponse as $, testDecisionModel as $t, environmentCredentialsPath as A, runEndNotice as At, userPromptCount as B, parsePluginScanPathEnv as Bt, defaultEnvironmentKind as C, localEnvironmentProvider as Ct, resolveProviderConfig as D, teardownWorktree as Dt, readEnvironmentSettings as E, prepareWorktree as Et, TITLE_CHECK_KEY as F, folderlessCwd as Ft, readPinnedSkills as G, saveMcpToolsCache as Gt, normalizeLaunchOverrides as H, loadMcpToolsCache as Ht, TITLE_SOURCE_KEY as I, resolveSessionCwd as It, ASK_USER_TOOL as J, imageModelSources as Jt, isStaleRunMarker as K, subscribeMcpToolsCache as Kt, autoTitleAction as L, scopeCwd as Lt, createWorkspaceConfinement as M, readFileSafe as Mt, isInside as N, resolveCwdPath as Nt, createFileEnvironmentSecrets as O, readRemoteSandboxRef as Ot, TITLE_CHECKED_KEY as P, serializePreview as Pt, buildResumedToolResultsTurn as Q, resolveDecisionsOption as Qt, describeTitleStatus as R, buildPluginContributions as Rt, applyEnvironmentSettingsChange as S, builtinEnvironmentProviders as St, isEnvironmentEnabled as T, createWorktreeEnvironmentProvider as Tt, PINNED_SKILLS_META_KEY as U, mcpToolsCachePath as Ut, launchOverridesFrom as V, clearMcpToolsCache as Vt, pinnedSkillsValue as W, refreshMcpToolsCatalog as Wt, HOST_INTERACTION_ID_PREFIX as X, listDecisionModels as Xt, AUTOMATIC_INTERACTION_INSTRUCTION as Y, listImageModels as Yt, PRESENT_PLAN_TOOL as Z, parseDecisionModel as Zt, sandboxUnreadableDirs as _, discoverAgentsMd as _t, tryOpenBrowser as a, serializeInteractionResponse as at, patchMcpCredential as b, machineDiscoveryCwd as bt, mcpsWritePath as c, defaultSkillScanPaths as ct, createExtensionMcpHost as d, applyThinkingBindingSetting as dt, EditOutcomeLedger as en, createInteractionTools as et, resolveConfig as f, chatAutoCompactBehavior as ft, resolveSandboxForRoots as g, installProviderDiagnosticHook as gt, createInteractionHub as h, createChatTurnsReadTool as ht, supportsOAuth as i, pendingInteractionsFromTurns as it, createSessionExecutionCache as j, extractEditPayloadForGate as jt, createMemoryEnvironmentSecrets as k, MachineLinkLostError as kt, removeMcpServer as l, discoverProjectSkills as lt, createChatHost as m, chatReferenceTokensForPrompt as mt, pickOAuthSelectOption as n, createApprovalHub as nn, isModelInteraction as nt, tryRevealPath as o, buildSkillsConfig as ot, resolveStoragePaths as p, chatWindowBehavior as pt, toTodosSnapshot as q, imageGenerationTools as qt, runOAuthLogin as r, createMemoryApprovalsStore as rn, makeRequestInteraction as rt, testModel as s, createSkillNameProbe as st, oauthUsesManualCodePaste as t, runCompaction as tn, isInteractionTool as tt, upsertMcpServer as u, createBuiltinCommands as ut, createFileMcpCredentialStore as v, renderAgentsMdBlock as vt, describeEnvironments as w, WORKTREE_ENVIRONMENT_KIND as wt, provisionSessionEnvironment as x, insideDeclaredRoots as xt, mcpCredentialsPath as y, createProviderBuilder as yt, isTitleStale as z, discoverProjectPlugins as zt };
|
|
16555
16555
|
|
|
16556
|
-
//# sourceMappingURL=oauth-
|
|
16556
|
+
//# sourceMappingURL=oauth-BwPiX0hL.js.map
|