@agimon-ai/doompi-sandbox 0.0.1-alpha.37

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.
Files changed (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  4. package/dist/adapters/brokerHost.cjs +2 -0
  5. package/dist/adapters/brokerHost.cjs.map +1 -0
  6. package/dist/adapters/brokerHost.d.cts +16 -0
  7. package/dist/adapters/brokerHost.d.cts.map +1 -0
  8. package/dist/adapters/brokerHost.d.mts +16 -0
  9. package/dist/adapters/brokerHost.d.mts.map +1 -0
  10. package/dist/adapters/brokerHost.mjs +2 -0
  11. package/dist/adapters/brokerHost.mjs.map +1 -0
  12. package/dist/adapters/brokerServer.cjs +2 -0
  13. package/dist/adapters/brokerServer.cjs.map +1 -0
  14. package/dist/adapters/brokerServer.mjs +2 -0
  15. package/dist/adapters/brokerServer.mjs.map +1 -0
  16. package/dist/adapters/devcontainer.cjs +2 -0
  17. package/dist/adapters/devcontainer.cjs.map +1 -0
  18. package/dist/adapters/devcontainer.mjs +2 -0
  19. package/dist/adapters/devcontainer.mjs.map +1 -0
  20. package/dist/adapters/engineProcess.cjs +2 -0
  21. package/dist/adapters/engineProcess.cjs.map +1 -0
  22. package/dist/adapters/engineProcess.mjs +2 -0
  23. package/dist/adapters/engineProcess.mjs.map +1 -0
  24. package/dist/adapters/harness.cjs +2 -0
  25. package/dist/adapters/harness.cjs.map +1 -0
  26. package/dist/adapters/harness.d.cts +26 -0
  27. package/dist/adapters/harness.d.cts.map +1 -0
  28. package/dist/adapters/harness.d.mts +26 -0
  29. package/dist/adapters/harness.d.mts.map +1 -0
  30. package/dist/adapters/harness.mjs +2 -0
  31. package/dist/adapters/harness.mjs.map +1 -0
  32. package/dist/adapters/loginPorts.cjs +2 -0
  33. package/dist/adapters/loginPorts.cjs.map +1 -0
  34. package/dist/adapters/loginPorts.mjs +2 -0
  35. package/dist/adapters/loginPorts.mjs.map +1 -0
  36. package/dist/adapters/pi/extension.cjs +2 -0
  37. package/dist/adapters/pi/extension.cjs.map +1 -0
  38. package/dist/adapters/pi/extension.d.cts +9 -0
  39. package/dist/adapters/pi/extension.d.cts.map +1 -0
  40. package/dist/adapters/pi/extension.d.mts +9 -0
  41. package/dist/adapters/pi/extension.d.mts.map +1 -0
  42. package/dist/adapters/pi/extension.mjs +2 -0
  43. package/dist/adapters/pi/extension.mjs.map +1 -0
  44. package/dist/adapters/sandboxImageTag.cjs +2 -0
  45. package/dist/adapters/sandboxImageTag.cjs.map +1 -0
  46. package/dist/adapters/sandboxImageTag.mjs +2 -0
  47. package/dist/adapters/sandboxImageTag.mjs.map +1 -0
  48. package/dist/commands/doomSandboxCommand.cjs +2 -0
  49. package/dist/commands/doomSandboxCommand.cjs.map +1 -0
  50. package/dist/commands/doomSandboxCommand.mjs +2 -0
  51. package/dist/commands/doomSandboxCommand.mjs.map +1 -0
  52. package/dist/container/index.cjs +2 -0
  53. package/dist/container/index.cjs.map +1 -0
  54. package/dist/container/index.d.cts +6 -0
  55. package/dist/container/index.d.cts.map +1 -0
  56. package/dist/container/index.d.mts +6 -0
  57. package/dist/container/index.d.mts.map +1 -0
  58. package/dist/container/index.mjs +2 -0
  59. package/dist/container/index.mjs.map +1 -0
  60. package/dist/extensions/pi.cjs +1 -0
  61. package/dist/extensions/pi.d.cts +2 -0
  62. package/dist/extensions/pi.d.mts +2 -0
  63. package/dist/extensions/pi.mjs +1 -0
  64. package/dist/index.cjs +1 -0
  65. package/dist/index.d.cts +5 -0
  66. package/dist/index.d.mts +5 -0
  67. package/dist/index.mjs +1 -0
  68. package/dist/sandboxHarness.cjs +1 -0
  69. package/dist/sandboxHarness.d.cts +2 -0
  70. package/dist/sandboxHarness.d.mts +2 -0
  71. package/dist/sandboxHarness.mjs +1 -0
  72. package/dist/services/brokerProviders.cjs +2 -0
  73. package/dist/services/brokerProviders.cjs.map +1 -0
  74. package/dist/services/brokerProviders.mjs +2 -0
  75. package/dist/services/brokerProviders.mjs.map +1 -0
  76. package/dist/services/brokerRoutes.cjs +2 -0
  77. package/dist/services/brokerRoutes.cjs.map +1 -0
  78. package/dist/services/brokerRoutes.mjs +2 -0
  79. package/dist/services/brokerRoutes.mjs.map +1 -0
  80. package/dist/services/devcontainer.cjs +3 -0
  81. package/dist/services/devcontainer.cjs.map +1 -0
  82. package/dist/services/devcontainer.mjs +3 -0
  83. package/dist/services/devcontainer.mjs.map +1 -0
  84. package/dist/services/extensionService.cjs +2 -0
  85. package/dist/services/extensionService.cjs.map +1 -0
  86. package/dist/services/extensionService.d.cts +10 -0
  87. package/dist/services/extensionService.d.cts.map +1 -0
  88. package/dist/services/extensionService.d.mts +10 -0
  89. package/dist/services/extensionService.d.mts.map +1 -0
  90. package/dist/services/extensionService.mjs +2 -0
  91. package/dist/services/extensionService.mjs.map +1 -0
  92. package/dist/services/oauthCallback.cjs +2 -0
  93. package/dist/services/oauthCallback.cjs.map +1 -0
  94. package/dist/services/oauthCallback.mjs +2 -0
  95. package/dist/services/oauthCallback.mjs.map +1 -0
  96. package/dist/services/runFlags.cjs +2 -0
  97. package/dist/services/runFlags.cjs.map +1 -0
  98. package/dist/services/runFlags.mjs +2 -0
  99. package/dist/services/runFlags.mjs.map +1 -0
  100. package/dist/services/sandboxBridge.cjs +3 -0
  101. package/dist/services/sandboxBridge.cjs.map +1 -0
  102. package/dist/services/sandboxBridge.mjs +3 -0
  103. package/dist/services/sandboxBridge.mjs.map +1 -0
  104. package/dist/services/sandboxEnvironment.cjs +2 -0
  105. package/dist/services/sandboxEnvironment.cjs.map +1 -0
  106. package/dist/services/sandboxEnvironment.mjs +2 -0
  107. package/dist/services/sandboxEnvironment.mjs.map +1 -0
  108. package/dist/services/sandboxImage.cjs +3 -0
  109. package/dist/services/sandboxImage.cjs.map +1 -0
  110. package/dist/services/sandboxImage.mjs +3 -0
  111. package/dist/services/sandboxImage.mjs.map +1 -0
  112. package/dist/services/sandboxPlan.cjs +2 -0
  113. package/dist/services/sandboxPlan.cjs.map +1 -0
  114. package/dist/services/sandboxPlan.mjs +2 -0
  115. package/dist/services/sandboxPlan.mjs.map +1 -0
  116. package/dist/types/extension.d.cts +15 -0
  117. package/dist/types/extension.d.cts.map +1 -0
  118. package/dist/types/extension.d.mts +15 -0
  119. package/dist/types/extension.d.mts.map +1 -0
  120. package/dist/types/sandboxHarness.d.cts +38 -0
  121. package/dist/types/sandboxHarness.d.cts.map +1 -0
  122. package/dist/types/sandboxHarness.d.mts +38 -0
  123. package/dist/types/sandboxHarness.d.mts.map +1 -0
  124. package/llms.txt +11 -0
  125. package/package.json +94 -0
  126. package/src/prompts/doompi-use-sandbox/SKILL.md +14 -0
@@ -0,0 +1,3 @@
1
+ const e=require("./sandboxBridge.cjs"),t=/[^A-Za-z0-9_.-]/g;function n(e,n){return`doompi-sandbox:v${e.replaceAll(t,`-`)}-${n}`}function r(){return[`FROM node:22-bookworm-slim`,`RUN apt-get update \\`,` && apt-get install -y --no-install-recommends ca-certificates curl git nano openssh-client ripgrep \\`,` && rm -rf /var/lib/apt/lists/*`,`ARG DOOMPI_VERSION`,"RUN npm install -g @agimon-ai/doompi@${DOOMPI_VERSION}",`COPY ${e.BRIDGE_FILE_NAME} ${e.BRIDGE_CONTAINER_PATH}`,`# World-writable so the launch can map any host user id onto it.`,`RUN mkdir -m 0777 /doompi-home`,`ENV DOOMPI_SANDBOX=1 HOME=/doompi-home`,``].join(`
2
+ `)}exports.formatImageTag=n,exports.sandboxDockerfile=r;
3
+ //# sourceMappingURL=sandboxImage.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxImage.cjs","names":["BRIDGE_FILE_NAME","BRIDGE_CONTAINER_PATH"],"sources":["../../src/services/sandboxImage.ts"],"sourcesContent":["import { BRIDGE_CONTAINER_PATH, BRIDGE_FILE_NAME } from './sandboxBridge.ts';\n\nconst IMAGE_REPOSITORY = 'doompi-sandbox';\nconst TAG_SAFE = /[^A-Za-z0-9_.-]/g;\n\n/**\n * Names one image build: a distribution version plus its image definition.\n *\n * The digest matters as much as the version. Editing the Dockerfile or the\n * bridge without it would silently reuse a cached image that predates the\n * change.\n */\nexport function formatImageTag(version: string, digest: string): string {\n return `${IMAGE_REPOSITORY}:v${version.replaceAll(TAG_SAFE, '-')}-${digest}`;\n}\n\n/**\n * Self-contained Linux image for sandboxed sessions.\n *\n * nano is present because Pi falls back to it for the external editor when\n * VISUAL and EDITOR are unset, which is always the case here: a host editor\n * variable naming a desktop application would resolve to a binary the\n * container does not have, so it is deliberately not forwarded.\n *\n * The distribution installs from the registry rather than mounting host\n * modules: host installs carry platform-specific binaries a Linux container\n * cannot run. DOOMPI_SANDBOX is baked in so nothing that reaches a shell in\n * the container can present itself as an unsandboxed session.\n */\nexport function sandboxDockerfile(): string {\n return [\n 'FROM node:22-bookworm-slim',\n 'RUN apt-get update \\\\',\n ' && apt-get install -y --no-install-recommends ca-certificates curl git nano openssh-client ripgrep \\\\',\n ' && rm -rf /var/lib/apt/lists/*',\n 'ARG DOOMPI_VERSION',\n 'RUN npm install -g @agimon-ai/doompi@${DOOMPI_VERSION}',\n `COPY ${BRIDGE_FILE_NAME} ${BRIDGE_CONTAINER_PATH}`,\n '# World-writable so the launch can map any host user id onto it.',\n 'RUN mkdir -m 0777 /doompi-home',\n 'ENV DOOMPI_SANDBOX=1 HOME=/doompi-home',\n '',\n ].join('\\n');\n}\n"],"mappings":"uCAGM,EAAW,mBASjB,SAAgB,EAAe,EAAiB,EAAwB,CACtE,MAAO,mBAAwB,EAAQ,WAAW,EAAU,GAAG,EAAE,GAAG,GACtE,CAeA,SAAgB,GAA4B,CAC1C,MAAO,CACL,6BACA,wBACA,0GACA,mCACA,qBACA,yDACA,QAAQA,EAAAA,iBAAiB,GAAGC,EAAAA,wBAC5B,mEACA,iCACA,yCACA,EACF,CAAC,CAAC,KAAK;CAAI,CACb"}
@@ -0,0 +1,3 @@
1
+ import{BRIDGE_CONTAINER_PATH as e,BRIDGE_FILE_NAME as t}from"./sandboxBridge.mjs";const n=/[^A-Za-z0-9_.-]/g;function r(e,t){return`doompi-sandbox:v${e.replaceAll(n,`-`)}-${t}`}function i(){return[`FROM node:22-bookworm-slim`,`RUN apt-get update \\`,` && apt-get install -y --no-install-recommends ca-certificates curl git nano openssh-client ripgrep \\`,` && rm -rf /var/lib/apt/lists/*`,`ARG DOOMPI_VERSION`,"RUN npm install -g @agimon-ai/doompi@${DOOMPI_VERSION}",`COPY ${t} ${e}`,`# World-writable so the launch can map any host user id onto it.`,`RUN mkdir -m 0777 /doompi-home`,`ENV DOOMPI_SANDBOX=1 HOME=/doompi-home`,``].join(`
2
+ `)}export{r as formatImageTag,i as sandboxDockerfile};
3
+ //# sourceMappingURL=sandboxImage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxImage.mjs","names":[],"sources":["../../src/services/sandboxImage.ts"],"sourcesContent":["import { BRIDGE_CONTAINER_PATH, BRIDGE_FILE_NAME } from './sandboxBridge.ts';\n\nconst IMAGE_REPOSITORY = 'doompi-sandbox';\nconst TAG_SAFE = /[^A-Za-z0-9_.-]/g;\n\n/**\n * Names one image build: a distribution version plus its image definition.\n *\n * The digest matters as much as the version. Editing the Dockerfile or the\n * bridge without it would silently reuse a cached image that predates the\n * change.\n */\nexport function formatImageTag(version: string, digest: string): string {\n return `${IMAGE_REPOSITORY}:v${version.replaceAll(TAG_SAFE, '-')}-${digest}`;\n}\n\n/**\n * Self-contained Linux image for sandboxed sessions.\n *\n * nano is present because Pi falls back to it for the external editor when\n * VISUAL and EDITOR are unset, which is always the case here: a host editor\n * variable naming a desktop application would resolve to a binary the\n * container does not have, so it is deliberately not forwarded.\n *\n * The distribution installs from the registry rather than mounting host\n * modules: host installs carry platform-specific binaries a Linux container\n * cannot run. DOOMPI_SANDBOX is baked in so nothing that reaches a shell in\n * the container can present itself as an unsandboxed session.\n */\nexport function sandboxDockerfile(): string {\n return [\n 'FROM node:22-bookworm-slim',\n 'RUN apt-get update \\\\',\n ' && apt-get install -y --no-install-recommends ca-certificates curl git nano openssh-client ripgrep \\\\',\n ' && rm -rf /var/lib/apt/lists/*',\n 'ARG DOOMPI_VERSION',\n 'RUN npm install -g @agimon-ai/doompi@${DOOMPI_VERSION}',\n `COPY ${BRIDGE_FILE_NAME} ${BRIDGE_CONTAINER_PATH}`,\n '# World-writable so the launch can map any host user id onto it.',\n 'RUN mkdir -m 0777 /doompi-home',\n 'ENV DOOMPI_SANDBOX=1 HOME=/doompi-home',\n '',\n ].join('\\n');\n}\n"],"mappings":"kFAEA,MACM,EAAW,mBASjB,SAAgB,EAAe,EAAiB,EAAwB,CACtE,MAAO,mBAAwB,EAAQ,WAAW,EAAU,GAAG,EAAE,GAAG,GACtE,CAeA,SAAgB,GAA4B,CAC1C,MAAO,CACL,6BACA,wBACA,0GACA,mCACA,qBACA,yDACA,QAAQ,EAAiB,GAAG,IAC5B,mEACA,iCACA,yCACA,EACF,CAAC,CAAC,KAAK;CAAI,CACb"}
@@ -0,0 +1,2 @@
1
+ const e=require("./sandboxBridge.cjs"),t=require("./oauthCallback.cjs"),n=require("./sandboxEnvironment.cjs");let r=require("@agimon-ai/doompi-extension-contracts/sandbox-harness");const i=`/doompi-home`;function a(t,r){let i={};for(let[e,r]of Object.entries(t))n.isCredentialEnvName(e)||(i[e]=r);for(let e of r.withheldEnv)i[e]=r.token;return r.endpoint.transport===`unix`?(i[e.BROKER_SOCKET_ENV]=e.BROKER_SOCKET_CONTAINER_PATH,i[e.BROKER_PORT_ENV]=String(e.BROKER_CONTAINER_PORT)):i[e.BROKER_ADDRESS_ENV]=`${e.BROKER_HOST_GATEWAY}:${r.endpoint.port}`,i[e.BROKER_PROVIDERS_ENV]=r.providers.join(`,`),i}function o(t){return t?t.endpoint.transport===`unix`?[`-v`,`${t.endpoint.socketDirectory}:/run/doompi`]:[`--add-host`,`${e.BROKER_HOST_GATEWAY}:host-gateway`]:[]}function s(e,i,o=[]){let s=n.filterSandboxEnvironment(e),c=i?a(s,i):s;return c[r.DOOMPI_SANDBOX_ENV]=`1`,o.length>0&&(c[t.OAUTH_CALLBACK_HOST_ENV]=t.OAUTH_CONTAINER_BIND),c}function c(n){let{repoRoot:r,cwd:a,engine:c,host:l,broker:u,imageTag:d}=n,f=n.loginPorts??[],p=Object.entries(s(n.environment,u,f)).sort(([e],[t])=>e.localeCompare(t));return{imageTag:d,runArgs:[`run`,`--rm`,`-i`,...l.hasTty?[`-t`]:[],`--label`,`doompi.sandbox.repo=${r}`,`-v`,`${r}:${r}`,`-v`,`${l.repoKey}-home:${i}`,`-v`,`${l.repoKey}-pi:${r}/.pi`,...o(u),...t.oauthPublishArgs(f),`-w`,a,`-e`,`HOME=${i}`,...p.flatMap(([e,t])=>[`-e`,`${e}=${t}`]),...l.platform===`linux`&&l.userId!==void 0?[`--user`,`${l.userId}:${l.groupId??l.userId}`,...c===`podman`?[`--userns=keep-id`]:[]]:[],...n.runFlags??[],d,...u?.endpoint.transport===`unix`?[`node`,e.BRIDGE_CONTAINER_PATH]:[],`doompi`,...n.forwardArgs]}}exports.buildSandboxPlan=c,exports.containerEnvironment=s;
2
+ //# sourceMappingURL=sandboxPlan.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxPlan.cjs","names":["isCredentialEnvName","BROKER_SOCKET_ENV","BROKER_SOCKET_CONTAINER_PATH","BROKER_PORT_ENV","BROKER_CONTAINER_PORT","BROKER_ADDRESS_ENV","BROKER_HOST_GATEWAY","BROKER_PROVIDERS_ENV","filterSandboxEnvironment","DOOMPI_SANDBOX_ENV","OAUTH_CALLBACK_HOST_ENV","OAUTH_CONTAINER_BIND","oauthPublishArgs","BRIDGE_CONTAINER_PATH"],"sources":["../../src/services/sandboxPlan.ts"],"sourcesContent":["import { DOOMPI_SANDBOX_ENV } from '@agimon-ai/doompi-extension-contracts/sandbox-harness';\nimport type { BrokerEndpoint, SandboxEngine, SandboxHostFacts } from '../types/sandboxHarness.ts';\nimport { filterSandboxEnvironment, isCredentialEnvName } from './sandboxEnvironment.ts';\nimport { OAUTH_CALLBACK_HOST_ENV, OAUTH_CONTAINER_BIND, oauthPublishArgs } from './oauthCallback.ts';\nimport {\n BRIDGE_CONTAINER_PATH,\n BROKER_ADDRESS_ENV,\n BROKER_CONTAINER_PORT,\n BROKER_HOST_GATEWAY,\n BROKER_PORT_ENV,\n BROKER_PROVIDERS_ENV,\n BROKER_SOCKET_CONTAINER_PATH,\n BROKER_SOCKET_ENV,\n} from './sandboxBridge.ts';\n\nconst CONTAINER_HOME = '/doompi-home';\nconst REPOSITORY_LABEL = 'doompi.sandbox.repo';\n// The harness binary, which accepts every forwarded flag; dpi hands its\n// arguments straight to Pi and would reject harness options like --preset.\nconst LAUNCHER_BINARY = 'doompi';\nconst NODE_BINARY = 'node';\nconst LINUX_PLATFORM = 'linux';\nconst ENABLED = '1';\nconst BROKER_MOUNT_DIRECTORY = '/run/doompi';\n\n/** Host broker facts the plan projects into mounts and environment. */\nexport interface SandboxPlanBroker {\n endpoint: BrokerEndpoint;\n token: string;\n providers: readonly string[];\n /** Credential variables whose value the container receives as the token. */\n withheldEnv: readonly string[];\n}\n\nexport interface SandboxPlanInput {\n repoRoot: string;\n cwd: string;\n forwardArgs: string[];\n environment: Readonly<Record<string, string | undefined>>;\n engine: SandboxEngine;\n host: SandboxHostFacts;\n /** Image the launch resolved, which also pins the image definition. */\n imageTag: string;\n /** Engine options the operator configured, such as an alternate runtime. */\n runFlags?: readonly string[];\n /** OAuth callback ports free on the host, published so a browser can reach them. */\n loginPorts?: readonly number[];\n broker?: SandboxPlanBroker;\n}\n\nexport interface SandboxPlan {\n imageTag: string;\n /** Full engine argv after the engine binary itself. */\n runArgs: string[];\n}\n\n/**\n * Replaces every credential in the container with the broker's session token.\n *\n * Dropping all credential-shaped variables first is what makes the promise\n * hold for providers the broker does not carry: an unbrokered key would\n * otherwise stay readable inside the container.\n */\nfunction brokeredEnvironment(filtered: Record<string, string>, broker: SandboxPlanBroker): Record<string, string> {\n const environment: Record<string, string> = {};\n for (const [name, value] of Object.entries(filtered)) {\n if (!isCredentialEnvName(name)) environment[name] = value;\n }\n for (const name of broker.withheldEnv) environment[name] = broker.token;\n if (broker.endpoint.transport === 'unix') {\n environment[BROKER_SOCKET_ENV] = BROKER_SOCKET_CONTAINER_PATH;\n // Only the bridge reads this, and only a socket needs the bridge.\n environment[BROKER_PORT_ENV] = String(BROKER_CONTAINER_PORT);\n } else {\n environment[BROKER_ADDRESS_ENV] = `${BROKER_HOST_GATEWAY}:${broker.endpoint.port}`;\n }\n environment[BROKER_PROVIDERS_ENV] = broker.providers.join(',');\n return environment;\n}\n\n/**\n * Grants the container the one route it needs to reach the broker.\n *\n * A mounted socket needs no network at all. TCP needs the engine's host\n * gateway named explicitly, because it is not resolvable by default on every\n * engine.\n */\nfunction brokerAccessArgs(broker: SandboxPlanBroker | undefined): string[] {\n if (!broker) return [];\n if (broker.endpoint.transport === 'unix') {\n return ['-v', `${broker.endpoint.socketDirectory}:${BROKER_MOUNT_DIRECTORY}`];\n }\n return ['--add-host', `${BROKER_HOST_GATEWAY}:host-gateway`];\n}\n\n/**\n * Projects one launch into a disposable engine run.\n *\n * The container is ephemeral; persistence lives in two named volumes: the\n * container home (Pi sessions, sync cache) and a shadow over the repository's\n * `.pi` store, which keeps Linux installs from corrupting the host's own\n * platform-specific packages on the shared workspace mount.\n */\n/**\n * The environment a sandboxed session runs with, whichever container hosts it.\n *\n * Shared with the dev container path, which builds no run arguments of its own\n * but must apply the same allowlist and the same credential substitution.\n */\nexport function containerEnvironment(\n environment: Readonly<Record<string, string | undefined>>,\n broker?: SandboxPlanBroker,\n loginPorts: readonly number[] = [],\n): Record<string, string> {\n const filtered = filterSandboxEnvironment(environment);\n const resolved = broker ? brokeredEnvironment(filtered, broker) : filtered;\n resolved[DOOMPI_SANDBOX_ENV] = ENABLED;\n if (loginPorts.length > 0) resolved[OAUTH_CALLBACK_HOST_ENV] = OAUTH_CONTAINER_BIND;\n return resolved;\n}\n\nexport function buildSandboxPlan(input: SandboxPlanInput): SandboxPlan {\n const { repoRoot, cwd, engine, host, broker, imageTag } = input;\n const loginPorts = input.loginPorts ?? [];\n const environmentPairs = Object.entries(containerEnvironment(input.environment, broker, loginPorts)).sort(\n ([left], [right]) => left.localeCompare(right),\n );\n\n const runArgs = [\n 'run',\n '--rm',\n '-i',\n ...(host.hasTty ? ['-t'] : []),\n '--label',\n `${REPOSITORY_LABEL}=${repoRoot}`,\n '-v',\n `${repoRoot}:${repoRoot}`,\n '-v',\n `${host.repoKey}-home:${CONTAINER_HOME}`,\n '-v',\n `${host.repoKey}-pi:${repoRoot}/.pi`,\n ...brokerAccessArgs(broker),\n ...oauthPublishArgs(loginPorts),\n '-w',\n cwd,\n '-e',\n `HOME=${CONTAINER_HOME}`,\n ...environmentPairs.flatMap(([name, value]) => ['-e', `${name}=${value}`]),\n ...(host.platform === LINUX_PLATFORM && host.userId !== undefined\n ? [\n '--user',\n `${host.userId}:${host.groupId ?? host.userId}`,\n ...(engine === 'podman' ? ['--userns=keep-id'] : []),\n ]\n : []),\n // Last before the image so a configured option wins over the defaults\n // above it, and cannot be mistaken for the image or its command.\n ...(input.runFlags ?? []),\n imageTag,\n // Only a mounted socket needs the bridge: a broker on a host port is\n // addressed directly, so the launcher runs unwrapped.\n ...(broker?.endpoint.transport === 'unix' ? [NODE_BINARY, BRIDGE_CONTAINER_PATH] : []),\n LAUNCHER_BINARY,\n ...input.forwardArgs,\n ];\n\n return { imageTag, runArgs };\n}\n"],"mappings":"qLAeA,MAAM,EAAiB,eAgDvB,SAAS,EAAoB,EAAkC,EAAmD,CAChH,IAAM,EAAsC,CAAC,EAC7C,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAQ,EAC5CA,EAAAA,oBAAoB,CAAI,IAAG,EAAY,GAAQ,GAEtD,IAAK,IAAM,KAAQ,EAAO,YAAa,EAAY,GAAQ,EAAO,MASlE,OARI,EAAO,SAAS,YAAc,QAChC,EAAYC,EAAAA,mBAAqBC,EAAAA,6BAEjC,EAAYC,EAAAA,iBAAmB,OAAOC,EAAAA,qBAAqB,GAE3D,EAAYC,EAAAA,oBAAsB,GAAGC,EAAAA,oBAAoB,GAAG,EAAO,SAAS,OAE9E,EAAYC,EAAAA,sBAAwB,EAAO,UAAU,KAAK,GAAG,EACtD,CACT,CASA,SAAS,EAAiB,EAAiD,CAKzE,OAJK,EACD,EAAO,SAAS,YAAc,OACzB,CAAC,KAAM,GAAG,EAAO,SAAS,gBAAgB,aAA2B,EAEvE,CAAC,aAAc,GAAGD,EAAAA,oBAAoB,cAAc,EAJvC,CAAC,CAKvB,CAgBA,SAAgB,EACd,EACA,EACA,EAAgC,CAAC,EACT,CACxB,IAAM,EAAWE,EAAAA,yBAAyB,CAAW,EAC/C,EAAW,EAAS,EAAoB,EAAU,CAAM,EAAI,EAGlE,MAFA,GAASC,EAAAA,oBAAsB,IAC3B,EAAW,OAAS,IAAG,EAASC,EAAAA,yBAA2BC,EAAAA,sBACxD,CACT,CAEA,SAAgB,EAAiB,EAAsC,CACrE,GAAM,CAAE,WAAU,MAAK,SAAQ,OAAM,SAAQ,YAAa,EACpD,EAAa,EAAM,YAAc,CAAC,EAClC,EAAmB,OAAO,QAAQ,EAAqB,EAAM,YAAa,EAAQ,CAAU,CAAC,CAAC,CAAC,MAClG,CAAC,GAAO,CAAC,KAAW,EAAK,cAAc,CAAK,CAC/C,EAwCA,MAAO,CAAE,WAAU,QAAA,CArCjB,MACA,OACA,KACA,GAAI,EAAK,OAAS,CAAC,IAAI,EAAI,CAAC,EAC5B,UACA,uBAAuB,IACvB,KACA,GAAG,EAAS,GAAG,IACf,KACA,GAAG,EAAK,QAAQ,QAAQ,IACxB,KACA,GAAG,EAAK,QAAQ,MAAM,EAAS,MAC/B,GAAG,EAAiB,CAAM,EAC1B,GAAGC,EAAAA,iBAAiB,CAAU,EAC9B,KACA,EACA,KACA,QAAQ,IACR,GAAG,EAAiB,SAAS,CAAC,EAAM,KAAW,CAAC,KAAM,GAAG,EAAK,GAAG,GAAO,CAAC,EACzE,GAAI,EAAK,WAAa,SAAkB,EAAK,SAAW,IAAA,GACpD,CACE,SACA,GAAG,EAAK,OAAO,GAAG,EAAK,SAAW,EAAK,SACvC,GAAI,IAAW,SAAW,CAAC,kBAAkB,EAAI,CAAC,CACpD,EACA,CAAC,EAGL,GAAI,EAAM,UAAY,CAAC,EACvB,EAGA,GAAI,GAAQ,SAAS,YAAc,OAAS,CAAC,OAAaC,EAAAA,qBAAqB,EAAI,CAAC,EACpF,SACA,GAAG,EAAM,WAGc,CAAE,CAC7B"}
@@ -0,0 +1,2 @@
1
+ import{BRIDGE_CONTAINER_PATH as e,BROKER_ADDRESS_ENV as t,BROKER_CONTAINER_PORT as n,BROKER_HOST_GATEWAY as r,BROKER_PORT_ENV as i,BROKER_PROVIDERS_ENV as a,BROKER_SOCKET_CONTAINER_PATH as o,BROKER_SOCKET_ENV as s}from"./sandboxBridge.mjs";import{OAUTH_CALLBACK_HOST_ENV as c,OAUTH_CONTAINER_BIND as l,oauthPublishArgs as u}from"./oauthCallback.mjs";import{filterSandboxEnvironment as d,isCredentialEnvName as f}from"./sandboxEnvironment.mjs";import{DOOMPI_SANDBOX_ENV as p}from"@agimon-ai/doompi-extension-contracts/sandbox-harness";const m=`/doompi-home`;function h(e,c){let l={};for(let[t,n]of Object.entries(e))f(t)||(l[t]=n);for(let e of c.withheldEnv)l[e]=c.token;return c.endpoint.transport===`unix`?(l[s]=o,l[i]=String(n)):l[t]=`${r}:${c.endpoint.port}`,l[a]=c.providers.join(`,`),l}function g(e){return e?e.endpoint.transport===`unix`?[`-v`,`${e.endpoint.socketDirectory}:/run/doompi`]:[`--add-host`,`${r}:host-gateway`]:[]}function _(e,t,n=[]){let r=d(e),i=t?h(r,t):r;return i[p]=`1`,n.length>0&&(i[c]=l),i}function v(t){let{repoRoot:n,cwd:r,engine:i,host:a,broker:o,imageTag:s}=t,c=t.loginPorts??[],l=Object.entries(_(t.environment,o,c)).sort(([e],[t])=>e.localeCompare(t));return{imageTag:s,runArgs:[`run`,`--rm`,`-i`,...a.hasTty?[`-t`]:[],`--label`,`doompi.sandbox.repo=${n}`,`-v`,`${n}:${n}`,`-v`,`${a.repoKey}-home:${m}`,`-v`,`${a.repoKey}-pi:${n}/.pi`,...g(o),...u(c),`-w`,r,`-e`,`HOME=${m}`,...l.flatMap(([e,t])=>[`-e`,`${e}=${t}`]),...a.platform===`linux`&&a.userId!==void 0?[`--user`,`${a.userId}:${a.groupId??a.userId}`,...i===`podman`?[`--userns=keep-id`]:[]]:[],...t.runFlags??[],s,...o?.endpoint.transport===`unix`?[`node`,e]:[],`doompi`,...t.forwardArgs]}}export{v as buildSandboxPlan,_ as containerEnvironment};
2
+ //# sourceMappingURL=sandboxPlan.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxPlan.mjs","names":[],"sources":["../../src/services/sandboxPlan.ts"],"sourcesContent":["import { DOOMPI_SANDBOX_ENV } from '@agimon-ai/doompi-extension-contracts/sandbox-harness';\nimport type { BrokerEndpoint, SandboxEngine, SandboxHostFacts } from '../types/sandboxHarness.ts';\nimport { filterSandboxEnvironment, isCredentialEnvName } from './sandboxEnvironment.ts';\nimport { OAUTH_CALLBACK_HOST_ENV, OAUTH_CONTAINER_BIND, oauthPublishArgs } from './oauthCallback.ts';\nimport {\n BRIDGE_CONTAINER_PATH,\n BROKER_ADDRESS_ENV,\n BROKER_CONTAINER_PORT,\n BROKER_HOST_GATEWAY,\n BROKER_PORT_ENV,\n BROKER_PROVIDERS_ENV,\n BROKER_SOCKET_CONTAINER_PATH,\n BROKER_SOCKET_ENV,\n} from './sandboxBridge.ts';\n\nconst CONTAINER_HOME = '/doompi-home';\nconst REPOSITORY_LABEL = 'doompi.sandbox.repo';\n// The harness binary, which accepts every forwarded flag; dpi hands its\n// arguments straight to Pi and would reject harness options like --preset.\nconst LAUNCHER_BINARY = 'doompi';\nconst NODE_BINARY = 'node';\nconst LINUX_PLATFORM = 'linux';\nconst ENABLED = '1';\nconst BROKER_MOUNT_DIRECTORY = '/run/doompi';\n\n/** Host broker facts the plan projects into mounts and environment. */\nexport interface SandboxPlanBroker {\n endpoint: BrokerEndpoint;\n token: string;\n providers: readonly string[];\n /** Credential variables whose value the container receives as the token. */\n withheldEnv: readonly string[];\n}\n\nexport interface SandboxPlanInput {\n repoRoot: string;\n cwd: string;\n forwardArgs: string[];\n environment: Readonly<Record<string, string | undefined>>;\n engine: SandboxEngine;\n host: SandboxHostFacts;\n /** Image the launch resolved, which also pins the image definition. */\n imageTag: string;\n /** Engine options the operator configured, such as an alternate runtime. */\n runFlags?: readonly string[];\n /** OAuth callback ports free on the host, published so a browser can reach them. */\n loginPorts?: readonly number[];\n broker?: SandboxPlanBroker;\n}\n\nexport interface SandboxPlan {\n imageTag: string;\n /** Full engine argv after the engine binary itself. */\n runArgs: string[];\n}\n\n/**\n * Replaces every credential in the container with the broker's session token.\n *\n * Dropping all credential-shaped variables first is what makes the promise\n * hold for providers the broker does not carry: an unbrokered key would\n * otherwise stay readable inside the container.\n */\nfunction brokeredEnvironment(filtered: Record<string, string>, broker: SandboxPlanBroker): Record<string, string> {\n const environment: Record<string, string> = {};\n for (const [name, value] of Object.entries(filtered)) {\n if (!isCredentialEnvName(name)) environment[name] = value;\n }\n for (const name of broker.withheldEnv) environment[name] = broker.token;\n if (broker.endpoint.transport === 'unix') {\n environment[BROKER_SOCKET_ENV] = BROKER_SOCKET_CONTAINER_PATH;\n // Only the bridge reads this, and only a socket needs the bridge.\n environment[BROKER_PORT_ENV] = String(BROKER_CONTAINER_PORT);\n } else {\n environment[BROKER_ADDRESS_ENV] = `${BROKER_HOST_GATEWAY}:${broker.endpoint.port}`;\n }\n environment[BROKER_PROVIDERS_ENV] = broker.providers.join(',');\n return environment;\n}\n\n/**\n * Grants the container the one route it needs to reach the broker.\n *\n * A mounted socket needs no network at all. TCP needs the engine's host\n * gateway named explicitly, because it is not resolvable by default on every\n * engine.\n */\nfunction brokerAccessArgs(broker: SandboxPlanBroker | undefined): string[] {\n if (!broker) return [];\n if (broker.endpoint.transport === 'unix') {\n return ['-v', `${broker.endpoint.socketDirectory}:${BROKER_MOUNT_DIRECTORY}`];\n }\n return ['--add-host', `${BROKER_HOST_GATEWAY}:host-gateway`];\n}\n\n/**\n * Projects one launch into a disposable engine run.\n *\n * The container is ephemeral; persistence lives in two named volumes: the\n * container home (Pi sessions, sync cache) and a shadow over the repository's\n * `.pi` store, which keeps Linux installs from corrupting the host's own\n * platform-specific packages on the shared workspace mount.\n */\n/**\n * The environment a sandboxed session runs with, whichever container hosts it.\n *\n * Shared with the dev container path, which builds no run arguments of its own\n * but must apply the same allowlist and the same credential substitution.\n */\nexport function containerEnvironment(\n environment: Readonly<Record<string, string | undefined>>,\n broker?: SandboxPlanBroker,\n loginPorts: readonly number[] = [],\n): Record<string, string> {\n const filtered = filterSandboxEnvironment(environment);\n const resolved = broker ? brokeredEnvironment(filtered, broker) : filtered;\n resolved[DOOMPI_SANDBOX_ENV] = ENABLED;\n if (loginPorts.length > 0) resolved[OAUTH_CALLBACK_HOST_ENV] = OAUTH_CONTAINER_BIND;\n return resolved;\n}\n\nexport function buildSandboxPlan(input: SandboxPlanInput): SandboxPlan {\n const { repoRoot, cwd, engine, host, broker, imageTag } = input;\n const loginPorts = input.loginPorts ?? [];\n const environmentPairs = Object.entries(containerEnvironment(input.environment, broker, loginPorts)).sort(\n ([left], [right]) => left.localeCompare(right),\n );\n\n const runArgs = [\n 'run',\n '--rm',\n '-i',\n ...(host.hasTty ? ['-t'] : []),\n '--label',\n `${REPOSITORY_LABEL}=${repoRoot}`,\n '-v',\n `${repoRoot}:${repoRoot}`,\n '-v',\n `${host.repoKey}-home:${CONTAINER_HOME}`,\n '-v',\n `${host.repoKey}-pi:${repoRoot}/.pi`,\n ...brokerAccessArgs(broker),\n ...oauthPublishArgs(loginPorts),\n '-w',\n cwd,\n '-e',\n `HOME=${CONTAINER_HOME}`,\n ...environmentPairs.flatMap(([name, value]) => ['-e', `${name}=${value}`]),\n ...(host.platform === LINUX_PLATFORM && host.userId !== undefined\n ? [\n '--user',\n `${host.userId}:${host.groupId ?? host.userId}`,\n ...(engine === 'podman' ? ['--userns=keep-id'] : []),\n ]\n : []),\n // Last before the image so a configured option wins over the defaults\n // above it, and cannot be mistaken for the image or its command.\n ...(input.runFlags ?? []),\n imageTag,\n // Only a mounted socket needs the bridge: a broker on a host port is\n // addressed directly, so the launcher runs unwrapped.\n ...(broker?.endpoint.transport === 'unix' ? [NODE_BINARY, BRIDGE_CONTAINER_PATH] : []),\n LAUNCHER_BINARY,\n ...input.forwardArgs,\n ];\n\n return { imageTag, runArgs };\n}\n"],"mappings":"shBAeA,MAAM,EAAiB,eAgDvB,SAAS,EAAoB,EAAkC,EAAmD,CAChH,IAAM,EAAsC,CAAC,EAC7C,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAQ,EAC5C,EAAoB,CAAI,IAAG,EAAY,GAAQ,GAEtD,IAAK,IAAM,KAAQ,EAAO,YAAa,EAAY,GAAQ,EAAO,MASlE,OARI,EAAO,SAAS,YAAc,QAChC,EAAY,GAAqB,EAEjC,EAAY,GAAmB,OAAO,CAAqB,GAE3D,EAAY,GAAsB,GAAG,EAAoB,GAAG,EAAO,SAAS,OAE9E,EAAY,GAAwB,EAAO,UAAU,KAAK,GAAG,EACtD,CACT,CASA,SAAS,EAAiB,EAAiD,CAKzE,OAJK,EACD,EAAO,SAAS,YAAc,OACzB,CAAC,KAAM,GAAG,EAAO,SAAS,gBAAgB,aAA2B,EAEvE,CAAC,aAAc,GAAG,EAAoB,cAAc,EAJvC,CAAC,CAKvB,CAgBA,SAAgB,EACd,EACA,EACA,EAAgC,CAAC,EACT,CACxB,IAAM,EAAW,EAAyB,CAAW,EAC/C,EAAW,EAAS,EAAoB,EAAU,CAAM,EAAI,EAGlE,MAFA,GAAS,GAAsB,IAC3B,EAAW,OAAS,IAAG,EAAS,GAA2B,GACxD,CACT,CAEA,SAAgB,EAAiB,EAAsC,CACrE,GAAM,CAAE,WAAU,MAAK,SAAQ,OAAM,SAAQ,YAAa,EACpD,EAAa,EAAM,YAAc,CAAC,EAClC,EAAmB,OAAO,QAAQ,EAAqB,EAAM,YAAa,EAAQ,CAAU,CAAC,CAAC,CAAC,MAClG,CAAC,GAAO,CAAC,KAAW,EAAK,cAAc,CAAK,CAC/C,EAwCA,MAAO,CAAE,WAAU,QAAA,CArCjB,MACA,OACA,KACA,GAAI,EAAK,OAAS,CAAC,IAAI,EAAI,CAAC,EAC5B,UACA,uBAAuB,IACvB,KACA,GAAG,EAAS,GAAG,IACf,KACA,GAAG,EAAK,QAAQ,QAAQ,IACxB,KACA,GAAG,EAAK,QAAQ,MAAM,EAAS,MAC/B,GAAG,EAAiB,CAAM,EAC1B,GAAG,EAAiB,CAAU,EAC9B,KACA,EACA,KACA,QAAQ,IACR,GAAG,EAAiB,SAAS,CAAC,EAAM,KAAW,CAAC,KAAM,GAAG,EAAK,GAAG,GAAO,CAAC,EACzE,GAAI,EAAK,WAAa,SAAkB,EAAK,SAAW,IAAA,GACpD,CACE,SACA,GAAG,EAAK,OAAO,GAAG,EAAK,SAAW,EAAK,SACvC,GAAI,IAAW,SAAW,CAAC,kBAAkB,EAAI,CAAC,CACpD,EACA,CAAC,EAGL,GAAI,EAAM,UAAY,CAAC,EACvB,EAGA,GAAI,GAAQ,SAAS,YAAc,OAAS,CAAC,OAAa,CAAqB,EAAI,CAAC,EACpF,SACA,GAAG,EAAM,WAGc,CAAE,CAC7B"}
@@ -0,0 +1,15 @@
1
+ //#region src/types/extension.d.ts
2
+ type SandboxNotificationLevel = 'info';
3
+ interface SandboxExtensionResult {
4
+ message: string;
5
+ level: SandboxNotificationLevel;
6
+ }
7
+ interface SandboxExtensionService {
8
+ execute(): Promise<SandboxExtensionResult>;
9
+ }
10
+ interface SandboxExtensionDependencies {
11
+ service: SandboxExtensionService;
12
+ }
13
+ //#endregion
14
+ export { SandboxExtensionDependencies, SandboxExtensionResult, SandboxExtensionService, SandboxNotificationLevel };
15
+ //# sourceMappingURL=extension.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../src/types/extension.ts"],"mappings":";KACY;UAEK;EACf;EACA,OAAO;;UAGQ;EACf,WAAW,QAAQ;;UAGJ;EACf,SAAS"}
@@ -0,0 +1,15 @@
1
+ //#region src/types/extension.d.ts
2
+ type SandboxNotificationLevel = 'info';
3
+ interface SandboxExtensionResult {
4
+ message: string;
5
+ level: SandboxNotificationLevel;
6
+ }
7
+ interface SandboxExtensionService {
8
+ execute(): Promise<SandboxExtensionResult>;
9
+ }
10
+ interface SandboxExtensionDependencies {
11
+ service: SandboxExtensionService;
12
+ }
13
+ //#endregion
14
+ export { SandboxExtensionDependencies, SandboxExtensionResult, SandboxExtensionService, SandboxNotificationLevel };
15
+ //# sourceMappingURL=extension.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../src/types/extension.ts"],"mappings":";KACY;UAEK;EACf;EACA,OAAO;;UAGQ;EACf,WAAW,QAAQ;;UAGJ;EACf,SAAS"}
@@ -0,0 +1,38 @@
1
+ //#region src/types/sandboxHarness.d.ts
2
+ interface EngineRunOptions {
3
+ /** Pipes this to stdin instead of attaching the session's stdio. */
4
+ input?: string;
5
+ }
6
+ interface EngineCaptureResult {
7
+ exitCode: number;
8
+ stdout: string;
9
+ }
10
+ /** Runs container engine commands with the session's terminal attached. */
11
+ interface EngineProcessRunner {
12
+ run(command: string, args: string[], options?: EngineRunOptions): Promise<number>;
13
+ /** Captures stdout for probes; an unspawnable command reports undefined. */
14
+ capture(command: string, args: string[]): Promise<EngineCaptureResult | undefined>;
15
+ }
16
+ /** Host facts the plan builder projects into engine arguments. */
17
+ interface SandboxHostFacts {
18
+ /** Both ends of the session are terminals, so the container gets one too. */
19
+ hasTty: boolean;
20
+ platform: string;
21
+ userId?: number;
22
+ groupId?: number;
23
+ /** Stable key derived from the repository path; prefixes container volumes. */
24
+ repoKey: string;
25
+ /** Distribution version, which tags the sandbox image. */
26
+ version: string;
27
+ }
28
+ /** How a sandboxed container reaches the host broker. */
29
+ type BrokerEndpoint = {
30
+ transport: 'unix';
31
+ socketDirectory: string;
32
+ } | {
33
+ transport: 'tcp';
34
+ port: number;
35
+ };
36
+ //#endregion
37
+ export { BrokerEndpoint, EngineCaptureResult, EngineProcessRunner, EngineRunOptions, SandboxHostFacts };
38
+ //# sourceMappingURL=sandboxHarness.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxHarness.d.cts","names":[],"sources":["../../src/types/sandboxHarness.ts"],"mappings":";UAEiB;;EAEf;;UAGe;EACf;EACA;;;UAIe;EACf,IAAI,iBAAiB,gBAAgB,UAAU,mBAAmB;;EAElE,QAAQ,iBAAiB,iBAAiB,QAAQ;;;UAInC;;EAEf;EACA;EACA;EACA;;EAEA;;EAEA;;;KAIU;EAAmB;EAAmB;;EAA8B;EAAkB"}
@@ -0,0 +1,38 @@
1
+ //#region src/types/sandboxHarness.d.ts
2
+ interface EngineRunOptions {
3
+ /** Pipes this to stdin instead of attaching the session's stdio. */
4
+ input?: string;
5
+ }
6
+ interface EngineCaptureResult {
7
+ exitCode: number;
8
+ stdout: string;
9
+ }
10
+ /** Runs container engine commands with the session's terminal attached. */
11
+ interface EngineProcessRunner {
12
+ run(command: string, args: string[], options?: EngineRunOptions): Promise<number>;
13
+ /** Captures stdout for probes; an unspawnable command reports undefined. */
14
+ capture(command: string, args: string[]): Promise<EngineCaptureResult | undefined>;
15
+ }
16
+ /** Host facts the plan builder projects into engine arguments. */
17
+ interface SandboxHostFacts {
18
+ /** Both ends of the session are terminals, so the container gets one too. */
19
+ hasTty: boolean;
20
+ platform: string;
21
+ userId?: number;
22
+ groupId?: number;
23
+ /** Stable key derived from the repository path; prefixes container volumes. */
24
+ repoKey: string;
25
+ /** Distribution version, which tags the sandbox image. */
26
+ version: string;
27
+ }
28
+ /** How a sandboxed container reaches the host broker. */
29
+ type BrokerEndpoint = {
30
+ transport: 'unix';
31
+ socketDirectory: string;
32
+ } | {
33
+ transport: 'tcp';
34
+ port: number;
35
+ };
36
+ //#endregion
37
+ export { BrokerEndpoint, EngineCaptureResult, EngineProcessRunner, EngineRunOptions, SandboxHostFacts };
38
+ //# sourceMappingURL=sandboxHarness.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxHarness.d.mts","names":[],"sources":["../../src/types/sandboxHarness.ts"],"mappings":";UAEiB;;EAEf;;UAGe;EACf;EACA;;;UAIe;EACf,IAAI,iBAAiB,gBAAgB,UAAU,mBAAmB;;EAElE,QAAQ,iBAAiB,iBAAiB,QAAQ;;;UAInC;;EAEf;EACA;EACA;EACA;;EAEA;;EAEA;;;KAIU;EAAmB;EAAmB;;EAA8B;EAAkB"}
package/llms.txt ADDED
@@ -0,0 +1,11 @@
1
+ # @agimon-ai/doompi-sandbox
2
+
3
+ Package-owned guidance for Container sandbox for DoomPi launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host
4
+
5
+ ## How to use
6
+
7
+ - [Use Sandbox](./src/prompts/doompi-use-sandbox/SKILL.md): Run the package command and follow its package-specific usage guidance.
8
+
9
+ ## Resources
10
+
11
+ - [Package README](./README.md): Installation, development commands, Pi entrypoint, and extension-specific usage.
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "@agimon-ai/doompi-sandbox",
3
+ "version": "0.0.1-alpha.37",
4
+ "description": "Container sandbox for DoomPi launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host",
5
+ "keywords": [
6
+ "coding-agent",
7
+ "container-sandbox",
8
+ "doompi",
9
+ "pi-coding-agent",
10
+ "pi-extension",
11
+ "pi-package",
12
+ "typescript"
13
+ ],
14
+ "homepage": "https://agimon.ai",
15
+ "bugs": {
16
+ "url": "https://github.com/AgiFlow/doompi/issues"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Vuong Ngo",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/AgiFlow/doompi.git",
23
+ "directory": "layers/sandbox/doompi-sandbox"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "src/prompts",
28
+ "llms.txt",
29
+ "README.md",
30
+ "LICENSE",
31
+ "package.json"
32
+ ],
33
+ "type": "module",
34
+ "main": "./dist/index.cjs",
35
+ "types": "./dist/index.d.mts",
36
+ "jsnext:main": "./dist/index.mjs",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.mts",
40
+ "import": "./dist/index.mjs",
41
+ "require": "./dist/index.cjs"
42
+ },
43
+ "./sandbox-harness": {
44
+ "types": "./dist/sandboxHarness.d.mts",
45
+ "import": "./dist/sandboxHarness.mjs",
46
+ "require": "./dist/sandboxHarness.cjs"
47
+ },
48
+ "./extensions/pi": {
49
+ "types": "./dist/extensions/pi.d.mts",
50
+ "import": "./dist/extensions/pi.mjs",
51
+ "require": "./dist/extensions/pi.cjs"
52
+ },
53
+ "./package.json": "./package.json"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "dependencies": {
59
+ "@deepseek-ai/cordis": "4.0.1",
60
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.37"
61
+ },
62
+ "devDependencies": {
63
+ "@earendil-works/pi-coding-agent": "0.84.2",
64
+ "@types/node": "26.2.0",
65
+ "@vitest/coverage-v8": "4.1.11",
66
+ "tsdown": "0.22.14",
67
+ "typescript": "7.0.2",
68
+ "vitest": "4.1.11",
69
+ "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.35"
70
+ },
71
+ "peerDependencies": {
72
+ "@earendil-works/pi-coding-agent": "0.84.2"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "@earendil-works/pi-coding-agent": {
76
+ "optional": true
77
+ }
78
+ },
79
+ "engines": {
80
+ "node": ">=22.19.0"
81
+ },
82
+ "pi": {
83
+ "extensions": [
84
+ "./dist/extensions/pi.mjs"
85
+ ]
86
+ },
87
+ "scripts": {
88
+ "build": "tsdown",
89
+ "test": "vitest --run",
90
+ "typecheck": "tsc --noEmit",
91
+ "lint": "oxlint . && oxfmt . --check",
92
+ "fixcode": "oxlint . --fix && oxfmt ."
93
+ }
94
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: doompi-use-sandbox
3
+ description: 'Use @agimon-ai/doompi-sandbox: Container sandbox for DoomPi launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host'
4
+ ---
5
+
6
+ # Use Sandbox
7
+
8
+ Read the package [README](../../../README.md) for its exact installation, command, configuration, and behavior.
9
+
10
+ ## Guidance
11
+
12
+ - Use `/doom-sandbox` as the package's primary Pi entrypoint.
13
+ - Treat the package README and its linked resources as the source of truth for package-specific behavior.
14
+ - Do not require DoomPi Help for runtime activation. Help only makes this package guidance discoverable while the minor mode is active.