apex-code 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -1
- package/README.md +7 -8
- package/dist/cli/agent-lifecycle.d.ts +24 -0
- package/dist/cli/agent-lifecycle.d.ts.map +1 -0
- package/dist/cli/agent-lifecycle.js +126 -0
- package/dist/cli/agent-lifecycle.js.map +1 -0
- package/dist/cli/args.d.ts +13 -12
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +80 -30
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -130
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -8
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +160 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +265 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/delegation/agents.d.ts.map +1 -1
- package/dist/core/delegation/agents.js +2 -1
- package/dist/core/delegation/agents.js.map +1 -1
- package/dist/core/delegation/runtime.d.ts +674 -1
- package/dist/core/delegation/runtime.d.ts.map +1 -1
- package/dist/core/delegation/runtime.js +1338 -66
- package/dist/core/delegation/runtime.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +3 -4
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/source-runtime.d.ts +4 -5
- package/dist/core/extensions/source-runtime.d.ts.map +1 -1
- package/dist/core/extensions/source-runtime.js +4 -5
- package/dist/core/extensions/source-runtime.js.map +1 -1
- package/dist/core/formatter-lifecycle.d.ts +2 -1
- package/dist/core/formatter-lifecycle.d.ts.map +1 -1
- package/dist/core/formatter-lifecycle.js +2 -1
- package/dist/core/formatter-lifecycle.js.map +1 -1
- package/dist/core/hooks/types.d.ts +2 -3
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js +2 -3
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/http-idle-timeout.d.ts +3 -5
- package/dist/core/http-idle-timeout.d.ts.map +1 -1
- package/dist/core/http-idle-timeout.js +3 -5
- package/dist/core/http-idle-timeout.js.map +1 -1
- package/dist/core/mcp/config.d.ts +18 -1
- package/dist/core/mcp/config.d.ts.map +1 -1
- package/dist/core/mcp/config.js +24 -7
- package/dist/core/mcp/config.js.map +1 -1
- package/dist/core/mcp/connector.d.ts +2 -3
- package/dist/core/mcp/connector.d.ts.map +1 -1
- package/dist/core/mcp/connector.js.map +1 -1
- package/dist/core/mcp/oauth/authorize.d.ts +2 -0
- package/dist/core/mcp/oauth/authorize.d.ts.map +1 -1
- package/dist/core/mcp/oauth/authorize.js +5 -2
- package/dist/core/mcp/oauth/authorize.js.map +1 -1
- package/dist/core/mcp/oauth/mcp-token.d.ts +4 -6
- package/dist/core/mcp/oauth/mcp-token.d.ts.map +1 -1
- package/dist/core/mcp/oauth/mcp-token.js +5 -7
- package/dist/core/mcp/oauth/mcp-token.js.map +1 -1
- package/dist/core/mcp/runtime.d.ts +1 -0
- package/dist/core/mcp/runtime.d.ts.map +1 -1
- package/dist/core/mcp/runtime.js +2 -1
- package/dist/core/mcp/runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +0 -15
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions/store.d.ts +6 -11
- package/dist/core/permissions/store.d.ts.map +1 -1
- package/dist/core/permissions/store.js +23 -51
- package/dist/core/permissions/store.js.map +1 -1
- package/dist/core/project-resources.d.ts +62 -0
- package/dist/core/project-resources.d.ts.map +1 -0
- package/dist/core/project-resources.js +42 -0
- package/dist/core/project-resources.js.map +1 -0
- package/dist/core/sdk.d.ts +62 -12
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +313 -44
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-share.d.ts +6 -8
- package/dist/core/session-share.d.ts.map +1 -1
- package/dist/core/session-share.js +9 -12
- package/dist/core/session-share.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -21
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -12
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +0 -47
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +8 -0
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +33 -3
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/web-fetch.d.ts.map +1 -1
- package/dist/core/tools/web-fetch.js +4 -8
- package/dist/core/tools/web-fetch.js.map +1 -1
- package/dist/core/tools/web-search-exa.d.ts +3 -6
- package/dist/core/tools/web-search-exa.d.ts.map +1 -1
- package/dist/core/tools/web-search-exa.js +5 -8
- package/dist/core/tools/web-search-exa.js.map +1 -1
- package/dist/core/trust-manager.d.ts +6 -5
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +42 -19
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/web-search-provider.d.ts +0 -10
- package/dist/core/web-search-provider.d.ts.map +1 -1
- package/dist/core/web-search-provider.js +2 -16
- package/dist/core/web-search-provider.js.map +1 -1
- package/dist/core/workspace/git-observer.d.ts +16 -0
- package/dist/core/workspace/git-observer.d.ts.map +1 -1
- package/dist/core/workspace/git-observer.js +8 -1
- package/dist/core/workspace/git-observer.js.map +1 -1
- package/dist/core/workspace/git-worktree-owner.d.ts +89 -0
- package/dist/core/workspace/git-worktree-owner.d.ts.map +1 -0
- package/dist/core/workspace/git-worktree-owner.js +240 -0
- package/dist/core/workspace/git-worktree-owner.js.map +1 -0
- package/dist/main.d.ts +0 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +22 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/server.d.ts +43 -1
- package/dist/modes/acp/server.d.ts.map +1 -1
- package/dist/modes/acp/server.js +78 -0
- package/dist/modes/acp/server.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +0 -29
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +38 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +110 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +0 -25
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +3 -52
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +0 -2
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +0 -2
- package/dist/utils/version-check.js.map +1 -1
- package/docs/settings.md +2 -7
- package/npm-shrinkwrap.json +5 -5
- package/package.json +2 -2
- package/dist/core/sandbox/bwrap-arguments.d.ts +0 -41
- package/dist/core/sandbox/bwrap-arguments.d.ts.map +0 -1
- package/dist/core/sandbox/bwrap-arguments.js +0 -136
- package/dist/core/sandbox/bwrap-arguments.js.map +0 -1
- package/dist/core/sandbox/child-entry.d.ts +0 -2
- package/dist/core/sandbox/child-entry.d.ts.map +0 -1
- package/dist/core/sandbox/child-entry.js +0 -24
- package/dist/core/sandbox/child-entry.js.map +0 -1
- package/dist/core/sandbox/cli-launch.d.ts +0 -162
- package/dist/core/sandbox/cli-launch.d.ts.map +0 -1
- package/dist/core/sandbox/cli-launch.js +0 -366
- package/dist/core/sandbox/cli-launch.js.map +0 -1
- package/dist/core/sandbox/cli-supervisor.d.ts +0 -31
- package/dist/core/sandbox/cli-supervisor.d.ts.map +0 -1
- package/dist/core/sandbox/cli-supervisor.js +0 -147
- package/dist/core/sandbox/cli-supervisor.js.map +0 -1
- package/dist/core/sandbox/default-hosts.d.ts +0 -28
- package/dist/core/sandbox/default-hosts.d.ts.map +0 -1
- package/dist/core/sandbox/default-hosts.js +0 -69
- package/dist/core/sandbox/default-hosts.js.map +0 -1
- package/dist/core/sandbox/full-access.d.ts +0 -28
- package/dist/core/sandbox/full-access.d.ts.map +0 -1
- package/dist/core/sandbox/full-access.js +0 -63
- package/dist/core/sandbox/full-access.js.map +0 -1
- package/dist/core/sandbox/git-identity.d.ts +0 -57
- package/dist/core/sandbox/git-identity.d.ts.map +0 -1
- package/dist/core/sandbox/git-identity.js +0 -78
- package/dist/core/sandbox/git-identity.js.map +0 -1
- package/dist/core/sandbox/host-approval.d.ts +0 -42
- package/dist/core/sandbox/host-approval.d.ts.map +0 -1
- package/dist/core/sandbox/host-approval.js +0 -99
- package/dist/core/sandbox/host-approval.js.map +0 -1
- package/dist/core/sandbox/linux-backend.d.ts +0 -48
- package/dist/core/sandbox/linux-backend.d.ts.map +0 -1
- package/dist/core/sandbox/linux-backend.js +0 -328
- package/dist/core/sandbox/linux-backend.js.map +0 -1
- package/dist/core/sandbox/macos-backend.d.ts +0 -30
- package/dist/core/sandbox/macos-backend.d.ts.map +0 -1
- package/dist/core/sandbox/macos-backend.js +0 -385
- package/dist/core/sandbox/macos-backend.js.map +0 -1
- package/dist/core/sandbox/network-proxy.d.ts +0 -38
- package/dist/core/sandbox/network-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/network-proxy.js +0 -153
- package/dist/core/sandbox/network-proxy.js.map +0 -1
- package/dist/core/sandbox/network-refusal.d.ts +0 -24
- package/dist/core/sandbox/network-refusal.d.ts.map +0 -1
- package/dist/core/sandbox/network-refusal.js +0 -72
- package/dist/core/sandbox/network-refusal.js.map +0 -1
- package/dist/core/sandbox/policy.d.ts +0 -40
- package/dist/core/sandbox/policy.d.ts.map +0 -1
- package/dist/core/sandbox/policy.js +0 -55
- package/dist/core/sandbox/policy.js.map +0 -1
- package/dist/core/sandbox/profiles.d.ts +0 -25
- package/dist/core/sandbox/profiles.d.ts.map +0 -1
- package/dist/core/sandbox/profiles.js +0 -23
- package/dist/core/sandbox/profiles.js.map +0 -1
- package/dist/core/sandbox/rpc/command-client.d.ts +0 -28
- package/dist/core/sandbox/rpc/command-client.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/command-client.js +0 -86
- package/dist/core/sandbox/rpc/command-client.js.map +0 -1
- package/dist/core/sandbox/rpc/command-proxy.d.ts +0 -48
- package/dist/core/sandbox/rpc/command-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/command-proxy.js +0 -120
- package/dist/core/sandbox/rpc/command-proxy.js.map +0 -1
- package/dist/core/sandbox/rpc/credential-client.d.ts +0 -20
- package/dist/core/sandbox/rpc/credential-client.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/credential-client.js +0 -170
- package/dist/core/sandbox/rpc/credential-client.js.map +0 -1
- package/dist/core/sandbox/rpc/credential-proxy.d.ts +0 -44
- package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/credential-proxy.js +0 -287
- package/dist/core/sandbox/rpc/credential-proxy.js.map +0 -1
- package/dist/core/sandbox/rpc/framing.d.ts +0 -35
- package/dist/core/sandbox/rpc/framing.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/framing.js +0 -114
- package/dist/core/sandbox/rpc/framing.js.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts +0 -47
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-helper.js +0 -222
- package/dist/core/sandbox/rpc/git-credential-helper.js.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +0 -66
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +0 -1
- package/dist/core/sandbox/rpc/git-credential-proxy.js +0 -209
- package/dist/core/sandbox/rpc/git-credential-proxy.js.map +0 -1
- package/dist/core/sandbox/supervisor-temp.d.ts +0 -18
- package/dist/core/sandbox/supervisor-temp.d.ts.map +0 -1
- package/dist/core/sandbox/supervisor-temp.js +0 -21
- package/dist/core/sandbox/supervisor-temp.js.map +0 -1
- package/dist/core/sandbox/supervisor.d.ts +0 -62
- package/dist/core/sandbox/supervisor.d.ts.map +0 -1
- package/dist/core/sandbox/supervisor.js +0 -32
- package/dist/core/sandbox/supervisor.js.map +0 -1
- package/dist/core/sandbox/terminal-handoff.d.ts +0 -68
- package/dist/core/sandbox/terminal-handoff.d.ts.map +0 -1
- package/dist/core/sandbox/terminal-handoff.js +0 -221
- package/dist/core/sandbox/terminal-handoff.js.map +0 -1
- package/dist/core/sandbox/terminal-size.d.ts +0 -53
- package/dist/core/sandbox/terminal-size.d.ts.map +0 -1
- package/dist/core/sandbox/terminal-size.js +0 -126
- package/dist/core/sandbox/terminal-size.js.map +0 -1
- package/dist/core/sandbox/violations.d.ts +0 -23
- package/dist/core/sandbox/violations.d.ts.map +0 -1
- package/dist/core/sandbox/violations.js +0 -30
- package/dist/core/sandbox/violations.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAiB9D;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAED,wBAAsB,wBAAwB,CAC7C,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAiC5C;AAED,wBAAsB,wBAAwB,CAC7C,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAYnH","sourcesContent":["import { compare, valid } from \"semver\";\nimport { PACKAGE_NAME } from \"../config.ts\";\nimport { getApexEnvironment } from \"../core/environment.ts\";\nimport { getApexCodeUserAgent } from \"./apex-code-user-agent.ts\";\nimport { fetchWithRetry } from \"./management-http.ts\";\n\n/**\n * npm's own per-tag registry endpoint, not a custom API this project would need to\n * host and operate. Compares against \"latest\", which is the tag a release publishes\n * under and the tag a bare `npm install apex-code` resolves (ADR 0026). While no\n * stable version exists that is the newest prerelease; afterwards it is the newest\n * stable. Querying \"next\" instead would report no update available for the whole\n * pre-stable period, because \"next\" does not advance until a stable line exists.\n */\nconst LATEST_VERSION_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestApexCodeRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\n/** Include useful errno details hidden behind Node's generic \"fetch failed\" error. */\nexport function formatVersionCheckError(error: unknown): string {\n\tconst rootMessage = error instanceof Error && error.message ? error.message : String(error);\n\tconst cause = error instanceof Error ? error.cause : undefined;\n\tconst causes = cause instanceof AggregateError ? cause.errors : cause === undefined ? [] : [cause];\n\tconst codes = causes\n\t\t.map((value) =>\n\t\t\ttypeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\"\n\t\t\t\t? value.code\n\t\t\t\t: undefined,\n\t\t)\n\t\t.filter((code): code is string => code !== undefined);\n\n\tif (codes.length > 0) return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n\tconst causeMessage = causes.find(\n\t\t(value): value is Error => value instanceof Error && Boolean(value.message),\n\t)?.message;\n\treturn causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestApexCodeRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<LatestApexCodeRelease | undefined> {\n\tif (getApexEnvironment(\"APEX_CODE_OFFLINE\")) return undefined;\n\n\tconst response = await fetchWithRetry(\n\t\tLATEST_VERSION_URL,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\": getApexCodeUserAgent(currentVersion),\n\t\t\t\taccept: \"application/json\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmaxRetries: options.retry ? 2 : 0,\n\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS,\n\t\t},\n\t);\n\tif (!response.ok) return undefined;\n\n\t// npm's per-tag registry endpoint returns the full package manifest for that\n\t// version; \"packageName\"/\"note\" have no npm-registry equivalent and are left\n\t// undefined -- callers already treat both as optional with sensible fallbacks.\n\tconst data = (await response.json()) as {\n\t\tname?: unknown;\n\t\tversion?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName = typeof data.name === \"string\" && data.name.trim() ? data.name.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\t...(packageName && packageName !== PACKAGE_NAME ? { packageName } : {}),\n\t};\n}\n\nexport async function getLatestApexCodeVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestApexCodeRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewApexCodeVersion(currentVersion: string): Promise<LatestApexCodeRelease | undefined> {\n\tif (getApexEnvironment(\"APEX_CODE_SKIP_VERSION_CHECK\")) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestApexCodeRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -12,8 +12,6 @@ import { fetchWithRetry } from "./management-http.js";
|
|
|
12
12
|
* pre-stable period, because "next" does not advance until a stable line exists.
|
|
13
13
|
*/
|
|
14
14
|
const LATEST_VERSION_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
15
|
-
/** Exported so the sandbox's default allowlist cannot drift from the URL used here. */
|
|
16
|
-
export const VERSION_CHECK_HOST = new URL(LATEST_VERSION_URL).host;
|
|
17
15
|
const DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;
|
|
18
16
|
/** Include useful errno details hidden behind Node's generic "fetch failed" error. */
|
|
19
17
|
export function formatVersionCheckError(error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,kBAAkB,GAAG,8BAA8B,YAAY,SAAS,CAAC;AAC/E,
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { compare, valid } from \"semver\";\nimport { PACKAGE_NAME } from \"../config.ts\";\nimport { getApexEnvironment } from \"../core/environment.ts\";\nimport { getApexCodeUserAgent } from \"./apex-code-user-agent.ts\";\nimport { fetchWithRetry } from \"./management-http.ts\";\n\n/**\n * npm's own per-tag registry endpoint, not a custom API this project would need to\n * host and operate. Compares against \"latest\", which is the tag a release publishes\n * under and the tag a bare `npm install apex-code` resolves (ADR 0026). While no\n * stable version exists that is the newest prerelease; afterwards it is the newest\n * stable. Querying \"next\" instead would report no update available for the whole\n * pre-stable period, because \"next\" does not advance until a stable line exists.\n */\nconst LATEST_VERSION_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestApexCodeRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\n/** Include useful errno details hidden behind Node's generic \"fetch failed\" error. */\nexport function formatVersionCheckError(error: unknown): string {\n\tconst rootMessage = error instanceof Error && error.message ? error.message : String(error);\n\tconst cause = error instanceof Error ? error.cause : undefined;\n\tconst causes = cause instanceof AggregateError ? cause.errors : cause === undefined ? [] : [cause];\n\tconst codes = causes\n\t\t.map((value) =>\n\t\t\ttypeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\"\n\t\t\t\t? value.code\n\t\t\t\t: undefined,\n\t\t)\n\t\t.filter((code): code is string => code !== undefined);\n\n\tif (codes.length > 0) return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n\tconst causeMessage = causes.find(\n\t\t(value): value is Error => value instanceof Error && Boolean(value.message),\n\t)?.message;\n\treturn causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestApexCodeRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<LatestApexCodeRelease | undefined> {\n\tif (getApexEnvironment(\"APEX_CODE_OFFLINE\")) return undefined;\n\n\tconst response = await fetchWithRetry(\n\t\tLATEST_VERSION_URL,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\": getApexCodeUserAgent(currentVersion),\n\t\t\t\taccept: \"application/json\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmaxRetries: options.retry ? 2 : 0,\n\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS,\n\t\t},\n\t);\n\tif (!response.ok) return undefined;\n\n\t// npm's per-tag registry endpoint returns the full package manifest for that\n\t// version; \"packageName\"/\"note\" have no npm-registry equivalent and are left\n\t// undefined -- callers already treat both as optional with sensible fallbacks.\n\tconst data = (await response.json()) as {\n\t\tname?: unknown;\n\t\tversion?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName = typeof data.name === \"string\" && data.name.trim() ? data.name.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\t...(packageName && packageName !== PACKAGE_NAME ? { packageName } : {}),\n\t};\n}\n\nexport async function getLatestApexCodeVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestApexCodeRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewApexCodeVersion(currentVersion: string): Promise<LatestApexCodeRelease | undefined> {\n\tif (getApexEnvironment(\"APEX_CODE_SKIP_VERSION_CHECK\")) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestApexCodeRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
package/docs/settings.md
CHANGED
|
@@ -117,13 +117,8 @@ below only matter if you want to override a default.
|
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
A credential stored under `exa` in `auth.json` is also used, and takes precedence over
|
|
120
|
-
the environment variable. Note that nothing writes it for you today
|
|
121
|
-
|
|
122
|
-
`auth.json` can only be edited outside a running session. `EXA_API_KEY` is the
|
|
123
|
-
supported path.
|
|
124
|
-
|
|
125
|
-
The backend's host is added to the sandbox network allowlist automatically once a
|
|
126
|
-
credential is configured, so `network.allowedHosts` needs no entry for it.
|
|
120
|
+
the environment variable. Note that nothing writes it for you today, so edit `auth.json`
|
|
121
|
+
yourself or use `EXA_API_KEY`, which is the supported path.
|
|
127
122
|
|
|
128
123
|
### Warnings
|
|
129
124
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apex-code",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "apex-code",
|
|
9
|
-
"version": "0.0
|
|
9
|
+
"version": "0.1.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@earendil-works/pi-ai": "^0.84.4",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@modelcontextprotocol/client": "2.0.0",
|
|
17
17
|
"@modelcontextprotocol/core": "2.0.0",
|
|
18
18
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
19
|
-
"apex-code-agent-core": "0.0
|
|
19
|
+
"apex-code-agent-core": "0.1.0",
|
|
20
20
|
"chalk": "5.6.2",
|
|
21
21
|
"cross-spawn": "7.0.6",
|
|
22
22
|
"diff": "9.0.0",
|
|
@@ -1100,8 +1100,8 @@
|
|
|
1100
1100
|
}
|
|
1101
1101
|
},
|
|
1102
1102
|
"node_modules/apex-code-agent-core": {
|
|
1103
|
-
"version": "0.0
|
|
1104
|
-
"resolved": "https://registry.npmjs.org/apex-code-agent-core/-/apex-code-agent-core-0.0.
|
|
1103
|
+
"version": "0.1.0",
|
|
1104
|
+
"resolved": "https://registry.npmjs.org/apex-code-agent-core/-/apex-code-agent-core-0.1.0.tgz",
|
|
1105
1105
|
"license": "MIT",
|
|
1106
1106
|
"dependencies": {
|
|
1107
1107
|
"@earendil-works/pi-ai": "^0.84.4",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apex-code",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@modelcontextprotocol/client": "2.0.0",
|
|
51
51
|
"@modelcontextprotocol/core": "2.0.0",
|
|
52
52
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
53
|
-
"apex-code-agent-core": "0.0
|
|
53
|
+
"apex-code-agent-core": "0.1.0",
|
|
54
54
|
"chalk": "5.6.2",
|
|
55
55
|
"cross-spawn": "7.0.6",
|
|
56
56
|
"diff": "9.0.0",
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The single source of the child's `bwrap` argv.
|
|
3
|
-
*
|
|
4
|
-
* Extracted when per-command escalation needed a second child. Two hand-maintained argv
|
|
5
|
-
* builders is the divergence ADR 0010 exists to prevent for tool contracts, and it is
|
|
6
|
-
* worse here: a mount tightened in the primary child and missed in the escalated one
|
|
7
|
-
* would be invisible until the escalated path was the one that mattered. Everything that
|
|
8
|
-
* differs between the two children is an input to this function, so there is nothing to
|
|
9
|
-
* keep in sync by hand.
|
|
10
|
-
*/
|
|
11
|
-
/** A unix socket projected from the host into the child. */
|
|
12
|
-
export interface BwrapSocketMount {
|
|
13
|
-
readonly hostPath: string;
|
|
14
|
-
readonly childPath: string;
|
|
15
|
-
}
|
|
16
|
-
/** A host executable placed read-only at an exact path inside the child. */
|
|
17
|
-
export interface BwrapBinaryMount {
|
|
18
|
-
readonly source: string;
|
|
19
|
-
readonly destination: string;
|
|
20
|
-
}
|
|
21
|
-
export interface BwrapSpec {
|
|
22
|
-
/** The primary writable root, and where the child starts. */
|
|
23
|
-
readonly workspace: string;
|
|
24
|
-
/** Further writable roots, each bound exactly as the workspace is. */
|
|
25
|
-
readonly additionalWritableRoots: readonly string[];
|
|
26
|
-
/** Directories whose contents the child may read but not write. */
|
|
27
|
-
readonly readOnlyPaths: readonly string[];
|
|
28
|
-
/** Individual read-only files, projected by descriptor from index 3 upward. */
|
|
29
|
-
readonly readOnlyFiles: readonly string[];
|
|
30
|
-
readonly readOnlyBinaries: readonly BwrapBinaryMount[];
|
|
31
|
-
readonly sockets: readonly BwrapSocketMount[];
|
|
32
|
-
readonly environment: Readonly<Record<string, string>>;
|
|
33
|
-
readonly command: string;
|
|
34
|
-
readonly args: readonly string[];
|
|
35
|
-
}
|
|
36
|
-
export declare function readOnlyMountArguments(path: string): string[];
|
|
37
|
-
/** Directory paths are mounted from matching fd 3 onward to preserve sibling exclusion. */
|
|
38
|
-
export declare function descriptorBackedReadOnlyPaths(paths: readonly string[]): string[];
|
|
39
|
-
/** Build the complete argv. Mount order below is load-bearing; the comments say why. */
|
|
40
|
-
export declare function buildBwrapArguments(spec: BwrapSpec): string[];
|
|
41
|
-
//# sourceMappingURL=bwrap-arguments.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bwrap-arguments.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/bwrap-arguments.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,uBAAuB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpD,mEAAmE;IACnE,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAYD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI7D;AAED,2FAA2F;AAC3F,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAQhF;AAmED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,CA+D7D","sourcesContent":["import { statSync } from \"node:fs\";\nimport { dirname, resolve, sep } from \"node:path\";\n\n/**\n * The single source of the child's `bwrap` argv.\n *\n * Extracted when per-command escalation needed a second child. Two hand-maintained argv\n * builders is the divergence ADR 0010 exists to prevent for tool contracts, and it is\n * worse here: a mount tightened in the primary child and missed in the escalated one\n * would be invisible until the escalated path was the one that mattered. Everything that\n * differs between the two children is an input to this function, so there is nothing to\n * keep in sync by hand.\n */\n\n/** A unix socket projected from the host into the child. */\nexport interface BwrapSocketMount {\n\treadonly hostPath: string;\n\treadonly childPath: string;\n}\n\n/** A host executable placed read-only at an exact path inside the child. */\nexport interface BwrapBinaryMount {\n\treadonly source: string;\n\treadonly destination: string;\n}\n\nexport interface BwrapSpec {\n\t/** The primary writable root, and where the child starts. */\n\treadonly workspace: string;\n\t/** Further writable roots, each bound exactly as the workspace is. */\n\treadonly additionalWritableRoots: readonly string[];\n\t/** Directories whose contents the child may read but not write. */\n\treadonly readOnlyPaths: readonly string[];\n\t/** Individual read-only files, projected by descriptor from index 3 upward. */\n\treadonly readOnlyFiles: readonly string[];\n\treadonly readOnlyBinaries: readonly BwrapBinaryMount[];\n\treadonly sockets: readonly BwrapSocketMount[];\n\treadonly environment: Readonly<Record<string, string>>;\n\treadonly command: string;\n\treadonly args: readonly string[];\n}\n\nfunction ancestorDirectoryArguments(directory: string): string[] {\n\tconst ancestors: string[] = [];\n\tlet current = directory;\n\twhile (current !== \"/\" && current !== \"/home\") {\n\t\tancestors.push(current);\n\t\tcurrent = dirname(current);\n\t}\n\treturn ancestors.reverse().flatMap((ancestor) => [\"--dir\", ancestor]);\n}\n\nexport function readOnlyMountArguments(path: string): string[] {\n\tconst target = resolve(path);\n\tconst parent = dirname(target);\n\treturn [...ancestorDirectoryArguments(parent), \"--ro-bind\", parent, parent];\n}\n\n/** Directory paths are mounted from matching fd 3 onward to preserve sibling exclusion. */\nexport function descriptorBackedReadOnlyPaths(paths: readonly string[]): string[] {\n\treturn paths.filter((path) => {\n\t\ttry {\n\t\t\treturn statSync(resolve(path)).isDirectory();\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t});\n}\n\ninterface DescriptorBackedDirectory {\n\treadonly path: string;\n\treadonly descriptor: number;\n}\n\ninterface DescriptorBackedFile extends DescriptorBackedDirectory {}\n\ninterface ProjectionGroup {\n\treadonly directories: DescriptorBackedDirectory[];\n\treadonly files: DescriptorBackedFile[];\n}\n\nfunction isWithin(path: string, root: string): boolean {\n\tconst target = resolve(path);\n\tconst boundary = resolve(root);\n\treturn target === boundary || target.startsWith(boundary.endsWith(sep) ? boundary : `${boundary}${sep}`);\n}\n\nfunction nestedReadOnlyMountArguments(projections: readonly DescriptorBackedDirectory[]): string[] {\n\treturn projections.flatMap(({ path, descriptor }) => {\n\t\tconst target = resolve(path);\n\t\treturn [\"--ro-bind\", `/proc/self/fd/${descriptor}`, target];\n\t});\n}\n\nfunction externalReadOnlyMountArguments(\n\tdirectories: readonly DescriptorBackedDirectory[],\n\tfiles: readonly DescriptorBackedFile[],\n\twritableRoots: readonly string[],\n): string[] {\n\tconst byParent = new Map<string, ProjectionGroup>();\n\tconst add = (kind: keyof ProjectionGroup, projection: DescriptorBackedDirectory): void => {\n\t\tconst parent = dirname(resolve(projection.path));\n\t\tconst group = byParent.get(parent) ?? { directories: [], files: [] };\n\t\tgroup[kind].push(projection);\n\t\tbyParent.set(parent, group);\n\t};\n\tfor (const directory of directories) add(\"directories\", directory);\n\tfor (const file of files) add(\"files\", file);\n\n\tconst groups = [...byParent].sort(([left], [right]) => left.split(sep).length - right.split(sep).length);\n\tconst laterMountpoints = [...byParent.keys(), ...writableRoots];\n\treturn groups.flatMap(([parent, group]) => [\n\t\t...ancestorDirectoryArguments(parent),\n\t\t\"--tmpfs\",\n\t\tparent,\n\t\t...laterMountpoints\n\t\t\t.filter((mountpoint) => mountpoint !== parent && isWithin(mountpoint, parent))\n\t\t\t.flatMap(ancestorDirectoryArguments),\n\t\t...group.directories.flatMap(({ path, descriptor }) => {\n\t\t\tconst target = resolve(path);\n\t\t\treturn [\"--dir\", target, \"--ro-bind\", `/proc/self/fd/${descriptor}`, target];\n\t\t}),\n\t\t...group.files.flatMap(({ path, descriptor }) => [\n\t\t\t\"--perms\",\n\t\t\t\"0400\",\n\t\t\t\"--file\",\n\t\t\tString(descriptor),\n\t\t\tresolve(path),\n\t\t]),\n\t\t\"--remount-ro\",\n\t\tparent,\n\t]);\n}\n\n/** Build the complete argv. Mount order below is load-bearing; the comments say why. */\nexport function buildBwrapArguments(spec: BwrapSpec): string[] {\n\tconst directoryPaths = descriptorBackedReadOnlyPaths(spec.readOnlyPaths);\n\tconst ordinaryPaths = spec.readOnlyPaths.filter((path) => !directoryPaths.includes(path));\n\tconst writableRoots = [spec.workspace, ...spec.additionalWritableRoots];\n\tconst directoryMounts = directoryPaths.map((path, index) => ({ path, descriptor: 3 + index }));\n\tconst fileMounts = spec.readOnlyFiles.map((path, index) => ({\n\t\tpath,\n\t\tdescriptor: 3 + directoryPaths.length + index,\n\t}));\n\tconst nestedDirectoryMounts = directoryMounts.filter(({ path }) =>\n\t\twritableRoots.some((root) => isWithin(path, root)),\n\t);\n\tconst externalDirectoryMounts = directoryMounts.filter(({ path }) =>\n\t\twritableRoots.every((root) => !isWithin(path, root)),\n\t);\n\tconst nestedFileMounts = fileMounts.filter(({ path }) => writableRoots.some((root) => isWithin(path, root)));\n\tconst externalFileMounts = fileMounts.filter(({ path }) => writableRoots.every((root) => !isWithin(path, root)));\n\treturn [\n\t\t\"--new-session\",\n\t\t\"--die-with-parent\",\n\t\t\"--unshare-user\",\n\t\t\"--unshare-pid\",\n\t\t\"--unshare-net\",\n\t\t\"--ro-bind\",\n\t\t\"/\",\n\t\t\"/\",\n\t\t\"--tmpfs\",\n\t\t\"/home\",\n\t\t// Immediately after the /home tmpfs: that is the only writable mount at this\n\t\t// point, so it is the only place bwrap can create a socket mountpoint.\n\t\t...spec.sockets.flatMap(({ hostPath, childPath }) => [\"--bind\", hostPath, childPath]),\n\t\t// External directory projections shadow their parent to exclude siblings. Do\n\t\t// that before writable roots. The root binds below restore paths that the\n\t\t// projection's parent shadow may have hidden.\n\t\t...externalReadOnlyMountArguments(externalDirectoryMounts, externalFileMounts, writableRoots),\n\t\t...writableRoots.flatMap((root) => [\"--dir\", root]),\n\t\t\"--bind\",\n\t\tspec.workspace,\n\t\tspec.workspace,\n\t\t// Each extra root is bound exactly as the workspace is, and only ever from an\n\t\t// argv-parsed flag: a repository that could name its own writable root would be\n\t\t// granting itself authority (ADR 0016).\n\t\t...spec.additionalWritableRoots.flatMap((root) => [\"--bind\", root, root]),\n\t\t// These mounts must follow the writable roots: otherwise binding a workspace\n\t\t// would mask a read-only projection nested inside it.\n\t\t...ordinaryPaths.flatMap((path) => readOnlyMountArguments(path)),\n\t\t// A directory already inside a writable root needs no parent shadow: that root\n\t\t// already exposes its siblings by policy. Rebind only the requested directory.\n\t\t...nestedReadOnlyMountArguments([...nestedDirectoryMounts, ...nestedFileMounts]),\n\t\t// After the workspace bind: these destinations sit inside it, and an earlier mount\n\t\t// would be masked when the workspace is bound over them.\n\t\t...spec.readOnlyBinaries.flatMap(({ source, destination }) => [\"--ro-bind\", source, destination]),\n\t\t\"--dev\",\n\t\t\"/dev\",\n\t\t\"--proc\",\n\t\t\"/proc\",\n\t\t\"--chdir\",\n\t\tspec.workspace,\n\t\t...Object.entries(spec.environment).flatMap(([name, value]) => [\"--setenv\", name, value]),\n\t\t\"--\",\n\t\tspec.command,\n\t\t...spec.args,\n\t];\n}\n"]}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { statSync } from "node:fs";
|
|
2
|
-
import { dirname, resolve, sep } from "node:path";
|
|
3
|
-
function ancestorDirectoryArguments(directory) {
|
|
4
|
-
const ancestors = [];
|
|
5
|
-
let current = directory;
|
|
6
|
-
while (current !== "/" && current !== "/home") {
|
|
7
|
-
ancestors.push(current);
|
|
8
|
-
current = dirname(current);
|
|
9
|
-
}
|
|
10
|
-
return ancestors.reverse().flatMap((ancestor) => ["--dir", ancestor]);
|
|
11
|
-
}
|
|
12
|
-
export function readOnlyMountArguments(path) {
|
|
13
|
-
const target = resolve(path);
|
|
14
|
-
const parent = dirname(target);
|
|
15
|
-
return [...ancestorDirectoryArguments(parent), "--ro-bind", parent, parent];
|
|
16
|
-
}
|
|
17
|
-
/** Directory paths are mounted from matching fd 3 onward to preserve sibling exclusion. */
|
|
18
|
-
export function descriptorBackedReadOnlyPaths(paths) {
|
|
19
|
-
return paths.filter((path) => {
|
|
20
|
-
try {
|
|
21
|
-
return statSync(resolve(path)).isDirectory();
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
function isWithin(path, root) {
|
|
29
|
-
const target = resolve(path);
|
|
30
|
-
const boundary = resolve(root);
|
|
31
|
-
return target === boundary || target.startsWith(boundary.endsWith(sep) ? boundary : `${boundary}${sep}`);
|
|
32
|
-
}
|
|
33
|
-
function nestedReadOnlyMountArguments(projections) {
|
|
34
|
-
return projections.flatMap(({ path, descriptor }) => {
|
|
35
|
-
const target = resolve(path);
|
|
36
|
-
return ["--ro-bind", `/proc/self/fd/${descriptor}`, target];
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function externalReadOnlyMountArguments(directories, files, writableRoots) {
|
|
40
|
-
const byParent = new Map();
|
|
41
|
-
const add = (kind, projection) => {
|
|
42
|
-
const parent = dirname(resolve(projection.path));
|
|
43
|
-
const group = byParent.get(parent) ?? { directories: [], files: [] };
|
|
44
|
-
group[kind].push(projection);
|
|
45
|
-
byParent.set(parent, group);
|
|
46
|
-
};
|
|
47
|
-
for (const directory of directories)
|
|
48
|
-
add("directories", directory);
|
|
49
|
-
for (const file of files)
|
|
50
|
-
add("files", file);
|
|
51
|
-
const groups = [...byParent].sort(([left], [right]) => left.split(sep).length - right.split(sep).length);
|
|
52
|
-
const laterMountpoints = [...byParent.keys(), ...writableRoots];
|
|
53
|
-
return groups.flatMap(([parent, group]) => [
|
|
54
|
-
...ancestorDirectoryArguments(parent),
|
|
55
|
-
"--tmpfs",
|
|
56
|
-
parent,
|
|
57
|
-
...laterMountpoints
|
|
58
|
-
.filter((mountpoint) => mountpoint !== parent && isWithin(mountpoint, parent))
|
|
59
|
-
.flatMap(ancestorDirectoryArguments),
|
|
60
|
-
...group.directories.flatMap(({ path, descriptor }) => {
|
|
61
|
-
const target = resolve(path);
|
|
62
|
-
return ["--dir", target, "--ro-bind", `/proc/self/fd/${descriptor}`, target];
|
|
63
|
-
}),
|
|
64
|
-
...group.files.flatMap(({ path, descriptor }) => [
|
|
65
|
-
"--perms",
|
|
66
|
-
"0400",
|
|
67
|
-
"--file",
|
|
68
|
-
String(descriptor),
|
|
69
|
-
resolve(path),
|
|
70
|
-
]),
|
|
71
|
-
"--remount-ro",
|
|
72
|
-
parent,
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
|
-
/** Build the complete argv. Mount order below is load-bearing; the comments say why. */
|
|
76
|
-
export function buildBwrapArguments(spec) {
|
|
77
|
-
const directoryPaths = descriptorBackedReadOnlyPaths(spec.readOnlyPaths);
|
|
78
|
-
const ordinaryPaths = spec.readOnlyPaths.filter((path) => !directoryPaths.includes(path));
|
|
79
|
-
const writableRoots = [spec.workspace, ...spec.additionalWritableRoots];
|
|
80
|
-
const directoryMounts = directoryPaths.map((path, index) => ({ path, descriptor: 3 + index }));
|
|
81
|
-
const fileMounts = spec.readOnlyFiles.map((path, index) => ({
|
|
82
|
-
path,
|
|
83
|
-
descriptor: 3 + directoryPaths.length + index,
|
|
84
|
-
}));
|
|
85
|
-
const nestedDirectoryMounts = directoryMounts.filter(({ path }) => writableRoots.some((root) => isWithin(path, root)));
|
|
86
|
-
const externalDirectoryMounts = directoryMounts.filter(({ path }) => writableRoots.every((root) => !isWithin(path, root)));
|
|
87
|
-
const nestedFileMounts = fileMounts.filter(({ path }) => writableRoots.some((root) => isWithin(path, root)));
|
|
88
|
-
const externalFileMounts = fileMounts.filter(({ path }) => writableRoots.every((root) => !isWithin(path, root)));
|
|
89
|
-
return [
|
|
90
|
-
"--new-session",
|
|
91
|
-
"--die-with-parent",
|
|
92
|
-
"--unshare-user",
|
|
93
|
-
"--unshare-pid",
|
|
94
|
-
"--unshare-net",
|
|
95
|
-
"--ro-bind",
|
|
96
|
-
"/",
|
|
97
|
-
"/",
|
|
98
|
-
"--tmpfs",
|
|
99
|
-
"/home",
|
|
100
|
-
// Immediately after the /home tmpfs: that is the only writable mount at this
|
|
101
|
-
// point, so it is the only place bwrap can create a socket mountpoint.
|
|
102
|
-
...spec.sockets.flatMap(({ hostPath, childPath }) => ["--bind", hostPath, childPath]),
|
|
103
|
-
// External directory projections shadow their parent to exclude siblings. Do
|
|
104
|
-
// that before writable roots. The root binds below restore paths that the
|
|
105
|
-
// projection's parent shadow may have hidden.
|
|
106
|
-
...externalReadOnlyMountArguments(externalDirectoryMounts, externalFileMounts, writableRoots),
|
|
107
|
-
...writableRoots.flatMap((root) => ["--dir", root]),
|
|
108
|
-
"--bind",
|
|
109
|
-
spec.workspace,
|
|
110
|
-
spec.workspace,
|
|
111
|
-
// Each extra root is bound exactly as the workspace is, and only ever from an
|
|
112
|
-
// argv-parsed flag: a repository that could name its own writable root would be
|
|
113
|
-
// granting itself authority (ADR 0016).
|
|
114
|
-
...spec.additionalWritableRoots.flatMap((root) => ["--bind", root, root]),
|
|
115
|
-
// These mounts must follow the writable roots: otherwise binding a workspace
|
|
116
|
-
// would mask a read-only projection nested inside it.
|
|
117
|
-
...ordinaryPaths.flatMap((path) => readOnlyMountArguments(path)),
|
|
118
|
-
// A directory already inside a writable root needs no parent shadow: that root
|
|
119
|
-
// already exposes its siblings by policy. Rebind only the requested directory.
|
|
120
|
-
...nestedReadOnlyMountArguments([...nestedDirectoryMounts, ...nestedFileMounts]),
|
|
121
|
-
// After the workspace bind: these destinations sit inside it, and an earlier mount
|
|
122
|
-
// would be masked when the workspace is bound over them.
|
|
123
|
-
...spec.readOnlyBinaries.flatMap(({ source, destination }) => ["--ro-bind", source, destination]),
|
|
124
|
-
"--dev",
|
|
125
|
-
"/dev",
|
|
126
|
-
"--proc",
|
|
127
|
-
"/proc",
|
|
128
|
-
"--chdir",
|
|
129
|
-
spec.workspace,
|
|
130
|
-
...Object.entries(spec.environment).flatMap(([name, value]) => ["--setenv", name, value]),
|
|
131
|
-
"--",
|
|
132
|
-
spec.command,
|
|
133
|
-
...spec.args,
|
|
134
|
-
];
|
|
135
|
-
}
|
|
136
|
-
//# sourceMappingURL=bwrap-arguments.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bwrap-arguments.js","sourceRoot":"","sources":["../../../src/core/sandbox/bwrap-arguments.ts"],"names":[],"mappings":"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","sourcesContent":["import { statSync } from \"node:fs\";\nimport { dirname, resolve, sep } from \"node:path\";\n\n/**\n * The single source of the child's `bwrap` argv.\n *\n * Extracted when per-command escalation needed a second child. Two hand-maintained argv\n * builders is the divergence ADR 0010 exists to prevent for tool contracts, and it is\n * worse here: a mount tightened in the primary child and missed in the escalated one\n * would be invisible until the escalated path was the one that mattered. Everything that\n * differs between the two children is an input to this function, so there is nothing to\n * keep in sync by hand.\n */\n\n/** A unix socket projected from the host into the child. */\nexport interface BwrapSocketMount {\n\treadonly hostPath: string;\n\treadonly childPath: string;\n}\n\n/** A host executable placed read-only at an exact path inside the child. */\nexport interface BwrapBinaryMount {\n\treadonly source: string;\n\treadonly destination: string;\n}\n\nexport interface BwrapSpec {\n\t/** The primary writable root, and where the child starts. */\n\treadonly workspace: string;\n\t/** Further writable roots, each bound exactly as the workspace is. */\n\treadonly additionalWritableRoots: readonly string[];\n\t/** Directories whose contents the child may read but not write. */\n\treadonly readOnlyPaths: readonly string[];\n\t/** Individual read-only files, projected by descriptor from index 3 upward. */\n\treadonly readOnlyFiles: readonly string[];\n\treadonly readOnlyBinaries: readonly BwrapBinaryMount[];\n\treadonly sockets: readonly BwrapSocketMount[];\n\treadonly environment: Readonly<Record<string, string>>;\n\treadonly command: string;\n\treadonly args: readonly string[];\n}\n\nfunction ancestorDirectoryArguments(directory: string): string[] {\n\tconst ancestors: string[] = [];\n\tlet current = directory;\n\twhile (current !== \"/\" && current !== \"/home\") {\n\t\tancestors.push(current);\n\t\tcurrent = dirname(current);\n\t}\n\treturn ancestors.reverse().flatMap((ancestor) => [\"--dir\", ancestor]);\n}\n\nexport function readOnlyMountArguments(path: string): string[] {\n\tconst target = resolve(path);\n\tconst parent = dirname(target);\n\treturn [...ancestorDirectoryArguments(parent), \"--ro-bind\", parent, parent];\n}\n\n/** Directory paths are mounted from matching fd 3 onward to preserve sibling exclusion. */\nexport function descriptorBackedReadOnlyPaths(paths: readonly string[]): string[] {\n\treturn paths.filter((path) => {\n\t\ttry {\n\t\t\treturn statSync(resolve(path)).isDirectory();\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t});\n}\n\ninterface DescriptorBackedDirectory {\n\treadonly path: string;\n\treadonly descriptor: number;\n}\n\ninterface DescriptorBackedFile extends DescriptorBackedDirectory {}\n\ninterface ProjectionGroup {\n\treadonly directories: DescriptorBackedDirectory[];\n\treadonly files: DescriptorBackedFile[];\n}\n\nfunction isWithin(path: string, root: string): boolean {\n\tconst target = resolve(path);\n\tconst boundary = resolve(root);\n\treturn target === boundary || target.startsWith(boundary.endsWith(sep) ? boundary : `${boundary}${sep}`);\n}\n\nfunction nestedReadOnlyMountArguments(projections: readonly DescriptorBackedDirectory[]): string[] {\n\treturn projections.flatMap(({ path, descriptor }) => {\n\t\tconst target = resolve(path);\n\t\treturn [\"--ro-bind\", `/proc/self/fd/${descriptor}`, target];\n\t});\n}\n\nfunction externalReadOnlyMountArguments(\n\tdirectories: readonly DescriptorBackedDirectory[],\n\tfiles: readonly DescriptorBackedFile[],\n\twritableRoots: readonly string[],\n): string[] {\n\tconst byParent = new Map<string, ProjectionGroup>();\n\tconst add = (kind: keyof ProjectionGroup, projection: DescriptorBackedDirectory): void => {\n\t\tconst parent = dirname(resolve(projection.path));\n\t\tconst group = byParent.get(parent) ?? { directories: [], files: [] };\n\t\tgroup[kind].push(projection);\n\t\tbyParent.set(parent, group);\n\t};\n\tfor (const directory of directories) add(\"directories\", directory);\n\tfor (const file of files) add(\"files\", file);\n\n\tconst groups = [...byParent].sort(([left], [right]) => left.split(sep).length - right.split(sep).length);\n\tconst laterMountpoints = [...byParent.keys(), ...writableRoots];\n\treturn groups.flatMap(([parent, group]) => [\n\t\t...ancestorDirectoryArguments(parent),\n\t\t\"--tmpfs\",\n\t\tparent,\n\t\t...laterMountpoints\n\t\t\t.filter((mountpoint) => mountpoint !== parent && isWithin(mountpoint, parent))\n\t\t\t.flatMap(ancestorDirectoryArguments),\n\t\t...group.directories.flatMap(({ path, descriptor }) => {\n\t\t\tconst target = resolve(path);\n\t\t\treturn [\"--dir\", target, \"--ro-bind\", `/proc/self/fd/${descriptor}`, target];\n\t\t}),\n\t\t...group.files.flatMap(({ path, descriptor }) => [\n\t\t\t\"--perms\",\n\t\t\t\"0400\",\n\t\t\t\"--file\",\n\t\t\tString(descriptor),\n\t\t\tresolve(path),\n\t\t]),\n\t\t\"--remount-ro\",\n\t\tparent,\n\t]);\n}\n\n/** Build the complete argv. Mount order below is load-bearing; the comments say why. */\nexport function buildBwrapArguments(spec: BwrapSpec): string[] {\n\tconst directoryPaths = descriptorBackedReadOnlyPaths(spec.readOnlyPaths);\n\tconst ordinaryPaths = spec.readOnlyPaths.filter((path) => !directoryPaths.includes(path));\n\tconst writableRoots = [spec.workspace, ...spec.additionalWritableRoots];\n\tconst directoryMounts = directoryPaths.map((path, index) => ({ path, descriptor: 3 + index }));\n\tconst fileMounts = spec.readOnlyFiles.map((path, index) => ({\n\t\tpath,\n\t\tdescriptor: 3 + directoryPaths.length + index,\n\t}));\n\tconst nestedDirectoryMounts = directoryMounts.filter(({ path }) =>\n\t\twritableRoots.some((root) => isWithin(path, root)),\n\t);\n\tconst externalDirectoryMounts = directoryMounts.filter(({ path }) =>\n\t\twritableRoots.every((root) => !isWithin(path, root)),\n\t);\n\tconst nestedFileMounts = fileMounts.filter(({ path }) => writableRoots.some((root) => isWithin(path, root)));\n\tconst externalFileMounts = fileMounts.filter(({ path }) => writableRoots.every((root) => !isWithin(path, root)));\n\treturn [\n\t\t\"--new-session\",\n\t\t\"--die-with-parent\",\n\t\t\"--unshare-user\",\n\t\t\"--unshare-pid\",\n\t\t\"--unshare-net\",\n\t\t\"--ro-bind\",\n\t\t\"/\",\n\t\t\"/\",\n\t\t\"--tmpfs\",\n\t\t\"/home\",\n\t\t// Immediately after the /home tmpfs: that is the only writable mount at this\n\t\t// point, so it is the only place bwrap can create a socket mountpoint.\n\t\t...spec.sockets.flatMap(({ hostPath, childPath }) => [\"--bind\", hostPath, childPath]),\n\t\t// External directory projections shadow their parent to exclude siblings. Do\n\t\t// that before writable roots. The root binds below restore paths that the\n\t\t// projection's parent shadow may have hidden.\n\t\t...externalReadOnlyMountArguments(externalDirectoryMounts, externalFileMounts, writableRoots),\n\t\t...writableRoots.flatMap((root) => [\"--dir\", root]),\n\t\t\"--bind\",\n\t\tspec.workspace,\n\t\tspec.workspace,\n\t\t// Each extra root is bound exactly as the workspace is, and only ever from an\n\t\t// argv-parsed flag: a repository that could name its own writable root would be\n\t\t// granting itself authority (ADR 0016).\n\t\t...spec.additionalWritableRoots.flatMap((root) => [\"--bind\", root, root]),\n\t\t// These mounts must follow the writable roots: otherwise binding a workspace\n\t\t// would mask a read-only projection nested inside it.\n\t\t...ordinaryPaths.flatMap((path) => readOnlyMountArguments(path)),\n\t\t// A directory already inside a writable root needs no parent shadow: that root\n\t\t// already exposes its siblings by policy. Rebind only the requested directory.\n\t\t...nestedReadOnlyMountArguments([...nestedDirectoryMounts, ...nestedFileMounts]),\n\t\t// After the workspace bind: these destinations sit inside it, and an earlier mount\n\t\t// would be masked when the workspace is bound over them.\n\t\t...spec.readOnlyBinaries.flatMap(({ source, destination }) => [\"--ro-bind\", source, destination]),\n\t\t\"--dev\",\n\t\t\"/dev\",\n\t\t\"--proc\",\n\t\t\"/proc\",\n\t\t\"--chdir\",\n\t\tspec.workspace,\n\t\t...Object.entries(spec.environment).flatMap(([name, value]) => [\"--setenv\", name, value]),\n\t\t\"--\",\n\t\tspec.command,\n\t\t...spec.args,\n\t];\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"child-entry.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/child-entry.ts"],"names":[],"mappings":"","sourcesContent":["import { parseCliCommand } from \"../../cli/args.ts\";\nimport { APP_NAME } from \"../../config.ts\";\nimport { main } from \"../../main.ts\";\nimport { setApexEnvironment } from \"../environment.ts\";\nimport { configureHttpDispatcher } from \"../http-dispatcher.ts\";\nimport { installSandboxNetworkRefusalMessages } from \"./network-refusal.ts\";\nimport { applyTerminalSize, TERMINAL_SIZE_PATH_VARIABLE } from \"./terminal-size.ts\";\n\nprocess.title = APP_NAME;\nsetApexEnvironment(\"APEX_CODE_CODING_AGENT\", \"true\");\nprocess.env.AI_AGENT = \"apex-code\";\nprocess.emitWarning = (() => {}) as typeof process.emitWarning;\nconfigureHttpDispatcher();\n// Only the sandboxed child installs this, which is what makes attributing a refused\n// request to the sandbox allowlist accurate rather than a guess about whose proxy replied.\ninstallSandboxNetworkRefusalMessages();\n// bwrap --new-session leaves this process without a controlling terminal, so\n// its stdout reports a window size frozen at sandbox creation. The supervisor\n// publishes the real one; adopt it before any UI is built.\nconst terminalSizePath = process.env[TERMINAL_SIZE_PATH_VARIABLE];\nif (terminalSizePath) applyTerminalSize(terminalSizePath);\n\nconst args = process.argv.slice(2);\nawait main(args, { sessionLeaseOwner: \"supervisor\", parsedCommand: parseCliCommand(args) });\n"]}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { parseCliCommand } from "../../cli/args.js";
|
|
2
|
-
import { APP_NAME } from "../../config.js";
|
|
3
|
-
import { main } from "../../main.js";
|
|
4
|
-
import { setApexEnvironment } from "../environment.js";
|
|
5
|
-
import { configureHttpDispatcher } from "../http-dispatcher.js";
|
|
6
|
-
import { installSandboxNetworkRefusalMessages } from "./network-refusal.js";
|
|
7
|
-
import { applyTerminalSize, TERMINAL_SIZE_PATH_VARIABLE } from "./terminal-size.js";
|
|
8
|
-
process.title = APP_NAME;
|
|
9
|
-
setApexEnvironment("APEX_CODE_CODING_AGENT", "true");
|
|
10
|
-
process.env.AI_AGENT = "apex-code";
|
|
11
|
-
process.emitWarning = (() => { });
|
|
12
|
-
configureHttpDispatcher();
|
|
13
|
-
// Only the sandboxed child installs this, which is what makes attributing a refused
|
|
14
|
-
// request to the sandbox allowlist accurate rather than a guess about whose proxy replied.
|
|
15
|
-
installSandboxNetworkRefusalMessages();
|
|
16
|
-
// bwrap --new-session leaves this process without a controlling terminal, so
|
|
17
|
-
// its stdout reports a window size frozen at sandbox creation. The supervisor
|
|
18
|
-
// publishes the real one; adopt it before any UI is built.
|
|
19
|
-
const terminalSizePath = process.env[TERMINAL_SIZE_PATH_VARIABLE];
|
|
20
|
-
if (terminalSizePath)
|
|
21
|
-
applyTerminalSize(terminalSizePath);
|
|
22
|
-
const args = process.argv.slice(2);
|
|
23
|
-
await main(args, { sessionLeaseOwner: "supervisor", parsedCommand: parseCliCommand(args) });
|
|
24
|
-
//# sourceMappingURL=child-entry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"child-entry.js","sourceRoot":"","sources":["../../../src/core/sandbox/child-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oCAAoC,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAEpF,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC;AACzB,kBAAkB,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;AACrD,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,WAAW,CAAC;AACnC,OAAO,CAAC,WAAW,GAAG,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAA+B,CAAC;AAC/D,uBAAuB,EAAE,CAAC;AAC1B,oFAAoF;AACpF,2FAA2F;AAC3F,oCAAoC,EAAE,CAAC;AACvC,6EAA6E;AAC7E,8EAA8E;AAC9E,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAClE,IAAI,gBAAgB;IAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;AAE1D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC","sourcesContent":["import { parseCliCommand } from \"../../cli/args.ts\";\nimport { APP_NAME } from \"../../config.ts\";\nimport { main } from \"../../main.ts\";\nimport { setApexEnvironment } from \"../environment.ts\";\nimport { configureHttpDispatcher } from \"../http-dispatcher.ts\";\nimport { installSandboxNetworkRefusalMessages } from \"./network-refusal.ts\";\nimport { applyTerminalSize, TERMINAL_SIZE_PATH_VARIABLE } from \"./terminal-size.ts\";\n\nprocess.title = APP_NAME;\nsetApexEnvironment(\"APEX_CODE_CODING_AGENT\", \"true\");\nprocess.env.AI_AGENT = \"apex-code\";\nprocess.emitWarning = (() => {}) as typeof process.emitWarning;\nconfigureHttpDispatcher();\n// Only the sandboxed child installs this, which is what makes attributing a refused\n// request to the sandbox allowlist accurate rather than a guess about whose proxy replied.\ninstallSandboxNetworkRefusalMessages();\n// bwrap --new-session leaves this process without a controlling terminal, so\n// its stdout reports a window size frozen at sandbox creation. The supervisor\n// publishes the real one; adopt it before any UI is built.\nconst terminalSizePath = process.env[TERMINAL_SIZE_PATH_VARIABLE];\nif (terminalSizePath) applyTerminalSize(terminalSizePath);\n\nconst args = process.argv.slice(2);\nawait main(args, { sessionLeaseOwner: \"supervisor\", parsedCommand: parseCliCommand(args) });\n"]}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import type { ParsedCliCommand } from "../../cli/args.ts";
|
|
2
|
-
import type { HostToolBinary } from "../../utils/tools-manager.ts";
|
|
3
|
-
import type { SandboxLaunch } from "./supervisor.ts";
|
|
4
|
-
/**
|
|
5
|
-
* OS containment is the normal startup path for every parsed command that can
|
|
6
|
-
* construct an agent session. Classification consumes the same typed parse result
|
|
7
|
-
* as execution, so option values and text after `--` cannot impersonate metadata.
|
|
8
|
-
*/
|
|
9
|
-
export declare function requiresSandboxedChild(command: ParsedCliCommand): boolean;
|
|
10
|
-
export interface SandboxedCliLaunch extends SandboxLaunch {
|
|
11
|
-
readonly environment: NodeJS.ProcessEnv;
|
|
12
|
-
/**
|
|
13
|
-
* The supervisor's own 0700 state directory, outside every writable root the child
|
|
14
|
-
* has.
|
|
15
|
-
*/
|
|
16
|
-
readonly supervisorStateDirectory: string;
|
|
17
|
-
}
|
|
18
|
-
export declare function getSandboxSessionDirectory(workspace: string): string;
|
|
19
|
-
/**
|
|
20
|
-
* Env var naming the file that carries the host's `policy` and `user` permission scopes
|
|
21
|
-
* into the child (PS.3).
|
|
22
|
-
*
|
|
23
|
-
* Deliberately absent from `SAFE_CHILD_ENVIRONMENT_KEYS`: only the supervisor's own
|
|
24
|
-
* resolution may name it, never the invoking shell and never a project file (ADR 0016).
|
|
25
|
-
*/
|
|
26
|
-
export declare const POLICY_SNAPSHOT_PATH_VARIABLE = "APEX_CODE_POLICY_SNAPSHOT_PATH";
|
|
27
|
-
/**
|
|
28
|
-
* The marker asserting that an OS boundary is actually enforcing this process (PS.5).
|
|
29
|
-
*
|
|
30
|
-
* Set only on the supervisor's own launch environment for a child it is about to contain.
|
|
31
|
-
* It is not in the child-environment allowlist, so a value of this name in the invoking
|
|
32
|
-
* shell never survives into a child; the supervisor's own value is the only one that can.
|
|
33
|
-
* `core/sdk.ts` reads it for `sandbox: "required"` and keeps the same two literals -- a
|
|
34
|
-
* marker spelled two ways would be a drift the SDK could not detect at runtime, so
|
|
35
|
-
* `test/sdk-sandbox-contract.test.ts` pins them to each other.
|
|
36
|
-
*/
|
|
37
|
-
export declare const SANDBOX_ENFORCEMENT_MARKER_VARIABLE = "APEX_CODE_SANDBOX_ENFORCED";
|
|
38
|
-
export declare const SANDBOX_ENFORCEMENT_MARKER_VALUE = "1";
|
|
39
|
-
export interface SupervisorStateDirectory {
|
|
40
|
-
/** A 0700 directory under the supervisor temp root, outside every child-writable root. */
|
|
41
|
-
readonly path: string;
|
|
42
|
-
readonly dispose: () => void;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Allocate the directory the supervisor keeps its own launch state in.
|
|
46
|
-
*
|
|
47
|
-
* Everything the supervisor writes for a launch -- the terminal handoff latch, the
|
|
48
|
-
* published terminal size, the network relay, the git credential helper, the permission
|
|
49
|
-
* snapshot -- used to live in `workspace/.apex-code/sandbox-state`, which is inside the
|
|
50
|
-
* one writable bind the child has. A child that planted a symlink there redirected the
|
|
51
|
-
* *next* launch's supervisor writes onto arbitrary host paths, and could rewrite the
|
|
52
|
-
* scripts the supervisor was about to run. Under the supervisor temp root the child sees
|
|
53
|
-
* these files through the read-only root bind (Linux) or Seatbelt's write denial outside
|
|
54
|
-
* the workspace (macOS), so it can neither replace them nor plant a link where one goes.
|
|
55
|
-
*/
|
|
56
|
-
export declare function createSupervisorStateDirectory(): SupervisorStateDirectory;
|
|
57
|
-
/**
|
|
58
|
-
* The managed policy file this host resolves, read before the child's environment exists.
|
|
59
|
-
*
|
|
60
|
-
* `cli-launch`'s child-environment allowlist filters `APEX_CODE_POLICY_PATH` out, so a
|
|
61
|
-
* host that configured a custom managed policy had it silently disappear at the boundary
|
|
62
|
-
* and the child fell back to the system path -- the config-projection defect PS.3 closes.
|
|
63
|
-
* Resolution here mirrors `core/permissions/store.ts`'s own default exactly.
|
|
64
|
-
*/
|
|
65
|
-
export declare function resolveSupervisorPolicyPath(environment?: NodeJS.ProcessEnv): string;
|
|
66
|
-
/**
|
|
67
|
-
* Capture the host `policy` and `user` permission scopes into the supervisor's private
|
|
68
|
-
* directory and return the file's path.
|
|
69
|
-
*
|
|
70
|
-
* Called before `buildSandboxedCliLaunch` repoints `APEX_CODE_CODING_AGENT_DIR` at a
|
|
71
|
-
* workspace directory the child can write. Without it the child's `user` scope came from a
|
|
72
|
-
* file the child itself owns, and its `policy` scope from a path the environment allowlist
|
|
73
|
-
* had already removed.
|
|
74
|
-
*/
|
|
75
|
-
export declare function writeSupervisorPolicySnapshot(options: {
|
|
76
|
-
directory: string;
|
|
77
|
-
/** The *host* agent directory, before the launch repoints it. */
|
|
78
|
-
agentDir: string;
|
|
79
|
-
policyPath?: string;
|
|
80
|
-
environment?: NodeJS.ProcessEnv;
|
|
81
|
-
}): string;
|
|
82
|
-
/**
|
|
83
|
-
* Read supervisor policy only from global settings; project settings are untrusted here.
|
|
84
|
-
*
|
|
85
|
-
* The built-in provider hosts are added unless explicitly refused, because a deny-all
|
|
86
|
-
* default made a fresh install unable to reach any model while giving the user no way to
|
|
87
|
-
* learn which host to permit. Configured hosts are additive on top, and
|
|
88
|
-
* `allowDefaultHosts: false` restores the strict behaviour for anyone who wants it.
|
|
89
|
-
*/
|
|
90
|
-
export declare function resolveSupervisorAllowedHosts(cwd: string, agentDir: string): readonly string[] | undefined;
|
|
91
|
-
/**
|
|
92
|
-
* The host's two user-scope skill roots, each present only when it exists on the
|
|
93
|
-
* host. Kept as two named slots rather than one list because
|
|
94
|
-
* `core/package-manager.ts` discovers them in different modes -- root `.md` files
|
|
95
|
-
* count as skills under `agentSkills` ("pi" mode) and are ignored under
|
|
96
|
-
* `agentsHomeSkills` ("agents" mode), per `docs/skills.md` -- and a flat list of 0-2
|
|
97
|
-
* paths cannot tell the child which root a lone survivor was.
|
|
98
|
-
*/
|
|
99
|
-
export interface HostSkillPaths {
|
|
100
|
-
/** Host `<agentDir>/skills`. */
|
|
101
|
-
readonly agentSkills?: string;
|
|
102
|
-
/** Host `<home>/.agents/skills`. */
|
|
103
|
-
readonly agentsHomeSkills?: string;
|
|
104
|
-
}
|
|
105
|
-
/** A candidate skill root that exists but was excluded, and why. */
|
|
106
|
-
export interface HostSkillPathRefusal {
|
|
107
|
-
readonly root: keyof HostSkillPaths;
|
|
108
|
-
readonly path: string;
|
|
109
|
-
readonly reason: string;
|
|
110
|
-
}
|
|
111
|
-
export interface ResolvedHostSkillPaths {
|
|
112
|
-
readonly paths: HostSkillPaths;
|
|
113
|
-
readonly refusals: readonly HostSkillPathRefusal[];
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Resolve the host's user-scope skill directories, before the sandbox exists to hide
|
|
117
|
-
* them. Read only from the runtime environment and the host agent directory --
|
|
118
|
-
* never from project files -- matching ADR 0016's rule that supervisor policy is
|
|
119
|
-
* trust-first. Mirrors `core/package-manager.ts`'s own user-scope roots so the two
|
|
120
|
-
* sides agree on where a skill lives. A candidate that resolves (directly or via a
|
|
121
|
-
* symlink) onto the host home or an ancestor of it is refused rather than mounted --
|
|
122
|
-
* see `isHomeOrAncestorOfHome` -- and reported so the caller can surface a startup
|
|
123
|
-
* diagnostic instead of silently mounting or silently skipping it.
|
|
124
|
-
*/
|
|
125
|
-
export declare function resolveHostSkillPaths(agentDir: string, homeDir: string): ResolvedHostSkillPaths;
|
|
126
|
-
/**
|
|
127
|
-
* Allocate agent-owned state under the sole writable workspace mount. The child does
|
|
128
|
-
* not inherit a host home or a host session/config directory, preventing the sandbox
|
|
129
|
-
* from presenting a write boundary while its own state quietly escapes it.
|
|
130
|
-
*/
|
|
131
|
-
export declare function buildSandboxedCliLaunch(options: {
|
|
132
|
-
workspace: string;
|
|
133
|
-
command: string;
|
|
134
|
-
args: readonly string[];
|
|
135
|
-
environment: NodeJS.ProcessEnv;
|
|
136
|
-
allowedHosts?: readonly string[];
|
|
137
|
-
additionalWritableRoots?: readonly string[];
|
|
138
|
-
readOnlyPaths?: readonly string[];
|
|
139
|
-
sessionPath?: string;
|
|
140
|
-
authPath?: string;
|
|
141
|
-
/**
|
|
142
|
-
* A synthesized two-key git config, projected read-only so the child can author a
|
|
143
|
-
* commit as the user. Absent when the host had no global identity to resolve.
|
|
144
|
-
*/
|
|
145
|
-
gitConfigPath?: string;
|
|
146
|
-
toolBinaries?: readonly HostToolBinary[];
|
|
147
|
-
/**
|
|
148
|
-
* Host user-scope skill directories, pre-filtered by the caller to those that
|
|
149
|
-
* exist and pass the host-home escape check (SKILL.4). Mounted read-only at their
|
|
150
|
-
* original host location -- Seatbelt cannot remap a path, so this must hold for
|
|
151
|
-
* both backends -- and named to the child via `APEX_CODE_SKILL_PATH_*` so its
|
|
152
|
-
* discovery can find them under the sandbox's own repointed `HOME`/agent dir.
|
|
153
|
-
*/
|
|
154
|
-
skillPaths?: HostSkillPaths;
|
|
155
|
-
/** The supervisor-owned credential write channel, when one was opened. */
|
|
156
|
-
credentialChannel?: SandboxLaunch["credentialChannel"];
|
|
157
|
-
/** The supervisor's private 0700 state directory for this launch. */
|
|
158
|
-
supervisorStateDirectory?: string;
|
|
159
|
-
/** The captured host permission scopes, named to the child read-only. */
|
|
160
|
-
policySnapshotPath?: string;
|
|
161
|
-
}): SandboxedCliLaunch;
|
|
162
|
-
//# sourceMappingURL=cli-launch.d.ts.map
|