@agimon-ai/po-sandbox 0.0.0-alpha.13 → 0.0.0-alpha.14

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.
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  //#region src/schemas/apiContracts.ts
6
- /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
6
+ /** This server plugin contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
7
7
  const apiContracts = (0, require("@agimon-ai/po-core/apiContracts").defineApiContract)({
8
8
  version: 1,
9
9
  http: [],
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.cjs","names":["defineApiContract"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/po-core/apiContracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;;;;AAGA,MAAa,gBAAA,4CAAeA,CAAAA,CAAAA,kBAAAA,CAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
1
+ {"version":3,"file":"apiContracts.cjs","names":["defineApiContract"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/po-core/apiContracts';\n\n/** This server plugin contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;;;;AAGA,MAAa,gBAAA,4CAAeA,CAAAA,CAAAA,kBAAAA,CAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
@@ -1,5 +1,5 @@
1
1
  //#region src/schemas/apiContracts.d.ts
2
- /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
2
+ /** This server plugin contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
3
3
  export declare const apiContracts: {
4
4
  version: 1;
5
5
  protocols?: Record<string, string> | undefined;
@@ -1,6 +1,6 @@
1
1
  import { defineApiContract } from "@agimon-ai/po-core/apiContracts";
2
2
  //#region src/schemas/apiContracts.ts
3
- /** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
3
+ /** This server plugin contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */
4
4
  const apiContracts = defineApiContract({
5
5
  version: 1,
6
6
  http: [],
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/po-core/apiContracts';\n\n/** This facet contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;AAGA,MAAa,eAAe,kBAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract } from '@agimon-ai/po-core/apiContracts';\n\n/** This server plugin contributes agent tools, commands or lifecycle only, with no separate HTTP or socket surface. */\nexport const apiContracts = defineApiContract({ version: 1, http: [], sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":";;;AAGA,MAAa,eAAe,kBAAkB;CAAE,SAAS;CAAG,MAAM,CAAC;CAAG,SAAS,CAAC;CAAG,SAAS,CAAC;AAAE,CAAC"}
@@ -3,12 +3,12 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  let _agimon_ai_po_core_mcpFacet = require("@agimon-ai/po-core/mcpFacet");
6
- let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
6
+ let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
7
7
  //#region src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp.ts
8
8
  var po_use_sandbox_mcp_default = (0, _agimon_ai_po_core_mcpFacet.defineMcpSkill)({
9
9
  name: "po-use-sandbox",
10
10
  description: "Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host",
11
- read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-sandbox/SKILL.md")
11
+ read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-sandbox/SKILL.md")
12
12
  });
13
13
  //#endregion
14
14
  //#region generated/mcp.ts
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.cjs","names":["defineMcpSkill","readPackageResource","defineMcpPlugin","skillPoUseSandbox"],"sources":["../../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { defineMcpSkill } from '@agimon-ai/po-core/mcpFacet';\nimport { readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nexport default defineMcpSkill({\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type PoMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport skillPoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-sandbox',\n session: (context) => ({\n get skills(): PoMcpSessionPlugin['skills'] { return [at(skillPoUseSandbox, context)]; },\n }) satisfies PoMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;;;;;AAGA,IAAA,8BAAA,GAAeA,4BAAAA,eAAAA,CAAe;CAC5B,MAAM;CACN,aACE;CACF,aAAA,GAAYC,+BAAAA,oBAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,MAAqC,qCAAqC;AACxF,CAAC;;;ACFD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAa,OAAA,GAAMC,4BAAAA,gBAAAA,CAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,SAAuC;EAAE,OAAO,CAAC,GAAGC,4BAAmB,OAAO,CAAC;CAAG,EACxF;AACF,CAAC"}
1
+ {"version":3,"file":"mcp.cjs","names":["defineMcpSkill","readPackageResource","defineMcpPlugin","skillPoUseSandbox"],"sources":["../../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { defineMcpSkill } from '@agimon-ai/po-core/mcpFacet';\nimport { readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nexport default defineMcpSkill({\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type PoMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport skillPoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-sandbox',\n session: (context) => ({\n get skills(): PoMcpSessionPlugin['skills'] { return [at(skillPoUseSandbox, context)]; },\n }) satisfies PoMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;;;;;AAGA,IAAA,8BAAA,GAAeA,4BAAAA,eAAAA,CAAe;CAC5B,MAAM;CACN,aACE;CACF,aAAA,GAAYC,gCAAAA,oBAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,MAAqC,qCAAqC;AACxF,CAAC;;;ACFD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAa,OAAA,GAAMC,4BAAAA,gBAAAA,CAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,SAAuC;EAAE,OAAO,CAAC,GAAGC,4BAAmB,OAAO,CAAC;CAAG,EACxF;AACF,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { defineMcpPlugin, defineMcpSkill } from "@agimon-ai/po-core/mcpFacet";
2
- import { readPackageResource } from "@agimon-ai/po-core/serverFacet";
2
+ import { readPackageResource } from "@agimon-ai/po-core/serverPlugin";
3
3
  //#region src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp.ts
4
4
  var po_use_sandbox_mcp_default = defineMcpSkill({
5
5
  name: "po-use-sandbox",
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.mjs","names":["skillPoUseSandbox"],"sources":["../../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { defineMcpSkill } from '@agimon-ai/po-core/mcpFacet';\nimport { readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nexport default defineMcpSkill({\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type PoMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport skillPoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-sandbox',\n session: (context) => ({\n get skills(): PoMcpSessionPlugin['skills'] { return [at(skillPoUseSandbox, context)]; },\n }) satisfies PoMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;AAGA,IAAA,6BAAe,eAAe;CAC5B,MAAM;CACN,aACE;CACF,YAAY,oBAAoB,YAAY,KAAK,qCAAqC;AACxF,CAAC;;;ACFD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAa,MAAM,gBAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,SAAuC;EAAE,OAAO,CAAC,GAAGA,4BAAmB,OAAO,CAAC;CAAG,EACxF;AACF,CAAC"}
1
+ {"version":3,"file":"mcp.mjs","names":["skillPoUseSandbox"],"sources":["../../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { defineMcpSkill } from '@agimon-ai/po-core/mcpFacet';\nimport { readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nexport default defineMcpSkill({\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineMcpPlugin, type PoMcpSessionPlugin } from '@agimon-ai/po-core/mcpFacet';\n\nimport skillPoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/skill/po-use-sandbox.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/po-sandbox',\n session: (context) => ({\n get skills(): PoMcpSessionPlugin['skills'] { return [at(skillPoUseSandbox, context)]; },\n }) satisfies PoMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":";;;AAGA,IAAA,6BAAe,eAAe;CAC5B,MAAM;CACN,aACE;CACF,YAAY,oBAAoB,YAAY,KAAK,qCAAqC;AACxF,CAAC;;;ACFD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AAEpE,MAAa,MAAM,gBAAgB;CACjC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,SAAuC;EAAE,OAAO,CAAC,GAAGA,4BAAmB,OAAO,CAAC;CAAG,EACxF;AACF,CAAC"}
@@ -11,7 +11,7 @@ node_fs = require_sandboxBridge.__toESM(node_fs, 1);
11
11
  let node_os = require("node:os");
12
12
  node_os = require_sandboxBridge.__toESM(node_os, 1);
13
13
  let node_crypto = require("node:crypto");
14
- let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
14
+ let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
15
15
  let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
16
16
  let node_http = require("node:http");
17
17
  node_http = require_sandboxBridge.__toESM(node_http, 1);
@@ -383,7 +383,7 @@ var root_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoot)(Objec
383
383
  function createSandboxServerCommands(context) {
384
384
  const service = context.root.service;
385
385
  if (!service) return [];
386
- return [(0, _agimon_ai_po_core_serverFacet.defineCommand)({
386
+ return [(0, _agimon_ai_po_core_serverPlugin.defineCommand)({
387
387
  name: COMMAND_NAME,
388
388
  description: COMMAND_DESCRIPTION,
389
389
  async execute() {
@@ -412,7 +412,7 @@ function createSandboxContextResource(root) {
412
412
  },
413
413
  name: "po-sandbox",
414
414
  kind: "context",
415
- read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "llms.txt")
415
+ read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "llms.txt")
416
416
  };
417
417
  }
418
418
  function createSandboxSkillResource(root) {
@@ -427,7 +427,7 @@ function createSandboxSkillResource(root) {
427
427
  }
428
428
  },
429
429
  kind: "skill",
430
- read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-sandbox/SKILL.md")
430
+ read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-sandbox/SKILL.md")
431
431
  };
432
432
  }
433
433
  //#endregion
@@ -445,11 +445,12 @@ const many = (value, context) => {
445
445
  };
446
446
  /* v8 ignore next -- generated normalization branch */
447
447
  const defined = (values) => values.filter((value) => value !== void 0);
448
- const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
448
+ const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
449
449
  name: "@agimon-ai/po-sandbox",
450
- providerOverrides: (0, _agimon_ai_po_core_serverFacet.composeServerProviderOverrides)(root_server_default),
450
+ providerOverrides: (0, _agimon_ai_po_core_serverPlugin.composeServerProviderOverrides)(root_server_default),
451
+ injects: (0, _agimon_ai_po_core_extensionFile.composeRootInjects)({ session: [root_server_default] }),
451
452
  session: async (context) => {
452
- const scopeSession = await root_server_default(context);
453
+ const scopeSession = await context.scopeRoot("session", root_server_default, context);
453
454
  const contextSession = {
454
455
  ...context,
455
456
  root: scopeSession.value
@@ -470,7 +471,7 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
470
471
  }
471
472
  });
472
473
  //#endregion
473
- exports.default = facet;
474
- exports.facet = facet;
474
+ exports.default = serverPlugin;
475
+ exports.serverPlugin = serverPlugin;
475
476
 
476
477
  //# sourceMappingURL=server.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["BROKER_PROVIDERS_ENV","BROKER_CONTAINER_PORT","BROKER_ADDRESS_ENV","timingSafeEqual","https","http","randomBytes","fs","path","os","DefaultSandboxExtensionService","defineRoot","defineCommand","defineRoutedContribution","readPackageResource","defineRoutedContribution","defineResource","defineRoutedContribution","defineResource","defineServerPlugin","composeServerProviderOverrides","rootSession","composeRootHooks","commandSandbox","resourcePoSandbox","resourcePoUseSandbox"],"sources":["../../src/services/brokerProviders/index.ts","../../src/constants/sandbox.ts","../../src/services/brokerRoutes/index.ts","../../src/services/brokerServer/index.ts","../../src/services/brokerHost/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxCommands.ts","../../src/extensions/workspaces/sessions/(backend)/command/sandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxResources.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server.ts","../../generated/server.ts"],"sourcesContent":["import { BROKER_ADDRESS_ENV, BROKER_CONTAINER_PORT, BROKER_PROVIDERS_ENV, BROKER_SOCKET_ENV } from '../sandboxBridge';\n\nexport interface BrokeredProviderOverride {\n provider: string;\n baseUrl: string;\n}\n\n/**\n * Points brokered providers at whichever route the launch granted.\n *\n * Pi reads base URLs from package-internal provider data, so redirecting a\n * session means overriding the provider rather than setting an environment\n * variable. The credential is left alone: the launch already replaced it with\n * the session token the broker expects.\n *\n * A broker on a host port is addressed directly. Only a mounted socket needs\n * the loopback bridge, because no SDK can dial a socket path.\n */\nexport function brokeredProviderOverrides(\n environment: Readonly<Record<string, string | undefined>>,\n): BrokeredProviderOverride[] {\n const configured = environment[BROKER_PROVIDERS_ENV]?.trim();\n if (!configured) return [];\n const authority = environment[BROKER_SOCKET_ENV]?.trim()\n ? `127.0.0.1:${BROKER_CONTAINER_PORT}`\n : environment[BROKER_ADDRESS_ENV]?.trim();\n if (!authority) return [];\n return configured\n .split(',')\n .map((provider) => provider.trim())\n .filter((provider) => provider.length > 0)\n .map((provider) => ({ provider, baseUrl: `http://${authority}/${provider}` }));\n}\n","export const COMMAND_NAME = 'po-sandbox';\nexport const COMMAND_DESCRIPTION = 'Show sandbox container status for this session';\n\nexport const BROKER_DISABLED_ENV = 'PO_SANDBOX_BROKER';\nexport const DISABLED_VALUE = '0';\nexport const BROKER_STATUS_SOURCE = 'po-sandbox-broker';\n","export interface BrokerRoute {\n /** Pi provider name, which is also the broker's first path segment. */\n provider: string;\n /** Upstream origin plus any base path Pi's own provider data carries. */\n upstream: string;\n /** Host environment variables that may hold the real credential, in priority order. */\n hostKeyEnv: readonly string[];\n}\n\n/**\n * Providers the broker can terminate, mirroring Pi's own provider data.\n *\n * Curated rather than derived: Pi keeps base URLs in package-internal JSON that\n * carries no stability promise. A provider missing here is simply not brokered,\n * and its credential stays on the host.\n */\nconst ROUTES: readonly BrokerRoute[] = [\n { provider: 'anthropic', upstream: 'https://api.anthropic.com', hostKeyEnv: ['ANTHROPIC_API_KEY'] },\n { provider: 'openai', upstream: 'https://api.openai.com/v1', hostKeyEnv: ['OPENAI_API_KEY'] },\n { provider: 'google', upstream: 'https://generativelanguage.googleapis.com/v1beta', hostKeyEnv: ['GEMINI_API_KEY'] },\n { provider: 'groq', upstream: 'https://api.groq.com/openai/v1', hostKeyEnv: ['GROQ_API_KEY'] },\n { provider: 'xai', upstream: 'https://api.x.ai/v1', hostKeyEnv: ['XAI_API_KEY'] },\n { provider: 'openrouter', upstream: 'https://openrouter.ai/api/v1', hostKeyEnv: ['OPENROUTER_API_KEY'] },\n { provider: 'deepseek', upstream: 'https://api.deepseek.com', hostKeyEnv: ['DEEPSEEK_API_KEY'] },\n { provider: 'mistral', upstream: 'https://api.mistral.ai', hostKeyEnv: ['MISTRAL_API_KEY'] },\n { provider: 'together', upstream: 'https://api.together.ai/v1', hostKeyEnv: ['TOGETHER_API_KEY'] },\n { provider: 'cerebras', upstream: 'https://api.cerebras.ai/v1', hostKeyEnv: ['CEREBRAS_API_KEY'] },\n { provider: 'moonshotai', upstream: 'https://api.moonshot.ai/v1', hostKeyEnv: ['MOONSHOT_API_KEY'] },\n { provider: 'zai', upstream: 'https://api.z.ai/api/coding/paas/v4', hostKeyEnv: ['ZAI_API_KEY'] },\n];\n\nexport function brokerRoutes(): readonly BrokerRoute[] {\n return ROUTES;\n}\n\nexport function findBrokerRoute(provider: string): BrokerRoute | undefined {\n return ROUTES.find((route) => route.provider === provider);\n}\n\nexport interface ResolvedCredential {\n route: BrokerRoute;\n /** Environment variable the container would otherwise have received. */\n envName: string;\n value: string;\n}\n\n/** Selects the providers this host can actually broker for a session. */\nexport function resolveBrokeredCredentials(\n environment: Readonly<Record<string, string | undefined>>,\n): ResolvedCredential[] {\n const resolved: ResolvedCredential[] = [];\n for (const route of ROUTES) {\n for (const envName of route.hostKeyEnv) {\n const value = environment[envName]?.trim();\n if (value) {\n resolved.push({ route, envName, value });\n break;\n }\n }\n }\n return resolved;\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport http from 'node:http';\nimport https from 'node:https';\n\nimport type { ResolvedCredential } from '../brokerRoutes';\n\n/** Headers a provider SDK may carry its credential in. */\nconst CREDENTIAL_HEADERS = ['x-api-key', 'authorization', 'x-goog-api-key'] as const;\n/** Query parameter some Google clients use instead of a header. */\nconst CREDENTIAL_QUERY = 'key';\nconst BEARER_PREFIX = 'bearer ';\n/** Connection-scoped headers that must not cross to the upstream request. */\nconst HOP_BY_HOP = new Set([\n 'connection',\n 'keep-alive',\n 'proxy-authenticate',\n 'proxy-authorization',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n 'host',\n 'content-length',\n]);\nconst PATH_PATTERN = /^\\/([^/?]+)(.*)$/;\n\nexport interface BrokerServerOptions {\n /** Providers this session may reach, keyed by Pi provider name. */\n credentials: ReadonlyMap<string, ResolvedCredential>;\n /** Secret the container presents in place of a real credential. */\n token: string;\n /** Receives one line per rejected request, for host-side visibility. */\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to the real https transport. */\n requestUpstream?: typeof https.request;\n}\n\nfunction matchesToken(candidate: string, token: string): boolean {\n const left = Buffer.from(candidate);\n const right = Buffer.from(token);\n return left.length === right.length && timingSafeEqual(left, right);\n}\n\nfunction credentialValue(headerValue: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? headerValue.slice(BEARER_PREFIX.length) : headerValue;\n}\n\nfunction withCredential(headerValue: string, realKey: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? `Bearer ${realKey}` : realKey;\n}\n\n/**\n * Rewrites the request's credential, proving the caller holds the session token.\n *\n * Which header carries the key differs per provider SDK, so every candidate is\n * checked rather than assumed. Returns undefined when nothing presented the\n * token, which is what makes an unauthenticated caller indistinguishable from a\n * misrouted one.\n */\nfunction swapCredential(\n headers: http.IncomingHttpHeaders,\n search: URLSearchParams,\n token: string,\n realKey: string,\n): http.OutgoingHttpHeaders | undefined {\n const forwarded: http.OutgoingHttpHeaders = {};\n let authenticated = false;\n\n for (const [name, value] of Object.entries(headers)) {\n if (value === undefined || HOP_BY_HOP.has(name)) continue;\n const single = Array.isArray(value) ? value[0] : value;\n if ((CREDENTIAL_HEADERS as readonly string[]).includes(name) && single !== undefined) {\n if (!matchesToken(credentialValue(single), token)) return undefined;\n forwarded[name] = withCredential(single, realKey);\n authenticated = true;\n continue;\n }\n forwarded[name] = value;\n }\n\n const queryKey = search.get(CREDENTIAL_QUERY);\n if (queryKey !== null) {\n if (!matchesToken(queryKey, token)) return undefined;\n search.set(CREDENTIAL_QUERY, realKey);\n authenticated = true;\n }\n\n return authenticated ? forwarded : undefined;\n}\n\nfunction reject(response: http.ServerResponse, status: number, message: string): void {\n response.writeHead(status, { 'content-type': 'application/json' });\n response.end(JSON.stringify({ error: { type: 'po_broker', message } }));\n}\n\n/**\n * Terminates provider calls from a sandboxed session on the host.\n *\n * The container never holds a real credential: it presents the session token,\n * and only a request that proves possession of it is forwarded upstream with\n * the host's key attached. Bodies stream in both directions so token-by-token\n * responses are not buffered.\n */\nexport function createBrokerServer(options: BrokerServerOptions): http.Server {\n const requestUpstream = options.requestUpstream ?? https.request;\n\n return http.createServer((request, response) => {\n const match = PATH_PATTERN.exec(request.url ?? '');\n const provider = match?.[1];\n const credential = provider ? options.credentials.get(provider) : undefined;\n if (!match || !credential) {\n options.onDenied?.(`unroutable provider path ${request.url ?? ''}`);\n reject(response, 404, 'Unknown provider for this sandbox session.');\n return;\n }\n\n const target = new URL(`${credential.route.upstream}${match[2] || ''}`);\n const headers = swapCredential(request.headers, target.searchParams, options.token, credential.value);\n if (!headers) {\n options.onDenied?.(`missing or invalid session token for ${credential.route.provider}`);\n reject(response, 401, 'This sandbox session did not present its broker token.');\n return;\n }\n\n const upstream = requestUpstream(\n target,\n { method: request.method, headers: { ...headers, host: target.host } },\n (upstreamResponse) => {\n response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);\n upstreamResponse.pipe(response);\n },\n );\n upstream.on('error', (error: Error) => {\n options.onDenied?.(`upstream ${credential.route.provider} failed: ${error.message}`);\n if (!response.headersSent) reject(response, 502, 'The provider could not be reached from the host.');\n else response.destroy();\n });\n request.on('aborted', () => upstream.destroy());\n request.pipe(upstream);\n });\n}\n","import { randomBytes } from 'node:crypto';\nimport fs from 'node:fs';\nimport type http from 'node:http';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { BrokerEndpoint } from '../../types/sandboxHarness';\nimport { resolveBrokeredCredentials } from '../brokerRoutes';\nimport { createBrokerServer } from '../brokerServer';\n\nconst SOCKET_DIRECTORY_PREFIX = 'po-broker-';\nconst SOCKET_FILE_NAME = 'broker.sock';\nconst OWNER_ONLY_DIRECTORY = 0o700;\nconst TOKEN_BYTES = 32;\nconst LOOPBACK = '127.0.0.1';\nconst LINUX_PLATFORM = 'linux';\nconst EPHEMERAL_PORT = 0;\n\nexport interface RunningBroker {\n /** How a container reaches this broker. */\n endpoint: BrokerEndpoint;\n /** Secret the container presents instead of any real credential. */\n token: string;\n /** Pi provider names the session may reach. */\n providers: string[];\n /** Host environment variables whose value the container receives as the token. */\n withheldEnv: string[];\n stop(): Promise<void>;\n}\n\nexport interface StartBrokerOptions {\n environment: Readonly<Record<string, string | undefined>>;\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to this host's platform. */\n platform?: string;\n /**\n * Fixed directory to hold the socket instead of a fresh temporary one.\n *\n * A reused container keeps the mounts it was created with, so a dev\n * container has to find the socket at the same path on every launch.\n */\n socketDirectory?: string;\n /** Forces the loopback transport even where a socket would work. */\n forceLoopback?: boolean;\n}\n\n/**\n * Starts the host-side provider broker for one sandboxed session.\n *\n * Answers undefined when the host holds no brokerable credential, which keeps\n * a session that authenticates some other way on the unbrokered path instead\n * of failing it.\n */\nexport async function startBroker(options: StartBrokerOptions): Promise<RunningBroker | undefined> {\n const resolved = resolveBrokeredCredentials(options.environment);\n if (resolved.length === 0) return undefined;\n\n const token = randomBytes(TOKEN_BYTES).toString('base64url');\n const credentials = new Map(resolved.map((credential) => [credential.route.provider, credential]));\n const server = createBrokerServer({ credentials, token, onDenied: options.onDenied });\n const platform = options.platform ?? process.platform;\n\n const useSocket = platform === LINUX_PLATFORM && options.forceLoopback !== true;\n const { endpoint, dispose } = useSocket\n ? await listenOnSocket(server, options.socketDirectory)\n : await listenOnLoopback(server);\n\n return {\n endpoint,\n token,\n providers: resolved.map((credential) => credential.route.provider),\n withheldEnv: resolved.map((credential) => credential.envName),\n stop: () => stopBroker(server, dispose),\n };\n}\n\n/**\n * Native Linux shares a kernel with the container, so a bind-mounted socket\n * needs no port and is reachable as an ordinary file.\n */\nasync function listenOnSocket(\n server: http.Server,\n fixedDirectory?: string,\n): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n const socketDirectory = fixedDirectory ?? fs.mkdtempSync(path.join(os.tmpdir(), SOCKET_DIRECTORY_PREFIX));\n fs.mkdirSync(socketDirectory, { recursive: true });\n fs.chmodSync(socketDirectory, OWNER_ONLY_DIRECTORY);\n const socketPath = path.join(socketDirectory, SOCKET_FILE_NAME);\n // A previous session that died without closing leaves the node behind, and\n // bind fails on an existing path.\n fs.rmSync(socketPath, { force: true });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(socketPath, () => resolve());\n });\n return {\n endpoint: { transport: 'unix', socketDirectory },\n // A fixed directory outlives the session that borrowed it.\n dispose: () =>\n fixedDirectory\n ? fs.rmSync(socketPath, { force: true })\n : fs.rmSync(socketDirectory, { recursive: true, force: true }),\n };\n}\n\n/**\n * Everywhere else the container runs in its own virtual machine, which cannot\n * connect to a host unix socket even when the file is shared through: the\n * connect fails with ENOTSUP. Loopback keeps the broker off the network while\n * still being reachable through the engine's host gateway, and the session\n * token is what stops another local process from using it.\n */\nasync function listenOnLoopback(server: http.Server): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(EPHEMERAL_PORT, LOOPBACK, () => resolve());\n });\n const address = server.address();\n if (address === null || typeof address === 'string') throw new Error('The broker did not report a listening port.');\n return { endpoint: { transport: 'tcp', port: address.port }, dispose: () => undefined };\n}\n\nasync function stopBroker(server: http.Server, dispose: () => void): Promise<void> {\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n // An in-flight provider stream would otherwise hold the listener open past\n // the session that owns it.\n server.closeAllConnections();\n });\n dispose();\n}\n","import type { PoHeadlessActivity } from '@agimon-ai/po-core/headless';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { BROKER_DISABLED_ENV, BROKER_STATUS_SOURCE, DISABLED_VALUE } from '../../../../../constants/sandbox';\nimport { startBroker, type RunningBroker } from '../../../../../services/brokerHost';\nimport { DefaultSandboxExtensionService } from '../../../../../services/extensionService';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerRoot({ agent }: PoServerPluginContext) {\n if (!agent) return { value: {} as SandboxServerScope };\n const service = new DefaultSandboxExtensionService(agent.context.environment);\n let broker: RunningBroker | undefined;\n const activity: PoHeadlessActivity = {\n name: BROKER_STATUS_SOURCE,\n async start(execution) {\n if (execution.environment[BROKER_DISABLED_ENV] === DISABLED_VALUE) return () => undefined;\n const started = await startBroker({\n environment: execution.environment,\n onDenied: (reason) => {\n void execution.client.notify({\n title: 'Po sandbox broker',\n body: `Broker refused a call: ${reason}`,\n level: 'warning',\n });\n },\n });\n broker = started;\n if (started === undefined) return () => undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, `provider broker: ${started.providers.join(', ')}`);\n return async () => {\n if (broker !== started) return;\n broker = undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, undefined);\n await started.stop();\n };\n },\n };\n return { value: { service }, activities: [activity] };\n}\n","import { defineRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerProviderOverrides } from '@agimon-ai/po-core/serverFacet';\n\nimport { brokeredProviderOverrides } from '../../../../services/brokerProviders';\nimport { createSandboxServerRoot } from './_lib/serverRoot';\n\nexport default defineRoot(\n Object.assign(createSandboxServerRoot, {\n providerOverrides: (({ environment }) =>\n brokeredProviderOverrides(environment).map(({ provider, baseUrl }) => ({\n name: provider,\n baseUrl,\n }))) satisfies PoServerProviderOverrides,\n }),\n);\n","import type { WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport { defineCommand } from '@agimon-ai/po-core/serverFacet';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { COMMAND_DESCRIPTION, COMMAND_NAME } from '../../../../../constants/sandbox';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerCommands(context: WithRoot<PoServerPluginContext, SandboxServerScope>) {\n const service = context.root.service;\n if (!service) return [];\n return [\n defineCommand({\n name: COMMAND_NAME,\n description: COMMAND_DESCRIPTION,\n async execute() {\n const result = await service.execute();\n await context.agent?.context.client.notify({ body: result.message, level: result.level });\n },\n }),\n ];\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createSandboxServerCommands } from '../_lib/sandboxCommands';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PoServerPluginContext, SandboxServerScope>) => createSandboxServerCommands(context),\n { cardinality: 'many' },\n);\n","import type { PoHeadlessResource } from '@agimon-ai/po-core/headless';\nimport { readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxContextResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n // The package index is Help-catalog material, not standing instruction. The Pi\n // facet has always routed it through the Help service; this is the server's gate.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'po-sandbox',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n };\n}\n\nexport function createSandboxSkillResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n name: 'po-use-sandbox',\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n };\n}\n\nexport function createSandboxHelpResource(moduleUrl: string) {\n return {\n source: '@agimon-ai/po-sandbox',\n moduleUrl,\n skills: [\n {\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n },\n ],\n };\n}\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createSandboxContextResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxContextResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createSandboxSkillResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxSkillResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport commandSandbox from '../src/extensions/workspaces/sessions/(backend)/command/sandbox.server';\nimport resourcePoSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server';\nimport resourcePoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/po-sandbox',\n providerOverrides: composeServerProviderOverrides(rootSession),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PoServerSessionPlugin['commands'] { return [...many(commandSandbox, contextSession)]; },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoSandbox, contextSession), at(resourcePoUseSandbox, contextSession)]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":["BROKER_PROVIDERS_ENV","BROKER_CONTAINER_PORT","BROKER_ADDRESS_ENV","timingSafeEqual","https","http","randomBytes","fs","path","os","DefaultSandboxExtensionService","defineRoot","defineCommand","defineRoutedContribution","readPackageResource","defineRoutedContribution","defineResource","defineRoutedContribution","defineResource","defineServerPlugin","composeServerProviderOverrides","rootSession","composeRootInjects","composeRootHooks","commandSandbox","resourcePoSandbox","resourcePoUseSandbox"],"sources":["../../src/services/brokerProviders/index.ts","../../src/constants/sandbox.ts","../../src/services/brokerRoutes/index.ts","../../src/services/brokerServer/index.ts","../../src/services/brokerHost/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxCommands.ts","../../src/extensions/workspaces/sessions/(backend)/command/sandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxResources.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server.ts","../../generated/server.ts"],"sourcesContent":["import { BROKER_ADDRESS_ENV, BROKER_CONTAINER_PORT, BROKER_PROVIDERS_ENV, BROKER_SOCKET_ENV } from '../sandboxBridge';\n\nexport interface BrokeredProviderOverride {\n provider: string;\n baseUrl: string;\n}\n\n/**\n * Points brokered providers at whichever route the launch granted.\n *\n * Pi reads base URLs from package-internal provider data, so redirecting a\n * session means overriding the provider rather than setting an environment\n * variable. The credential is left alone: the launch already replaced it with\n * the session token the broker expects.\n *\n * A broker on a host port is addressed directly. Only a mounted socket needs\n * the loopback bridge, because no SDK can dial a socket path.\n */\nexport function brokeredProviderOverrides(\n environment: Readonly<Record<string, string | undefined>>,\n): BrokeredProviderOverride[] {\n const configured = environment[BROKER_PROVIDERS_ENV]?.trim();\n if (!configured) return [];\n const authority = environment[BROKER_SOCKET_ENV]?.trim()\n ? `127.0.0.1:${BROKER_CONTAINER_PORT}`\n : environment[BROKER_ADDRESS_ENV]?.trim();\n if (!authority) return [];\n return configured\n .split(',')\n .map((provider) => provider.trim())\n .filter((provider) => provider.length > 0)\n .map((provider) => ({ provider, baseUrl: `http://${authority}/${provider}` }));\n}\n","export const COMMAND_NAME = 'po-sandbox';\nexport const COMMAND_DESCRIPTION = 'Show sandbox container status for this session';\n\nexport const BROKER_DISABLED_ENV = 'PO_SANDBOX_BROKER';\nexport const DISABLED_VALUE = '0';\nexport const BROKER_STATUS_SOURCE = 'po-sandbox-broker';\n","export interface BrokerRoute {\n /** Pi provider name, which is also the broker's first path segment. */\n provider: string;\n /** Upstream origin plus any base path Pi's own provider data carries. */\n upstream: string;\n /** Host environment variables that may hold the real credential, in priority order. */\n hostKeyEnv: readonly string[];\n}\n\n/**\n * Providers the broker can terminate, mirroring Pi's own provider data.\n *\n * Curated rather than derived: Pi keeps base URLs in package-internal JSON that\n * carries no stability promise. A provider missing here is simply not brokered,\n * and its credential stays on the host.\n */\nconst ROUTES: readonly BrokerRoute[] = [\n { provider: 'anthropic', upstream: 'https://api.anthropic.com', hostKeyEnv: ['ANTHROPIC_API_KEY'] },\n { provider: 'openai', upstream: 'https://api.openai.com/v1', hostKeyEnv: ['OPENAI_API_KEY'] },\n { provider: 'google', upstream: 'https://generativelanguage.googleapis.com/v1beta', hostKeyEnv: ['GEMINI_API_KEY'] },\n { provider: 'groq', upstream: 'https://api.groq.com/openai/v1', hostKeyEnv: ['GROQ_API_KEY'] },\n { provider: 'xai', upstream: 'https://api.x.ai/v1', hostKeyEnv: ['XAI_API_KEY'] },\n { provider: 'openrouter', upstream: 'https://openrouter.ai/api/v1', hostKeyEnv: ['OPENROUTER_API_KEY'] },\n { provider: 'deepseek', upstream: 'https://api.deepseek.com', hostKeyEnv: ['DEEPSEEK_API_KEY'] },\n { provider: 'mistral', upstream: 'https://api.mistral.ai', hostKeyEnv: ['MISTRAL_API_KEY'] },\n { provider: 'together', upstream: 'https://api.together.ai/v1', hostKeyEnv: ['TOGETHER_API_KEY'] },\n { provider: 'cerebras', upstream: 'https://api.cerebras.ai/v1', hostKeyEnv: ['CEREBRAS_API_KEY'] },\n { provider: 'moonshotai', upstream: 'https://api.moonshot.ai/v1', hostKeyEnv: ['MOONSHOT_API_KEY'] },\n { provider: 'zai', upstream: 'https://api.z.ai/api/coding/paas/v4', hostKeyEnv: ['ZAI_API_KEY'] },\n];\n\nexport function brokerRoutes(): readonly BrokerRoute[] {\n return ROUTES;\n}\n\nexport function findBrokerRoute(provider: string): BrokerRoute | undefined {\n return ROUTES.find((route) => route.provider === provider);\n}\n\nexport interface ResolvedCredential {\n route: BrokerRoute;\n /** Environment variable the container would otherwise have received. */\n envName: string;\n value: string;\n}\n\n/** Selects the providers this host can actually broker for a session. */\nexport function resolveBrokeredCredentials(\n environment: Readonly<Record<string, string | undefined>>,\n): ResolvedCredential[] {\n const resolved: ResolvedCredential[] = [];\n for (const route of ROUTES) {\n for (const envName of route.hostKeyEnv) {\n const value = environment[envName]?.trim();\n if (value) {\n resolved.push({ route, envName, value });\n break;\n }\n }\n }\n return resolved;\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport http from 'node:http';\nimport https from 'node:https';\n\nimport type { ResolvedCredential } from '../brokerRoutes';\n\n/** Headers a provider SDK may carry its credential in. */\nconst CREDENTIAL_HEADERS = ['x-api-key', 'authorization', 'x-goog-api-key'] as const;\n/** Query parameter some Google clients use instead of a header. */\nconst CREDENTIAL_QUERY = 'key';\nconst BEARER_PREFIX = 'bearer ';\n/** Connection-scoped headers that must not cross to the upstream request. */\nconst HOP_BY_HOP = new Set([\n 'connection',\n 'keep-alive',\n 'proxy-authenticate',\n 'proxy-authorization',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n 'host',\n 'content-length',\n]);\nconst PATH_PATTERN = /^\\/([^/?]+)(.*)$/;\n\nexport interface BrokerServerOptions {\n /** Providers this session may reach, keyed by Pi provider name. */\n credentials: ReadonlyMap<string, ResolvedCredential>;\n /** Secret the container presents in place of a real credential. */\n token: string;\n /** Receives one line per rejected request, for host-side visibility. */\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to the real https transport. */\n requestUpstream?: typeof https.request;\n}\n\nfunction matchesToken(candidate: string, token: string): boolean {\n const left = Buffer.from(candidate);\n const right = Buffer.from(token);\n return left.length === right.length && timingSafeEqual(left, right);\n}\n\nfunction credentialValue(headerValue: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? headerValue.slice(BEARER_PREFIX.length) : headerValue;\n}\n\nfunction withCredential(headerValue: string, realKey: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? `Bearer ${realKey}` : realKey;\n}\n\n/**\n * Rewrites the request's credential, proving the caller holds the session token.\n *\n * Which header carries the key differs per provider SDK, so every candidate is\n * checked rather than assumed. Returns undefined when nothing presented the\n * token, which is what makes an unauthenticated caller indistinguishable from a\n * misrouted one.\n */\nfunction swapCredential(\n headers: http.IncomingHttpHeaders,\n search: URLSearchParams,\n token: string,\n realKey: string,\n): http.OutgoingHttpHeaders | undefined {\n const forwarded: http.OutgoingHttpHeaders = {};\n let authenticated = false;\n\n for (const [name, value] of Object.entries(headers)) {\n if (value === undefined || HOP_BY_HOP.has(name)) continue;\n const single = Array.isArray(value) ? value[0] : value;\n if ((CREDENTIAL_HEADERS as readonly string[]).includes(name) && single !== undefined) {\n if (!matchesToken(credentialValue(single), token)) return undefined;\n forwarded[name] = withCredential(single, realKey);\n authenticated = true;\n continue;\n }\n forwarded[name] = value;\n }\n\n const queryKey = search.get(CREDENTIAL_QUERY);\n if (queryKey !== null) {\n if (!matchesToken(queryKey, token)) return undefined;\n search.set(CREDENTIAL_QUERY, realKey);\n authenticated = true;\n }\n\n return authenticated ? forwarded : undefined;\n}\n\nfunction reject(response: http.ServerResponse, status: number, message: string): void {\n response.writeHead(status, { 'content-type': 'application/json' });\n response.end(JSON.stringify({ error: { type: 'po_broker', message } }));\n}\n\n/**\n * Terminates provider calls from a sandboxed session on the host.\n *\n * The container never holds a real credential: it presents the session token,\n * and only a request that proves possession of it is forwarded upstream with\n * the host's key attached. Bodies stream in both directions so token-by-token\n * responses are not buffered.\n */\nexport function createBrokerServer(options: BrokerServerOptions): http.Server {\n const requestUpstream = options.requestUpstream ?? https.request;\n\n return http.createServer((request, response) => {\n const match = PATH_PATTERN.exec(request.url ?? '');\n const provider = match?.[1];\n const credential = provider ? options.credentials.get(provider) : undefined;\n if (!match || !credential) {\n options.onDenied?.(`unroutable provider path ${request.url ?? ''}`);\n reject(response, 404, 'Unknown provider for this sandbox session.');\n return;\n }\n\n const target = new URL(`${credential.route.upstream}${match[2] || ''}`);\n const headers = swapCredential(request.headers, target.searchParams, options.token, credential.value);\n if (!headers) {\n options.onDenied?.(`missing or invalid session token for ${credential.route.provider}`);\n reject(response, 401, 'This sandbox session did not present its broker token.');\n return;\n }\n\n const upstream = requestUpstream(\n target,\n { method: request.method, headers: { ...headers, host: target.host } },\n (upstreamResponse) => {\n response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);\n upstreamResponse.pipe(response);\n },\n );\n upstream.on('error', (error: Error) => {\n options.onDenied?.(`upstream ${credential.route.provider} failed: ${error.message}`);\n if (!response.headersSent) reject(response, 502, 'The provider could not be reached from the host.');\n else response.destroy();\n });\n request.on('aborted', () => upstream.destroy());\n request.pipe(upstream);\n });\n}\n","import { randomBytes } from 'node:crypto';\nimport fs from 'node:fs';\nimport type http from 'node:http';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { BrokerEndpoint } from '../../types/sandboxHarness';\nimport { resolveBrokeredCredentials } from '../brokerRoutes';\nimport { createBrokerServer } from '../brokerServer';\n\nconst SOCKET_DIRECTORY_PREFIX = 'po-broker-';\nconst SOCKET_FILE_NAME = 'broker.sock';\nconst OWNER_ONLY_DIRECTORY = 0o700;\nconst TOKEN_BYTES = 32;\nconst LOOPBACK = '127.0.0.1';\nconst LINUX_PLATFORM = 'linux';\nconst EPHEMERAL_PORT = 0;\n\nexport interface RunningBroker {\n /** How a container reaches this broker. */\n endpoint: BrokerEndpoint;\n /** Secret the container presents instead of any real credential. */\n token: string;\n /** Pi provider names the session may reach. */\n providers: string[];\n /** Host environment variables whose value the container receives as the token. */\n withheldEnv: string[];\n stop(): Promise<void>;\n}\n\nexport interface StartBrokerOptions {\n environment: Readonly<Record<string, string | undefined>>;\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to this host's platform. */\n platform?: string;\n /**\n * Fixed directory to hold the socket instead of a fresh temporary one.\n *\n * A reused container keeps the mounts it was created with, so a dev\n * container has to find the socket at the same path on every launch.\n */\n socketDirectory?: string;\n /** Forces the loopback transport even where a socket would work. */\n forceLoopback?: boolean;\n}\n\n/**\n * Starts the host-side provider broker for one sandboxed session.\n *\n * Answers undefined when the host holds no brokerable credential, which keeps\n * a session that authenticates some other way on the unbrokered path instead\n * of failing it.\n */\nexport async function startBroker(options: StartBrokerOptions): Promise<RunningBroker | undefined> {\n const resolved = resolveBrokeredCredentials(options.environment);\n if (resolved.length === 0) return undefined;\n\n const token = randomBytes(TOKEN_BYTES).toString('base64url');\n const credentials = new Map(resolved.map((credential) => [credential.route.provider, credential]));\n const server = createBrokerServer({ credentials, token, onDenied: options.onDenied });\n const platform = options.platform ?? process.platform;\n\n const useSocket = platform === LINUX_PLATFORM && options.forceLoopback !== true;\n const { endpoint, dispose } = useSocket\n ? await listenOnSocket(server, options.socketDirectory)\n : await listenOnLoopback(server);\n\n return {\n endpoint,\n token,\n providers: resolved.map((credential) => credential.route.provider),\n withheldEnv: resolved.map((credential) => credential.envName),\n stop: () => stopBroker(server, dispose),\n };\n}\n\n/**\n * Native Linux shares a kernel with the container, so a bind-mounted socket\n * needs no port and is reachable as an ordinary file.\n */\nasync function listenOnSocket(\n server: http.Server,\n fixedDirectory?: string,\n): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n const socketDirectory = fixedDirectory ?? fs.mkdtempSync(path.join(os.tmpdir(), SOCKET_DIRECTORY_PREFIX));\n fs.mkdirSync(socketDirectory, { recursive: true });\n fs.chmodSync(socketDirectory, OWNER_ONLY_DIRECTORY);\n const socketPath = path.join(socketDirectory, SOCKET_FILE_NAME);\n // A previous session that died without closing leaves the node behind, and\n // bind fails on an existing path.\n fs.rmSync(socketPath, { force: true });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(socketPath, () => resolve());\n });\n return {\n endpoint: { transport: 'unix', socketDirectory },\n // A fixed directory outlives the session that borrowed it.\n dispose: () =>\n fixedDirectory\n ? fs.rmSync(socketPath, { force: true })\n : fs.rmSync(socketDirectory, { recursive: true, force: true }),\n };\n}\n\n/**\n * Everywhere else the container runs in its own virtual machine, which cannot\n * connect to a host unix socket even when the file is shared through: the\n * connect fails with ENOTSUP. Loopback keeps the broker off the network while\n * still being reachable through the engine's host gateway, and the session\n * token is what stops another local process from using it.\n */\nasync function listenOnLoopback(server: http.Server): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(EPHEMERAL_PORT, LOOPBACK, () => resolve());\n });\n const address = server.address();\n if (address === null || typeof address === 'string') throw new Error('The broker did not report a listening port.');\n return { endpoint: { transport: 'tcp', port: address.port }, dispose: () => undefined };\n}\n\nasync function stopBroker(server: http.Server, dispose: () => void): Promise<void> {\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n // An in-flight provider stream would otherwise hold the listener open past\n // the session that owns it.\n server.closeAllConnections();\n });\n dispose();\n}\n","import type { PoHeadlessActivity } from '@agimon-ai/po-core/headless';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { BROKER_DISABLED_ENV, BROKER_STATUS_SOURCE, DISABLED_VALUE } from '../../../../../constants/sandbox';\nimport { startBroker, type RunningBroker } from '../../../../../services/brokerHost';\nimport { DefaultSandboxExtensionService } from '../../../../../services/extensionService';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerRoot({ agent }: PoServerPluginContext) {\n if (!agent) return { value: {} as SandboxServerScope };\n const service = new DefaultSandboxExtensionService(agent.context.environment);\n let broker: RunningBroker | undefined;\n const activity: PoHeadlessActivity = {\n name: BROKER_STATUS_SOURCE,\n async start(execution) {\n if (execution.environment[BROKER_DISABLED_ENV] === DISABLED_VALUE) return () => undefined;\n const started = await startBroker({\n environment: execution.environment,\n onDenied: (reason) => {\n void execution.client.notify({\n title: 'Po sandbox broker',\n body: `Broker refused a call: ${reason}`,\n level: 'warning',\n });\n },\n });\n broker = started;\n if (started === undefined) return () => undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, `provider broker: ${started.providers.join(', ')}`);\n return async () => {\n if (broker !== started) return;\n broker = undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, undefined);\n await started.stop();\n };\n },\n };\n return { value: { service }, activities: [activity] };\n}\n","import { defineRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\n\nimport { brokeredProviderOverrides } from '../../../../services/brokerProviders';\nimport { createSandboxServerRoot } from './_lib/serverRoot';\n\nexport default defineRoot(\n Object.assign(createSandboxServerRoot, {\n providerOverrides: (({ environment }) =>\n brokeredProviderOverrides(environment).map(({ provider, baseUrl }) => ({\n name: provider,\n baseUrl,\n }))) satisfies PoServerProviderOverrides,\n }),\n);\n","import type { WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport { defineCommand } from '@agimon-ai/po-core/serverPlugin';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { COMMAND_DESCRIPTION, COMMAND_NAME } from '../../../../../constants/sandbox';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerCommands(context: WithRoot<PoServerPluginContext, SandboxServerScope>) {\n const service = context.root.service;\n if (!service) return [];\n return [\n defineCommand({\n name: COMMAND_NAME,\n description: COMMAND_DESCRIPTION,\n async execute() {\n const result = await service.execute();\n await context.agent?.context.client.notify({ body: result.message, level: result.level });\n },\n }),\n ];\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { createSandboxServerCommands } from '../_lib/sandboxCommands';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PoServerPluginContext, SandboxServerScope>) => createSandboxServerCommands(context),\n { cardinality: 'many' },\n);\n","import type { PoHeadlessResource } from '@agimon-ai/po-core/headless';\nimport { readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxContextResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n // The package index is Help-catalog material, not standing instruction. The Pi\n // extension has always routed it through the Help service; this is the server's gate.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'po-sandbox',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n };\n}\n\nexport function createSandboxSkillResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n name: 'po-use-sandbox',\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n };\n}\n\nexport function createSandboxHelpResource(moduleUrl: string) {\n return {\n source: '@agimon-ai/po-sandbox',\n moduleUrl,\n skills: [\n {\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n },\n ],\n };\n}\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { createSandboxContextResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxContextResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { createSandboxSkillResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxSkillResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\nimport { composeRootHooks, composeRootInjects } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport commandSandbox from '../src/extensions/workspaces/sessions/(backend)/command/sandbox.server';\nimport resourcePoSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server';\nimport resourcePoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-sandbox',\n providerOverrides: composeServerProviderOverrides(rootSession),\n injects: composeRootInjects({ session: [rootSession] }),\n session: async (context) => {\n const scopeSession = await context.scopeRoot('session', rootSession, context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PoServerSessionPlugin['commands'] { return [...many(commandSandbox, contextSession)]; },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoSandbox, contextSession), at(resourcePoUseSandbox, contextSession)]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region generated/server.d.ts
2
- export declare const facet: import("@agimon-ai/po-core/serverFacet").PoServerFacet;
2
+ export declare const serverPlugin: import("@agimon-ai/po-core/serverPlugin").PoServerPlugin;
3
3
  //#endregion
4
- export { facet as default };
4
+ export { serverPlugin as default };
5
5
  //# sourceMappingURL=server.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../../generated/server.ts"],"mappings":";qBAsBa,gDAAK"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../../generated/server.ts"],"mappings":";qBAsBa,wDAAY"}
@@ -4,8 +4,8 @@ import path from "node:path";
4
4
  import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import { randomBytes, timingSafeEqual } from "node:crypto";
7
- import { composeServerProviderOverrides, defineCommand, defineServerPlugin, readPackageResource } from "@agimon-ai/po-core/serverFacet";
8
- import { composeRootHooks, defineResource, defineRoot, defineRoutedContribution } from "@agimon-ai/po-core/extensionFile";
7
+ import { composeServerProviderOverrides, defineCommand, defineServerPlugin, readPackageResource } from "@agimon-ai/po-core/serverPlugin";
8
+ import { composeRootHooks, composeRootInjects, defineResource, defineRoot, defineRoutedContribution } from "@agimon-ai/po-core/extensionFile";
9
9
  import http from "node:http";
10
10
  import https from "node:https";
11
11
  //#region src/services/brokerProviders/index.ts
@@ -436,11 +436,12 @@ const many = (value, context) => {
436
436
  };
437
437
  /* v8 ignore next -- generated normalization branch */
438
438
  const defined = (values) => values.filter((value) => value !== void 0);
439
- const facet = defineServerPlugin({
439
+ const serverPlugin = defineServerPlugin({
440
440
  name: "@agimon-ai/po-sandbox",
441
441
  providerOverrides: composeServerProviderOverrides(root_server_default),
442
+ injects: composeRootInjects({ session: [root_server_default] }),
442
443
  session: async (context) => {
443
- const scopeSession = await root_server_default(context);
444
+ const scopeSession = await context.scopeRoot("session", root_server_default, context);
444
445
  const contextSession = {
445
446
  ...context,
446
447
  root: scopeSession.value
@@ -461,6 +462,6 @@ const facet = defineServerPlugin({
461
462
  }
462
463
  });
463
464
  //#endregion
464
- export { facet as default, facet };
465
+ export { serverPlugin as default, serverPlugin };
465
466
 
466
467
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":["rootSession","commandSandbox","resourcePoSandbox","resourcePoUseSandbox"],"sources":["../../src/services/brokerProviders/index.ts","../../src/constants/sandbox.ts","../../src/services/brokerRoutes/index.ts","../../src/services/brokerServer/index.ts","../../src/services/brokerHost/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxCommands.ts","../../src/extensions/workspaces/sessions/(backend)/command/sandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxResources.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server.ts","../../generated/server.ts"],"sourcesContent":["import { BROKER_ADDRESS_ENV, BROKER_CONTAINER_PORT, BROKER_PROVIDERS_ENV, BROKER_SOCKET_ENV } from '../sandboxBridge';\n\nexport interface BrokeredProviderOverride {\n provider: string;\n baseUrl: string;\n}\n\n/**\n * Points brokered providers at whichever route the launch granted.\n *\n * Pi reads base URLs from package-internal provider data, so redirecting a\n * session means overriding the provider rather than setting an environment\n * variable. The credential is left alone: the launch already replaced it with\n * the session token the broker expects.\n *\n * A broker on a host port is addressed directly. Only a mounted socket needs\n * the loopback bridge, because no SDK can dial a socket path.\n */\nexport function brokeredProviderOverrides(\n environment: Readonly<Record<string, string | undefined>>,\n): BrokeredProviderOverride[] {\n const configured = environment[BROKER_PROVIDERS_ENV]?.trim();\n if (!configured) return [];\n const authority = environment[BROKER_SOCKET_ENV]?.trim()\n ? `127.0.0.1:${BROKER_CONTAINER_PORT}`\n : environment[BROKER_ADDRESS_ENV]?.trim();\n if (!authority) return [];\n return configured\n .split(',')\n .map((provider) => provider.trim())\n .filter((provider) => provider.length > 0)\n .map((provider) => ({ provider, baseUrl: `http://${authority}/${provider}` }));\n}\n","export const COMMAND_NAME = 'po-sandbox';\nexport const COMMAND_DESCRIPTION = 'Show sandbox container status for this session';\n\nexport const BROKER_DISABLED_ENV = 'PO_SANDBOX_BROKER';\nexport const DISABLED_VALUE = '0';\nexport const BROKER_STATUS_SOURCE = 'po-sandbox-broker';\n","export interface BrokerRoute {\n /** Pi provider name, which is also the broker's first path segment. */\n provider: string;\n /** Upstream origin plus any base path Pi's own provider data carries. */\n upstream: string;\n /** Host environment variables that may hold the real credential, in priority order. */\n hostKeyEnv: readonly string[];\n}\n\n/**\n * Providers the broker can terminate, mirroring Pi's own provider data.\n *\n * Curated rather than derived: Pi keeps base URLs in package-internal JSON that\n * carries no stability promise. A provider missing here is simply not brokered,\n * and its credential stays on the host.\n */\nconst ROUTES: readonly BrokerRoute[] = [\n { provider: 'anthropic', upstream: 'https://api.anthropic.com', hostKeyEnv: ['ANTHROPIC_API_KEY'] },\n { provider: 'openai', upstream: 'https://api.openai.com/v1', hostKeyEnv: ['OPENAI_API_KEY'] },\n { provider: 'google', upstream: 'https://generativelanguage.googleapis.com/v1beta', hostKeyEnv: ['GEMINI_API_KEY'] },\n { provider: 'groq', upstream: 'https://api.groq.com/openai/v1', hostKeyEnv: ['GROQ_API_KEY'] },\n { provider: 'xai', upstream: 'https://api.x.ai/v1', hostKeyEnv: ['XAI_API_KEY'] },\n { provider: 'openrouter', upstream: 'https://openrouter.ai/api/v1', hostKeyEnv: ['OPENROUTER_API_KEY'] },\n { provider: 'deepseek', upstream: 'https://api.deepseek.com', hostKeyEnv: ['DEEPSEEK_API_KEY'] },\n { provider: 'mistral', upstream: 'https://api.mistral.ai', hostKeyEnv: ['MISTRAL_API_KEY'] },\n { provider: 'together', upstream: 'https://api.together.ai/v1', hostKeyEnv: ['TOGETHER_API_KEY'] },\n { provider: 'cerebras', upstream: 'https://api.cerebras.ai/v1', hostKeyEnv: ['CEREBRAS_API_KEY'] },\n { provider: 'moonshotai', upstream: 'https://api.moonshot.ai/v1', hostKeyEnv: ['MOONSHOT_API_KEY'] },\n { provider: 'zai', upstream: 'https://api.z.ai/api/coding/paas/v4', hostKeyEnv: ['ZAI_API_KEY'] },\n];\n\nexport function brokerRoutes(): readonly BrokerRoute[] {\n return ROUTES;\n}\n\nexport function findBrokerRoute(provider: string): BrokerRoute | undefined {\n return ROUTES.find((route) => route.provider === provider);\n}\n\nexport interface ResolvedCredential {\n route: BrokerRoute;\n /** Environment variable the container would otherwise have received. */\n envName: string;\n value: string;\n}\n\n/** Selects the providers this host can actually broker for a session. */\nexport function resolveBrokeredCredentials(\n environment: Readonly<Record<string, string | undefined>>,\n): ResolvedCredential[] {\n const resolved: ResolvedCredential[] = [];\n for (const route of ROUTES) {\n for (const envName of route.hostKeyEnv) {\n const value = environment[envName]?.trim();\n if (value) {\n resolved.push({ route, envName, value });\n break;\n }\n }\n }\n return resolved;\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport http from 'node:http';\nimport https from 'node:https';\n\nimport type { ResolvedCredential } from '../brokerRoutes';\n\n/** Headers a provider SDK may carry its credential in. */\nconst CREDENTIAL_HEADERS = ['x-api-key', 'authorization', 'x-goog-api-key'] as const;\n/** Query parameter some Google clients use instead of a header. */\nconst CREDENTIAL_QUERY = 'key';\nconst BEARER_PREFIX = 'bearer ';\n/** Connection-scoped headers that must not cross to the upstream request. */\nconst HOP_BY_HOP = new Set([\n 'connection',\n 'keep-alive',\n 'proxy-authenticate',\n 'proxy-authorization',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n 'host',\n 'content-length',\n]);\nconst PATH_PATTERN = /^\\/([^/?]+)(.*)$/;\n\nexport interface BrokerServerOptions {\n /** Providers this session may reach, keyed by Pi provider name. */\n credentials: ReadonlyMap<string, ResolvedCredential>;\n /** Secret the container presents in place of a real credential. */\n token: string;\n /** Receives one line per rejected request, for host-side visibility. */\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to the real https transport. */\n requestUpstream?: typeof https.request;\n}\n\nfunction matchesToken(candidate: string, token: string): boolean {\n const left = Buffer.from(candidate);\n const right = Buffer.from(token);\n return left.length === right.length && timingSafeEqual(left, right);\n}\n\nfunction credentialValue(headerValue: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? headerValue.slice(BEARER_PREFIX.length) : headerValue;\n}\n\nfunction withCredential(headerValue: string, realKey: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? `Bearer ${realKey}` : realKey;\n}\n\n/**\n * Rewrites the request's credential, proving the caller holds the session token.\n *\n * Which header carries the key differs per provider SDK, so every candidate is\n * checked rather than assumed. Returns undefined when nothing presented the\n * token, which is what makes an unauthenticated caller indistinguishable from a\n * misrouted one.\n */\nfunction swapCredential(\n headers: http.IncomingHttpHeaders,\n search: URLSearchParams,\n token: string,\n realKey: string,\n): http.OutgoingHttpHeaders | undefined {\n const forwarded: http.OutgoingHttpHeaders = {};\n let authenticated = false;\n\n for (const [name, value] of Object.entries(headers)) {\n if (value === undefined || HOP_BY_HOP.has(name)) continue;\n const single = Array.isArray(value) ? value[0] : value;\n if ((CREDENTIAL_HEADERS as readonly string[]).includes(name) && single !== undefined) {\n if (!matchesToken(credentialValue(single), token)) return undefined;\n forwarded[name] = withCredential(single, realKey);\n authenticated = true;\n continue;\n }\n forwarded[name] = value;\n }\n\n const queryKey = search.get(CREDENTIAL_QUERY);\n if (queryKey !== null) {\n if (!matchesToken(queryKey, token)) return undefined;\n search.set(CREDENTIAL_QUERY, realKey);\n authenticated = true;\n }\n\n return authenticated ? forwarded : undefined;\n}\n\nfunction reject(response: http.ServerResponse, status: number, message: string): void {\n response.writeHead(status, { 'content-type': 'application/json' });\n response.end(JSON.stringify({ error: { type: 'po_broker', message } }));\n}\n\n/**\n * Terminates provider calls from a sandboxed session on the host.\n *\n * The container never holds a real credential: it presents the session token,\n * and only a request that proves possession of it is forwarded upstream with\n * the host's key attached. Bodies stream in both directions so token-by-token\n * responses are not buffered.\n */\nexport function createBrokerServer(options: BrokerServerOptions): http.Server {\n const requestUpstream = options.requestUpstream ?? https.request;\n\n return http.createServer((request, response) => {\n const match = PATH_PATTERN.exec(request.url ?? '');\n const provider = match?.[1];\n const credential = provider ? options.credentials.get(provider) : undefined;\n if (!match || !credential) {\n options.onDenied?.(`unroutable provider path ${request.url ?? ''}`);\n reject(response, 404, 'Unknown provider for this sandbox session.');\n return;\n }\n\n const target = new URL(`${credential.route.upstream}${match[2] || ''}`);\n const headers = swapCredential(request.headers, target.searchParams, options.token, credential.value);\n if (!headers) {\n options.onDenied?.(`missing or invalid session token for ${credential.route.provider}`);\n reject(response, 401, 'This sandbox session did not present its broker token.');\n return;\n }\n\n const upstream = requestUpstream(\n target,\n { method: request.method, headers: { ...headers, host: target.host } },\n (upstreamResponse) => {\n response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);\n upstreamResponse.pipe(response);\n },\n );\n upstream.on('error', (error: Error) => {\n options.onDenied?.(`upstream ${credential.route.provider} failed: ${error.message}`);\n if (!response.headersSent) reject(response, 502, 'The provider could not be reached from the host.');\n else response.destroy();\n });\n request.on('aborted', () => upstream.destroy());\n request.pipe(upstream);\n });\n}\n","import { randomBytes } from 'node:crypto';\nimport fs from 'node:fs';\nimport type http from 'node:http';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { BrokerEndpoint } from '../../types/sandboxHarness';\nimport { resolveBrokeredCredentials } from '../brokerRoutes';\nimport { createBrokerServer } from '../brokerServer';\n\nconst SOCKET_DIRECTORY_PREFIX = 'po-broker-';\nconst SOCKET_FILE_NAME = 'broker.sock';\nconst OWNER_ONLY_DIRECTORY = 0o700;\nconst TOKEN_BYTES = 32;\nconst LOOPBACK = '127.0.0.1';\nconst LINUX_PLATFORM = 'linux';\nconst EPHEMERAL_PORT = 0;\n\nexport interface RunningBroker {\n /** How a container reaches this broker. */\n endpoint: BrokerEndpoint;\n /** Secret the container presents instead of any real credential. */\n token: string;\n /** Pi provider names the session may reach. */\n providers: string[];\n /** Host environment variables whose value the container receives as the token. */\n withheldEnv: string[];\n stop(): Promise<void>;\n}\n\nexport interface StartBrokerOptions {\n environment: Readonly<Record<string, string | undefined>>;\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to this host's platform. */\n platform?: string;\n /**\n * Fixed directory to hold the socket instead of a fresh temporary one.\n *\n * A reused container keeps the mounts it was created with, so a dev\n * container has to find the socket at the same path on every launch.\n */\n socketDirectory?: string;\n /** Forces the loopback transport even where a socket would work. */\n forceLoopback?: boolean;\n}\n\n/**\n * Starts the host-side provider broker for one sandboxed session.\n *\n * Answers undefined when the host holds no brokerable credential, which keeps\n * a session that authenticates some other way on the unbrokered path instead\n * of failing it.\n */\nexport async function startBroker(options: StartBrokerOptions): Promise<RunningBroker | undefined> {\n const resolved = resolveBrokeredCredentials(options.environment);\n if (resolved.length === 0) return undefined;\n\n const token = randomBytes(TOKEN_BYTES).toString('base64url');\n const credentials = new Map(resolved.map((credential) => [credential.route.provider, credential]));\n const server = createBrokerServer({ credentials, token, onDenied: options.onDenied });\n const platform = options.platform ?? process.platform;\n\n const useSocket = platform === LINUX_PLATFORM && options.forceLoopback !== true;\n const { endpoint, dispose } = useSocket\n ? await listenOnSocket(server, options.socketDirectory)\n : await listenOnLoopback(server);\n\n return {\n endpoint,\n token,\n providers: resolved.map((credential) => credential.route.provider),\n withheldEnv: resolved.map((credential) => credential.envName),\n stop: () => stopBroker(server, dispose),\n };\n}\n\n/**\n * Native Linux shares a kernel with the container, so a bind-mounted socket\n * needs no port and is reachable as an ordinary file.\n */\nasync function listenOnSocket(\n server: http.Server,\n fixedDirectory?: string,\n): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n const socketDirectory = fixedDirectory ?? fs.mkdtempSync(path.join(os.tmpdir(), SOCKET_DIRECTORY_PREFIX));\n fs.mkdirSync(socketDirectory, { recursive: true });\n fs.chmodSync(socketDirectory, OWNER_ONLY_DIRECTORY);\n const socketPath = path.join(socketDirectory, SOCKET_FILE_NAME);\n // A previous session that died without closing leaves the node behind, and\n // bind fails on an existing path.\n fs.rmSync(socketPath, { force: true });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(socketPath, () => resolve());\n });\n return {\n endpoint: { transport: 'unix', socketDirectory },\n // A fixed directory outlives the session that borrowed it.\n dispose: () =>\n fixedDirectory\n ? fs.rmSync(socketPath, { force: true })\n : fs.rmSync(socketDirectory, { recursive: true, force: true }),\n };\n}\n\n/**\n * Everywhere else the container runs in its own virtual machine, which cannot\n * connect to a host unix socket even when the file is shared through: the\n * connect fails with ENOTSUP. Loopback keeps the broker off the network while\n * still being reachable through the engine's host gateway, and the session\n * token is what stops another local process from using it.\n */\nasync function listenOnLoopback(server: http.Server): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(EPHEMERAL_PORT, LOOPBACK, () => resolve());\n });\n const address = server.address();\n if (address === null || typeof address === 'string') throw new Error('The broker did not report a listening port.');\n return { endpoint: { transport: 'tcp', port: address.port }, dispose: () => undefined };\n}\n\nasync function stopBroker(server: http.Server, dispose: () => void): Promise<void> {\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n // An in-flight provider stream would otherwise hold the listener open past\n // the session that owns it.\n server.closeAllConnections();\n });\n dispose();\n}\n","import type { PoHeadlessActivity } from '@agimon-ai/po-core/headless';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { BROKER_DISABLED_ENV, BROKER_STATUS_SOURCE, DISABLED_VALUE } from '../../../../../constants/sandbox';\nimport { startBroker, type RunningBroker } from '../../../../../services/brokerHost';\nimport { DefaultSandboxExtensionService } from '../../../../../services/extensionService';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerRoot({ agent }: PoServerPluginContext) {\n if (!agent) return { value: {} as SandboxServerScope };\n const service = new DefaultSandboxExtensionService(agent.context.environment);\n let broker: RunningBroker | undefined;\n const activity: PoHeadlessActivity = {\n name: BROKER_STATUS_SOURCE,\n async start(execution) {\n if (execution.environment[BROKER_DISABLED_ENV] === DISABLED_VALUE) return () => undefined;\n const started = await startBroker({\n environment: execution.environment,\n onDenied: (reason) => {\n void execution.client.notify({\n title: 'Po sandbox broker',\n body: `Broker refused a call: ${reason}`,\n level: 'warning',\n });\n },\n });\n broker = started;\n if (started === undefined) return () => undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, `provider broker: ${started.providers.join(', ')}`);\n return async () => {\n if (broker !== started) return;\n broker = undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, undefined);\n await started.stop();\n };\n },\n };\n return { value: { service }, activities: [activity] };\n}\n","import { defineRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerProviderOverrides } from '@agimon-ai/po-core/serverFacet';\n\nimport { brokeredProviderOverrides } from '../../../../services/brokerProviders';\nimport { createSandboxServerRoot } from './_lib/serverRoot';\n\nexport default defineRoot(\n Object.assign(createSandboxServerRoot, {\n providerOverrides: (({ environment }) =>\n brokeredProviderOverrides(environment).map(({ provider, baseUrl }) => ({\n name: provider,\n baseUrl,\n }))) satisfies PoServerProviderOverrides,\n }),\n);\n","import type { WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport { defineCommand } from '@agimon-ai/po-core/serverFacet';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { COMMAND_DESCRIPTION, COMMAND_NAME } from '../../../../../constants/sandbox';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerCommands(context: WithRoot<PoServerPluginContext, SandboxServerScope>) {\n const service = context.root.service;\n if (!service) return [];\n return [\n defineCommand({\n name: COMMAND_NAME,\n description: COMMAND_DESCRIPTION,\n async execute() {\n const result = await service.execute();\n await context.agent?.context.client.notify({ body: result.message, level: result.level });\n },\n }),\n ];\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createSandboxServerCommands } from '../_lib/sandboxCommands';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PoServerPluginContext, SandboxServerScope>) => createSandboxServerCommands(context),\n { cardinality: 'many' },\n);\n","import type { PoHeadlessResource } from '@agimon-ai/po-core/headless';\nimport { readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxContextResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n // The package index is Help-catalog material, not standing instruction. The Pi\n // facet has always routed it through the Help service; this is the server's gate.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'po-sandbox',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n };\n}\n\nexport function createSandboxSkillResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n name: 'po-use-sandbox',\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n };\n}\n\nexport function createSandboxHelpResource(moduleUrl: string) {\n return {\n source: '@agimon-ai/po-sandbox',\n moduleUrl,\n skills: [\n {\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n },\n ],\n };\n}\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createSandboxContextResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxContextResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createSandboxSkillResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxSkillResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport commandSandbox from '../src/extensions/workspaces/sessions/(backend)/command/sandbox.server';\nimport resourcePoSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server';\nimport resourcePoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/po-sandbox',\n providerOverrides: composeServerProviderOverrides(rootSession),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PoServerSessionPlugin['commands'] { return [...many(commandSandbox, contextSession)]; },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoSandbox, contextSession), at(resourcePoUseSandbox, contextSession)]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","names":["rootSession","commandSandbox","resourcePoSandbox","resourcePoUseSandbox"],"sources":["../../src/services/brokerProviders/index.ts","../../src/constants/sandbox.ts","../../src/services/brokerRoutes/index.ts","../../src/services/brokerServer/index.ts","../../src/services/brokerHost/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxCommands.ts","../../src/extensions/workspaces/sessions/(backend)/command/sandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/sandboxResources.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server.ts","../../generated/server.ts"],"sourcesContent":["import { BROKER_ADDRESS_ENV, BROKER_CONTAINER_PORT, BROKER_PROVIDERS_ENV, BROKER_SOCKET_ENV } from '../sandboxBridge';\n\nexport interface BrokeredProviderOverride {\n provider: string;\n baseUrl: string;\n}\n\n/**\n * Points brokered providers at whichever route the launch granted.\n *\n * Pi reads base URLs from package-internal provider data, so redirecting a\n * session means overriding the provider rather than setting an environment\n * variable. The credential is left alone: the launch already replaced it with\n * the session token the broker expects.\n *\n * A broker on a host port is addressed directly. Only a mounted socket needs\n * the loopback bridge, because no SDK can dial a socket path.\n */\nexport function brokeredProviderOverrides(\n environment: Readonly<Record<string, string | undefined>>,\n): BrokeredProviderOverride[] {\n const configured = environment[BROKER_PROVIDERS_ENV]?.trim();\n if (!configured) return [];\n const authority = environment[BROKER_SOCKET_ENV]?.trim()\n ? `127.0.0.1:${BROKER_CONTAINER_PORT}`\n : environment[BROKER_ADDRESS_ENV]?.trim();\n if (!authority) return [];\n return configured\n .split(',')\n .map((provider) => provider.trim())\n .filter((provider) => provider.length > 0)\n .map((provider) => ({ provider, baseUrl: `http://${authority}/${provider}` }));\n}\n","export const COMMAND_NAME = 'po-sandbox';\nexport const COMMAND_DESCRIPTION = 'Show sandbox container status for this session';\n\nexport const BROKER_DISABLED_ENV = 'PO_SANDBOX_BROKER';\nexport const DISABLED_VALUE = '0';\nexport const BROKER_STATUS_SOURCE = 'po-sandbox-broker';\n","export interface BrokerRoute {\n /** Pi provider name, which is also the broker's first path segment. */\n provider: string;\n /** Upstream origin plus any base path Pi's own provider data carries. */\n upstream: string;\n /** Host environment variables that may hold the real credential, in priority order. */\n hostKeyEnv: readonly string[];\n}\n\n/**\n * Providers the broker can terminate, mirroring Pi's own provider data.\n *\n * Curated rather than derived: Pi keeps base URLs in package-internal JSON that\n * carries no stability promise. A provider missing here is simply not brokered,\n * and its credential stays on the host.\n */\nconst ROUTES: readonly BrokerRoute[] = [\n { provider: 'anthropic', upstream: 'https://api.anthropic.com', hostKeyEnv: ['ANTHROPIC_API_KEY'] },\n { provider: 'openai', upstream: 'https://api.openai.com/v1', hostKeyEnv: ['OPENAI_API_KEY'] },\n { provider: 'google', upstream: 'https://generativelanguage.googleapis.com/v1beta', hostKeyEnv: ['GEMINI_API_KEY'] },\n { provider: 'groq', upstream: 'https://api.groq.com/openai/v1', hostKeyEnv: ['GROQ_API_KEY'] },\n { provider: 'xai', upstream: 'https://api.x.ai/v1', hostKeyEnv: ['XAI_API_KEY'] },\n { provider: 'openrouter', upstream: 'https://openrouter.ai/api/v1', hostKeyEnv: ['OPENROUTER_API_KEY'] },\n { provider: 'deepseek', upstream: 'https://api.deepseek.com', hostKeyEnv: ['DEEPSEEK_API_KEY'] },\n { provider: 'mistral', upstream: 'https://api.mistral.ai', hostKeyEnv: ['MISTRAL_API_KEY'] },\n { provider: 'together', upstream: 'https://api.together.ai/v1', hostKeyEnv: ['TOGETHER_API_KEY'] },\n { provider: 'cerebras', upstream: 'https://api.cerebras.ai/v1', hostKeyEnv: ['CEREBRAS_API_KEY'] },\n { provider: 'moonshotai', upstream: 'https://api.moonshot.ai/v1', hostKeyEnv: ['MOONSHOT_API_KEY'] },\n { provider: 'zai', upstream: 'https://api.z.ai/api/coding/paas/v4', hostKeyEnv: ['ZAI_API_KEY'] },\n];\n\nexport function brokerRoutes(): readonly BrokerRoute[] {\n return ROUTES;\n}\n\nexport function findBrokerRoute(provider: string): BrokerRoute | undefined {\n return ROUTES.find((route) => route.provider === provider);\n}\n\nexport interface ResolvedCredential {\n route: BrokerRoute;\n /** Environment variable the container would otherwise have received. */\n envName: string;\n value: string;\n}\n\n/** Selects the providers this host can actually broker for a session. */\nexport function resolveBrokeredCredentials(\n environment: Readonly<Record<string, string | undefined>>,\n): ResolvedCredential[] {\n const resolved: ResolvedCredential[] = [];\n for (const route of ROUTES) {\n for (const envName of route.hostKeyEnv) {\n const value = environment[envName]?.trim();\n if (value) {\n resolved.push({ route, envName, value });\n break;\n }\n }\n }\n return resolved;\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport http from 'node:http';\nimport https from 'node:https';\n\nimport type { ResolvedCredential } from '../brokerRoutes';\n\n/** Headers a provider SDK may carry its credential in. */\nconst CREDENTIAL_HEADERS = ['x-api-key', 'authorization', 'x-goog-api-key'] as const;\n/** Query parameter some Google clients use instead of a header. */\nconst CREDENTIAL_QUERY = 'key';\nconst BEARER_PREFIX = 'bearer ';\n/** Connection-scoped headers that must not cross to the upstream request. */\nconst HOP_BY_HOP = new Set([\n 'connection',\n 'keep-alive',\n 'proxy-authenticate',\n 'proxy-authorization',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n 'host',\n 'content-length',\n]);\nconst PATH_PATTERN = /^\\/([^/?]+)(.*)$/;\n\nexport interface BrokerServerOptions {\n /** Providers this session may reach, keyed by Pi provider name. */\n credentials: ReadonlyMap<string, ResolvedCredential>;\n /** Secret the container presents in place of a real credential. */\n token: string;\n /** Receives one line per rejected request, for host-side visibility. */\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to the real https transport. */\n requestUpstream?: typeof https.request;\n}\n\nfunction matchesToken(candidate: string, token: string): boolean {\n const left = Buffer.from(candidate);\n const right = Buffer.from(token);\n return left.length === right.length && timingSafeEqual(left, right);\n}\n\nfunction credentialValue(headerValue: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? headerValue.slice(BEARER_PREFIX.length) : headerValue;\n}\n\nfunction withCredential(headerValue: string, realKey: string): string {\n return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? `Bearer ${realKey}` : realKey;\n}\n\n/**\n * Rewrites the request's credential, proving the caller holds the session token.\n *\n * Which header carries the key differs per provider SDK, so every candidate is\n * checked rather than assumed. Returns undefined when nothing presented the\n * token, which is what makes an unauthenticated caller indistinguishable from a\n * misrouted one.\n */\nfunction swapCredential(\n headers: http.IncomingHttpHeaders,\n search: URLSearchParams,\n token: string,\n realKey: string,\n): http.OutgoingHttpHeaders | undefined {\n const forwarded: http.OutgoingHttpHeaders = {};\n let authenticated = false;\n\n for (const [name, value] of Object.entries(headers)) {\n if (value === undefined || HOP_BY_HOP.has(name)) continue;\n const single = Array.isArray(value) ? value[0] : value;\n if ((CREDENTIAL_HEADERS as readonly string[]).includes(name) && single !== undefined) {\n if (!matchesToken(credentialValue(single), token)) return undefined;\n forwarded[name] = withCredential(single, realKey);\n authenticated = true;\n continue;\n }\n forwarded[name] = value;\n }\n\n const queryKey = search.get(CREDENTIAL_QUERY);\n if (queryKey !== null) {\n if (!matchesToken(queryKey, token)) return undefined;\n search.set(CREDENTIAL_QUERY, realKey);\n authenticated = true;\n }\n\n return authenticated ? forwarded : undefined;\n}\n\nfunction reject(response: http.ServerResponse, status: number, message: string): void {\n response.writeHead(status, { 'content-type': 'application/json' });\n response.end(JSON.stringify({ error: { type: 'po_broker', message } }));\n}\n\n/**\n * Terminates provider calls from a sandboxed session on the host.\n *\n * The container never holds a real credential: it presents the session token,\n * and only a request that proves possession of it is forwarded upstream with\n * the host's key attached. Bodies stream in both directions so token-by-token\n * responses are not buffered.\n */\nexport function createBrokerServer(options: BrokerServerOptions): http.Server {\n const requestUpstream = options.requestUpstream ?? https.request;\n\n return http.createServer((request, response) => {\n const match = PATH_PATTERN.exec(request.url ?? '');\n const provider = match?.[1];\n const credential = provider ? options.credentials.get(provider) : undefined;\n if (!match || !credential) {\n options.onDenied?.(`unroutable provider path ${request.url ?? ''}`);\n reject(response, 404, 'Unknown provider for this sandbox session.');\n return;\n }\n\n const target = new URL(`${credential.route.upstream}${match[2] || ''}`);\n const headers = swapCredential(request.headers, target.searchParams, options.token, credential.value);\n if (!headers) {\n options.onDenied?.(`missing or invalid session token for ${credential.route.provider}`);\n reject(response, 401, 'This sandbox session did not present its broker token.');\n return;\n }\n\n const upstream = requestUpstream(\n target,\n { method: request.method, headers: { ...headers, host: target.host } },\n (upstreamResponse) => {\n response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);\n upstreamResponse.pipe(response);\n },\n );\n upstream.on('error', (error: Error) => {\n options.onDenied?.(`upstream ${credential.route.provider} failed: ${error.message}`);\n if (!response.headersSent) reject(response, 502, 'The provider could not be reached from the host.');\n else response.destroy();\n });\n request.on('aborted', () => upstream.destroy());\n request.pipe(upstream);\n });\n}\n","import { randomBytes } from 'node:crypto';\nimport fs from 'node:fs';\nimport type http from 'node:http';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { BrokerEndpoint } from '../../types/sandboxHarness';\nimport { resolveBrokeredCredentials } from '../brokerRoutes';\nimport { createBrokerServer } from '../brokerServer';\n\nconst SOCKET_DIRECTORY_PREFIX = 'po-broker-';\nconst SOCKET_FILE_NAME = 'broker.sock';\nconst OWNER_ONLY_DIRECTORY = 0o700;\nconst TOKEN_BYTES = 32;\nconst LOOPBACK = '127.0.0.1';\nconst LINUX_PLATFORM = 'linux';\nconst EPHEMERAL_PORT = 0;\n\nexport interface RunningBroker {\n /** How a container reaches this broker. */\n endpoint: BrokerEndpoint;\n /** Secret the container presents instead of any real credential. */\n token: string;\n /** Pi provider names the session may reach. */\n providers: string[];\n /** Host environment variables whose value the container receives as the token. */\n withheldEnv: string[];\n stop(): Promise<void>;\n}\n\nexport interface StartBrokerOptions {\n environment: Readonly<Record<string, string | undefined>>;\n onDenied?: (reason: string) => void;\n /** Seam for tests; defaults to this host's platform. */\n platform?: string;\n /**\n * Fixed directory to hold the socket instead of a fresh temporary one.\n *\n * A reused container keeps the mounts it was created with, so a dev\n * container has to find the socket at the same path on every launch.\n */\n socketDirectory?: string;\n /** Forces the loopback transport even where a socket would work. */\n forceLoopback?: boolean;\n}\n\n/**\n * Starts the host-side provider broker for one sandboxed session.\n *\n * Answers undefined when the host holds no brokerable credential, which keeps\n * a session that authenticates some other way on the unbrokered path instead\n * of failing it.\n */\nexport async function startBroker(options: StartBrokerOptions): Promise<RunningBroker | undefined> {\n const resolved = resolveBrokeredCredentials(options.environment);\n if (resolved.length === 0) return undefined;\n\n const token = randomBytes(TOKEN_BYTES).toString('base64url');\n const credentials = new Map(resolved.map((credential) => [credential.route.provider, credential]));\n const server = createBrokerServer({ credentials, token, onDenied: options.onDenied });\n const platform = options.platform ?? process.platform;\n\n const useSocket = platform === LINUX_PLATFORM && options.forceLoopback !== true;\n const { endpoint, dispose } = useSocket\n ? await listenOnSocket(server, options.socketDirectory)\n : await listenOnLoopback(server);\n\n return {\n endpoint,\n token,\n providers: resolved.map((credential) => credential.route.provider),\n withheldEnv: resolved.map((credential) => credential.envName),\n stop: () => stopBroker(server, dispose),\n };\n}\n\n/**\n * Native Linux shares a kernel with the container, so a bind-mounted socket\n * needs no port and is reachable as an ordinary file.\n */\nasync function listenOnSocket(\n server: http.Server,\n fixedDirectory?: string,\n): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n const socketDirectory = fixedDirectory ?? fs.mkdtempSync(path.join(os.tmpdir(), SOCKET_DIRECTORY_PREFIX));\n fs.mkdirSync(socketDirectory, { recursive: true });\n fs.chmodSync(socketDirectory, OWNER_ONLY_DIRECTORY);\n const socketPath = path.join(socketDirectory, SOCKET_FILE_NAME);\n // A previous session that died without closing leaves the node behind, and\n // bind fails on an existing path.\n fs.rmSync(socketPath, { force: true });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(socketPath, () => resolve());\n });\n return {\n endpoint: { transport: 'unix', socketDirectory },\n // A fixed directory outlives the session that borrowed it.\n dispose: () =>\n fixedDirectory\n ? fs.rmSync(socketPath, { force: true })\n : fs.rmSync(socketDirectory, { recursive: true, force: true }),\n };\n}\n\n/**\n * Everywhere else the container runs in its own virtual machine, which cannot\n * connect to a host unix socket even when the file is shared through: the\n * connect fails with ENOTSUP. Loopback keeps the broker off the network while\n * still being reachable through the engine's host gateway, and the session\n * token is what stops another local process from using it.\n */\nasync function listenOnLoopback(server: http.Server): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(EPHEMERAL_PORT, LOOPBACK, () => resolve());\n });\n const address = server.address();\n if (address === null || typeof address === 'string') throw new Error('The broker did not report a listening port.');\n return { endpoint: { transport: 'tcp', port: address.port }, dispose: () => undefined };\n}\n\nasync function stopBroker(server: http.Server, dispose: () => void): Promise<void> {\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n // An in-flight provider stream would otherwise hold the listener open past\n // the session that owns it.\n server.closeAllConnections();\n });\n dispose();\n}\n","import type { PoHeadlessActivity } from '@agimon-ai/po-core/headless';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { BROKER_DISABLED_ENV, BROKER_STATUS_SOURCE, DISABLED_VALUE } from '../../../../../constants/sandbox';\nimport { startBroker, type RunningBroker } from '../../../../../services/brokerHost';\nimport { DefaultSandboxExtensionService } from '../../../../../services/extensionService';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerRoot({ agent }: PoServerPluginContext) {\n if (!agent) return { value: {} as SandboxServerScope };\n const service = new DefaultSandboxExtensionService(agent.context.environment);\n let broker: RunningBroker | undefined;\n const activity: PoHeadlessActivity = {\n name: BROKER_STATUS_SOURCE,\n async start(execution) {\n if (execution.environment[BROKER_DISABLED_ENV] === DISABLED_VALUE) return () => undefined;\n const started = await startBroker({\n environment: execution.environment,\n onDenied: (reason) => {\n void execution.client.notify({\n title: 'Po sandbox broker',\n body: `Broker refused a call: ${reason}`,\n level: 'warning',\n });\n },\n });\n broker = started;\n if (started === undefined) return () => undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, `provider broker: ${started.providers.join(', ')}`);\n return async () => {\n if (broker !== started) return;\n broker = undefined;\n execution.client.setStatus(BROKER_STATUS_SOURCE, undefined);\n await started.stop();\n };\n },\n };\n return { value: { service }, activities: [activity] };\n}\n","import { defineRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\n\nimport { brokeredProviderOverrides } from '../../../../services/brokerProviders';\nimport { createSandboxServerRoot } from './_lib/serverRoot';\n\nexport default defineRoot(\n Object.assign(createSandboxServerRoot, {\n providerOverrides: (({ environment }) =>\n brokeredProviderOverrides(environment).map(({ provider, baseUrl }) => ({\n name: provider,\n baseUrl,\n }))) satisfies PoServerProviderOverrides,\n }),\n);\n","import type { WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport { defineCommand } from '@agimon-ai/po-core/serverPlugin';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { COMMAND_DESCRIPTION, COMMAND_NAME } from '../../../../../constants/sandbox';\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxServerCommands(context: WithRoot<PoServerPluginContext, SandboxServerScope>) {\n const service = context.root.service;\n if (!service) return [];\n return [\n defineCommand({\n name: COMMAND_NAME,\n description: COMMAND_DESCRIPTION,\n async execute() {\n const result = await service.execute();\n await context.agent?.context.client.notify({ body: result.message, level: result.level });\n },\n }),\n ];\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { createSandboxServerCommands } from '../_lib/sandboxCommands';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n (context: WithRoot<PoServerPluginContext, SandboxServerScope>) => createSandboxServerCommands(context),\n { cardinality: 'many' },\n);\n","import type { PoHeadlessResource } from '@agimon-ai/po-core/headless';\nimport { readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { SandboxServerScope } from './sandboxScope';\n\nexport function createSandboxContextResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n // The package index is Help-catalog material, not standing instruction. The Pi\n // extension has always routed it through the Help service; this is the server's gate.\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n name: 'po-sandbox',\n kind: 'context',\n read: () => readPackageResource(import.meta.url, 'llms.txt'),\n };\n}\n\nexport function createSandboxSkillResource(root: SandboxServerScope): PoHeadlessResource | undefined {\n if (!root.service) return undefined;\n return {\n name: 'po-use-sandbox',\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor', mode: 'help' } },\n kind: 'skill',\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-sandbox/SKILL.md'),\n };\n}\n\nexport function createSandboxHelpResource(moduleUrl: string) {\n return {\n source: '@agimon-ai/po-sandbox',\n moduleUrl,\n skills: [\n {\n name: 'po-use-sandbox',\n description:\n 'Use @agimon-ai/po-sandbox: Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host',\n },\n ],\n };\n}\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { createSandboxContextResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxContextResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","import { defineResource, defineRoutedContribution, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { createSandboxSkillResource } from '../_lib/sandboxResources';\nimport type { SandboxServerScope } from '../_lib/sandboxScope';\n\nexport default defineRoutedContribution(\n defineResource((context: WithRoot<PoServerPluginContext, SandboxServerScope>) =>\n createSandboxSkillResource(context.root),\n ),\n { cardinality: 'optional' },\n);\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverPlugin';\nimport { composeRootHooks, composeRootInjects } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport commandSandbox from '../src/extensions/workspaces/sessions/(backend)/command/sandbox.server';\nimport resourcePoSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poSandbox.server';\nimport resourcePoUseSandbox from '../src/extensions/workspaces/sessions/(backend)/resource/poUseSandbox.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-sandbox',\n providerOverrides: composeServerProviderOverrides(rootSession),\n injects: composeRootInjects({ session: [rootSession] }),\n session: async (context) => {\n const scopeSession = await context.scopeRoot('session', rootSession, context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PoServerSessionPlugin['commands'] { return [...many(commandSandbox, contextSession)]; },\n get resources(): PoServerSessionPlugin['resources'] { return defined([at(resourcePoSandbox, contextSession), at(resourcePoUseSandbox, contextSession)]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-sandbox",
3
- "version": "0.0.0-alpha.13",
3
+ "version": "0.0.0-alpha.14",
4
4
  "description": "Container sandbox for Po launches: the agent, extensions, and tools run inside Docker or Podman while the terminal stays on the host",
5
5
  "keywords": [
6
6
  "ai",
@@ -64,12 +64,12 @@
64
64
  "access": "public"
65
65
  },
66
66
  "dependencies": {
67
- "@agimon-ai/po-core": "0.0.0-alpha.13",
68
- "@deepseek-ai/cordis": "4.0.4"
67
+ "@agimon-ai/po-core": "0.0.0-alpha.14",
68
+ "@deepseek-ai/cordis": "4.0.5"
69
69
  },
70
70
  "devDependencies": {
71
- "@agimon-ai/po-build": "0.0.0-alpha.13",
72
- "@agimon-ai/vibe-lint-plugin-po-extension": "0.0.0-alpha.13",
71
+ "@agimon-ai/po-build": "0.0.0-alpha.14",
72
+ "@agimon-ai/vibe-lint-plugin-po-extension": "0.0.0-alpha.14",
73
73
  "@earendil-works/pi-coding-agent": "1.3.0",
74
74
  "@types/node": "26.6.5",
75
75
  "@vitest/coverage-v8": "5.0.4",