@agimon-ai/doompi-domain 0.0.1-alpha.2 → 0.0.1-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/dist/adapters/applyDomains.cjs +1 -1
- package/dist/adapters/applyDomains.cjs.map +1 -1
- package/dist/adapters/applyDomains.d.cts +2 -2
- package/dist/adapters/applyDomains.d.cts.map +1 -1
- package/dist/adapters/applyDomains.d.mts +2 -2
- package/dist/adapters/applyDomains.d.mts.map +1 -1
- package/dist/adapters/applyDomains.mjs +1 -1
- package/dist/adapters/applyDomains.mjs.map +1 -1
- package/dist/adapters/domainCatalog.cjs +1 -1
- package/dist/adapters/domainCatalog.cjs.map +1 -1
- package/dist/adapters/domainCatalog.d.cts +4 -3
- package/dist/adapters/domainCatalog.d.cts.map +1 -1
- package/dist/adapters/domainCatalog.d.mts +4 -3
- package/dist/adapters/domainCatalog.d.mts.map +1 -1
- package/dist/adapters/domainCatalog.mjs +1 -1
- package/dist/adapters/domainCatalog.mjs.map +1 -1
- package/dist/adapters/domainSwitchHandoff.cjs +1 -1
- package/dist/adapters/domainSwitchHandoff.cjs.map +1 -1
- package/dist/adapters/domainSwitchHandoff.mjs +1 -1
- package/dist/adapters/domainSwitchHandoff.mjs.map +1 -1
- package/dist/adapters/mcpFilter.cjs +2 -2
- package/dist/adapters/mcpFilter.mjs +2 -2
- package/dist/adapters/pi/extension.cjs +1 -1
- package/dist/adapters/pi/extension.cjs.map +1 -1
- package/dist/adapters/pi/extension.d.cts +1 -6
- package/dist/adapters/pi/extension.d.cts.map +1 -1
- package/dist/adapters/pi/extension.d.mts +1 -6
- package/dist/adapters/pi/extension.d.mts.map +1 -1
- package/dist/adapters/pi/extension.mjs +1 -1
- package/dist/adapters/pi/extension.mjs.map +1 -1
- package/dist/adapters/pi/voiceTool.cjs +1 -1
- package/dist/adapters/pi/voiceTool.cjs.map +1 -1
- package/dist/adapters/pi/voiceTool.d.cts +5 -2
- package/dist/adapters/pi/voiceTool.d.cts.map +1 -1
- package/dist/adapters/pi/voiceTool.d.mts +5 -2
- package/dist/adapters/pi/voiceTool.d.mts.map +1 -1
- package/dist/adapters/pi/voiceTool.mjs +1 -1
- package/dist/adapters/pi/voiceTool.mjs.map +1 -1
- package/dist/adapters/pluginMaterializer.cjs +1 -1
- package/dist/adapters/pluginMaterializer.cjs.map +1 -1
- package/dist/adapters/pluginMaterializer.d.cts.map +1 -1
- package/dist/adapters/pluginMaterializer.d.mts.map +1 -1
- package/dist/adapters/pluginMaterializer.mjs +1 -1
- package/dist/adapters/pluginMaterializer.mjs.map +1 -1
- package/dist/adapters/resourceCollector.cjs +2 -2
- package/dist/adapters/resourceCollector.cjs.map +1 -1
- package/dist/adapters/resourceCollector.d.cts +4 -2
- package/dist/adapters/resourceCollector.d.cts.map +1 -1
- package/dist/adapters/resourceCollector.d.mts +4 -2
- package/dist/adapters/resourceCollector.d.mts.map +1 -1
- package/dist/adapters/resourceCollector.mjs +2 -2
- package/dist/adapters/resourceCollector.mjs.map +1 -1
- package/dist/adapters/skillCacheLocation.cjs +1 -1
- package/dist/adapters/skillCacheLocation.mjs +1 -1
- package/dist/commands/domainsCommand.cjs +1 -1
- package/dist/commands/domainsCommand.cjs.map +1 -1
- package/dist/commands/domainsCommand.d.cts +4 -0
- package/dist/commands/domainsCommand.d.cts.map +1 -1
- package/dist/commands/domainsCommand.d.mts +4 -0
- package/dist/commands/domainsCommand.d.mts.map +1 -1
- package/dist/commands/domainsCommand.mjs +1 -1
- package/dist/commands/domainsCommand.mjs.map +1 -1
- package/dist/resources.cjs +1 -1
- package/dist/resources.d.cts +3 -3
- package/dist/resources.d.mts +3 -3
- package/dist/resources.mjs +1 -1
- package/dist/types/handoff.d.cts +1 -1
- package/dist/types/handoff.d.mts +1 -1
- package/dist/types/resources.d.cts +26 -7
- package/dist/types/resources.d.cts.map +1 -1
- package/dist/types/resources.d.mts +26 -7
- package/dist/types/resources.d.mts.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -48,9 +48,14 @@ selection:
|
|
|
48
48
|
worktree so a second session does not rescan the tree;
|
|
49
49
|
- adapts each plugin's Claude-authored agent definitions into the form Pi loads, and stages them
|
|
50
50
|
privately (`0600`) beside a dispatcher agent;
|
|
51
|
-
- merges the repository and plugin `.mcp.json` layers,
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
- merges the repository and legacy plugin `.mcp.json` layers, and validates root `mcp.json` for
|
|
52
|
+
schema-gated Agent Plugins v1 (including plugin-relative commands, data directories and transport
|
|
53
|
+
normalization);
|
|
54
|
+
- applies the selected domains' MCP allowlists and rewrites the proxy's upstream list into a
|
|
55
|
+
private per-run config; and
|
|
56
|
+
- atomically stores an immutable MCP projection in harness state, then reloads Pi. The replacement
|
|
57
|
+
Config factory publishes that snapshot through the session Cordis registry for DoomPi MCP to
|
|
58
|
+
consume; Domain never reaches into the live MCP runtime.
|
|
54
59
|
|
|
55
60
|
An allowlist only takes effect once **every** selected domain declares one. Mixing a scoped domain
|
|
56
61
|
with a domain that has not opted in leaves the session unfiltered, so an unmigrated domain cannot
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./mcpFilter.cjs"),n=require("./
|
|
1
|
+
const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./mcpFilter.cjs"),n=require("./pluginMaterializer.cjs"),r=require("./resourceCollector.cjs");let i=require("node:fs");i=e.__toESM(i,1);let a=require("node:path");a=e.__toESM(a,1);let o=require("@agimon-ai/doompi-config/domains"),s=require("@agimon-ai/doompi-config/harnessStore");async function c(e,c){let{root:l,temporaryDirectory:u}=(0,s.requireHarnessPaths)(c),d=await n.materializePluginEntries((0,o.resolvePluginEntries)(l,e,[...c.pluginDirectories])),f=t.resolveMcpAllowlist(l,e),p=await i.default.promises.mkdtemp(a.default.join(u,`domains-`)),m;try{m=await r.collectResources(l,d,{agents:c.agents,mcp:c.mcp,temporaryDirectory:p,sharedSkills:(0,o.resolveSharedSkills)(l,e),mcpAllowlist:f})}catch(e){throw await i.default.promises.rm(p,{recursive:!0,force:!0}),e}let h;try{h=(0,s.updateHarnessState)({domains:e,skillDirectories:m.skillDirectories,pluginHooks:m.pluginHooks,mcpConfigPath:m.mcpConfigPath,mcpProjection:m.mcpProjection})}catch(e){throw await i.default.promises.rm(p,{recursive:!0,force:!0}),e}return process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS=m.agentDirectories.join(a.default.delimiter),process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS=m.skillDirectories.join(a.default.delimiter),h}exports.applyDomains=c;
|
|
2
2
|
//# sourceMappingURL=applyDomains.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyDomains.cjs","names":["requireHarnessPaths","materializePluginEntries","resolvePluginEntries","resolveMcpAllowlist","
|
|
1
|
+
{"version":3,"file":"applyDomains.cjs","names":["requireHarnessPaths","materializePluginEntries","resolvePluginEntries","resolveMcpAllowlist","fs","path","collectResources","resolveSharedSkills","updateHarnessState"],"sources":["../../src/adapters/applyDomains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { resolvePluginEntries, resolveSharedSkills } from '@agimon-ai/doompi-config/domains';\nimport { requireHarnessPaths, updateHarnessState } from '@agimon-ai/doompi-config/harnessStore';\nimport type { DoomHarnessContext, HarnessState } from '@agimon-ai/doompi-config/types';\nimport { resolveMcpAllowlist } from './mcpFilter.ts';\nimport { materializePluginEntries } from './pluginMaterializer.ts';\nimport { collectResources } from './resourceCollector.ts';\n\n/**\n * Live domain switching: skills, plugin hooks, MCP config and subagent directories.\n *\n * Writes through the harness state module and relies on Pi's reload\n * re-executing extension modules. The replacement Config factory publishes the\n * persisted MCP projection on the new session's Cordis root.\n *\n * What reload cannot do is change the SET of loaded extensions: Pi freezes the\n * CLI --extension list at construction and re-resolves that same array on every\n * reload. Callers report those parts as needing a relaunch instead of pretending\n * they applied.\n *\n * The major-mode and profile switches live in\n * @agimon-ai/doompi-config/selectionSwitch: they are config writes with no\n * resource staging, and the synced startup path applies them before any command\n * exists to run. Domains stays here because it stages plugins, skills and MCP\n * config.\n */\nexport async function applyDomains(domainNames: string[], state: DoomHarnessContext): Promise<HarnessState> {\n const { root, temporaryDirectory } = requireHarnessPaths(state);\n\n const pluginEntries = await materializePluginEntries(\n resolvePluginEntries(root, domainNames, [...state.pluginDirectories]),\n );\n const mcpAllowlist = resolveMcpAllowlist(root, domainNames);\n // Keep the active generation untouched while the candidate is parsed and\n // normalized. Pi's reload later removes the whole process-owned run root, so\n // retired generations need no eager destructive cleanup here.\n const candidateDirectory = await fs.promises.mkdtemp(path.join(temporaryDirectory, 'domains-'));\n let resources: Awaited<ReturnType<typeof collectResources>>;\n try {\n resources = await collectResources(root, pluginEntries, {\n agents: state.agents,\n mcp: state.mcp,\n temporaryDirectory: candidateDirectory,\n sharedSkills: resolveSharedSkills(root, domainNames),\n mcpAllowlist,\n });\n } catch (error) {\n await fs.promises.rm(candidateDirectory, { recursive: true, force: true });\n throw error;\n }\n\n let updated: HarnessState;\n try {\n updated = updateHarnessState({\n domains: domainNames,\n skillDirectories: resources.skillDirectories,\n pluginHooks: resources.pluginHooks,\n mcpConfigPath: resources.mcpConfigPath,\n mcpProjection: resources.mcpProjection,\n });\n } catch (error) {\n await fs.promises.rm(candidateDirectory, { recursive: true, force: true });\n throw error;\n }\n process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS = resources.agentDirectories.join(path.delimiter);\n process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS = resources.skillDirectories.join(path.delimiter);\n return updated;\n}\n"],"mappings":"wVA2BA,eAAsB,EAAa,EAAuB,EAAkD,CAC1G,GAAM,CAAE,OAAM,uBAAA,EAAuBA,EAAAA,oBAAAA,CAAoB,CAAK,EAExD,EAAgB,MAAMC,EAAAA,0BAAAA,EAC1BC,EAAAA,qBAAAA,CAAqB,EAAM,EAAa,CAAC,GAAG,EAAM,iBAAiB,CAAC,CACtE,EACM,EAAeC,EAAAA,oBAAoB,EAAM,CAAW,EAIpD,EAAqB,MAAMC,EAAAA,QAAG,SAAS,QAAQC,EAAAA,QAAK,KAAK,EAAoB,UAAU,CAAC,EAC1F,EACJ,GAAI,CACF,EAAY,MAAMC,EAAAA,iBAAiB,EAAM,EAAe,CACtD,OAAQ,EAAM,OACd,IAAK,EAAM,IACX,mBAAoB,EACpB,cAAA,EAAcC,EAAAA,oBAAAA,CAAoB,EAAM,CAAW,EACnD,cACF,CAAC,CACH,OAAS,EAAO,CAEd,MADA,MAAMH,EAAAA,QAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACnE,CACR,CAEA,IAAI,EACJ,GAAI,CACF,GAAA,EAAUI,EAAAA,mBAAAA,CAAmB,CAC3B,QAAS,EACT,iBAAkB,EAAU,iBAC5B,YAAa,EAAU,YACvB,cAAe,EAAU,cACzB,cAAe,EAAU,aAC3B,CAAC,CACH,OAAS,EAAO,CAEd,MADA,MAAMJ,EAAAA,QAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACnE,CACR,CAGA,MAFA,SAAQ,IAAI,6BAA+B,EAAU,iBAAiB,KAAKC,EAAAA,QAAK,SAAS,EACzF,QAAQ,IAAI,6BAA+B,EAAU,iBAAiB,KAAKA,EAAAA,QAAK,SAAS,EAClF,CACT"}
|
|
@@ -4,8 +4,8 @@ import { DoomHarnessContext, HarnessState } from "@agimon-ai/doompi-config/types
|
|
|
4
4
|
* Live domain switching: skills, plugin hooks, MCP config and subagent directories.
|
|
5
5
|
*
|
|
6
6
|
* Writes through the harness state module and relies on Pi's reload
|
|
7
|
-
* re-executing extension modules
|
|
8
|
-
*
|
|
7
|
+
* re-executing extension modules. The replacement Config factory publishes the
|
|
8
|
+
* persisted MCP projection on the new session's Cordis root.
|
|
9
9
|
*
|
|
10
10
|
* What reload cannot do is change the SET of loaded extensions: Pi freezes the
|
|
11
11
|
* CLI --extension list at construction and re-resolves that same array on every
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyDomains.d.cts","names":[],"sources":["../../src/adapters/applyDomains.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"applyDomains.d.cts","names":[],"sources":["../../src/adapters/applyDomains.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;iBA2BsB,aAAa,uBAAuB,OAAO,qBAAqB,QAAQ"}
|
|
@@ -4,8 +4,8 @@ import { DoomHarnessContext, HarnessState } from "@agimon-ai/doompi-config/types
|
|
|
4
4
|
* Live domain switching: skills, plugin hooks, MCP config and subagent directories.
|
|
5
5
|
*
|
|
6
6
|
* Writes through the harness state module and relies on Pi's reload
|
|
7
|
-
* re-executing extension modules
|
|
8
|
-
*
|
|
7
|
+
* re-executing extension modules. The replacement Config factory publishes the
|
|
8
|
+
* persisted MCP projection on the new session's Cordis root.
|
|
9
9
|
*
|
|
10
10
|
* What reload cannot do is change the SET of loaded extensions: Pi freezes the
|
|
11
11
|
* CLI --extension list at construction and re-resolves that same array on every
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyDomains.d.mts","names":[],"sources":["../../src/adapters/applyDomains.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"applyDomains.d.mts","names":[],"sources":["../../src/adapters/applyDomains.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;iBA2BsB,aAAa,uBAAuB,OAAO,qBAAqB,QAAQ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{resolveMcpAllowlist as e}from"./mcpFilter.mjs";import{
|
|
1
|
+
import{resolveMcpAllowlist as e}from"./mcpFilter.mjs";import{materializePluginEntries as t}from"./pluginMaterializer.mjs";import{collectResources as n}from"./resourceCollector.mjs";import r from"node:fs";import i from"node:path";import{resolvePluginEntries as a,resolveSharedSkills as o}from"@agimon-ai/doompi-config/domains";import{requireHarnessPaths as s,updateHarnessState as c}from"@agimon-ai/doompi-config/harnessStore";async function l(l,u){let{root:d,temporaryDirectory:f}=s(u),p=await t(a(d,l,[...u.pluginDirectories])),m=e(d,l),h=await r.promises.mkdtemp(i.join(f,`domains-`)),g;try{g=await n(d,p,{agents:u.agents,mcp:u.mcp,temporaryDirectory:h,sharedSkills:o(d,l),mcpAllowlist:m})}catch(e){throw await r.promises.rm(h,{recursive:!0,force:!0}),e}let _;try{_=c({domains:l,skillDirectories:g.skillDirectories,pluginHooks:g.pluginHooks,mcpConfigPath:g.mcpConfigPath,mcpProjection:g.mcpProjection})}catch(e){throw await r.promises.rm(h,{recursive:!0,force:!0}),e}return process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS=g.agentDirectories.join(i.delimiter),process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS=g.skillDirectories.join(i.delimiter),_}export{l as applyDomains};
|
|
2
2
|
//# sourceMappingURL=applyDomains.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyDomains.mjs","names":[],"sources":["../../src/adapters/applyDomains.ts"],"sourcesContent":["import path from 'node:path';\nimport { resolvePluginEntries, resolveSharedSkills } from '@agimon-ai/doompi-config/domains';\nimport { requireHarnessPaths, updateHarnessState } from '@agimon-ai/doompi-config/harnessStore';\nimport type { DoomHarnessContext, HarnessState } from '@agimon-ai/doompi-config/types';\nimport {
|
|
1
|
+
{"version":3,"file":"applyDomains.mjs","names":[],"sources":["../../src/adapters/applyDomains.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { resolvePluginEntries, resolveSharedSkills } from '@agimon-ai/doompi-config/domains';\nimport { requireHarnessPaths, updateHarnessState } from '@agimon-ai/doompi-config/harnessStore';\nimport type { DoomHarnessContext, HarnessState } from '@agimon-ai/doompi-config/types';\nimport { resolveMcpAllowlist } from './mcpFilter.ts';\nimport { materializePluginEntries } from './pluginMaterializer.ts';\nimport { collectResources } from './resourceCollector.ts';\n\n/**\n * Live domain switching: skills, plugin hooks, MCP config and subagent directories.\n *\n * Writes through the harness state module and relies on Pi's reload\n * re-executing extension modules. The replacement Config factory publishes the\n * persisted MCP projection on the new session's Cordis root.\n *\n * What reload cannot do is change the SET of loaded extensions: Pi freezes the\n * CLI --extension list at construction and re-resolves that same array on every\n * reload. Callers report those parts as needing a relaunch instead of pretending\n * they applied.\n *\n * The major-mode and profile switches live in\n * @agimon-ai/doompi-config/selectionSwitch: they are config writes with no\n * resource staging, and the synced startup path applies them before any command\n * exists to run. Domains stays here because it stages plugins, skills and MCP\n * config.\n */\nexport async function applyDomains(domainNames: string[], state: DoomHarnessContext): Promise<HarnessState> {\n const { root, temporaryDirectory } = requireHarnessPaths(state);\n\n const pluginEntries = await materializePluginEntries(\n resolvePluginEntries(root, domainNames, [...state.pluginDirectories]),\n );\n const mcpAllowlist = resolveMcpAllowlist(root, domainNames);\n // Keep the active generation untouched while the candidate is parsed and\n // normalized. Pi's reload later removes the whole process-owned run root, so\n // retired generations need no eager destructive cleanup here.\n const candidateDirectory = await fs.promises.mkdtemp(path.join(temporaryDirectory, 'domains-'));\n let resources: Awaited<ReturnType<typeof collectResources>>;\n try {\n resources = await collectResources(root, pluginEntries, {\n agents: state.agents,\n mcp: state.mcp,\n temporaryDirectory: candidateDirectory,\n sharedSkills: resolveSharedSkills(root, domainNames),\n mcpAllowlist,\n });\n } catch (error) {\n await fs.promises.rm(candidateDirectory, { recursive: true, force: true });\n throw error;\n }\n\n let updated: HarnessState;\n try {\n updated = updateHarnessState({\n domains: domainNames,\n skillDirectories: resources.skillDirectories,\n pluginHooks: resources.pluginHooks,\n mcpConfigPath: resources.mcpConfigPath,\n mcpProjection: resources.mcpProjection,\n });\n } catch (error) {\n await fs.promises.rm(candidateDirectory, { recursive: true, force: true });\n throw error;\n }\n process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS = resources.agentDirectories.join(path.delimiter);\n process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS = resources.skillDirectories.join(path.delimiter);\n return updated;\n}\n"],"mappings":"0aA2BA,eAAsB,EAAa,EAAuB,EAAkD,CAC1G,GAAM,CAAE,OAAM,sBAAuB,EAAoB,CAAK,EAExD,EAAgB,MAAM,EAC1B,EAAqB,EAAM,EAAa,CAAC,GAAG,EAAM,iBAAiB,CAAC,CACtE,EACM,EAAe,EAAoB,EAAM,CAAW,EAIpD,EAAqB,MAAM,EAAG,SAAS,QAAQ,EAAK,KAAK,EAAoB,UAAU,CAAC,EAC1F,EACJ,GAAI,CACF,EAAY,MAAM,EAAiB,EAAM,EAAe,CACtD,OAAQ,EAAM,OACd,IAAK,EAAM,IACX,mBAAoB,EACpB,aAAc,EAAoB,EAAM,CAAW,EACnD,cACF,CAAC,CACH,OAAS,EAAO,CAEd,MADA,MAAM,EAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACnE,CACR,CAEA,IAAI,EACJ,GAAI,CACF,EAAU,EAAmB,CAC3B,QAAS,EACT,iBAAkB,EAAU,iBAC5B,YAAa,EAAU,YACvB,cAAe,EAAU,cACzB,cAAe,EAAU,aAC3B,CAAC,CACH,OAAS,EAAO,CAEd,MADA,MAAM,EAAG,SAAS,GAAG,EAAoB,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACnE,CACR,CAGA,MAFA,SAAQ,IAAI,6BAA+B,EAAU,iBAAiB,KAAK,EAAK,SAAS,EACzF,QAAQ,IAAI,6BAA+B,EAAU,iBAAiB,KAAK,EAAK,SAAS,EAClF,CACT"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../services/domainText.cjs");let t=require("@agimon-ai/doompi-config/harnessStore"),n=require("@agimon-ai/doompi-config/piContext");function r(){let
|
|
1
|
+
const e=require("../services/domainText.cjs");let t=require("@agimon-ai/doompi-config/harnessStore"),n=require("@agimon-ai/doompi-config/piContext");function r(r){let i,a=()=>i??=import(`@agimon-ai/doompi-config/domains`);return{list:async e=>{let i=(0,n.requireDoomConfigContext)(r()),o=i.harness,s=(0,t.requireHarnessRoot)(o),{defaultDomainsForMajorMode:c,listDomainNames:l,loadDomains:u}=await a(),d=[...new Set(l(s))].sort(),f=u(s),p=i.pendingSelection?void 0:(0,n.readDoomConfigSelection)(e),m=p?[...p.domains]:[...o.domains],h=c(o.majorMode,process.env,f.defaultDomains);return{active:m,effective:p?[...p.domains]:o.domains.length>0?[...o.domains]:[...h],available:d}},validate:async(i,o)=>{let s=e.normalizeDomainNames(o),c=(0,n.requireDoomConfigContext)(r()).harness,l=(0,t.requireHarnessRoot)(c),{listDomainNames:u,resolvePluginEntries:d}=await a(),f=new Set(u(l)),p=s.filter(e=>!f.has(e));if(p.length>0)throw Error(`Unknown domain: ${p.join(`, `)}`);return d(l,s,[...c.pluginDirectories]),s},describe:async e=>{let t=(0,n.requireDoomConfigContext)(r()).harness.root;if(!t)return{};let{loadDomains:i}=await a();return Object.fromEntries(Object.entries(i(t).domains).map(([e,t])=>[e,t.description]))},completions:async(e,t)=>{let{domainCompletionItems:n,domainCompletionPrefix:r,listDomainNames:i}=await a(),o=r(t);if(o===void 0)return;let s=n(i(e),o);return s.length===0?void 0:{prefix:o,items:s}}}}exports.createDomainCatalog=r;
|
|
2
2
|
//# sourceMappingURL=domainCatalog.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domainCatalog.cjs","names":["requireDoomConfigContext","requireHarnessRoot","readDoomConfigSelection","normalizeDomainNames"],"sources":["../../src/adapters/domainCatalog.ts"],"sourcesContent":["import { requireHarnessRoot } from '@agimon-ai/doompi-config/harnessStore';\nimport { readDoomConfigSelection, requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { normalizeDomainNames } from '../services/domainText.ts';\nimport type { DomainCompletion, DomainListing } from '../types/domains.ts';\n\n/**\n * The manifest reader every surface of this package shares.\n *\n * Every session registers `/domains`, but most never run it, so the plugin\n * catalogue and the domain manifest stay behind a dynamic import: only a session\n * that actually lists or switches domains pays to read them.\n */\nexport function createDomainCatalog() {\n let config: Promise<typeof import('@agimon-ai/doompi-config/domains')> | undefined;\n const load = () => (config ??= import('@agimon-ai/doompi-config/domains'));\n\n const list = async (ctx: ExtensionContext): Promise<DomainListing> => {\n const
|
|
1
|
+
{"version":3,"file":"domainCatalog.cjs","names":["requireDoomConfigContext","requireHarnessRoot","readDoomConfigSelection","normalizeDomainNames"],"sources":["../../src/adapters/domainCatalog.ts"],"sourcesContent":["import { requireHarnessRoot } from '@agimon-ai/doompi-config/harnessStore';\nimport { readDoomConfigSelection, requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { normalizeDomainNames } from '../services/domainText.ts';\nimport type { DomainCompletion, DomainListing } from '../types/domains.ts';\n\n/**\n * The manifest reader every surface of this package shares.\n *\n * Every session registers `/domains`, but most never run it, so the plugin\n * catalogue and the domain manifest stay behind a dynamic import: only a session\n * that actually lists or switches domains pays to read them.\n */\nexport function createDomainCatalog(cordisContext: () => Context) {\n let config: Promise<typeof import('@agimon-ai/doompi-config/domains')> | undefined;\n const load = () => (config ??= import('@agimon-ai/doompi-config/domains'));\n\n const list = async (ctx: ExtensionContext): Promise<DomainListing> => {\n const configContext = requireDoomConfigContext(cordisContext());\n const state = configContext.harness;\n const repoRoot = requireHarnessRoot(state);\n const { defaultDomainsForMajorMode, listDomainNames, loadDomains } = await load();\n const available = [...new Set(listDomainNames(repoRoot))].sort();\n const manifest = loadDomains(repoRoot);\n // A journalled selection outranks the environment, but only once the switch\n // that produced it has settled: a pending one has not been applied yet.\n const selection = configContext.pendingSelection ? undefined : readDoomConfigSelection(ctx);\n const active = selection ? [...selection.domains] : [...state.domains];\n const fallback = defaultDomainsForMajorMode(state.majorMode, process.env, manifest.defaultDomains);\n const effective = selection\n ? [...selection.domains]\n : state.domains.length > 0\n ? [...state.domains]\n : [...fallback];\n return { active, effective, available };\n };\n\n const validate = async (_ctx: ExtensionContext, values: readonly string[]): Promise<string[]> => {\n const selected = normalizeDomainNames(values);\n const state = requireDoomConfigContext(cordisContext()).harness;\n const repoRoot = requireHarnessRoot(state);\n const { listDomainNames, resolvePluginEntries } = await load();\n const available = new Set(listDomainNames(repoRoot));\n const unknown = selected.filter((name) => !available.has(name));\n if (unknown.length > 0) throw new Error(`Unknown domain: ${unknown.join(', ')}`);\n resolvePluginEntries(repoRoot, selected, [...state.pluginDirectories]);\n return selected;\n };\n\n const describe = async (_ctx: ExtensionContext): Promise<Record<string, string | undefined>> => {\n const root = requireDoomConfigContext(cordisContext()).harness.root;\n if (!root) return {};\n const { loadDomains } = await load();\n return Object.fromEntries(\n Object.entries(loadDomains(root).domains).map(([name, domain]) => [name, domain.description]),\n );\n };\n\n const completions = async (root: string, textBeforeCursor: string): Promise<DomainCompletion | undefined> => {\n const { domainCompletionItems, domainCompletionPrefix, listDomainNames } = await load();\n const prefix = domainCompletionPrefix(textBeforeCursor);\n if (prefix === undefined) return undefined;\n // Re-read on every keystroke: a domain added while the session is running\n // has to be completable without a reload.\n const items = domainCompletionItems(listDomainNames(root), prefix);\n return items.length === 0 ? undefined : { prefix, items };\n };\n\n return { list, validate, describe, completions };\n}\n\nexport type DomainCatalog = ReturnType<typeof createDomainCatalog>;\n"],"mappings":"qJAcA,SAAgB,EAAoB,EAA8B,CAChE,IAAI,EACE,MAAc,IAAW,OAAO,oCAqDtC,MAAO,CAAE,UAnDW,IAAkD,CACpE,IAAM,GAAA,EAAgBA,EAAAA,yBAAAA,CAAyB,EAAc,CAAC,EACxD,EAAQ,EAAc,QACtB,GAAA,EAAWC,EAAAA,mBAAAA,CAAmB,CAAK,EACnC,CAAE,6BAA4B,kBAAiB,eAAgB,MAAM,EAAK,EAC1E,EAAY,CAAC,GAAG,IAAI,IAAI,EAAgB,CAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,EACzD,EAAW,EAAY,CAAQ,EAG/B,EAAY,EAAc,iBAAmB,IAAA,IAAA,EAAYC,EAAAA,wBAAAA,CAAwB,CAAG,EACpF,EAAS,EAAY,CAAC,GAAG,EAAU,OAAO,EAAI,CAAC,GAAG,EAAM,OAAO,EAC/D,EAAW,EAA2B,EAAM,UAAW,QAAQ,IAAK,EAAS,cAAc,EAMjG,MAAO,CAAE,SAAQ,UALC,EACd,CAAC,GAAG,EAAU,OAAO,EACrB,EAAM,QAAQ,OAAS,EACrB,CAAC,GAAG,EAAM,OAAO,EACjB,CAAC,GAAG,CAAQ,EACU,WAAU,CACxC,EAiCe,eA/BS,EAAwB,IAAiD,CAC/F,IAAM,EAAWC,EAAAA,qBAAqB,CAAM,EACtC,GAAA,EAAQH,EAAAA,yBAAAA,CAAyB,EAAc,CAAC,CAAC,CAAC,QAClD,GAAA,EAAWC,EAAAA,mBAAAA,CAAmB,CAAK,EACnC,CAAE,kBAAiB,wBAAyB,MAAM,EAAK,EACvD,EAAY,IAAI,IAAI,EAAgB,CAAQ,CAAC,EAC7C,EAAU,EAAS,OAAQ,GAAS,CAAC,EAAU,IAAI,CAAI,CAAC,EAC9D,GAAI,EAAQ,OAAS,EAAG,MAAU,MAAM,mBAAmB,EAAQ,KAAK,IAAI,GAAG,EAE/E,OADA,EAAqB,EAAU,EAAU,CAAC,GAAG,EAAM,iBAAiB,CAAC,EAC9D,CACT,EAqByB,cAnBD,IAAwE,CAC9F,IAAM,GAAA,EAAOD,EAAAA,yBAAAA,CAAyB,EAAc,CAAC,CAAC,CAAC,QAAQ,KAC/D,GAAI,CAAC,EAAM,MAAO,CAAC,EACnB,GAAM,CAAE,eAAgB,MAAM,EAAK,EACnC,OAAO,OAAO,YACZ,OAAO,QAAQ,EAAY,CAAI,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAM,KAAY,CAAC,EAAM,EAAO,WAAW,CAAC,CAC9F,CACF,EAYmC,kBAVR,EAAc,IAAoE,CAC3G,GAAM,CAAE,wBAAuB,yBAAwB,mBAAoB,MAAM,EAAK,EAChF,EAAS,EAAuB,CAAgB,EACtD,GAAI,IAAW,IAAA,GAAW,OAG1B,IAAM,EAAQ,EAAsB,EAAgB,CAAI,EAAG,CAAM,EACjE,OAAO,EAAM,SAAW,EAAI,IAAA,GAAY,CAAE,SAAQ,OAAM,CAC1D,CAE+C,CACjD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DomainCompletion, DomainListing } from "../types/domains.cjs";
|
|
2
2
|
import { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
4
|
//#region src/adapters/domainCatalog.d.ts
|
|
4
5
|
/**
|
|
5
6
|
* The manifest reader every surface of this package shares.
|
|
@@ -8,10 +9,10 @@ import { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
8
9
|
* catalogue and the domain manifest stay behind a dynamic import: only a session
|
|
9
10
|
* that actually lists or switches domains pays to read them.
|
|
10
11
|
*/
|
|
11
|
-
declare function createDomainCatalog(): {
|
|
12
|
+
declare function createDomainCatalog(cordisContext: () => Context): {
|
|
12
13
|
list: (ctx: ExtensionContext) => Promise<DomainListing>;
|
|
13
|
-
validate: (
|
|
14
|
-
describe: (
|
|
14
|
+
validate: (_ctx: ExtensionContext, values: readonly string[]) => Promise<string[]>;
|
|
15
|
+
describe: (_ctx: ExtensionContext) => Promise<Record<string, string | undefined>>;
|
|
15
16
|
completions: (root: string, textBeforeCursor: string) => Promise<DomainCompletion | undefined>;
|
|
16
17
|
};
|
|
17
18
|
type DomainCatalog = ReturnType<typeof createDomainCatalog>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domainCatalog.d.cts","names":[],"sources":["../../src/adapters/domainCatalog.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"domainCatalog.d.cts","names":[],"sources":["../../src/adapters/domainCatalog.ts"],"mappings":";;;;;;;;;;;iBAcgB,oBAAoB,qBAAqB;EAI9B,OAAA,KAAA,qBAAmB,QAAQ;EAoBtB,WAAA,MAAA,kBAAgB,8BAA8B;EAY9C,WAAA,MAAA,qBAAmB,QAAQ;EASxB,cAAA,cAAM,6BAA6B,QAAQ;;KAalE,gBAAgB,kBAAkB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DomainCompletion, DomainListing } from "../types/domains.mjs";
|
|
2
2
|
import { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
4
|
//#region src/adapters/domainCatalog.d.ts
|
|
4
5
|
/**
|
|
5
6
|
* The manifest reader every surface of this package shares.
|
|
@@ -8,10 +9,10 @@ import { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
8
9
|
* catalogue and the domain manifest stay behind a dynamic import: only a session
|
|
9
10
|
* that actually lists or switches domains pays to read them.
|
|
10
11
|
*/
|
|
11
|
-
declare function createDomainCatalog(): {
|
|
12
|
+
declare function createDomainCatalog(cordisContext: () => Context): {
|
|
12
13
|
list: (ctx: ExtensionContext) => Promise<DomainListing>;
|
|
13
|
-
validate: (
|
|
14
|
-
describe: (
|
|
14
|
+
validate: (_ctx: ExtensionContext, values: readonly string[]) => Promise<string[]>;
|
|
15
|
+
describe: (_ctx: ExtensionContext) => Promise<Record<string, string | undefined>>;
|
|
15
16
|
completions: (root: string, textBeforeCursor: string) => Promise<DomainCompletion | undefined>;
|
|
16
17
|
};
|
|
17
18
|
type DomainCatalog = ReturnType<typeof createDomainCatalog>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domainCatalog.d.mts","names":[],"sources":["../../src/adapters/domainCatalog.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"domainCatalog.d.mts","names":[],"sources":["../../src/adapters/domainCatalog.ts"],"mappings":";;;;;;;;;;;iBAcgB,oBAAoB,qBAAqB;EAI9B,OAAA,KAAA,qBAAmB,QAAQ;EAoBtB,WAAA,MAAA,kBAAgB,8BAA8B;EAY9C,WAAA,MAAA,qBAAmB,QAAQ;EASxB,cAAA,cAAM,6BAA6B,QAAQ;;KAalE,gBAAgB,kBAAkB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{normalizeDomainNames as e}from"../services/domainText.mjs";import{requireHarnessRoot as t}from"@agimon-ai/doompi-config/harnessStore";import{readDoomConfigSelection as n,requireDoomConfigContext as r}from"@agimon-ai/doompi-config/piContext";function i(){let
|
|
1
|
+
import{normalizeDomainNames as e}from"../services/domainText.mjs";import{requireHarnessRoot as t}from"@agimon-ai/doompi-config/harnessStore";import{readDoomConfigSelection as n,requireDoomConfigContext as r}from"@agimon-ai/doompi-config/piContext";function i(i){let a,o=()=>a??=import(`@agimon-ai/doompi-config/domains`);return{list:async e=>{let a=r(i()),s=a.harness,c=t(s),{defaultDomainsForMajorMode:l,listDomainNames:u,loadDomains:d}=await o(),f=[...new Set(u(c))].sort(),p=d(c),m=a.pendingSelection?void 0:n(e),h=m?[...m.domains]:[...s.domains],g=l(s.majorMode,process.env,p.defaultDomains);return{active:h,effective:m?[...m.domains]:s.domains.length>0?[...s.domains]:[...g],available:f}},validate:async(n,a)=>{let s=e(a),c=r(i()).harness,l=t(c),{listDomainNames:u,resolvePluginEntries:d}=await o(),f=new Set(u(l)),p=s.filter(e=>!f.has(e));if(p.length>0)throw Error(`Unknown domain: ${p.join(`, `)}`);return d(l,s,[...c.pluginDirectories]),s},describe:async e=>{let t=r(i()).harness.root;if(!t)return{};let{loadDomains:n}=await o();return Object.fromEntries(Object.entries(n(t).domains).map(([e,t])=>[e,t.description]))},completions:async(e,t)=>{let{domainCompletionItems:n,domainCompletionPrefix:r,listDomainNames:i}=await o(),a=r(t);if(a===void 0)return;let s=n(i(e),a);return s.length===0?void 0:{prefix:a,items:s}}}}export{i as createDomainCatalog};
|
|
2
2
|
//# sourceMappingURL=domainCatalog.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domainCatalog.mjs","names":[],"sources":["../../src/adapters/domainCatalog.ts"],"sourcesContent":["import { requireHarnessRoot } from '@agimon-ai/doompi-config/harnessStore';\nimport { readDoomConfigSelection, requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { normalizeDomainNames } from '../services/domainText.ts';\nimport type { DomainCompletion, DomainListing } from '../types/domains.ts';\n\n/**\n * The manifest reader every surface of this package shares.\n *\n * Every session registers `/domains`, but most never run it, so the plugin\n * catalogue and the domain manifest stay behind a dynamic import: only a session\n * that actually lists or switches domains pays to read them.\n */\nexport function createDomainCatalog() {\n let config: Promise<typeof import('@agimon-ai/doompi-config/domains')> | undefined;\n const load = () => (config ??= import('@agimon-ai/doompi-config/domains'));\n\n const list = async (ctx: ExtensionContext): Promise<DomainListing> => {\n const
|
|
1
|
+
{"version":3,"file":"domainCatalog.mjs","names":[],"sources":["../../src/adapters/domainCatalog.ts"],"sourcesContent":["import { requireHarnessRoot } from '@agimon-ai/doompi-config/harnessStore';\nimport { readDoomConfigSelection, requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { normalizeDomainNames } from '../services/domainText.ts';\nimport type { DomainCompletion, DomainListing } from '../types/domains.ts';\n\n/**\n * The manifest reader every surface of this package shares.\n *\n * Every session registers `/domains`, but most never run it, so the plugin\n * catalogue and the domain manifest stay behind a dynamic import: only a session\n * that actually lists or switches domains pays to read them.\n */\nexport function createDomainCatalog(cordisContext: () => Context) {\n let config: Promise<typeof import('@agimon-ai/doompi-config/domains')> | undefined;\n const load = () => (config ??= import('@agimon-ai/doompi-config/domains'));\n\n const list = async (ctx: ExtensionContext): Promise<DomainListing> => {\n const configContext = requireDoomConfigContext(cordisContext());\n const state = configContext.harness;\n const repoRoot = requireHarnessRoot(state);\n const { defaultDomainsForMajorMode, listDomainNames, loadDomains } = await load();\n const available = [...new Set(listDomainNames(repoRoot))].sort();\n const manifest = loadDomains(repoRoot);\n // A journalled selection outranks the environment, but only once the switch\n // that produced it has settled: a pending one has not been applied yet.\n const selection = configContext.pendingSelection ? undefined : readDoomConfigSelection(ctx);\n const active = selection ? [...selection.domains] : [...state.domains];\n const fallback = defaultDomainsForMajorMode(state.majorMode, process.env, manifest.defaultDomains);\n const effective = selection\n ? [...selection.domains]\n : state.domains.length > 0\n ? [...state.domains]\n : [...fallback];\n return { active, effective, available };\n };\n\n const validate = async (_ctx: ExtensionContext, values: readonly string[]): Promise<string[]> => {\n const selected = normalizeDomainNames(values);\n const state = requireDoomConfigContext(cordisContext()).harness;\n const repoRoot = requireHarnessRoot(state);\n const { listDomainNames, resolvePluginEntries } = await load();\n const available = new Set(listDomainNames(repoRoot));\n const unknown = selected.filter((name) => !available.has(name));\n if (unknown.length > 0) throw new Error(`Unknown domain: ${unknown.join(', ')}`);\n resolvePluginEntries(repoRoot, selected, [...state.pluginDirectories]);\n return selected;\n };\n\n const describe = async (_ctx: ExtensionContext): Promise<Record<string, string | undefined>> => {\n const root = requireDoomConfigContext(cordisContext()).harness.root;\n if (!root) return {};\n const { loadDomains } = await load();\n return Object.fromEntries(\n Object.entries(loadDomains(root).domains).map(([name, domain]) => [name, domain.description]),\n );\n };\n\n const completions = async (root: string, textBeforeCursor: string): Promise<DomainCompletion | undefined> => {\n const { domainCompletionItems, domainCompletionPrefix, listDomainNames } = await load();\n const prefix = domainCompletionPrefix(textBeforeCursor);\n if (prefix === undefined) return undefined;\n // Re-read on every keystroke: a domain added while the session is running\n // has to be completable without a reload.\n const items = domainCompletionItems(listDomainNames(root), prefix);\n return items.length === 0 ? undefined : { prefix, items };\n };\n\n return { list, validate, describe, completions };\n}\n\nexport type DomainCatalog = ReturnType<typeof createDomainCatalog>;\n"],"mappings":"wPAcA,SAAgB,EAAoB,EAA8B,CAChE,IAAI,EACE,MAAc,IAAW,OAAO,oCAqDtC,MAAO,CAAE,UAnDW,IAAkD,CACpE,IAAM,EAAgB,EAAyB,EAAc,CAAC,EACxD,EAAQ,EAAc,QACtB,EAAW,EAAmB,CAAK,EACnC,CAAE,6BAA4B,kBAAiB,eAAgB,MAAM,EAAK,EAC1E,EAAY,CAAC,GAAG,IAAI,IAAI,EAAgB,CAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,EACzD,EAAW,EAAY,CAAQ,EAG/B,EAAY,EAAc,iBAAmB,IAAA,GAAY,EAAwB,CAAG,EACpF,EAAS,EAAY,CAAC,GAAG,EAAU,OAAO,EAAI,CAAC,GAAG,EAAM,OAAO,EAC/D,EAAW,EAA2B,EAAM,UAAW,QAAQ,IAAK,EAAS,cAAc,EAMjG,MAAO,CAAE,SAAQ,UALC,EACd,CAAC,GAAG,EAAU,OAAO,EACrB,EAAM,QAAQ,OAAS,EACrB,CAAC,GAAG,EAAM,OAAO,EACjB,CAAC,GAAG,CAAQ,EACU,WAAU,CACxC,EAiCe,eA/BS,EAAwB,IAAiD,CAC/F,IAAM,EAAW,EAAqB,CAAM,EACtC,EAAQ,EAAyB,EAAc,CAAC,CAAC,CAAC,QAClD,EAAW,EAAmB,CAAK,EACnC,CAAE,kBAAiB,wBAAyB,MAAM,EAAK,EACvD,EAAY,IAAI,IAAI,EAAgB,CAAQ,CAAC,EAC7C,EAAU,EAAS,OAAQ,GAAS,CAAC,EAAU,IAAI,CAAI,CAAC,EAC9D,GAAI,EAAQ,OAAS,EAAG,MAAU,MAAM,mBAAmB,EAAQ,KAAK,IAAI,GAAG,EAE/E,OADA,EAAqB,EAAU,EAAU,CAAC,GAAG,EAAM,iBAAiB,CAAC,EAC9D,CACT,EAqByB,cAnBD,IAAwE,CAC9F,IAAM,EAAO,EAAyB,EAAc,CAAC,CAAC,CAAC,QAAQ,KAC/D,GAAI,CAAC,EAAM,MAAO,CAAC,EACnB,GAAM,CAAE,eAAgB,MAAM,EAAK,EACnC,OAAO,OAAO,YACZ,OAAO,QAAQ,EAAY,CAAI,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAM,KAAY,CAAC,EAAM,EAAO,WAAW,CAAC,CAC9F,CACF,EAYmC,kBAVR,EAAc,IAAoE,CAC3G,GAAM,CAAE,wBAAuB,yBAAwB,mBAAoB,MAAM,EAAK,EAChF,EAAS,EAAuB,CAAgB,EACtD,GAAI,IAAW,IAAA,GAAW,OAG1B,IAAM,EAAQ,EAAsB,EAAgB,CAAI,EAAG,CAAM,EACjE,OAAO,EAAM,SAAW,EAAI,IAAA,GAAY,CAAE,SAAQ,OAAM,CAC1D,CAE+C,CACjD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../types/domains.cjs"),t=Symbol.for(`@agimon-ai/doompi-domain.switch-handoff.v1`),n=3e4;function r(){let e=globalThis;return e[t]??={records:new Map}}function i(e){return Error(`Invalid domain switch handoff ${e}.`)}function a(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function o(e,t,n,r){let o=e.trim()
|
|
1
|
+
const e=require("../types/domains.cjs"),t=Symbol.for(`@agimon-ai/doompi-domain.switch-handoff.v1`),n=3e4;function r(){let e=globalThis;return e[t]??={records:new Map}}function i(e){return Error(`Invalid domain switch handoff ${e}.`)}function a(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function o(e,t,n,r){let o=typeof e==`string`?e.trim():``;if(!o||o.length>n||a(o)||r&&!r.test(o))throw i(t);return o}function s(e){return o(e,`session id`,256)}function c(e){return o(e,`host generation`,256)}function l(t){return o(t,`operation id`,128,e.SAFE_DOMAIN_NAME)}function u(t){return o(t,`reload handoff token`,256,e.SAFE_DOMAIN_NAME)}function d(t){return o(t,`token`,256,e.SAFE_DOMAIN_NAME)}function f(t){if(t.length>32)throw Error(`A maximum of 32 domains may be selected.`);let n=[],r=new Set;for(let i of t){let t=o(i,`domain name`,128,e.SAFE_DOMAIN_NAME);r.has(t)||(r.add(t),n.push(t))}return n}function p(e=Date.now()){for(let[t,n]of r().records)n.expiresAt<=e&&r().records.delete(t)}function m(e,t){return e.sessionId===s(t.sessionId)&&e.hostGeneration===c(t.hostGeneration)}function h(e){return{...e,domains:[...e.domains]}}function g(e,t){p();let i=s(t.sessionId),a=c(t.hostGeneration),o=l(t.operationId),d=f(t.domains),m=u(t.reloadHandoffToken),g=Date.now(),_={token:`doom-domain-switch:${crypto.randomUUID()}`,sessionId:i,hostGeneration:a,operationId:o,domains:d,reloadHandoffToken:m,createdAt:g,expiresAt:g+n,ownerGeneration:e};return r().records.set(_.token,_),h(_)}function _(e,t){p();let n=d(t),i=r().records.get(n);if(!(!i||!m(i,e))&&(r().records.delete(n),!(i.expiresAt<=Date.now())))return h(i)}function v(e,t){p();let n=d(t),i=r().records.get(n);return!i||!m(i,e)?!1:r().records.delete(n)}function y(e,t){p();let n=s(t),i=0;for(let[t,a]of r().records)a.ownerGeneration===e&&a.sessionId===n&&(r().records.delete(t),i+=1);return i}function b(e){let t=0;for(let[n,i]of r().records)i.ownerGeneration===e&&(r().records.delete(n),t+=1);return t}function x(){let e=crypto.randomUUID(),t=!1;return{ownerGeneration:e,issue(n){if(t)throw Error(`Domain switch handoff store is disposed.`);return g(e,n)},consume(e,n){if(!t)return _(n,e)},discard(e,n){return!t&&v(n,e)},clearSession(n){return t?0:y(e,n)},dispose(){return t?0:(t=!0,b(e))}}}exports.DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS=32,exports.DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH=256,exports.DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH=128,exports.DOMAIN_SWITCH_HANDOFF_TTL_MS=n,exports.createDomainSwitchHandoffStore=x;
|
|
2
2
|
//# sourceMappingURL=domainSwitchHandoff.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domainSwitchHandoff.cjs","names":["SAFE_DOMAIN_NAME"],"sources":["../../src/adapters/domainSwitchHandoff.ts"],"sourcesContent":["import type {\n DomainSwitchHandoff,\n DomainSwitchHandoffIdentity,\n DomainSwitchHandoffRequest,\n DomainSwitchHandoffStore,\n} from '../types/handoff.ts';\nimport { SAFE_DOMAIN_NAME } from '../types/domains.ts';\n\nconst DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY = '@agimon-ai/doompi-domain.switch-handoff.v1';\nconst DOMAIN_SWITCH_HANDOFF_SYMBOL = Symbol.for(DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY);\nconst DOMAIN_SWITCH_TOKEN_PREFIX = 'doom-domain-switch:';\n\nexport const DOMAIN_SWITCH_HANDOFF_TTL_MS = 30_000;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS = 32;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH = 256;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH = 128;\n\ninterface StoredDomainSwitchHandoff extends DomainSwitchHandoff {\n readonly ownerGeneration: string;\n}\n\ninterface HandoffRegistry {\n readonly records: Map<string, StoredDomainSwitchHandoff>;\n}\n\ntype HandoffGlobal = typeof globalThis & { [DOMAIN_SWITCH_HANDOFF_SYMBOL]?: HandoffRegistry };\n\n/**\n * One registry per process, keyed by a well-known symbol.\n *\n * Pi can reload this module in place, and a reload that lost the parked handoffs\n * would strand the follow-up command the voice tool already sent. Ownership is\n * tracked per store instead, so a disposed store takes only its own records.\n */\nfunction registry(): HandoffRegistry {\n const root = globalThis as HandoffGlobal;\n return (root[DOMAIN_SWITCH_HANDOFF_SYMBOL] ??= { records: new Map() });\n}\n\nfunction invalid(label: string): Error {\n return new Error(`Invalid domain switch handoff ${label}.`);\n}\n\nfunction hasControlCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0);\n if (code !== undefined && (code <= 0x1f || code === 0x7f)) return true;\n }\n return false;\n}\n\nfunction normalized(value: string, label: string, maximum: number, pattern?: RegExp): string {\n const text = value.trim();\n if (!text || text.length > maximum || hasControlCharacter(text) || (pattern && !pattern.test(text))) {\n throw invalid(label);\n }\n return text;\n}\n\nfunction sessionId(value: string): string {\n return normalized(value, 'session id', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction hostGeneration(value: string): string {\n return normalized(value, 'host generation', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction operationId(value: string): string {\n return normalized(value, 'operation id', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction reloadToken(value: string): string {\n return normalized(value, 'reload handoff token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction token(value: string): string {\n return normalized(value, 'token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction domains(values: readonly string[]): string[] {\n if (values.length > DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS) {\n throw new Error(`A maximum of ${DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS} domains may be selected.`);\n }\n const result: string[] = [];\n const seen = new Set<string>();\n for (const value of values) {\n const name = normalized(value, 'domain name', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n if (seen.has(name)) continue;\n seen.add(name);\n result.push(name);\n }\n return result;\n}\n\nfunction prune(now = Date.now()): void {\n for (const [key, record] of registry().records) {\n if (record.expiresAt <= now) registry().records.delete(key);\n }\n}\n\nfunction identityMatches(record: DomainSwitchHandoff, identity: DomainSwitchHandoffIdentity): boolean {\n if (record.sessionId !== sessionId(identity.sessionId)) return false;\n return identity.hostGeneration === undefined || record.hostGeneration === hostGeneration(identity.hostGeneration);\n}\n\nfunction copy(record: DomainSwitchHandoff): DomainSwitchHandoff {\n return { ...record, domains: [...record.domains] };\n}\n\nfunction issue(ownerGeneration: string, request: DomainSwitchHandoffRequest): DomainSwitchHandoff {\n prune();\n const normalizedSessionId = sessionId(request.sessionId);\n const normalizedHostGeneration = hostGeneration(request.hostGeneration);\n const normalizedOperationId = operationId(request.operationId);\n const normalizedDomains = domains(request.domains);\n const normalizedReloadToken = reloadToken(request.reloadHandoffToken);\n const createdAt = Date.now();\n const record: StoredDomainSwitchHandoff = {\n token: `${DOMAIN_SWITCH_TOKEN_PREFIX}${crypto.randomUUID()}`,\n sessionId: normalizedSessionId,\n hostGeneration: normalizedHostGeneration,\n operationId: normalizedOperationId,\n domains: normalizedDomains,\n reloadHandoffToken: normalizedReloadToken,\n createdAt,\n expiresAt: createdAt + DOMAIN_SWITCH_HANDOFF_TTL_MS,\n ownerGeneration,\n };\n registry().records.set(record.token, record);\n return copy(record);\n}\n\nfunction consume(identity: DomainSwitchHandoffIdentity, handoffToken: string): DomainSwitchHandoff | undefined {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return undefined;\n registry().records.delete(normalizedToken);\n if (record.expiresAt <= Date.now()) return undefined;\n return copy(record);\n}\n\nfunction discard(identity: DomainSwitchHandoffIdentity, handoffToken: string): boolean {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return false;\n return registry().records.delete(normalizedToken);\n}\n\nfunction clearOwnedSession(ownerGeneration: string, requestedSessionId: string): number {\n prune();\n const normalizedSessionId = sessionId(requestedSessionId);\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration || record.sessionId !== normalizedSessionId) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nfunction disposeOwner(ownerGeneration: string): number {\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nexport function createDomainSwitchHandoffStore(): DomainSwitchHandoffStore {\n const ownerGeneration = crypto.randomUUID();\n let disposed = false;\n return {\n ownerGeneration,\n issue(request) {\n if (disposed) throw new Error('Domain switch handoff store is disposed.');\n return issue(ownerGeneration, request);\n },\n consume(handoffToken, identity) {\n if (disposed) return undefined;\n return consume(identity, handoffToken);\n },\n discard(handoffToken, identity) {\n if (disposed) return false;\n return discard(identity, handoffToken);\n },\n clearSession(requestedSessionId) {\n if (disposed) return 0;\n return clearOwnedSession(ownerGeneration, requestedSessionId);\n },\n dispose() {\n if (disposed) return 0;\n disposed = true;\n return disposeOwner(ownerGeneration);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"domainSwitchHandoff.cjs","names":["SAFE_DOMAIN_NAME"],"sources":["../../src/adapters/domainSwitchHandoff.ts"],"sourcesContent":["import type {\n DomainSwitchHandoff,\n DomainSwitchHandoffIdentity,\n DomainSwitchHandoffRequest,\n DomainSwitchHandoffStore,\n} from '../types/handoff.ts';\nimport { SAFE_DOMAIN_NAME } from '../types/domains.ts';\n\nconst DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY = '@agimon-ai/doompi-domain.switch-handoff.v1';\nconst DOMAIN_SWITCH_HANDOFF_SYMBOL = Symbol.for(DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY);\nconst DOMAIN_SWITCH_TOKEN_PREFIX = 'doom-domain-switch:';\n\nexport const DOMAIN_SWITCH_HANDOFF_TTL_MS = 30_000;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS = 32;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH = 256;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH = 128;\n\ninterface StoredDomainSwitchHandoff extends DomainSwitchHandoff {\n readonly ownerGeneration: string;\n}\n\ninterface HandoffRegistry {\n readonly records: Map<string, StoredDomainSwitchHandoff>;\n}\n\ntype HandoffGlobal = typeof globalThis & { [DOMAIN_SWITCH_HANDOFF_SYMBOL]?: HandoffRegistry };\n\n/**\n * One registry per process, keyed by a well-known symbol.\n *\n * Pi can reload this module in place, and a reload that lost the parked handoffs\n * would strand the follow-up command the voice tool already sent. Ownership is\n * tracked per store instead, so a disposed store takes only its own records.\n */\nfunction registry(): HandoffRegistry {\n const root = globalThis as HandoffGlobal;\n return (root[DOMAIN_SWITCH_HANDOFF_SYMBOL] ??= { records: new Map() });\n}\n\nfunction invalid(label: string): Error {\n return new Error(`Invalid domain switch handoff ${label}.`);\n}\n\nfunction hasControlCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0);\n if (code !== undefined && (code <= 0x1f || code === 0x7f)) return true;\n }\n return false;\n}\n\nfunction normalized(value: unknown, label: string, maximum: number, pattern?: RegExp): string {\n const text = typeof value === 'string' ? value.trim() : '';\n if (!text || text.length > maximum || hasControlCharacter(text) || (pattern && !pattern.test(text))) {\n throw invalid(label);\n }\n return text;\n}\n\nfunction sessionId(value: string): string {\n return normalized(value, 'session id', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction hostGeneration(value: string): string {\n return normalized(value, 'host generation', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction operationId(value: string): string {\n return normalized(value, 'operation id', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction reloadToken(value: string): string {\n return normalized(value, 'reload handoff token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction token(value: string): string {\n return normalized(value, 'token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction domains(values: readonly string[]): string[] {\n if (values.length > DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS) {\n throw new Error(`A maximum of ${DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS} domains may be selected.`);\n }\n const result: string[] = [];\n const seen = new Set<string>();\n for (const value of values) {\n const name = normalized(value, 'domain name', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n if (seen.has(name)) continue;\n seen.add(name);\n result.push(name);\n }\n return result;\n}\n\nfunction prune(now = Date.now()): void {\n for (const [key, record] of registry().records) {\n if (record.expiresAt <= now) registry().records.delete(key);\n }\n}\n\nfunction identityMatches(record: DomainSwitchHandoff, identity: DomainSwitchHandoffIdentity): boolean {\n if (record.sessionId !== sessionId(identity.sessionId)) return false;\n return record.hostGeneration === hostGeneration(identity.hostGeneration);\n}\n\nfunction copy(record: DomainSwitchHandoff): DomainSwitchHandoff {\n return { ...record, domains: [...record.domains] };\n}\n\nfunction issue(ownerGeneration: string, request: DomainSwitchHandoffRequest): DomainSwitchHandoff {\n prune();\n const normalizedSessionId = sessionId(request.sessionId);\n const normalizedHostGeneration = hostGeneration(request.hostGeneration);\n const normalizedOperationId = operationId(request.operationId);\n const normalizedDomains = domains(request.domains);\n const normalizedReloadToken = reloadToken(request.reloadHandoffToken);\n const createdAt = Date.now();\n const record: StoredDomainSwitchHandoff = {\n token: `${DOMAIN_SWITCH_TOKEN_PREFIX}${crypto.randomUUID()}`,\n sessionId: normalizedSessionId,\n hostGeneration: normalizedHostGeneration,\n operationId: normalizedOperationId,\n domains: normalizedDomains,\n reloadHandoffToken: normalizedReloadToken,\n createdAt,\n expiresAt: createdAt + DOMAIN_SWITCH_HANDOFF_TTL_MS,\n ownerGeneration,\n };\n registry().records.set(record.token, record);\n return copy(record);\n}\n\nfunction consume(identity: DomainSwitchHandoffIdentity, handoffToken: string): DomainSwitchHandoff | undefined {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return undefined;\n registry().records.delete(normalizedToken);\n if (record.expiresAt <= Date.now()) return undefined;\n return copy(record);\n}\n\nfunction discard(identity: DomainSwitchHandoffIdentity, handoffToken: string): boolean {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return false;\n return registry().records.delete(normalizedToken);\n}\n\nfunction clearOwnedSession(ownerGeneration: string, requestedSessionId: string): number {\n prune();\n const normalizedSessionId = sessionId(requestedSessionId);\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration || record.sessionId !== normalizedSessionId) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nfunction disposeOwner(ownerGeneration: string): number {\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nexport function createDomainSwitchHandoffStore(): DomainSwitchHandoffStore {\n const ownerGeneration = crypto.randomUUID();\n let disposed = false;\n return {\n ownerGeneration,\n issue(request) {\n if (disposed) throw new Error('Domain switch handoff store is disposed.');\n return issue(ownerGeneration, request);\n },\n consume(handoffToken, identity) {\n if (disposed) return undefined;\n return consume(identity, handoffToken);\n },\n discard(handoffToken, identity) {\n if (disposed) return false;\n return discard(identity, handoffToken);\n },\n clearSession(requestedSessionId) {\n if (disposed) return 0;\n return clearOwnedSession(ownerGeneration, requestedSessionId);\n },\n dispose() {\n if (disposed) return 0;\n disposed = true;\n return disposeOwner(ownerGeneration);\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{SAFE_DOMAIN_NAME as e}from"../types/domains.mjs";const t=Symbol.for(`@agimon-ai/doompi-domain.switch-handoff.v1`),n=3e4,r=32,i=256,a=128;function o(){let e=globalThis;return e[t]??={records:new Map}}function s(e){return Error(`Invalid domain switch handoff ${e}.`)}function c(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function l(e,t,n,r){let i=e.trim()
|
|
1
|
+
import{SAFE_DOMAIN_NAME as e}from"../types/domains.mjs";const t=Symbol.for(`@agimon-ai/doompi-domain.switch-handoff.v1`),n=3e4,r=32,i=256,a=128;function o(){let e=globalThis;return e[t]??={records:new Map}}function s(e){return Error(`Invalid domain switch handoff ${e}.`)}function c(e){for(let t of e){let e=t.codePointAt(0);if(e!==void 0&&(e<=31||e===127))return!0}return!1}function l(e,t,n,r){let i=typeof e==`string`?e.trim():``;if(!i||i.length>n||c(i)||r&&!r.test(i))throw s(t);return i}function u(e){return l(e,`session id`,256)}function d(e){return l(e,`host generation`,256)}function f(t){return l(t,`operation id`,128,e)}function p(t){return l(t,`reload handoff token`,256,e)}function m(t){return l(t,`token`,256,e)}function h(t){if(t.length>32)throw Error(`A maximum of 32 domains may be selected.`);let n=[],r=new Set;for(let i of t){let t=l(i,`domain name`,128,e);r.has(t)||(r.add(t),n.push(t))}return n}function g(e=Date.now()){for(let[t,n]of o().records)n.expiresAt<=e&&o().records.delete(t)}function _(e,t){return e.sessionId===u(t.sessionId)&&e.hostGeneration===d(t.hostGeneration)}function v(e){return{...e,domains:[...e.domains]}}function y(e,t){g();let r=u(t.sessionId),i=d(t.hostGeneration),a=f(t.operationId),s=h(t.domains),c=p(t.reloadHandoffToken),l=Date.now(),m={token:`doom-domain-switch:${crypto.randomUUID()}`,sessionId:r,hostGeneration:i,operationId:a,domains:s,reloadHandoffToken:c,createdAt:l,expiresAt:l+n,ownerGeneration:e};return o().records.set(m.token,m),v(m)}function b(e,t){g();let n=m(t),r=o().records.get(n);if(!(!r||!_(r,e))&&(o().records.delete(n),!(r.expiresAt<=Date.now())))return v(r)}function x(e,t){g();let n=m(t),r=o().records.get(n);return!r||!_(r,e)?!1:o().records.delete(n)}function S(e,t){g();let n=u(t),r=0;for(let[t,i]of o().records)i.ownerGeneration===e&&i.sessionId===n&&(o().records.delete(t),r+=1);return r}function C(e){let t=0;for(let[n,r]of o().records)r.ownerGeneration===e&&(o().records.delete(n),t+=1);return t}function w(){let e=crypto.randomUUID(),t=!1;return{ownerGeneration:e,issue(n){if(t)throw Error(`Domain switch handoff store is disposed.`);return y(e,n)},consume(e,n){if(!t)return b(n,e)},discard(e,n){return!t&&x(n,e)},clearSession(n){return t?0:S(e,n)},dispose(){return t?0:(t=!0,C(e))}}}export{r as DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS,i as DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH,a as DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH,n as DOMAIN_SWITCH_HANDOFF_TTL_MS,w as createDomainSwitchHandoffStore};
|
|
2
2
|
//# sourceMappingURL=domainSwitchHandoff.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domainSwitchHandoff.mjs","names":[],"sources":["../../src/adapters/domainSwitchHandoff.ts"],"sourcesContent":["import type {\n DomainSwitchHandoff,\n DomainSwitchHandoffIdentity,\n DomainSwitchHandoffRequest,\n DomainSwitchHandoffStore,\n} from '../types/handoff.ts';\nimport { SAFE_DOMAIN_NAME } from '../types/domains.ts';\n\nconst DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY = '@agimon-ai/doompi-domain.switch-handoff.v1';\nconst DOMAIN_SWITCH_HANDOFF_SYMBOL = Symbol.for(DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY);\nconst DOMAIN_SWITCH_TOKEN_PREFIX = 'doom-domain-switch:';\n\nexport const DOMAIN_SWITCH_HANDOFF_TTL_MS = 30_000;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS = 32;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH = 256;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH = 128;\n\ninterface StoredDomainSwitchHandoff extends DomainSwitchHandoff {\n readonly ownerGeneration: string;\n}\n\ninterface HandoffRegistry {\n readonly records: Map<string, StoredDomainSwitchHandoff>;\n}\n\ntype HandoffGlobal = typeof globalThis & { [DOMAIN_SWITCH_HANDOFF_SYMBOL]?: HandoffRegistry };\n\n/**\n * One registry per process, keyed by a well-known symbol.\n *\n * Pi can reload this module in place, and a reload that lost the parked handoffs\n * would strand the follow-up command the voice tool already sent. Ownership is\n * tracked per store instead, so a disposed store takes only its own records.\n */\nfunction registry(): HandoffRegistry {\n const root = globalThis as HandoffGlobal;\n return (root[DOMAIN_SWITCH_HANDOFF_SYMBOL] ??= { records: new Map() });\n}\n\nfunction invalid(label: string): Error {\n return new Error(`Invalid domain switch handoff ${label}.`);\n}\n\nfunction hasControlCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0);\n if (code !== undefined && (code <= 0x1f || code === 0x7f)) return true;\n }\n return false;\n}\n\nfunction normalized(value: string, label: string, maximum: number, pattern?: RegExp): string {\n const text = value.trim();\n if (!text || text.length > maximum || hasControlCharacter(text) || (pattern && !pattern.test(text))) {\n throw invalid(label);\n }\n return text;\n}\n\nfunction sessionId(value: string): string {\n return normalized(value, 'session id', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction hostGeneration(value: string): string {\n return normalized(value, 'host generation', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction operationId(value: string): string {\n return normalized(value, 'operation id', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction reloadToken(value: string): string {\n return normalized(value, 'reload handoff token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction token(value: string): string {\n return normalized(value, 'token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction domains(values: readonly string[]): string[] {\n if (values.length > DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS) {\n throw new Error(`A maximum of ${DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS} domains may be selected.`);\n }\n const result: string[] = [];\n const seen = new Set<string>();\n for (const value of values) {\n const name = normalized(value, 'domain name', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n if (seen.has(name)) continue;\n seen.add(name);\n result.push(name);\n }\n return result;\n}\n\nfunction prune(now = Date.now()): void {\n for (const [key, record] of registry().records) {\n if (record.expiresAt <= now) registry().records.delete(key);\n }\n}\n\nfunction identityMatches(record: DomainSwitchHandoff, identity: DomainSwitchHandoffIdentity): boolean {\n if (record.sessionId !== sessionId(identity.sessionId)) return false;\n return identity.hostGeneration === undefined || record.hostGeneration === hostGeneration(identity.hostGeneration);\n}\n\nfunction copy(record: DomainSwitchHandoff): DomainSwitchHandoff {\n return { ...record, domains: [...record.domains] };\n}\n\nfunction issue(ownerGeneration: string, request: DomainSwitchHandoffRequest): DomainSwitchHandoff {\n prune();\n const normalizedSessionId = sessionId(request.sessionId);\n const normalizedHostGeneration = hostGeneration(request.hostGeneration);\n const normalizedOperationId = operationId(request.operationId);\n const normalizedDomains = domains(request.domains);\n const normalizedReloadToken = reloadToken(request.reloadHandoffToken);\n const createdAt = Date.now();\n const record: StoredDomainSwitchHandoff = {\n token: `${DOMAIN_SWITCH_TOKEN_PREFIX}${crypto.randomUUID()}`,\n sessionId: normalizedSessionId,\n hostGeneration: normalizedHostGeneration,\n operationId: normalizedOperationId,\n domains: normalizedDomains,\n reloadHandoffToken: normalizedReloadToken,\n createdAt,\n expiresAt: createdAt + DOMAIN_SWITCH_HANDOFF_TTL_MS,\n ownerGeneration,\n };\n registry().records.set(record.token, record);\n return copy(record);\n}\n\nfunction consume(identity: DomainSwitchHandoffIdentity, handoffToken: string): DomainSwitchHandoff | undefined {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return undefined;\n registry().records.delete(normalizedToken);\n if (record.expiresAt <= Date.now()) return undefined;\n return copy(record);\n}\n\nfunction discard(identity: DomainSwitchHandoffIdentity, handoffToken: string): boolean {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return false;\n return registry().records.delete(normalizedToken);\n}\n\nfunction clearOwnedSession(ownerGeneration: string, requestedSessionId: string): number {\n prune();\n const normalizedSessionId = sessionId(requestedSessionId);\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration || record.sessionId !== normalizedSessionId) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nfunction disposeOwner(ownerGeneration: string): number {\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nexport function createDomainSwitchHandoffStore(): DomainSwitchHandoffStore {\n const ownerGeneration = crypto.randomUUID();\n let disposed = false;\n return {\n ownerGeneration,\n issue(request) {\n if (disposed) throw new Error('Domain switch handoff store is disposed.');\n return issue(ownerGeneration, request);\n },\n consume(handoffToken, identity) {\n if (disposed) return undefined;\n return consume(identity, handoffToken);\n },\n discard(handoffToken, identity) {\n if (disposed) return false;\n return discard(identity, handoffToken);\n },\n clearSession(requestedSessionId) {\n if (disposed) return 0;\n return clearOwnedSession(ownerGeneration, requestedSessionId);\n },\n dispose() {\n if (disposed) return 0;\n disposed = true;\n return disposeOwner(ownerGeneration);\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"domainSwitchHandoff.mjs","names":[],"sources":["../../src/adapters/domainSwitchHandoff.ts"],"sourcesContent":["import type {\n DomainSwitchHandoff,\n DomainSwitchHandoffIdentity,\n DomainSwitchHandoffRequest,\n DomainSwitchHandoffStore,\n} from '../types/handoff.ts';\nimport { SAFE_DOMAIN_NAME } from '../types/domains.ts';\n\nconst DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY = '@agimon-ai/doompi-domain.switch-handoff.v1';\nconst DOMAIN_SWITCH_HANDOFF_SYMBOL = Symbol.for(DOMAIN_SWITCH_HANDOFF_REGISTRY_KEY);\nconst DOMAIN_SWITCH_TOKEN_PREFIX = 'doom-domain-switch:';\n\nexport const DOMAIN_SWITCH_HANDOFF_TTL_MS = 30_000;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS = 32;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH = 256;\nexport const DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH = 128;\n\ninterface StoredDomainSwitchHandoff extends DomainSwitchHandoff {\n readonly ownerGeneration: string;\n}\n\ninterface HandoffRegistry {\n readonly records: Map<string, StoredDomainSwitchHandoff>;\n}\n\ntype HandoffGlobal = typeof globalThis & { [DOMAIN_SWITCH_HANDOFF_SYMBOL]?: HandoffRegistry };\n\n/**\n * One registry per process, keyed by a well-known symbol.\n *\n * Pi can reload this module in place, and a reload that lost the parked handoffs\n * would strand the follow-up command the voice tool already sent. Ownership is\n * tracked per store instead, so a disposed store takes only its own records.\n */\nfunction registry(): HandoffRegistry {\n const root = globalThis as HandoffGlobal;\n return (root[DOMAIN_SWITCH_HANDOFF_SYMBOL] ??= { records: new Map() });\n}\n\nfunction invalid(label: string): Error {\n return new Error(`Invalid domain switch handoff ${label}.`);\n}\n\nfunction hasControlCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0);\n if (code !== undefined && (code <= 0x1f || code === 0x7f)) return true;\n }\n return false;\n}\n\nfunction normalized(value: unknown, label: string, maximum: number, pattern?: RegExp): string {\n const text = typeof value === 'string' ? value.trim() : '';\n if (!text || text.length > maximum || hasControlCharacter(text) || (pattern && !pattern.test(text))) {\n throw invalid(label);\n }\n return text;\n}\n\nfunction sessionId(value: string): string {\n return normalized(value, 'session id', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction hostGeneration(value: string): string {\n return normalized(value, 'host generation', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH);\n}\n\nfunction operationId(value: string): string {\n return normalized(value, 'operation id', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction reloadToken(value: string): string {\n return normalized(value, 'reload handoff token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction token(value: string): string {\n return normalized(value, 'token', DOMAIN_SWITCH_HANDOFF_MAX_IDENTIFIER_LENGTH, SAFE_DOMAIN_NAME);\n}\n\nfunction domains(values: readonly string[]): string[] {\n if (values.length > DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS) {\n throw new Error(`A maximum of ${DOMAIN_SWITCH_HANDOFF_MAX_DOMAINS} domains may be selected.`);\n }\n const result: string[] = [];\n const seen = new Set<string>();\n for (const value of values) {\n const name = normalized(value, 'domain name', DOMAIN_SWITCH_HANDOFF_MAX_OPERATION_LENGTH, SAFE_DOMAIN_NAME);\n if (seen.has(name)) continue;\n seen.add(name);\n result.push(name);\n }\n return result;\n}\n\nfunction prune(now = Date.now()): void {\n for (const [key, record] of registry().records) {\n if (record.expiresAt <= now) registry().records.delete(key);\n }\n}\n\nfunction identityMatches(record: DomainSwitchHandoff, identity: DomainSwitchHandoffIdentity): boolean {\n if (record.sessionId !== sessionId(identity.sessionId)) return false;\n return record.hostGeneration === hostGeneration(identity.hostGeneration);\n}\n\nfunction copy(record: DomainSwitchHandoff): DomainSwitchHandoff {\n return { ...record, domains: [...record.domains] };\n}\n\nfunction issue(ownerGeneration: string, request: DomainSwitchHandoffRequest): DomainSwitchHandoff {\n prune();\n const normalizedSessionId = sessionId(request.sessionId);\n const normalizedHostGeneration = hostGeneration(request.hostGeneration);\n const normalizedOperationId = operationId(request.operationId);\n const normalizedDomains = domains(request.domains);\n const normalizedReloadToken = reloadToken(request.reloadHandoffToken);\n const createdAt = Date.now();\n const record: StoredDomainSwitchHandoff = {\n token: `${DOMAIN_SWITCH_TOKEN_PREFIX}${crypto.randomUUID()}`,\n sessionId: normalizedSessionId,\n hostGeneration: normalizedHostGeneration,\n operationId: normalizedOperationId,\n domains: normalizedDomains,\n reloadHandoffToken: normalizedReloadToken,\n createdAt,\n expiresAt: createdAt + DOMAIN_SWITCH_HANDOFF_TTL_MS,\n ownerGeneration,\n };\n registry().records.set(record.token, record);\n return copy(record);\n}\n\nfunction consume(identity: DomainSwitchHandoffIdentity, handoffToken: string): DomainSwitchHandoff | undefined {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return undefined;\n registry().records.delete(normalizedToken);\n if (record.expiresAt <= Date.now()) return undefined;\n return copy(record);\n}\n\nfunction discard(identity: DomainSwitchHandoffIdentity, handoffToken: string): boolean {\n prune();\n const normalizedToken = token(handoffToken);\n const record = registry().records.get(normalizedToken);\n if (!record || !identityMatches(record, identity)) return false;\n return registry().records.delete(normalizedToken);\n}\n\nfunction clearOwnedSession(ownerGeneration: string, requestedSessionId: string): number {\n prune();\n const normalizedSessionId = sessionId(requestedSessionId);\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration || record.sessionId !== normalizedSessionId) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nfunction disposeOwner(ownerGeneration: string): number {\n let removed = 0;\n for (const [key, record] of registry().records) {\n if (record.ownerGeneration !== ownerGeneration) continue;\n registry().records.delete(key);\n removed += 1;\n }\n return removed;\n}\n\nexport function createDomainSwitchHandoffStore(): DomainSwitchHandoffStore {\n const ownerGeneration = crypto.randomUUID();\n let disposed = false;\n return {\n ownerGeneration,\n issue(request) {\n if (disposed) throw new Error('Domain switch handoff store is disposed.');\n return issue(ownerGeneration, request);\n },\n consume(handoffToken, identity) {\n if (disposed) return undefined;\n return consume(identity, handoffToken);\n },\n discard(handoffToken, identity) {\n if (disposed) return false;\n return discard(identity, handoffToken);\n },\n clearSession(requestedSessionId) {\n if (disposed) return 0;\n return clearOwnedSession(ownerGeneration, requestedSessionId);\n },\n dispose() {\n if (disposed) return 0;\n disposed = true;\n return disposeOwner(ownerGeneration);\n },\n };\n}\n"],"mappings":"wDASA,MAAM,EAA+B,OAAO,IAAI,4CAAkC,EAGrE,EAA+B,IAC/B,EAAoC,GACpC,EAA8C,IAC9C,EAA6C,IAmB1D,SAAS,GAA4B,CACnC,IAAM,EAAO,WACb,MAAQ,GAAK,KAAkC,CAAE,QAAS,IAAI,GAAM,CACtE,CAEA,SAAS,EAAQ,EAAsB,CACrC,OAAW,MAAM,iCAAiC,EAAM,EAAE,CAC5D,CAEA,SAAS,EAAoB,EAAwB,CACnD,IAAK,IAAM,KAAa,EAAO,CAC7B,IAAM,EAAO,EAAU,YAAY,CAAC,EACpC,GAAI,IAAS,IAAA,KAAc,GAAQ,IAAQ,IAAS,KAAO,MAAO,EACpE,CACA,MAAO,EACT,CAEA,SAAS,EAAW,EAAgB,EAAe,EAAiB,EAA0B,CAC5F,IAAM,EAAO,OAAO,GAAU,SAAW,EAAM,KAAK,EAAI,GACxD,GAAI,CAAC,GAAQ,EAAK,OAAS,GAAW,EAAoB,CAAI,GAAM,GAAW,CAAC,EAAQ,KAAK,CAAI,EAC/F,MAAM,EAAQ,CAAK,EAErB,OAAO,CACT,CAEA,SAAS,EAAU,EAAuB,CACxC,OAAO,EAAW,EAAO,aAAA,GAAyD,CACpF,CAEA,SAAS,EAAe,EAAuB,CAC7C,OAAO,EAAW,EAAO,kBAAA,GAA8D,CACzF,CAEA,SAAS,EAAY,EAAuB,CAC1C,OAAO,EAAW,EAAO,eAAA,IAA4D,CAAgB,CACvG,CAEA,SAAS,EAAY,EAAuB,CAC1C,OAAO,EAAW,EAAO,uBAAA,IAAqE,CAAgB,CAChH,CAEA,SAAS,EAAM,EAAuB,CACpC,OAAO,EAAW,EAAO,QAAA,IAAsD,CAAgB,CACjG,CAEA,SAAS,EAAQ,EAAqC,CACpD,GAAI,EAAO,OAAA,GACT,MAAU,MAAM,0CAA4E,EAE9F,IAAM,EAAmB,CAAC,EACpB,EAAO,IAAI,IACjB,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAO,EAAW,EAAO,cAAA,IAA2D,CAAgB,EACtG,EAAK,IAAI,CAAI,IACjB,EAAK,IAAI,CAAI,EACb,EAAO,KAAK,CAAI,EAClB,CACA,OAAO,CACT,CAEA,SAAS,EAAM,EAAM,KAAK,IAAI,EAAS,CACrC,IAAK,GAAM,CAAC,EAAK,KAAW,EAAS,CAAC,CAAC,QACjC,EAAO,WAAa,GAAK,EAAS,CAAC,CAAC,QAAQ,OAAO,CAAG,CAE9D,CAEA,SAAS,EAAgB,EAA6B,EAAgD,CAEpG,OADI,EAAO,YAAc,EAAU,EAAS,SAAS,GAC9C,EAAO,iBAAmB,EAAe,EAAS,cAAc,CACzE,CAEA,SAAS,EAAK,EAAkD,CAC9D,MAAO,CAAE,GAAG,EAAQ,QAAS,CAAC,GAAG,EAAO,OAAO,CAAE,CACnD,CAEA,SAAS,EAAM,EAAyB,EAA0D,CAChG,EAAM,EACN,IAAM,EAAsB,EAAU,EAAQ,SAAS,EACjD,EAA2B,EAAe,EAAQ,cAAc,EAChE,EAAwB,EAAY,EAAQ,WAAW,EACvD,EAAoB,EAAQ,EAAQ,OAAO,EAC3C,EAAwB,EAAY,EAAQ,kBAAkB,EAC9D,EAAY,KAAK,IAAI,EACrB,EAAoC,CACxC,MAAO,sBAAgC,OAAO,WAAW,IACzD,UAAW,EACX,eAAgB,EAChB,YAAa,EACb,QAAS,EACT,mBAAoB,EACpB,YACA,UAAW,EAAY,EACvB,iBACF,EAEA,OADA,EAAS,CAAC,CAAC,QAAQ,IAAI,EAAO,MAAO,CAAM,EACpC,EAAK,CAAM,CACpB,CAEA,SAAS,EAAQ,EAAuC,EAAuD,CAC7G,EAAM,EACN,IAAM,EAAkB,EAAM,CAAY,EACpC,EAAS,EAAS,CAAC,CAAC,QAAQ,IAAI,CAAe,EACjD,MAAC,GAAU,CAAC,EAAgB,EAAQ,CAAQ,KAChD,EAAS,CAAC,CAAC,QAAQ,OAAO,CAAe,EACrC,IAAO,WAAa,KAAK,IAAI,IACjC,OAAO,EAAK,CAAM,CACpB,CAEA,SAAS,EAAQ,EAAuC,EAA+B,CACrF,EAAM,EACN,IAAM,EAAkB,EAAM,CAAY,EACpC,EAAS,EAAS,CAAC,CAAC,QAAQ,IAAI,CAAe,EAErD,MADI,CAAC,GAAU,CAAC,EAAgB,EAAQ,CAAQ,EAAU,GACnD,EAAS,CAAC,CAAC,QAAQ,OAAO,CAAe,CAClD,CAEA,SAAS,EAAkB,EAAyB,EAAoC,CACtF,EAAM,EACN,IAAM,EAAsB,EAAU,CAAkB,EACpD,EAAU,EACd,IAAK,GAAM,CAAC,EAAK,KAAW,EAAS,CAAC,CAAC,QACjC,EAAO,kBAAoB,GAAmB,EAAO,YAAc,IACvE,EAAS,CAAC,CAAC,QAAQ,OAAO,CAAG,EAC7B,GAAW,GAEb,OAAO,CACT,CAEA,SAAS,EAAa,EAAiC,CACrD,IAAI,EAAU,EACd,IAAK,GAAM,CAAC,EAAK,KAAW,EAAS,CAAC,CAAC,QACjC,EAAO,kBAAoB,IAC/B,EAAS,CAAC,CAAC,QAAQ,OAAO,CAAG,EAC7B,GAAW,GAEb,OAAO,CACT,CAEA,SAAgB,GAA2D,CACzE,IAAM,EAAkB,OAAO,WAAW,EACtC,EAAW,GACf,MAAO,CACL,kBACA,MAAM,EAAS,CACb,GAAI,EAAU,MAAU,MAAM,0CAA0C,EACxE,OAAO,EAAM,EAAiB,CAAO,CACvC,EACA,QAAQ,EAAc,EAAU,CAC1B,MACJ,OAAO,EAAQ,EAAU,CAAY,CACvC,EACA,QAAQ,EAAc,EAAU,CAE9B,MADA,CAAI,GACG,EAAQ,EAAU,CAAY,CACvC,EACA,aAAa,EAAoB,CAE/B,OADI,EAAiB,EACd,EAAkB,EAAiB,CAAkB,CAC9D,EACA,SAAU,CAGR,OAFI,EAAiB,GACrB,EAAW,GACJ,EAAa,CAAe,EACrC,CACF,CACF"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:
|
|
2
|
-
`)}${(0,i.stringify)({...n,mcpServers:a})}`}async function d(e,
|
|
1
|
+
const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("@agimon-ai/doompi-config/domains"),i=require("yaml");const a=`agiflow-proxy`,o=`mcp-config.yaml`,s=`--config`;function c(e,t){let n=(0,r.loadDomains)(e),i=(0,r.expandDomainNames)(n,t);if(i.length===0)return;let a=new Set,o=new Set;for(let e of i){let t=n.domains[e]?.mcp;if(!t)return;for(let e of t.servers??[])a.add(e);for(let e of t.proxy??[])o.add(e)}return{servers:[...a],proxy:[...o]}}function l(e,t){if(!t||t.length===0)return e;let n=e.mcpServers??{},r={};for(let[e,i]of Object.entries(n))t.includes(e)&&(r[e]=i);return{...e,mcpServers:r}}function u(e,t){if(!t||t.length===0)return e;let n=(0,i.parse)(e)??{},r=n.mcpServers??{},a={},o=[];for(let[e,n]of Object.entries(r))t.includes(e)?a[e]=n:o.push(e);return`${[`# Generated by doompi for this run. Do not edit.`,`# Upstreams kept: ${Object.keys(a).join(`, `)||`(none)`}`,`# Upstreams removed by the domain allowlist: ${o.join(`, `)||`(none)`}`,``].join(`
|
|
2
|
+
`)}${(0,i.stringify)({...n,mcpServers:a})}`}async function d(e,n){try{return await t.default.promises.copyFile(e,n),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function f(e,r,i){await t.default.promises.mkdir(i,{recursive:!0});let c=JSON.parse(await t.default.promises.readFile(e,`utf8`)),l=c.mcpServers??{},u=l[a],f=n.default.join(r,o);if(u){let e=[...u.args??[]],t=e.indexOf(s);if(t!==-1){let r=n.default.join(i,o);await d(f,r)&&(e[t+1]=r,l[a]={...u,args:e})}}let p=n.default.join(i,`mcp.json`);return await t.default.promises.writeFile(p,`${JSON.stringify({...c,mcpServers:l},null,2)}\n`,{mode:384}),p}async function p(e,r,i,c){if(!r)return e;let d=l(e,r.servers),f=d.mcpServers??{},p=f[a];if(!p||!r.proxy||r.proxy.length===0)return d;let m=[...p.args??[]],h=m.indexOf(s);if(h===-1||!m[h+1])return d;let g=n.default.resolve(i,m[h+1]),_;try{_=await t.default.promises.readFile(g,`utf8`)}catch(e){if(e.code===`ENOENT`)return d;throw e}let v=n.default.join(c,o);return await t.default.promises.writeFile(v,u(_,r.proxy),{mode:384}),m[h+1]=v,{...d,mcpServers:{...f,[a]:{...p,args:m}}}}exports.PROXY_SERVER_NAME=a,exports.applyMcpAllowlist=p,exports.filterMcpServers=l,exports.filterProxyConfig=u,exports.persistMcpConfig=f,exports.resolveMcpAllowlist=c;
|
|
3
3
|
//# sourceMappingURL=mcpFilter.cjs.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import e from"node:path";import{expandDomainNames as
|
|
2
|
-
`)}${a({...n,mcpServers:o})}`}async function f(
|
|
1
|
+
import e from"node:fs";import t from"node:path";import{expandDomainNames as n,loadDomains as r}from"@agimon-ai/doompi-config/domains";import{parse as i,stringify as a}from"yaml";const o=`agiflow-proxy`,s=`mcp-config.yaml`,c=`--config`;function l(e,t){let i=r(e),a=n(i,t);if(a.length===0)return;let o=new Set,s=new Set;for(let e of a){let t=i.domains[e]?.mcp;if(!t)return;for(let e of t.servers??[])o.add(e);for(let e of t.proxy??[])s.add(e)}return{servers:[...o],proxy:[...s]}}function u(e,t){if(!t||t.length===0)return e;let n=e.mcpServers??{},r={};for(let[e,i]of Object.entries(n))t.includes(e)&&(r[e]=i);return{...e,mcpServers:r}}function d(e,t){if(!t||t.length===0)return e;let n=i(e)??{},r=n.mcpServers??{},o={},s=[];for(let[e,n]of Object.entries(r))t.includes(e)?o[e]=n:s.push(e);return`${[`# Generated by doompi for this run. Do not edit.`,`# Upstreams kept: ${Object.keys(o).join(`, `)||`(none)`}`,`# Upstreams removed by the domain allowlist: ${s.join(`, `)||`(none)`}`,``].join(`
|
|
2
|
+
`)}${a({...n,mcpServers:o})}`}async function f(t,n){try{return await e.promises.copyFile(t,n),!0}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function p(n,r,i){await e.promises.mkdir(i,{recursive:!0});let a=JSON.parse(await e.promises.readFile(n,`utf8`)),l=a.mcpServers??{},u=l[o],d=t.join(r,s);if(u){let e=[...u.args??[]],n=e.indexOf(c);if(n!==-1){let r=t.join(i,s);await f(d,r)&&(e[n+1]=r,l[o]={...u,args:e})}}let p=t.join(i,`mcp.json`);return await e.promises.writeFile(p,`${JSON.stringify({...a,mcpServers:l},null,2)}\n`,{mode:384}),p}async function m(n,r,i,a){if(!r)return n;let l=u(n,r.servers),f=l.mcpServers??{},p=f[o];if(!p||!r.proxy||r.proxy.length===0)return l;let m=[...p.args??[]],h=m.indexOf(c);if(h===-1||!m[h+1])return l;let g=t.resolve(i,m[h+1]),_;try{_=await e.promises.readFile(g,`utf8`)}catch(e){if(e.code===`ENOENT`)return l;throw e}let v=t.join(a,s);return await e.promises.writeFile(v,d(_,r.proxy),{mode:384}),m[h+1]=v,{...l,mcpServers:{...f,[o]:{...p,args:m}}}}export{o as PROXY_SERVER_NAME,m as applyMcpAllowlist,u as filterMcpServers,d as filterProxyConfig,p as persistMcpConfig,l as resolveMcpAllowlist};
|
|
3
3
|
//# sourceMappingURL=mcpFilter.mjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../types/domains.cjs"),t=require("../domainCatalog.cjs"),n=require("../domainSwitchHandoff.cjs"),r=require("../../commands/domainsCommand.cjs"),i=require("../telemetry/logSinkTelemetry.cjs"),a=require("./voiceTool.cjs");let o=require("@agimon-ai/doompi-config/piContext"),s=require("@
|
|
1
|
+
const e=require("../../types/domains.cjs"),t=require("../domainCatalog.cjs"),n=require("../domainSwitchHandoff.cjs"),r=require("../../commands/domainsCommand.cjs"),i=require("../telemetry/logSinkTelemetry.cjs"),a=require("./voiceTool.cjs");let o=require("@agimon-ai/doompi-config/piContext"),s=require("@agimon-ai/doompi-extension-contracts/voice-tools"),c=require("@agimon-ai/doompi-extension-contracts/config"),l=require("@agimon-ai/doompi-extension-contracts/cordis-host"),u=require("@agimon-ai/doompi-extension-contracts/transition"),d=require("@agimon-ai/doompi-extension-contracts/voice-reload-handoff");function f(){let e,t,n;return{apply:()=>e??=Promise.resolve().then(()=>require("../applyDomains.cjs")),journal:()=>t??=import(`@agimon-ai/doompi-config/piContext`),picker:()=>n??=import(`@agimon-ai/doompi-ui/components/matrixPicker`)}}function p(i,{pi:l,telemetry:p}){let m=f(),h,g=i.inject([c.DOOM_CONFIG_SERVICE,u.DOOM_TRANSITION_SERVICE],e=>(h=e,()=>{h===e&&(h=void 0)})),_=()=>{if(!h)throw Error(`Doom domain runtime is waiting for the session config service.`);return h},v=t.createDomainCatalog(_),y=n.createDomainSwitchHandoffStore(),b=(0,d.createVoiceReloadHandoffStore)({now:()=>Date.now(),createToken:()=>crypto.randomUUID()});i.inject([c.DOOM_CONFIG_SERVICE,u.DOOM_TRANSITION_SERVICE,s.DOOM_VOICE_TOOLS_SERVICE],e=>a.registerDomainVoiceCapabilities((0,s.requireDoomVoiceToolsService)(e),l,v,y,b,()=>e)),i.effect(function*(){r.registerDomainsCommand(l,p,{cordisContext:_,catalog:v,handoffs:y,reloadHandoffs:b,applyDomains:async(e,t)=>(await m.apply()).applyDomains(e,t),loadConfigJournal:m.journal,loadPicker:m.picker}),l.on(`resources_discover`,(e,t)=>({skillPaths:[...(0,o.requireDoomConfigContext)(_()).harness.skillDirectories]})),l.on(`session_shutdown`,(e,t)=>{y.clearSession(t.sessionManager.getSessionId())}),l.on(`session_start`,async(e,t)=>{await g.await();let n=(0,o.requireDoomConfigContext)(_()).harness;t.ui.addAutocompleteProvider(e=>({triggerCharacters:[`,`],async getSuggestions(t,r,i,a){let o=n.root,s=t[r]??``;return(o?await v.completions(o,s.slice(0,i)):void 0)??e.getSuggestions(t,r,i,a)},applyCompletion(t,n,r,i,a){return e.applyCompletion(t,n,r,i,a)},shouldTriggerFileCompletion(t,n,r){return e.shouldTriggerFileCompletion?.(t,n,r)??!0}}))}),yield()=>{y.dispose()}},e.DOMAIN_SOURCE)}async function m(t,n=i.createDomainTelemetry()){let r=await(0,l.connectDoomCordisHost)(t,e.DOMAIN_SOURCE),a=r.root.plugin(p,{pi:t,telemetry:n});try{await a}catch(e){try{await a.dispose()}finally{await r.dispose()}throw e}let o;t.on(`session_shutdown`,()=>o??=(async()=>{try{await a.dispose()}finally{await r.dispose()}})())}exports.default=m,exports.domainsExtension=m;
|
|
2
2
|
//# sourceMappingURL=extension.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.cjs","names":["
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["DOOM_CONFIG_SERVICE","DOOM_TRANSITION_SERVICE","createDomainCatalog","createDomainSwitchHandoffStore","createVoiceReloadHandoffStore","DOOM_VOICE_TOOLS_SERVICE","registerDomainVoiceCapabilities","requireDoomVoiceToolsService","requireDoomConfigContext","DOMAIN_SOURCE","createDomainTelemetry","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_TRANSITION_SERVICE } from '@agimon-ai/doompi-extension-contracts/transition';\nimport {\n DOOM_VOICE_TOOLS_SERVICE,\n requireDoomVoiceToolsService,\n} from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport { createVoiceReloadHandoffStore } from '@agimon-ai/doompi-extension-contracts/voice-reload-handoff';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerDomainsCommand } from '../../commands/domainsCommand.ts';\nimport { DOMAIN_SOURCE } from '../../types/domains.ts';\nimport type { DomainTelemetry } from '../../types/telemetry.ts';\nimport { createDomainCatalog } from '../domainCatalog.ts';\nimport { createDomainSwitchHandoffStore } from '../domainSwitchHandoff.ts';\nimport { createDomainTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { registerDomainVoiceCapabilities } from './voiceTool.ts';\n\n/**\n * Everything a switch needs beyond the session, loaded on first use.\n *\n * Every session registers /domains, but most never run it, so the plugin\n * materializer, the resource collector and the picker stay off the startup path.\n */\nfunction lazyModules() {\n let apply: Promise<typeof import('../applyDomains.ts')> | undefined;\n let journal: Promise<typeof import('@agimon-ai/doompi-config/piContext')> | undefined;\n let picker: Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')> | undefined;\n return {\n apply: () => (apply ??= import('../applyDomains.ts')),\n journal: () => (journal ??= import('@agimon-ai/doompi-config/piContext')),\n picker: () => (picker ??= import('@agimon-ai/doompi-ui/components/matrixPicker')),\n };\n}\n\ninterface DomainPluginConfig {\n readonly pi: ExtensionAPI;\n readonly telemetry: DomainTelemetry;\n}\n\nfunction domainPlugin(cordis: Context, { pi, telemetry }: DomainPluginConfig): void {\n const load = lazyModules();\n let activeContext: Context | undefined;\n const runtimeInjection = cordis.inject([DOOM_CONFIG_SERVICE, DOOM_TRANSITION_SERVICE], (context) => {\n activeContext = context;\n return () => {\n if (activeContext === context) activeContext = undefined;\n };\n });\n const requireRuntimeContext = (): Context => {\n if (!activeContext) throw new Error('Doom domain runtime is waiting for the session config service.');\n return activeContext;\n };\n const catalog = createDomainCatalog(requireRuntimeContext);\n const handoffs = createDomainSwitchHandoffStore();\n const reloadHandoffs = createVoiceReloadHandoffStore({\n now: () => Date.now(),\n createToken: () => crypto.randomUUID(),\n });\n cordis.inject([DOOM_CONFIG_SERVICE, DOOM_TRANSITION_SERVICE, DOOM_VOICE_TOOLS_SERVICE], (voiceContext) =>\n registerDomainVoiceCapabilities(\n requireDoomVoiceToolsService(voiceContext),\n pi,\n catalog,\n handoffs,\n reloadHandoffs,\n () => voiceContext,\n ),\n );\n cordis.effect(function* () {\n registerDomainsCommand(pi, telemetry, {\n cordisContext: requireRuntimeContext,\n catalog,\n handoffs,\n reloadHandoffs,\n applyDomains: async (domains, state) => (await load.apply()).applyDomains(domains, state),\n loadConfigJournal: load.journal,\n loadPicker: load.picker,\n });\n\n // Pi reloads base resources, then asks extensions to extend them again.\n // Read the rebound context so a domain switch discovers only the new\n // selection.\n pi.on('resources_discover', (_event, _ctx) => ({\n skillPaths: [...requireDoomConfigContext(requireRuntimeContext()).harness.skillDirectories],\n }));\n\n pi.on('session_shutdown', (_event, ctx) => {\n handoffs.clearSession(ctx.sessionManager.getSessionId());\n });\n\n pi.on('session_start', async (_event, ctx) => {\n await runtimeInjection.await();\n const state = requireDoomConfigContext(requireRuntimeContext()).harness;\n ctx.ui.addAutocompleteProvider((current) => ({\n triggerCharacters: [','],\n async getSuggestions(lines, cursorLine, cursorCol, options) {\n const repoRoot = state.root;\n const line = lines[cursorLine] ?? '';\n const completion = repoRoot ? await catalog.completions(repoRoot, line.slice(0, cursorCol)) : undefined;\n return completion ?? current.getSuggestions(lines, cursorLine, cursorCol, options);\n },\n applyCompletion(lines, cursorLine, cursorCol, item, prefix) {\n return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);\n },\n shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {\n return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;\n },\n }));\n });\n\n yield () => {\n handoffs.dispose();\n };\n }, DOMAIN_SOURCE);\n}\n\n/** The package's single standard Pi factory. */\nexport async function domainsExtension(\n pi: ExtensionAPI,\n telemetry: DomainTelemetry = createDomainTelemetry(),\n): Promise<void> {\n const connection = await connectDoomCordisHost(pi, DOMAIN_SOURCE);\n const fiber = connection.root.plugin(domainPlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default domainsExtension;\n"],"mappings":"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"}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { DomainTelemetry } from "../../types/telemetry.cjs";
|
|
2
2
|
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
//#region src/adapters/pi/extension.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* The package's single standard Pi factory, and the owner of the cordis Context.
|
|
6
|
-
*
|
|
7
|
-
* Pi can reload an extension in-process, so every registration is yielded to the
|
|
8
|
-
* fiber and one dispose on session shutdown unwinds them in reverse.
|
|
9
|
-
*/
|
|
4
|
+
/** The package's single standard Pi factory. */
|
|
10
5
|
declare function domainsExtension(pi: ExtensionAPI, telemetry?: DomainTelemetry): Promise<void>;
|
|
11
6
|
//#endregion
|
|
12
7
|
export { domainsExtension as default, domainsExtension };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAuHsB,iBACpB,IAAI,cACJ,YAAW,kBACV"}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { DomainTelemetry } from "../../types/telemetry.mjs";
|
|
2
2
|
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
//#region src/adapters/pi/extension.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* The package's single standard Pi factory, and the owner of the cordis Context.
|
|
6
|
-
*
|
|
7
|
-
* Pi can reload an extension in-process, so every registration is yielded to the
|
|
8
|
-
* fiber and one dispose on session shutdown unwinds them in reverse.
|
|
9
|
-
*/
|
|
4
|
+
/** The package's single standard Pi factory. */
|
|
10
5
|
declare function domainsExtension(pi: ExtensionAPI, telemetry?: DomainTelemetry): Promise<void>;
|
|
11
6
|
//#endregion
|
|
12
7
|
export { domainsExtension as default, domainsExtension };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAuHsB,iBACpB,IAAI,cACJ,YAAW,kBACV"}
|