@agimon-ai/doompi-domain 0.0.1-alpha.10
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/LICENSE +21 -0
- package/README.md +85 -0
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/adapters/applyDomains.cjs +2 -0
- package/dist/adapters/applyDomains.cjs.map +1 -0
- package/dist/adapters/applyDomains.d.cts +24 -0
- package/dist/adapters/applyDomains.d.cts.map +1 -0
- package/dist/adapters/applyDomains.d.mts +24 -0
- package/dist/adapters/applyDomains.d.mts.map +1 -0
- package/dist/adapters/applyDomains.mjs +2 -0
- package/dist/adapters/applyDomains.mjs.map +1 -0
- package/dist/adapters/domainCatalog.cjs +2 -0
- package/dist/adapters/domainCatalog.cjs.map +1 -0
- package/dist/adapters/domainCatalog.d.cts +21 -0
- package/dist/adapters/domainCatalog.d.cts.map +1 -0
- package/dist/adapters/domainCatalog.d.mts +21 -0
- package/dist/adapters/domainCatalog.d.mts.map +1 -0
- package/dist/adapters/domainCatalog.mjs +2 -0
- package/dist/adapters/domainCatalog.mjs.map +1 -0
- package/dist/adapters/domainSwitchHandoff.cjs +2 -0
- package/dist/adapters/domainSwitchHandoff.cjs.map +1 -0
- package/dist/adapters/domainSwitchHandoff.d.cts +10 -0
- package/dist/adapters/domainSwitchHandoff.d.cts.map +1 -0
- package/dist/adapters/domainSwitchHandoff.d.mts +10 -0
- package/dist/adapters/domainSwitchHandoff.d.mts.map +1 -0
- package/dist/adapters/domainSwitchHandoff.mjs +2 -0
- package/dist/adapters/domainSwitchHandoff.mjs.map +1 -0
- package/dist/adapters/mcpFilter.cjs +3 -0
- package/dist/adapters/mcpFilter.cjs.map +1 -0
- package/dist/adapters/mcpFilter.d.cts +39 -0
- package/dist/adapters/mcpFilter.d.cts.map +1 -0
- package/dist/adapters/mcpFilter.d.mts +39 -0
- package/dist/adapters/mcpFilter.d.mts.map +1 -0
- package/dist/adapters/mcpFilter.mjs +3 -0
- package/dist/adapters/mcpFilter.mjs.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.cjs +2 -0
- package/dist/adapters/mcpSessionEnvironment.cjs.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.d.cts +14 -0
- package/dist/adapters/mcpSessionEnvironment.d.cts.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.d.mts +14 -0
- package/dist/adapters/mcpSessionEnvironment.d.mts.map +1 -0
- package/dist/adapters/mcpSessionEnvironment.mjs +2 -0
- package/dist/adapters/mcpSessionEnvironment.mjs.map +1 -0
- package/dist/adapters/pi/extension.cjs +2 -0
- package/dist/adapters/pi/extension.cjs.map +1 -0
- package/dist/adapters/pi/extension.d.cts +8 -0
- package/dist/adapters/pi/extension.d.cts.map +1 -0
- package/dist/adapters/pi/extension.d.mts +8 -0
- package/dist/adapters/pi/extension.d.mts.map +1 -0
- package/dist/adapters/pi/extension.mjs +2 -0
- package/dist/adapters/pi/extension.mjs.map +1 -0
- package/dist/adapters/pi/voiceTool.cjs +2 -0
- package/dist/adapters/pi/voiceTool.cjs.map +1 -0
- package/dist/adapters/pi/voiceTool.d.cts +19 -0
- package/dist/adapters/pi/voiceTool.d.cts.map +1 -0
- package/dist/adapters/pi/voiceTool.d.mts +19 -0
- package/dist/adapters/pi/voiceTool.d.mts.map +1 -0
- package/dist/adapters/pi/voiceTool.mjs +2 -0
- package/dist/adapters/pi/voiceTool.mjs.map +1 -0
- package/dist/adapters/pluginMaterializer.cjs +2 -0
- package/dist/adapters/pluginMaterializer.cjs.map +1 -0
- package/dist/adapters/pluginMaterializer.d.cts +14 -0
- package/dist/adapters/pluginMaterializer.d.cts.map +1 -0
- package/dist/adapters/pluginMaterializer.d.mts +14 -0
- package/dist/adapters/pluginMaterializer.d.mts.map +1 -0
- package/dist/adapters/pluginMaterializer.mjs +2 -0
- package/dist/adapters/pluginMaterializer.mjs.map +1 -0
- package/dist/adapters/resourceCollector.cjs +3 -0
- package/dist/adapters/resourceCollector.cjs.map +1 -0
- package/dist/adapters/resourceCollector.d.cts +27 -0
- package/dist/adapters/resourceCollector.d.cts.map +1 -0
- package/dist/adapters/resourceCollector.d.mts +27 -0
- package/dist/adapters/resourceCollector.d.mts.map +1 -0
- package/dist/adapters/resourceCollector.mjs +3 -0
- package/dist/adapters/resourceCollector.mjs.map +1 -0
- package/dist/adapters/skillCacheLocation.cjs +2 -0
- package/dist/adapters/skillCacheLocation.cjs.map +1 -0
- package/dist/adapters/skillCacheLocation.d.cts +16 -0
- package/dist/adapters/skillCacheLocation.d.cts.map +1 -0
- package/dist/adapters/skillCacheLocation.d.mts +16 -0
- package/dist/adapters/skillCacheLocation.d.mts.map +1 -0
- package/dist/adapters/skillCacheLocation.mjs +2 -0
- package/dist/adapters/skillCacheLocation.mjs.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.cjs +2 -0
- package/dist/adapters/telemetry/logSinkTelemetry.cjs.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts +14 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts +14 -0
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +1 -0
- package/dist/adapters/telemetry/logSinkTelemetry.mjs +2 -0
- package/dist/adapters/telemetry/logSinkTelemetry.mjs.map +1 -0
- package/dist/apply.cjs +1 -0
- package/dist/apply.d.cts +2 -0
- package/dist/apply.d.mts +2 -0
- package/dist/apply.mjs +1 -0
- package/dist/commands/domainsCommand.cjs +2 -0
- package/dist/commands/domainsCommand.cjs.map +1 -0
- package/dist/commands/domainsCommand.d.cts +28 -0
- package/dist/commands/domainsCommand.d.cts.map +1 -0
- package/dist/commands/domainsCommand.d.mts +28 -0
- package/dist/commands/domainsCommand.d.mts.map +1 -0
- package/dist/commands/domainsCommand.mjs +2 -0
- package/dist/commands/domainsCommand.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -0
- package/dist/extensions/pi.d.cts +2 -0
- package/dist/extensions/pi.d.mts +2 -0
- package/dist/extensions/pi.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.mjs +1 -0
- package/dist/mcp.cjs +1 -0
- package/dist/mcp.d.cts +4 -0
- package/dist/mcp.d.mts +4 -0
- package/dist/mcp.mjs +1 -0
- package/dist/plugins.cjs +1 -0
- package/dist/plugins.d.cts +2 -0
- package/dist/plugins.d.mts +2 -0
- package/dist/plugins.mjs +1 -0
- package/dist/resources.cjs +1 -0
- package/dist/resources.d.cts +4 -0
- package/dist/resources.d.mts +4 -0
- package/dist/resources.mjs +1 -0
- package/dist/schemas/domainVoiceTools.cjs +2 -0
- package/dist/schemas/domainVoiceTools.cjs.map +1 -0
- package/dist/schemas/domainVoiceTools.d.cts +22 -0
- package/dist/schemas/domainVoiceTools.d.cts.map +1 -0
- package/dist/schemas/domainVoiceTools.d.mts +22 -0
- package/dist/schemas/domainVoiceTools.d.mts.map +1 -0
- package/dist/schemas/domainVoiceTools.mjs +2 -0
- package/dist/schemas/domainVoiceTools.mjs.map +1 -0
- package/dist/services/domainText.cjs +2 -0
- package/dist/services/domainText.cjs.map +1 -0
- package/dist/services/domainText.d.cts +30 -0
- package/dist/services/domainText.d.cts.map +1 -0
- package/dist/services/domainText.d.mts +30 -0
- package/dist/services/domainText.d.mts.map +1 -0
- package/dist/services/domainText.mjs +2 -0
- package/dist/services/domainText.mjs.map +1 -0
- package/dist/services/toolNames.cjs +2 -0
- package/dist/services/toolNames.cjs.map +1 -0
- package/dist/services/toolNames.d.cts +21 -0
- package/dist/services/toolNames.d.cts.map +1 -0
- package/dist/services/toolNames.d.mts +21 -0
- package/dist/services/toolNames.d.mts.map +1 -0
- package/dist/services/toolNames.mjs +2 -0
- package/dist/services/toolNames.mjs.map +1 -0
- package/dist/types/domains.cjs +2 -0
- package/dist/types/domains.cjs.map +1 -0
- package/dist/types/domains.d.cts +33 -0
- package/dist/types/domains.d.cts.map +1 -0
- package/dist/types/domains.d.mts +33 -0
- package/dist/types/domains.d.mts.map +1 -0
- package/dist/types/domains.mjs +2 -0
- package/dist/types/domains.mjs.map +1 -0
- package/dist/types/handoff.d.cts +35 -0
- package/dist/types/handoff.d.cts.map +1 -0
- package/dist/types/handoff.d.mts +35 -0
- package/dist/types/handoff.d.mts.map +1 -0
- package/dist/types/resources.d.cts +65 -0
- package/dist/types/resources.d.cts.map +1 -0
- package/dist/types/resources.d.mts +65 -0
- package/dist/types/resources.d.mts.map +1 -0
- package/dist/types/telemetry.cjs +2 -0
- package/dist/types/telemetry.cjs.map +1 -0
- package/dist/types/telemetry.d.cts +15 -0
- package/dist/types/telemetry.d.cts.map +1 -0
- package/dist/types/telemetry.d.mts +15 -0
- package/dist/types/telemetry.d.mts.map +1 -0
- package/dist/types/telemetry.mjs +2 -0
- package/dist/types/telemetry.mjs.map +1 -0
- package/llms.txt +12 -0
- package/package.json +117 -0
- package/src/prompts/doompi-author-domain/SKILL.md +16 -0
- package/src/prompts/doompi-author-domain/references/domains-contract.md +165 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { HarnessResourceOptions, HarnessResources, JsonObject, McpResourceOptions, NamedResource, StagedMcpResources } from "../types/resources.cjs";
|
|
2
|
+
import { PluginEntry, PluginSkillDiscovery } from "@agimon-ai/doompi-config/domains";
|
|
3
|
+
//#region src/adapters/resourceCollector.d.ts
|
|
4
|
+
declare const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
5
|
+
/** Rewrites a Claude-authored agent definition into the form Pi loads. */
|
|
6
|
+
declare function adaptAgentDefinition(content: string): {
|
|
7
|
+
name: string;
|
|
8
|
+
content: string;
|
|
9
|
+
};
|
|
10
|
+
/** Cached skill metadata and exact files, ready for Pi without a second tree walk. */
|
|
11
|
+
declare function discoverSkills(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): NamedResource[];
|
|
12
|
+
declare function discoverSkillsAsync(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): Promise<NamedResource[]>;
|
|
13
|
+
declare function mergeMcpConfigs(configPaths: string[]): JsonObject;
|
|
14
|
+
declare function mergeMcpConfigsAsync(configPaths: string[]): Promise<JsonObject>;
|
|
15
|
+
/** Stages only the MCP slice shared by DoomPi and compatibility frontends. */
|
|
16
|
+
declare function stageMcpResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: McpResourceOptions): Promise<StagedMcpResources>;
|
|
17
|
+
/**
|
|
18
|
+
* Stages every resource the selected domains contribute, ready for one Pi session.
|
|
19
|
+
*
|
|
20
|
+
* The caller owns the returned cleanup(): the temporary directory holding agents
|
|
21
|
+
* and the generated MCP config has to outlive this function and be removed once
|
|
22
|
+
* the session that reads it is done.
|
|
23
|
+
*/
|
|
24
|
+
declare function collectResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: HarnessResourceOptions): Promise<HarnessResources>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { DISPATCHER_AGENT_NAME, adaptAgentDefinition, collectResources, discoverSkills, discoverSkillsAsync, mergeMcpConfigs, mergeMcpConfigsAsync, stageMcpResources };
|
|
27
|
+
//# sourceMappingURL=resourceCollector.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.d.cts","names":[],"sources":["../../src/adapters/resourceCollector.ts"],"mappings":";;;cA2Ba;;iBAiJG,qBAAqB;EAAoB;EAAc;;;iBA8MvD,eACd,kBACA,cACA,YAAW,sBACX,0BACC;iBAoDmB,oBACpB,kBACA,cACA,YAAW,sBACX,0BACC,QAAQ;iBAyEK,gBAAgB,wBAAwB;iBAoBlC,qBAAqB,wBAAwB,QAAQ;;iBAmFrD,kBACpB,kBACA,SAAS,eAAe,cACxB,SAAS,qBACR,QAAQ;;;;;;;;iBAyEW,iBACpB,kBACA,SAAS,eAAe,cACxB,SAAS,yBACR,QAAQ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { HarnessResourceOptions, HarnessResources, JsonObject, McpResourceOptions, NamedResource, StagedMcpResources } from "../types/resources.mjs";
|
|
2
|
+
import { PluginEntry, PluginSkillDiscovery } from "@agimon-ai/doompi-config/domains";
|
|
3
|
+
//#region src/adapters/resourceCollector.d.ts
|
|
4
|
+
declare const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
5
|
+
/** Rewrites a Claude-authored agent definition into the form Pi loads. */
|
|
6
|
+
declare function adaptAgentDefinition(content: string): {
|
|
7
|
+
name: string;
|
|
8
|
+
content: string;
|
|
9
|
+
};
|
|
10
|
+
/** Cached skill metadata and exact files, ready for Pi without a second tree walk. */
|
|
11
|
+
declare function discoverSkills(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): NamedResource[];
|
|
12
|
+
declare function discoverSkillsAsync(repoRoot: string, root: string, discovery?: PluginSkillDiscovery, cacheDirectory?: string): Promise<NamedResource[]>;
|
|
13
|
+
declare function mergeMcpConfigs(configPaths: string[]): JsonObject;
|
|
14
|
+
declare function mergeMcpConfigsAsync(configPaths: string[]): Promise<JsonObject>;
|
|
15
|
+
/** Stages only the MCP slice shared by DoomPi and compatibility frontends. */
|
|
16
|
+
declare function stageMcpResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: McpResourceOptions): Promise<StagedMcpResources>;
|
|
17
|
+
/**
|
|
18
|
+
* Stages every resource the selected domains contribute, ready for one Pi session.
|
|
19
|
+
*
|
|
20
|
+
* The caller owns the returned cleanup(): the temporary directory holding agents
|
|
21
|
+
* and the generated MCP config has to outlive this function and be removed once
|
|
22
|
+
* the session that reads it is done.
|
|
23
|
+
*/
|
|
24
|
+
declare function collectResources(repoRoot: string, plugins: Array<string | PluginEntry>, options: HarnessResourceOptions): Promise<HarnessResources>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { DISPATCHER_AGENT_NAME, adaptAgentDefinition, collectResources, discoverSkills, discoverSkillsAsync, mergeMcpConfigs, mergeMcpConfigsAsync, stageMcpResources };
|
|
27
|
+
//# sourceMappingURL=resourceCollector.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.d.mts","names":[],"sources":["../../src/adapters/resourceCollector.ts"],"mappings":";;;cA2Ba;;iBAiJG,qBAAqB;EAAoB;EAAc;;;iBA8MvD,eACd,kBACA,cACA,YAAW,sBACX,0BACC;iBAoDmB,oBACpB,kBACA,cACA,YAAW,sBACX,0BACC,QAAQ;iBAyEK,gBAAgB,wBAAwB;iBAoBlC,qBAAqB,wBAAwB,QAAQ;;iBAmFrD,kBACpB,kBACA,SAAS,eAAe,cACxB,SAAS,qBACR,QAAQ;;;;;;;;iBAyEW,iBACpB,kBACA,SAAS,eAAe,cACxB,SAAS,yBACR,QAAQ"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{applyMcpAllowlist as e}from"./mcpFilter.mjs";import{toPiToolName as t}from"../services/toolNames.mjs";import{resolveSkillCacheDirectory as n}from"./skillCacheLocation.mjs";import r from"node:fs";import i from"node:path";import{parse as a,stringify as o}from"yaml";import{createHash as s}from"node:crypto";import c from"node:os";import{globalDoomConfigDirectory as l}from"@agimon-ai/doompi-config/config";import{normalizeAgentPluginMcpSource as u}from"@agimon-ai/doompi-config/agentPluginMcp";import{AGENT_PLUGIN_MCP_SCHEMA_URL as d,DOOM_MCP_PROJECTION_VERSION as f}from"@agimon-ai/doompi-extension-contracts/mcp-projection";const p=`agiflow-dispatcher`,m=[`read`,`grep`,`find`,`ls`,`bash`,`launch_workflow`,`list_workflows`],h=`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`;function g(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function _(e){let t=e=>Array.isArray(e)?e.map(t):g(e)?Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,n])=>[e,t(n)])):e;return JSON.stringify(t(e))}function v(e){return s(`sha256`).update(_(e)).digest(`hex`)}function y(e){let t=e.source,n=t?.type===`git`?[`git`,t.url,t.path??``]:t?.type===`npm`?[`npm`,t.registry??``,t.package]:[`local`,r.realpathSync(e.directory)];return s(`sha256`).update(JSON.stringify(n)).digest(`hex`)}function b(e){let t=i.join(e.directory,`plugin.json`);if(e.manifest?.path===t&&e.manifest.agentPluginSchema===h)return h;try{let e=r.lstatSync(t);if(e.isSymbolicLink()||!e.isFile())return;let n=JSON.parse(r.readFileSync(t,`utf8`));return g(n)&&n.$schema===h?h:void 0}catch{return}}async function x(e,t){if(e.mcp===!1)return;let n=r.realpathSync(e.directory),a=b(e)===h,o=i.join(n,a?`mcp.json`:`.mcp.json`),c;try{c=await r.promises.lstat(o)}catch(e){if(e.code===`ENOENT`)return;throw e}if(!c.isFile()||c.isSymbolicLink())return;let l=await r.promises.readFile(o),u=s(`sha256`).update(l).digest(`hex`),f=y(e),p=`plugin:${f}`;return a?{sourceId:p,owner:`plugin`,format:`agent-plugin-v1`,configPath:o,contentDigest:u,pluginId:f,pluginRoot:n,pluginDataDirectory:i.join(t,f),mcpSchemaUrl:d}:{sourceId:p,owner:`plugin`,format:`native`,configPath:o,contentDigest:u}}function S(e){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);if(!t)throw Error(`Resource is missing YAML frontmatter`);return{attributes:a(t[1]),body:t[2]??``}}const C={sonnet:`anthropic/claude-sonnet-4-6`,opus:`anthropic/claude-opus-4-6`,haiku:`anthropic/claude-haiku-4-5`};function w(e){let t=e.trim();if(!t||t!==e||t===`.`||t===`..`||t.includes(`\0`)||/[\\/]/.test(t))throw Error(`Unsafe agent name: ${JSON.stringify(e)}`);return t}function T(e){return typeof e==`string`?C[e.toLowerCase()]??e:Array.isArray(e)?e.map(e=>T(e)):e}function E(e){let{attributes:n,body:r}=S(e),i=typeof n.name==`string`?n.name:void 0;if(!i)throw Error(`Agent definition requires a name`);let a=w(i),s=Object.hasOwn(n,`tools`),c=Array.isArray(n.tools)?n.tools.map(String):typeof n.tools==`string`?n.tools.split(`,`).map(e=>e.trim()).filter(Boolean):[],l=[...new Set(c.map(t).filter(e=>!!e))],u={...n,inheritProjectContext:!0,inheritSkills:!0,systemPromptMode:n.systemPromptMode??`replace`};if(s?u.tools=Array.isArray(n.tools)?l:l.join(`, `):delete u.tools,u.model!==void 0&&(u.model=T(u.model)),u.fallbackModels!==void 0&&(u.fallbackModels=T(u.fallbackModels)),u.memory===`project`||u.memory===`user`)u.memory={scope:u.memory,path:a};else if(u.memory!==void 0&&(typeof u.memory!=`object`||u.memory===null||Array.isArray(u.memory)))throw Error(`Unsupported memory declaration`);return delete u.permissionMode,{name:a,content:`---\n${o(u).trim()}\n---\n\n${r.trimStart()}`}}function D(e,t,r,a){let o=s(`sha256`).update(`${i.resolve(t)}\0${r}`).digest(`hex`).slice(0,16);return i.join(a??n(e),`${o}.json`)}function O(e){try{let t=r.statSync(e.path);return t.isFile()&&t.size===e.size&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}catch{return!1}}function k(e){try{let t=r.statSync(e.path);return t.isDirectory()&&t.mtimeMs===e.mtimeMs&&t.ctimeMs===e.ctimeMs}catch{return!1}}function A(e,t,n){try{let a=JSON.parse(r.readFileSync(e,`utf8`));return a.version!==2||a.root!==i.resolve(t)||a.discovery!==n||!Array.isArray(a.files)||!Array.isArray(a.directories)||!a.files.every(O)||!a.directories.every(k)?void 0:a}catch{return}}function j(e,t){r.mkdirSync(i.dirname(e),{recursive:!0,mode:448});let n=`${e}.${process.pid}.${Date.now()}.tmp`;r.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{r.renameSync(n,e)}catch(t){if(r.rmSync(n,{force:!0}),!r.existsSync(e))throw t}}async function M(e){try{return await r.promises.access(e),!0}catch{return!1}}async function N(e,t,n){try{let a=JSON.parse(await r.promises.readFile(e,`utf8`));if(a.version!==2||a.root!==i.resolve(t)||a.discovery!==n||!Array.isArray(a.files)||!Array.isArray(a.directories))return;for(let e of a.files){let t=await r.promises.stat(e.path);if(!t.isFile()||t.size!==e.size||t.mtimeMs!==e.mtimeMs||t.ctimeMs!==e.ctimeMs)return}for(let e of a.directories){let t=await r.promises.stat(e.path);if(!t.isDirectory()||t.mtimeMs!==e.mtimeMs||t.ctimeMs!==e.ctimeMs)return}return a}catch{return}}async function P(e,t){await r.promises.mkdir(i.dirname(e),{recursive:!0,mode:448});let n=`${e}.${process.pid}.${Date.now()}.tmp`;await r.promises.writeFile(n,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{await r.promises.rename(n,e)}catch(t){if(await r.promises.rm(n,{force:!0}),!await M(e))throw t}}function F(e,t){let n=[],a=[],o=(e,c)=>{if(!r.existsSync(e))return;let l=r.statSync(e);n.push({path:e,mtimeMs:l.mtimeMs,ctimeMs:l.ctimeMs});for(let n of r.readdirSync(e,{withFileTypes:!0})){let l=i.join(e,n.name);if(n.isDirectory()){(t===`recursive`||c===0)&&o(l,c+1);continue}if(!n.isFile()||n.name!==`SKILL.md`||t===`direct-children`&&c!==1)continue;let u=r.readFileSync(l,`utf8`),{attributes:d}=S(u);if(typeof d.name!=`string`)throw Error(`Resource requires a name: ${l}`);let f=r.statSync(l);a.push({path:l,name:d.name,digest:s(`sha256`).update(u).digest(`hex`),size:f.size,mtimeMs:f.mtimeMs,ctimeMs:f.ctimeMs})}},c=i.resolve(e);return o(c,0),a.sort((e,t)=>e.path.localeCompare(t.path)),n.sort((e,t)=>e.path.localeCompare(t.path)),{version:2,root:c,discovery:t,files:a,directories:n}}function I(e,t,n=`recursive`,i){if(!r.existsSync(t))return[];let a=D(e,t,n,i),o=A(a,t,n),s=o??F(t,n);return o||j(a,s),s.files.map(({name:e,path:t,digest:n})=>({name:e,path:t,digest:n}))}async function L(e,t){let n=[],a=[],o=async(e,c)=>{let l;try{let t=await r.promises.stat(e);n.push({path:e,mtimeMs:t.mtimeMs,ctimeMs:t.ctimeMs}),l=await r.promises.readdir(e,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return;throw e}for(let n of l){let l=i.join(e,n.name);if(n.isDirectory()){(t===`recursive`||c===0)&&await o(l,c+1);continue}if(!n.isFile()||n.name!==`SKILL.md`||t===`direct-children`&&c!==1)continue;let u=await r.promises.readFile(l,`utf8`),{attributes:d}=S(u);if(typeof d.name!=`string`)throw Error(`Resource requires a name: ${l}`);let f=await r.promises.stat(l);a.push({path:l,name:d.name,digest:s(`sha256`).update(u).digest(`hex`),size:f.size,mtimeMs:f.mtimeMs,ctimeMs:f.ctimeMs})}},c=i.resolve(e);return await o(c,0),a.sort((e,t)=>e.path.localeCompare(t.path)),n.sort((e,t)=>e.path.localeCompare(t.path)),{version:2,root:c,discovery:t,files:a,directories:n}}async function R(e,t,n=`recursive`,r){if(!await M(t))return[];let i=D(e,t,n,r),a=await N(i,t,n),o=a??await L(t,n);return a||await P(i,o),o.files.map(({name:e,path:t,digest:n})=>({name:e,path:t,digest:n}))}async function z(e){let t;try{t=await r.promises.readdir(e,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let n=[];for(let r of t){let t=i.join(e,r.name);r.isDirectory()&&n.push(...await z(t)),r.isFile()&&r.name.endsWith(`.md`)&&n.push(t)}return n}async function B(e){let{attributes:t}=S(await r.promises.readFile(e,`utf8`));if(typeof t.name!=`string`)throw Error(`Resource requires a name: ${e}`);return t.name}async function V(e,t){let n=new Map,i=new Map;for(let a of e){let e=n.get(a.name),o=a.digest??s(`sha256`).update(await r.promises.readFile(a.path)).digest(`hex`);if(e&&i.get(a.name)!==o)throw Error(`Conflicting ${t} "${a.name}": ${e} and ${a.path}`);n.set(a.name,a.path),i.set(a.name,o)}}function H(){let e={name:p,description:`Selects and launches Agiflow workflows for one loop pass without implementing the work.`,thinking:`high`,systemPromptMode:`replace`,inheritProjectContext:!0,inheritSkills:!0,tools:m.join(`, `),defaultContext:`fresh`,defaultProgress:!1},t=[`You are the Agiflow workflow dispatcher.`,`Reason about the supplied dispatch context and launch eligible workflows.`,`Launch workflows without monitoring them. After dispatching, report and exit.`,`Follow the task restrictions exactly. Do not implement jobs or edit repository files.`].join(`
|
|
2
|
+
`);return`---\n${o(e).trim()}\n---\n\n${t}\n`}function U(e){let t={mcpServers:{}},n=t.mcpServers,i=new Map;for(let t of e){if(!r.existsSync(t))continue;let e=JSON.parse(r.readFileSync(t,`utf8`)).mcpServers??{};for(let[r,a]of Object.entries(e)){let e=n[r];if(e&&JSON.stringify(e)!==JSON.stringify(a))throw Error(`Conflicting MCP server "${r}": ${i.get(r)} and ${t}`);n[r]=a,i.set(r,t)}}return t}async function W(e){let t={mcpServers:{}},n=t.mcpServers,i=new Map;for(let t of e){let e;try{e=await r.promises.readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)continue;throw e}let a=JSON.parse(e).mcpServers??{};for(let[e,r]of Object.entries(a)){let a=n[e];if(a&&JSON.stringify(a)!==JSON.stringify(r))throw Error(`Conflicting MCP server "${e}": ${i.get(e)} and ${t}`);n[e]=r,i.set(e,t)}}return t}async function G(e,t){let n={mcpServers:{}},i=n.mcpServers,a=new Map;for(let n of e){let e;if(n.format===`agent-plugin-v1`)e=u(n,{stagingDirectory:t,stripProxyWrappers:!1}).claudeConfig;else{let t;try{t=await r.promises.readFile(n.configPath,`utf8`)}catch(e){if(e.code===`ENOENT`)continue;throw e}e=JSON.parse(t)}let o=e.mcpServers??{};for(let[e,t]of Object.entries(o)){let r=i[e];if(r&&JSON.stringify(r)!==JSON.stringify(t))throw Error(`Conflicting MCP server "${e}": ${a.get(e)} and ${n.configPath}`);i[e]=t,a.set(e,n.configPath)}}return n}function K(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function q(e,t){return!e||e.some(e=>e.includes(`*`)?RegExp(`^${e.split(`*`).map(K).join(`.*`)}$`).test(t):e===t)}async function J(t,n,a){let o=n.map(e=>typeof e==`string`?{directory:e}:e),c=[],u=[],d=[],p=a.pluginDataRoot??i.join(l(),`plugin-data`),m=i.join(t,`.mcp.json`);if(await r.promises.mkdir(a.temporaryDirectory,{mode:448,recursive:!0}),await r.promises.chmod(a.temporaryDirectory,448),a.enabled&&await M(m)){let e=await r.promises.readFile(m);d.push({sourceId:`repository:.mcp.json`,owner:`repository`,format:`native`,configPath:m,contentDigest:s(`sha256`).update(e).digest(`hex`)})}if(a.enabled)for(let e of o){let t=await x(e,p);t&&(d.push(t),u.push(t),c.push(t.configPath))}let h;if(a.enabled){h=i.join(a.temporaryDirectory,`mcp.json`);let n=await e(await G(d,a.temporaryDirectory),a.mcpAllowlist,t,a.temporaryDirectory);await r.promises.writeFile(h,`${JSON.stringify(n,null,2)}\n`,{mode:384})}let g={version:f,enabled:a.enabled,repoRoot:t,...h?{generatedConfigPath:h}:{},sources:a.enabled?d:[],...a.mcpAllowlist?{allowlist:structuredClone(a.mcpAllowlist)}:{}};return{mcpConfigPath:h,mcpProjection:{...g,stagingDirectory:a.temporaryDirectory,fingerprint:v(g)},pluginMcpSources:u,pluginMcpConfigPaths:c}}async function Y(e,t,n){let a=t.map(e=>typeof e==`string`?{directory:e}:e),o=n.temporaryDirectory===void 0,s=n.temporaryDirectory??await r.promises.mkdtemp(i.join(c.tmpdir(),`doom-pi-`));await r.promises.mkdir(s,{mode:448,recursive:!0}),await r.promises.chmod(s,448);let l=i.join(e,`.claude`,`skills`),u=n.sharedSkills===!1?[]:await R(e,l,`recursive`,n.skillCacheDirectory),d=[],f=[],m=[],h=[];for(let t of a){let r=t.directory,a=i.join(r,`skills`);if(await M(a)){let r=(await R(e,a,t.skillDiscovery??`recursive`,n.skillCacheDirectory)).filter(e=>q(t.skills,e.name));d.push(...r.map(e=>e.path)),f.push(...r)}let o=await z(i.join(r,`agents`)),s=await Promise.all(o.map(e=>B(e)));m.push(...o.map((e,t)=>({name:s[t]??``,path:e})).filter(e=>q(t.agents,e.name)));let c=i.join(r,`hooks`,`hooks.json`);t.hooks!==!1&&await M(c)&&h.push({pluginRoot:r,configPath:c})}await V(f,`skill`),await V(u,`skill`);let g=new Set(f.map(e=>e.name)),_=u.filter(e=>!g.has(e.name));if(d.push(..._.map(e=>e.path)),f.push(..._),await V(m,`agent`),m.some(e=>e.name===`agiflow-dispatcher`))throw Error(`Conflicting agent "${p}": reserved by the agent harness`);let v=[],y=i.join(s,`agents`);if(await r.promises.rm(y,{recursive:!0,force:!0}),n.agents){await r.promises.mkdir(y,{mode:448});for(let e of m){let t=E(await r.promises.readFile(e.path,`utf8`));await r.promises.writeFile(i.join(y,`${w(t.name)}.md`),t.content,{mode:384})}await r.promises.writeFile(i.join(y,`${p}.md`),H(),{mode:384}),v.push(y)}let{mcpConfigPath:b,mcpProjection:x,pluginMcpSources:S,pluginMcpConfigPaths:C}=await J(e,a,{enabled:n.mcp,temporaryDirectory:s,...n.mcpAllowlist?{mcpAllowlist:n.mcpAllowlist}:{},...n.pluginDataRoot?{pluginDataRoot:n.pluginDataRoot}:{}});return{temporaryDirectory:s,skillDirectories:d,skillCount:f.length,agentCount:m.length,agentDirectories:v,pluginHooks:h,mcpConfigPath:b,mcpProjection:x,pluginMcpSources:S,pluginMcpConfigPaths:C,cleanup:()=>o?r.promises.rm(s,{recursive:!0,force:!0}):Promise.resolve()}}export{p as DISPATCHER_AGENT_NAME,E as adaptAgentDefinition,Y as collectResources,I as discoverSkills,R as discoverSkillsAsync,U as mergeMcpConfigs,W as mergeMcpConfigsAsync,J as stageMcpResources};
|
|
3
|
+
//# sourceMappingURL=resourceCollector.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceCollector.mjs","names":[],"sources":["../../src/adapters/resourceCollector.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { globalDoomConfigDirectory } from '@agimon-ai/doompi-config/config';\nimport type { PluginEntry, PluginSkillDiscovery } from '@agimon-ai/doompi-config/domains';\nimport { normalizeAgentPluginMcpSource } from '@agimon-ai/doompi-config/agentPluginMcp';\nimport {\n AGENT_PLUGIN_MCP_SCHEMA_URL,\n DOOM_MCP_PROJECTION_VERSION,\n type DoomMcpProjection,\n type DoomMcpProjectionSource,\n} from '@agimon-ai/doompi-extension-contracts/mcp-projection';\nimport { parse, stringify } from 'yaml';\nimport { toPiToolName } from '../services/toolNames.ts';\nimport type {\n HarnessResourceOptions,\n HarnessResources,\n JsonObject,\n McpResourceOptions,\n NamedResource,\n StagedMcpResources,\n} from '../types/resources.ts';\nimport type { PluginHookSource } from '@agimon-ai/doompi-config/types';\nimport { applyMcpAllowlist } from './mcpFilter.ts';\nimport { resolveSkillCacheDirectory } from './skillCacheLocation.ts';\n\nexport const DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst DISPATCHER_TOOLS = ['read', 'grep', 'find', 'ls', 'bash', 'launch_workflow', 'list_workflows'];\nconst SKILL_MANIFEST_VERSION = 2;\nconst SKILL_MANIFEST_HASH_LENGTH = 16;\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst PLUGIN_DATA_DIRECTORY = 'plugin-data';\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction canonicalJson(value: unknown): string {\n const normalize = (candidate: unknown): unknown => {\n if (Array.isArray(candidate)) return candidate.map(normalize);\n if (!isJsonObject(candidate)) return candidate;\n return Object.fromEntries(\n Object.entries(candidate)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, child]) => [key, normalize(child)]),\n );\n };\n return JSON.stringify(normalize(value));\n}\n\nfunction projectionFingerprint(input: Omit<DoomMcpProjection, 'fingerprint' | 'stagingDirectory'>): string {\n return createHash('sha256').update(canonicalJson(input)).digest('hex');\n}\n\nfunction stablePluginIdentity(entry: PluginEntry): string {\n const source = entry.source;\n const identity =\n source?.type === 'git'\n ? ['git', source.url, source.path ?? '']\n : source?.type === 'npm'\n ? ['npm', source.registry ?? '', source.package]\n : ['local', fs.realpathSync(entry.directory)];\n return createHash('sha256').update(JSON.stringify(identity)).digest('hex');\n}\n\nfunction rootAgentPluginSchema(entry: PluginEntry): string | undefined {\n const manifestPath = path.join(entry.directory, 'plugin.json');\n if (entry.manifest?.path === manifestPath && entry.manifest.agentPluginSchema === AGENT_PLUGIN_SCHEMA) {\n return AGENT_PLUGIN_SCHEMA;\n }\n try {\n const stat = fs.lstatSync(manifestPath);\n if (stat.isSymbolicLink() || !stat.isFile()) return undefined;\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n return isJsonObject(parsed) && parsed.$schema === AGENT_PLUGIN_SCHEMA ? AGENT_PLUGIN_SCHEMA : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function pluginMcpSource(\n entry: PluginEntry,\n pluginDataRoot: string,\n): Promise<DoomMcpProjectionSource | undefined> {\n if (entry.mcp === false) return undefined;\n const pluginRoot = fs.realpathSync(entry.directory);\n const agentPlugin = rootAgentPluginSchema(entry) === AGENT_PLUGIN_SCHEMA;\n const configPath = path.join(pluginRoot, agentPlugin ? 'mcp.json' : '.mcp.json');\n let stat: fs.Stats;\n try {\n stat = await fs.promises.lstat(configPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n if (!stat.isFile() || stat.isSymbolicLink()) return undefined;\n const content = await fs.promises.readFile(configPath);\n const contentDigest = createHash('sha256').update(content).digest('hex');\n const pluginId = stablePluginIdentity(entry);\n const sourceId = `plugin:${pluginId}`;\n if (!agentPlugin) return { sourceId, owner: 'plugin', format: 'native', configPath, contentDigest };\n return {\n sourceId,\n owner: 'plugin',\n format: 'agent-plugin-v1',\n configPath,\n contentDigest,\n pluginId,\n pluginRoot,\n pluginDataDirectory: path.join(pluginDataRoot, pluginId),\n mcpSchemaUrl: AGENT_PLUGIN_MCP_SCHEMA_URL,\n };\n}\n\ninterface SkillManifestFile {\n path: string;\n name: string;\n digest: string;\n size: number;\n mtimeMs: number;\n ctimeMs: number;\n}\n\ninterface SkillManifestDirectory {\n path: string;\n mtimeMs: number;\n ctimeMs: number;\n}\n\ninterface SkillManifest {\n version: number;\n root: string;\n discovery: PluginSkillDiscovery;\n files: SkillManifestFile[];\n directories: SkillManifestDirectory[];\n}\n\nfunction splitFrontmatter(content: string): { attributes: JsonObject; body: string } {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n if (!match) throw new Error('Resource is missing YAML frontmatter');\n return { attributes: parse(match[1]!) as JsonObject, body: match[2] ?? '' };\n}\n\nconst CLAUDE_MODEL_ALIASES: Record<string, string> = {\n sonnet: 'anthropic/claude-sonnet-4-6',\n opus: 'anthropic/claude-opus-4-6',\n haiku: 'anthropic/claude-haiku-4-5',\n};\n\nfunction assertSafeAgentName(name: string): string {\n const trimmed = name.trim();\n if (\n !trimmed ||\n trimmed !== name ||\n trimmed === '.' ||\n trimmed === '..' ||\n trimmed.includes('\\0') ||\n /[\\\\/]/.test(trimmed)\n ) {\n throw new Error(`Unsafe agent name: ${JSON.stringify(name)}`);\n }\n return trimmed;\n}\n\nfunction normalizeClaudeModel(value: unknown): unknown {\n if (typeof value === 'string') return CLAUDE_MODEL_ALIASES[value.toLowerCase()] ?? value;\n if (Array.isArray(value)) return value.map((entry) => normalizeClaudeModel(entry));\n return value;\n}\n\n/** Rewrites a Claude-authored agent definition into the form Pi loads. */\nexport function adaptAgentDefinition(content: string): { name: string; content: string } {\n const { attributes, body } = splitFrontmatter(content);\n const rawName = typeof attributes.name === 'string' ? attributes.name : undefined;\n if (!rawName) throw new Error('Agent definition requires a name');\n const name = assertSafeAgentName(rawName);\n const hasTools = Object.hasOwn(attributes, 'tools');\n const rawTools = Array.isArray(attributes.tools)\n ? attributes.tools.map(String)\n : typeof attributes.tools === 'string'\n ? attributes.tools\n .split(',')\n .map((tool) => tool.trim())\n .filter(Boolean)\n : [];\n const mappedTools = [...new Set(rawTools.map(toPiToolName).filter((tool): tool is string => Boolean(tool)))];\n const converted: JsonObject = {\n ...attributes,\n inheritProjectContext: true,\n inheritSkills: true,\n systemPromptMode: attributes.systemPromptMode ?? 'replace',\n };\n if (hasTools) converted.tools = Array.isArray(attributes.tools) ? mappedTools : mappedTools.join(', ');\n else delete converted.tools;\n if (converted.model !== undefined) converted.model = normalizeClaudeModel(converted.model);\n if (converted.fallbackModels !== undefined) converted.fallbackModels = normalizeClaudeModel(converted.fallbackModels);\n if (converted.memory === 'project' || converted.memory === 'user')\n converted.memory = { scope: converted.memory, path: name };\n else if (\n converted.memory !== undefined &&\n (typeof converted.memory !== 'object' || converted.memory === null || Array.isArray(converted.memory))\n )\n throw new Error('Unsupported memory declaration');\n delete converted.permissionMode;\n return { name, content: `---\\n${stringify(converted).trim()}\\n---\\n\\n${body.trimStart()}` };\n}\n\nfunction skillManifestPath(\n repoRoot: string,\n skillRoot: string,\n discovery: PluginSkillDiscovery,\n cacheDirectory?: string,\n): string {\n const key = createHash('sha256')\n .update(`${path.resolve(skillRoot)}\\0${discovery}`)\n .digest('hex')\n .slice(0, SKILL_MANIFEST_HASH_LENGTH);\n return path.join(cacheDirectory ?? resolveSkillCacheDirectory(repoRoot), `${key}.json`);\n}\n\nfunction fileMatches(previous: SkillManifestFile): boolean {\n try {\n const stat = fs.statSync(previous.path);\n return (\n stat.isFile() &&\n stat.size === previous.size &&\n stat.mtimeMs === previous.mtimeMs &&\n stat.ctimeMs === previous.ctimeMs\n );\n } catch {\n return false;\n }\n}\n\nfunction directoryMatches(previous: SkillManifestDirectory): boolean {\n try {\n const stat = fs.statSync(previous.path);\n return stat.isDirectory() && stat.mtimeMs === previous.mtimeMs && stat.ctimeMs === previous.ctimeMs;\n } catch {\n return false;\n }\n}\n\nfunction readSkillManifest(\n manifestPath: string,\n root: string,\n discovery: PluginSkillDiscovery,\n): SkillManifest | undefined {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as SkillManifest;\n if (\n manifest.version !== SKILL_MANIFEST_VERSION ||\n manifest.root !== path.resolve(root) ||\n manifest.discovery !== discovery ||\n !Array.isArray(manifest.files) ||\n !Array.isArray(manifest.directories) ||\n !manifest.files.every(fileMatches) ||\n !manifest.directories.every(directoryMatches)\n ) {\n return undefined;\n }\n return manifest;\n } catch {\n return undefined;\n }\n}\n\nfunction writeSkillManifest(manifestPath: string, manifest: SkillManifest): void {\n fs.mkdirSync(path.dirname(manifestPath), { recursive: true, mode: 0o700 });\n const temporary = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n try {\n fs.renameSync(temporary, manifestPath);\n } catch (error) {\n fs.rmSync(temporary, { force: true });\n if (!fs.existsSync(manifestPath)) throw error;\n }\n}\n\nasync function pathExists(target: string): Promise<boolean> {\n try {\n await fs.promises.access(target);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function readSkillManifestAsync(\n manifestPath: string,\n root: string,\n discovery: PluginSkillDiscovery,\n): Promise<SkillManifest | undefined> {\n try {\n const manifest = JSON.parse(await fs.promises.readFile(manifestPath, 'utf8')) as SkillManifest;\n if (\n manifest.version !== SKILL_MANIFEST_VERSION ||\n manifest.root !== path.resolve(root) ||\n manifest.discovery !== discovery ||\n !Array.isArray(manifest.files) ||\n !Array.isArray(manifest.directories)\n ) {\n return undefined;\n }\n for (const previous of manifest.files) {\n const stat = await fs.promises.stat(previous.path);\n if (\n !stat.isFile() ||\n stat.size !== previous.size ||\n stat.mtimeMs !== previous.mtimeMs ||\n stat.ctimeMs !== previous.ctimeMs\n ) {\n return undefined;\n }\n }\n for (const previous of manifest.directories) {\n const stat = await fs.promises.stat(previous.path);\n if (!stat.isDirectory() || stat.mtimeMs !== previous.mtimeMs || stat.ctimeMs !== previous.ctimeMs) {\n return undefined;\n }\n }\n return manifest;\n } catch {\n return undefined;\n }\n}\n\nasync function writeSkillManifestAsync(manifestPath: string, manifest: SkillManifest): Promise<void> {\n await fs.promises.mkdir(path.dirname(manifestPath), { recursive: true, mode: 0o700 });\n const temporary = `${manifestPath}.${process.pid}.${Date.now()}.tmp`;\n await fs.promises.writeFile(temporary, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n try {\n await fs.promises.rename(temporary, manifestPath);\n } catch (error) {\n await fs.promises.rm(temporary, { force: true });\n if (!(await pathExists(manifestPath))) throw error;\n }\n}\n\nfunction scanSkillManifest(root: string, discovery: PluginSkillDiscovery): SkillManifest {\n const directories: SkillManifestDirectory[] = [];\n const files: SkillManifestFile[] = [];\n const walk = (directory: string, depth: number): void => {\n if (!fs.existsSync(directory)) return;\n const directoryStat = fs.statSync(directory);\n directories.push({ path: directory, mtimeMs: directoryStat.mtimeMs, ctimeMs: directoryStat.ctimeMs });\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n if (discovery === 'recursive' || depth === 0) walk(candidate, depth + 1);\n continue;\n }\n if (!entry.isFile() || entry.name !== 'SKILL.md' || (discovery === 'direct-children' && depth !== 1)) {\n continue;\n }\n const content = fs.readFileSync(candidate, 'utf8');\n const { attributes } = splitFrontmatter(content);\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${candidate}`);\n const stat = fs.statSync(candidate);\n files.push({\n path: candidate,\n name: attributes.name,\n digest: createHash('sha256').update(content).digest('hex'),\n size: stat.size,\n mtimeMs: stat.mtimeMs,\n ctimeMs: stat.ctimeMs,\n });\n }\n };\n const resolvedRoot = path.resolve(root);\n walk(resolvedRoot, 0);\n files.sort((left, right) => left.path.localeCompare(right.path));\n directories.sort((left, right) => left.path.localeCompare(right.path));\n return { version: SKILL_MANIFEST_VERSION, root: resolvedRoot, discovery, files, directories };\n}\n\n/** Cached skill metadata and exact files, ready for Pi without a second tree walk. */\nexport function discoverSkills(\n repoRoot: string,\n root: string,\n discovery: PluginSkillDiscovery = 'recursive',\n cacheDirectory?: string,\n): NamedResource[] {\n if (!fs.existsSync(root)) return [];\n const manifestPath = skillManifestPath(repoRoot, root, discovery, cacheDirectory);\n const cached = readSkillManifest(manifestPath, root, discovery);\n const manifest = cached ?? scanSkillManifest(root, discovery);\n if (!cached) writeSkillManifest(manifestPath, manifest);\n return manifest.files.map(({ name, path: filePath, digest }) => ({ name, path: filePath, digest }));\n}\n\nasync function scanSkillManifestAsync(root: string, discovery: PluginSkillDiscovery): Promise<SkillManifest> {\n const directories: SkillManifestDirectory[] = [];\n const files: SkillManifestFile[] = [];\n const walk = async (directory: string, depth: number): Promise<void> => {\n let entries: fs.Dirent[];\n try {\n const directoryStat = await fs.promises.stat(directory);\n directories.push({ path: directory, mtimeMs: directoryStat.mtimeMs, ctimeMs: directoryStat.ctimeMs });\n entries = await fs.promises.readdir(directory, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n for (const entry of entries) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n if (discovery === 'recursive' || depth === 0) await walk(candidate, depth + 1);\n continue;\n }\n if (!entry.isFile() || entry.name !== 'SKILL.md' || (discovery === 'direct-children' && depth !== 1)) {\n continue;\n }\n const content = await fs.promises.readFile(candidate, 'utf8');\n const { attributes } = splitFrontmatter(content);\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${candidate}`);\n const stat = await fs.promises.stat(candidate);\n files.push({\n path: candidate,\n name: attributes.name,\n digest: createHash('sha256').update(content).digest('hex'),\n size: stat.size,\n mtimeMs: stat.mtimeMs,\n ctimeMs: stat.ctimeMs,\n });\n }\n };\n const resolvedRoot = path.resolve(root);\n await walk(resolvedRoot, 0);\n files.sort((left, right) => left.path.localeCompare(right.path));\n directories.sort((left, right) => left.path.localeCompare(right.path));\n return { version: SKILL_MANIFEST_VERSION, root: resolvedRoot, discovery, files, directories };\n}\n\nexport async function discoverSkillsAsync(\n repoRoot: string,\n root: string,\n discovery: PluginSkillDiscovery = 'recursive',\n cacheDirectory?: string,\n): Promise<NamedResource[]> {\n if (!(await pathExists(root))) return [];\n const manifestPath = skillManifestPath(repoRoot, root, discovery, cacheDirectory);\n const cached = await readSkillManifestAsync(manifestPath, root, discovery);\n const manifest = cached ?? (await scanSkillManifestAsync(root, discovery));\n if (!cached) await writeSkillManifestAsync(manifestPath, manifest);\n return manifest.files.map(({ name, path: filePath, digest }) => ({ name, path: filePath, digest }));\n}\n\nasync function markdownFilesAsync(directory: string): Promise<string[]> {\n let entries: fs.Dirent[];\n try {\n entries = await fs.promises.readdir(directory, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw error;\n }\n const results: string[] = [];\n for (const entry of entries) {\n const candidate = path.join(directory, entry.name);\n if (entry.isDirectory()) results.push(...(await markdownFilesAsync(candidate)));\n if (entry.isFile() && entry.name.endsWith('.md')) results.push(candidate);\n }\n return results;\n}\n\nasync function frontmatterNameAsync(filePath: string): Promise<string> {\n const { attributes } = splitFrontmatter(await fs.promises.readFile(filePath, 'utf8'));\n if (typeof attributes.name !== 'string') throw new Error(`Resource requires a name: ${filePath}`);\n return attributes.name;\n}\n\nasync function assertUniqueAsync(resources: NamedResource[], kind: string): Promise<void> {\n const seen = new Map<string, string>();\n const digestByName = new Map<string, string>();\n for (const resource of resources) {\n const previous = seen.get(resource.name);\n const digest =\n resource.digest ??\n createHash('sha256')\n .update(await fs.promises.readFile(resource.path))\n .digest('hex');\n if (previous && digestByName.get(resource.name) !== digest) {\n throw new Error(`Conflicting ${kind} \"${resource.name}\": ${previous} and ${resource.path}`);\n }\n seen.set(resource.name, resource.path);\n digestByName.set(resource.name, digest);\n }\n}\n\nfunction dispatcherAgentSource(): string {\n const attributes: JsonObject = {\n name: DISPATCHER_AGENT_NAME,\n description: 'Selects and launches Agiflow workflows for one loop pass without implementing the work.',\n thinking: 'high',\n systemPromptMode: 'replace',\n inheritProjectContext: true,\n inheritSkills: true,\n tools: DISPATCHER_TOOLS.join(', '),\n // No feature extension is named here. Team inherits the ordered child\n // composition projected from the selected layers for every helper process.\n defaultContext: 'fresh',\n defaultProgress: false,\n };\n const body = [\n 'You are the Agiflow workflow dispatcher.',\n 'Reason about the supplied dispatch context and launch eligible workflows.',\n 'Launch workflows without monitoring them. After dispatching, report and exit.',\n 'Follow the task restrictions exactly. Do not implement jobs or edit repository files.',\n ].join('\\n');\n return `---\\n${stringify(attributes).trim()}\\n---\\n\\n${body}\\n`;\n}\n\nexport function mergeMcpConfigs(configPaths: string[]): JsonObject {\n const merged: JsonObject = { mcpServers: {} };\n const servers = merged.mcpServers as Record<string, unknown>;\n const sources = new Map<string, string>();\n for (const configPath of configPaths) {\n if (!fs.existsSync(configPath)) continue;\n const config = JSON.parse(fs.readFileSync(configPath, 'utf8')) as JsonObject;\n const incoming = (config.mcpServers ?? {}) as Record<string, unknown>;\n for (const [name, definition] of Object.entries(incoming)) {\n const previous = servers[name];\n if (previous && JSON.stringify(previous) !== JSON.stringify(definition)) {\n throw new Error(`Conflicting MCP server \"${name}\": ${sources.get(name)} and ${configPath}`);\n }\n servers[name] = definition;\n sources.set(name, configPath);\n }\n }\n return merged;\n}\n\nexport async function mergeMcpConfigsAsync(configPaths: string[]): Promise<JsonObject> {\n const merged: JsonObject = { mcpServers: {} };\n const servers = merged.mcpServers as Record<string, unknown>;\n const sources = new Map<string, string>();\n for (const configPath of configPaths) {\n let content: string;\n try {\n content = await fs.promises.readFile(configPath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;\n throw error;\n }\n const config = JSON.parse(content) as JsonObject;\n const incoming = (config.mcpServers ?? {}) as Record<string, unknown>;\n for (const [name, definition] of Object.entries(incoming)) {\n const previous = servers[name];\n if (previous && JSON.stringify(previous) !== JSON.stringify(definition)) {\n throw new Error(`Conflicting MCP server \"${name}\": ${sources.get(name)} and ${configPath}`);\n }\n servers[name] = definition;\n sources.set(name, configPath);\n }\n }\n return merged;\n}\n\nasync function mergeProjectedMcpConfigs(\n sources: readonly DoomMcpProjectionSource[],\n stagingDirectory: string,\n): Promise<JsonObject> {\n const merged: JsonObject = { mcpServers: {} };\n const servers = merged.mcpServers as Record<string, unknown>;\n const origins = new Map<string, string>();\n\n for (const source of sources) {\n let config: JsonObject;\n if (source.format === 'agent-plugin-v1') {\n config = normalizeAgentPluginMcpSource(source, {\n stagingDirectory,\n // The generated file is consumed by external MCP clients. Keep wrapper\n // names there; Doom strips its own in-process wrapper at runtime.\n stripProxyWrappers: false,\n }).claudeConfig;\n } else {\n let content: string;\n try {\n content = await fs.promises.readFile(source.configPath, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;\n throw error;\n }\n config = JSON.parse(content) as JsonObject;\n }\n\n const incoming = (config.mcpServers ?? {}) as Record<string, unknown>;\n for (const [name, definition] of Object.entries(incoming)) {\n const previous = servers[name];\n if (previous && JSON.stringify(previous) !== JSON.stringify(definition)) {\n throw new Error(`Conflicting MCP server \"${name}\": ${origins.get(name)} and ${source.configPath}`);\n }\n servers[name] = definition;\n origins.set(name, source.configPath);\n }\n }\n\n return merged;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Matches a resource name against a subset filter. Undefined keeps everything. */\nfunction keepsName(allowed: string[] | undefined, name: string): boolean {\n if (!allowed) return true;\n return allowed.some((pattern) =>\n pattern.includes('*')\n ? new RegExp(`^${pattern.split('*').map(escapeRegExp).join('.*')}$`).test(name)\n : pattern === name,\n );\n}\n\n/** Stages only the MCP slice shared by DoomPi and compatibility frontends. */\nexport async function stageMcpResources(\n repoRoot: string,\n plugins: Array<string | PluginEntry>,\n options: McpResourceOptions,\n): Promise<StagedMcpResources> {\n const pluginEntries: PluginEntry[] = plugins.map((plugin) =>\n typeof plugin === 'string' ? { directory: plugin } : plugin,\n );\n const pluginMcpConfigPaths: string[] = [];\n const pluginMcpSources: DoomMcpProjectionSource[] = [];\n const mcpSources: DoomMcpProjectionSource[] = [];\n const pluginDataRoot = options.pluginDataRoot ?? path.join(globalDoomConfigDirectory(), PLUGIN_DATA_DIRECTORY);\n const repositoryMcpPath = path.join(repoRoot, '.mcp.json');\n\n await fs.promises.mkdir(options.temporaryDirectory, { mode: 0o700, recursive: true });\n await fs.promises.chmod(options.temporaryDirectory, 0o700);\n if (options.enabled && (await pathExists(repositoryMcpPath))) {\n const content = await fs.promises.readFile(repositoryMcpPath);\n mcpSources.push({\n sourceId: 'repository:.mcp.json',\n owner: 'repository',\n format: 'native',\n configPath: repositoryMcpPath,\n contentDigest: createHash('sha256').update(content).digest('hex'),\n });\n }\n\n if (options.enabled) {\n for (const entry of pluginEntries) {\n const source = await pluginMcpSource(entry, pluginDataRoot);\n if (!source) continue;\n mcpSources.push(source);\n pluginMcpSources.push(source);\n pluginMcpConfigPaths.push(source.configPath);\n }\n }\n\n let mcpConfigPath: string | undefined;\n if (options.enabled) {\n mcpConfigPath = path.join(options.temporaryDirectory, 'mcp.json');\n const merged = await applyMcpAllowlist(\n await mergeProjectedMcpConfigs(mcpSources, options.temporaryDirectory),\n options.mcpAllowlist,\n repoRoot,\n options.temporaryDirectory,\n );\n await fs.promises.writeFile(mcpConfigPath, `${JSON.stringify(merged, null, 2)}\\n`, { mode: 0o600 });\n }\n\n const projectionWithoutRuntimePath = {\n version: DOOM_MCP_PROJECTION_VERSION,\n enabled: options.enabled,\n repoRoot,\n ...(mcpConfigPath ? { generatedConfigPath: mcpConfigPath } : {}),\n sources: options.enabled ? mcpSources : [],\n ...(options.mcpAllowlist ? { allowlist: structuredClone(options.mcpAllowlist) } : {}),\n } satisfies Omit<DoomMcpProjection, 'fingerprint' | 'stagingDirectory'>;\n\n return {\n mcpConfigPath,\n mcpProjection: {\n ...projectionWithoutRuntimePath,\n stagingDirectory: options.temporaryDirectory,\n fingerprint: projectionFingerprint(projectionWithoutRuntimePath),\n },\n pluginMcpSources,\n pluginMcpConfigPaths,\n };\n}\n\n/**\n * Stages every resource the selected domains contribute, ready for one Pi session.\n *\n * The caller owns the returned cleanup(): the temporary directory holding agents\n * and the generated MCP config has to outlive this function and be removed once\n * the session that reads it is done.\n */\nexport async function collectResources(\n repoRoot: string,\n plugins: Array<string | PluginEntry>,\n options: HarnessResourceOptions,\n): Promise<HarnessResources> {\n const pluginEntries: PluginEntry[] = plugins.map((plugin) =>\n typeof plugin === 'string' ? { directory: plugin } : plugin,\n );\n // A caller-supplied directory is owned by the caller: it is either a live\n // session's directory or the synced one, and removing it here would delete\n // resources that outlive this collection.\n const ownsDirectory = options.temporaryDirectory === undefined;\n const temporaryDirectory =\n options.temporaryDirectory ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'doom-pi-')));\n await fs.promises.mkdir(temporaryDirectory, { mode: 0o700, recursive: true });\n await fs.promises.chmod(temporaryDirectory, 0o700);\n const sharedSkills = path.join(repoRoot, '.claude', 'skills');\n // A domain can opt out of the always-on shared skills to keep its context small.\n const sharedSkillSources =\n options.sharedSkills === false\n ? []\n : await discoverSkillsAsync(repoRoot, sharedSkills, 'recursive', options.skillCacheDirectory);\n const skillDirectories: string[] = [];\n const skillSources: NamedResource[] = [];\n const agentSources: Array<{ name: string; path: string }> = [];\n const pluginHooks: PluginHookSource[] = [];\n\n for (const entry of pluginEntries) {\n const pluginDirectory = entry.directory;\n const skills = path.join(pluginDirectory, 'skills');\n if (await pathExists(skills)) {\n const found = (\n await discoverSkillsAsync(repoRoot, skills, entry.skillDiscovery ?? 'recursive', options.skillCacheDirectory)\n ).filter((skill) => keepsName(entry.skills, skill.name));\n // Exact files let Pi skip another recursive traversal and make a plugin\n // subset unambiguous without staging copies of the skill bodies.\n skillDirectories.push(...found.map((skill) => skill.path));\n skillSources.push(...found);\n }\n const agents = path.join(pluginDirectory, 'agents');\n const agentFiles = await markdownFilesAsync(agents);\n const agentNames = await Promise.all(agentFiles.map((filePath) => frontmatterNameAsync(filePath)));\n agentSources.push(\n ...agentFiles\n .map((filePath, index) => ({ name: agentNames[index] ?? '', path: filePath }))\n .filter((agent) => keepsName(entry.agents, agent.name)),\n );\n const hookConfig = path.join(pluginDirectory, 'hooks', 'hooks.json');\n if (entry.hooks !== false && (await pathExists(hookConfig))) {\n pluginHooks.push({ pluginRoot: pluginDirectory, configPath: hookConfig });\n }\n }\n\n await assertUniqueAsync(skillSources, 'skill');\n await assertUniqueAsync(sharedSkillSources, 'skill');\n // Pi keeps the first skill for a duplicated name. Selected domain plugins are\n // authoritative; shared Claude skills remain fallbacks for names no plugin owns.\n const pluginSkillNames = new Set(skillSources.map((skill) => skill.name));\n const fallbackSharedSkills = sharedSkillSources.filter((skill) => !pluginSkillNames.has(skill.name));\n skillDirectories.push(...fallbackSharedSkills.map((skill) => skill.path));\n skillSources.push(...fallbackSharedSkills);\n\n await assertUniqueAsync(agentSources, 'agent');\n if (agentSources.some((source) => source.name === DISPATCHER_AGENT_NAME)) {\n throw new Error(`Conflicting agent \"${DISPATCHER_AGENT_NAME}\": reserved by the agent harness`);\n }\n\n const agentDirectories: string[] = [];\n const outputDirectory = path.join(temporaryDirectory, 'agents');\n await fs.promises.rm(outputDirectory, { recursive: true, force: true });\n if (options.agents) {\n await fs.promises.mkdir(outputDirectory, { mode: 0o700 });\n for (const source of agentSources) {\n const adapted = adaptAgentDefinition(await fs.promises.readFile(source.path, 'utf8'));\n await fs.promises.writeFile(\n path.join(outputDirectory, `${assertSafeAgentName(adapted.name)}.md`),\n adapted.content,\n { mode: 0o600 },\n );\n }\n await fs.promises.writeFile(path.join(outputDirectory, `${DISPATCHER_AGENT_NAME}.md`), dispatcherAgentSource(), {\n mode: 0o600,\n });\n agentDirectories.push(outputDirectory);\n }\n\n const { mcpConfigPath, mcpProjection, pluginMcpSources, pluginMcpConfigPaths } = await stageMcpResources(\n repoRoot,\n pluginEntries,\n {\n enabled: options.mcp,\n temporaryDirectory,\n ...(options.mcpAllowlist ? { mcpAllowlist: options.mcpAllowlist } : {}),\n ...(options.pluginDataRoot ? { pluginDataRoot: options.pluginDataRoot } : {}),\n },\n );\n\n return {\n temporaryDirectory,\n skillDirectories,\n skillCount: skillSources.length,\n agentCount: agentSources.length,\n agentDirectories,\n pluginHooks,\n mcpConfigPath,\n mcpProjection,\n pluginMcpSources,\n pluginMcpConfigPaths,\n cleanup: () =>\n ownsDirectory ? fs.promises.rm(temporaryDirectory, { recursive: true, force: true }) : Promise.resolve(),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
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("node:crypto");r=e.__toESM(r,1);let i=require("node:os");i=e.__toESM(i,1);const a=[`cache`,`skills`],o=`.git`,s=`repo`;function c(e,t=i.default.homedir()){let r=l(e),o=d(r),s=o?`git:${o}`:`root:${r}`,c=f(s),u=f(`${s}\0worktree:${r}`),h=m(o,r),g=p(n.default.basename(r),`worktree`);return n.default.join(n.default.resolve(t),`.pi`,`.doom`,`sync`,`${h}--${c}`,`worktrees`,`${g}--${u}`,...a)}function l(e){let r=n.default.resolve(e);try{return t.default.realpathSync.native(r)}catch{return r}}function u(e){let r=n.default.join(e,o);try{let i=t.default.statSync(r);if(i.isDirectory())return l(r);if(!i.isFile())return;let a=/^gitdir:\s*(.+)$/imu.exec(t.default.readFileSync(r,`utf8`).trim());return a?.[1]?l(n.default.resolve(e,a[1].trim())):void 0}catch{return}}function d(e){let r=u(e);if(r)try{let e=t.default.readFileSync(n.default.join(r,`commondir`),`utf8`).trim();return e?l(n.default.resolve(r,e)):r}catch{return r}}function f(e){return r.default.createHash(`sha256`).update(e,`utf8`).digest(`hex`).slice(0,32)}function p(e,t){let n=e.normalize(`NFKD`).replace(/[\u0300-\u036f]/gu,``).replace(/[^A-Za-z0-9._-]+/gu,`-`).replace(/^[._-]+|[._-]+$/gu,``).slice(0,48).replace(/[._-]+$/gu,``);return n===``||n===`.`||n===`..`?t:n}function m(e,t){if(!e)return p(n.default.basename(t),s);let r=n.default.basename(e);return p(r===o?n.default.basename(n.default.dirname(e)):r,s)}exports.resolveSkillCacheDirectory=c,exports.sanitizeSyncLabel=p;
|
|
2
|
+
//# sourceMappingURL=skillCacheLocation.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCacheLocation.cjs","names":["os","path","fs","crypto"],"sources":["../../src/adapters/skillCacheLocation.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nconst PI_DIRECTORY = '.pi';\nconst DOOM_CONFIG_DIRECTORY = '.doom';\nconst SYNC_DIRECTORY = 'sync';\nconst WORKTREES_DIRECTORY = 'worktrees';\nconst SKILL_CACHE_SEGMENTS = ['cache', 'skills'];\nconst GIT_DIRECTORY = '.git';\nconst COMMON_DIRECTORY_FILE = 'commondir';\nconst IDENTITY_HEX_LENGTH = 32;\nconst LABEL_MAX_LENGTH = 48;\nconst DEFAULT_REPOSITORY_LABEL = 'repo';\nconst DEFAULT_WORKTREE_LABEL = 'worktree';\n\n/**\n * The home-scoped skill manifest cache for one worktree.\n *\n * This mirrors the namespace the DoomPi launcher publishes into, so a session\n * that stages resources through the launcher and one that stages them through a\n * `/domains` switch hit the same manifests instead of rescanning every tree.\n * Two worktrees of one repository stay separate, and a checkout reached through\n * a symlink resolves to the same identity as the real path.\n */\nexport function resolveSkillCacheDirectory(repositoryRoot: string, homeDirectory: string = os.homedir()): string {\n const root = canonicalPath(repositoryRoot);\n const commonDirectory = gitCommonDirectory(root);\n const repositoryToken = commonDirectory ? `git:${commonDirectory}` : `root:${root}`;\n const repositoryId = identityHash(repositoryToken);\n const worktreeId = identityHash(`${repositoryToken}\\0worktree:${root}`);\n const repoLabel = repositoryLabel(commonDirectory, root);\n const worktreeLabel = sanitizeSyncLabel(path.basename(root), DEFAULT_WORKTREE_LABEL);\n return path.join(\n path.resolve(homeDirectory),\n PI_DIRECTORY,\n DOOM_CONFIG_DIRECTORY,\n SYNC_DIRECTORY,\n `${repoLabel}--${repositoryId}`,\n WORKTREES_DIRECTORY,\n `${worktreeLabel}--${worktreeId}`,\n ...SKILL_CACHE_SEGMENTS,\n );\n}\n\nfunction canonicalPath(target: string): string {\n const absolute = path.resolve(target);\n try {\n return fs.realpathSync.native(absolute);\n } catch {\n return absolute;\n }\n}\n\nfunction readGitDirectory(repositoryRoot: string): string | undefined {\n const gitPath = path.join(repositoryRoot, GIT_DIRECTORY);\n try {\n const stat = fs.statSync(gitPath);\n if (stat.isDirectory()) return canonicalPath(gitPath);\n if (!stat.isFile()) return undefined;\n const match = /^gitdir:\\s*(.+)$/imu.exec(fs.readFileSync(gitPath, 'utf8').trim());\n return match?.[1] ? canonicalPath(path.resolve(repositoryRoot, match[1].trim())) : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction gitCommonDirectory(repositoryRoot: string): string | undefined {\n const gitDirectory = readGitDirectory(repositoryRoot);\n if (!gitDirectory) return undefined;\n try {\n const relative = fs.readFileSync(path.join(gitDirectory, COMMON_DIRECTORY_FILE), 'utf8').trim();\n return relative ? canonicalPath(path.resolve(gitDirectory, relative)) : gitDirectory;\n } catch {\n return gitDirectory;\n }\n}\n\nfunction identityHash(value: string): string {\n return crypto.createHash('sha256').update(value, 'utf8').digest('hex').slice(0, IDENTITY_HEX_LENGTH);\n}\n\n/** Keeps a repository or worktree name usable as one path segment. */\nexport function sanitizeSyncLabel(value: string, fallback: string): string {\n const normalized = value\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/gu, '')\n .replace(/[^A-Za-z0-9._-]+/gu, '-')\n .replace(/^[._-]+|[._-]+$/gu, '')\n .slice(0, LABEL_MAX_LENGTH)\n .replace(/[._-]+$/gu, '');\n return normalized === '' || normalized === '.' || normalized === '..' ? fallback : normalized;\n}\n\nfunction repositoryLabel(commonDirectory: string | undefined, repositoryRoot: string): string {\n if (!commonDirectory) return sanitizeSyncLabel(path.basename(repositoryRoot), DEFAULT_REPOSITORY_LABEL);\n const base = path.basename(commonDirectory);\n const source = base === GIT_DIRECTORY ? path.basename(path.dirname(commonDirectory)) : base;\n return sanitizeSyncLabel(source, DEFAULT_REPOSITORY_LABEL);\n}\n"],"mappings":"mOAKA,MAIM,EAAuB,CAAC,QAAS,QAAQ,EACzC,EAAgB,OAIhB,EAA2B,OAYjC,SAAgB,EAA2B,EAAwB,EAAwBA,EAAAA,QAAG,QAAQ,EAAW,CAC/G,IAAM,EAAO,EAAc,CAAc,EACnC,EAAkB,EAAmB,CAAI,EACzC,EAAkB,EAAkB,OAAO,IAAoB,QAAQ,IACvE,EAAe,EAAa,CAAe,EAC3C,EAAa,EAAa,GAAG,EAAgB,aAAa,GAAM,EAChE,EAAY,EAAgB,EAAiB,CAAI,EACjD,EAAgB,EAAkBC,EAAAA,QAAK,SAAS,CAAI,EAAG,UAAsB,EACnF,OAAOA,EAAAA,QAAK,KACVA,EAAAA,QAAK,QAAQ,CAAa,EAC1B,MACA,QACA,OACA,GAAG,EAAU,IAAI,IACjB,YACA,GAAG,EAAc,IAAI,IACrB,GAAG,CACL,CACF,CAEA,SAAS,EAAc,EAAwB,CAC7C,IAAM,EAAWA,EAAAA,QAAK,QAAQ,CAAM,EACpC,GAAI,CACF,OAAOC,EAAAA,QAAG,aAAa,OAAO,CAAQ,CACxC,MAAQ,CACN,OAAO,CACT,CACF,CAEA,SAAS,EAAiB,EAA4C,CACpE,IAAM,EAAUD,EAAAA,QAAK,KAAK,EAAgB,CAAa,EACvD,GAAI,CACF,IAAM,EAAOC,EAAAA,QAAG,SAAS,CAAO,EAChC,GAAI,EAAK,YAAY,EAAG,OAAO,EAAc,CAAO,EACpD,GAAI,CAAC,EAAK,OAAO,EAAG,OACpB,IAAM,EAAQ,sBAAsB,KAAKA,EAAAA,QAAG,aAAa,EAAS,MAAM,CAAC,CAAC,KAAK,CAAC,EAChF,OAAO,IAAQ,GAAK,EAAcD,EAAAA,QAAK,QAAQ,EAAgB,EAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAI,IAAA,EACrF,MAAQ,CACN,MACF,CACF,CAEA,SAAS,EAAmB,EAA4C,CACtE,IAAM,EAAe,EAAiB,CAAc,EAC/C,KACL,GAAI,CACF,IAAM,EAAWC,EAAAA,QAAG,aAAaD,EAAAA,QAAK,KAAK,EAAc,WAAqB,EAAG,MAAM,CAAC,CAAC,KAAK,EAC9F,OAAO,EAAW,EAAcA,EAAAA,QAAK,QAAQ,EAAc,CAAQ,CAAC,EAAI,CAC1E,MAAQ,CACN,OAAO,CACT,CACF,CAEA,SAAS,EAAa,EAAuB,CAC3C,OAAOE,EAAAA,QAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,EAAO,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,EAAG,EAAmB,CACrG,CAGA,SAAgB,EAAkB,EAAe,EAA0B,CACzE,IAAM,EAAa,EAChB,UAAU,MAAM,CAAC,CACjB,QAAQ,oBAAqB,EAAE,CAAC,CAChC,QAAQ,qBAAsB,GAAG,CAAC,CAClC,QAAQ,oBAAqB,EAAE,CAAC,CAChC,MAAM,EAAG,EAAgB,CAAC,CAC1B,QAAQ,YAAa,EAAE,EAC1B,OAAO,IAAe,IAAM,IAAe,KAAO,IAAe,KAAO,EAAW,CACrF,CAEA,SAAS,EAAgB,EAAqC,EAAgC,CAC5F,GAAI,CAAC,EAAiB,OAAO,EAAkBF,EAAAA,QAAK,SAAS,CAAc,EAAG,CAAwB,EACtG,IAAM,EAAOA,EAAAA,QAAK,SAAS,CAAe,EAE1C,OAAO,EADQ,IAAS,EAAgBA,EAAAA,QAAK,SAASA,EAAAA,QAAK,QAAQ,CAAe,CAAC,EAAI,EACtD,CAAwB,CAC3D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/adapters/skillCacheLocation.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The home-scoped skill manifest cache for one worktree.
|
|
4
|
+
*
|
|
5
|
+
* This mirrors the namespace the DoomPi launcher publishes into, so a session
|
|
6
|
+
* that stages resources through the launcher and one that stages them through a
|
|
7
|
+
* `/domains` switch hit the same manifests instead of rescanning every tree.
|
|
8
|
+
* Two worktrees of one repository stay separate, and a checkout reached through
|
|
9
|
+
* a symlink resolves to the same identity as the real path.
|
|
10
|
+
*/
|
|
11
|
+
declare function resolveSkillCacheDirectory(repositoryRoot: string, homeDirectory?: string): string;
|
|
12
|
+
/** Keeps a repository or worktree name usable as one path segment. */
|
|
13
|
+
declare function sanitizeSyncLabel(value: string, fallback: string): string;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { resolveSkillCacheDirectory, sanitizeSyncLabel };
|
|
16
|
+
//# sourceMappingURL=skillCacheLocation.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCacheLocation.d.cts","names":[],"sources":["../../src/adapters/skillCacheLocation.ts"],"mappings":";;;;;;;;;;iBA0BgB,2BAA2B,wBAAwB;;iBA0DnD,kBAAkB,eAAe"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/adapters/skillCacheLocation.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The home-scoped skill manifest cache for one worktree.
|
|
4
|
+
*
|
|
5
|
+
* This mirrors the namespace the DoomPi launcher publishes into, so a session
|
|
6
|
+
* that stages resources through the launcher and one that stages them through a
|
|
7
|
+
* `/domains` switch hit the same manifests instead of rescanning every tree.
|
|
8
|
+
* Two worktrees of one repository stay separate, and a checkout reached through
|
|
9
|
+
* a symlink resolves to the same identity as the real path.
|
|
10
|
+
*/
|
|
11
|
+
declare function resolveSkillCacheDirectory(repositoryRoot: string, homeDirectory?: string): string;
|
|
12
|
+
/** Keeps a repository or worktree name usable as one path segment. */
|
|
13
|
+
declare function sanitizeSyncLabel(value: string, fallback: string): string;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { resolveSkillCacheDirectory, sanitizeSyncLabel };
|
|
16
|
+
//# sourceMappingURL=skillCacheLocation.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCacheLocation.d.mts","names":[],"sources":["../../src/adapters/skillCacheLocation.ts"],"mappings":";;;;;;;;;;iBA0BgB,2BAA2B,wBAAwB;;iBA0DnD,kBAAkB,eAAe"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"node:fs";import t from"node:path";import n from"node:crypto";import r from"node:os";const i=[`cache`,`skills`],a=`.git`,o=`repo`;function s(e,n=r.homedir()){let a=c(e),o=u(a),s=o?`git:${o}`:`root:${a}`,l=d(s),m=d(`${s}\0worktree:${a}`),h=p(o,a),g=f(t.basename(a),`worktree`);return t.join(t.resolve(n),`.pi`,`.doom`,`sync`,`${h}--${l}`,`worktrees`,`${g}--${m}`,...i)}function c(n){let r=t.resolve(n);try{return e.realpathSync.native(r)}catch{return r}}function l(n){let r=t.join(n,a);try{let i=e.statSync(r);if(i.isDirectory())return c(r);if(!i.isFile())return;let a=/^gitdir:\s*(.+)$/imu.exec(e.readFileSync(r,`utf8`).trim());return a?.[1]?c(t.resolve(n,a[1].trim())):void 0}catch{return}}function u(n){let r=l(n);if(r)try{let n=e.readFileSync(t.join(r,`commondir`),`utf8`).trim();return n?c(t.resolve(r,n)):r}catch{return r}}function d(e){return n.createHash(`sha256`).update(e,`utf8`).digest(`hex`).slice(0,32)}function f(e,t){let n=e.normalize(`NFKD`).replace(/[\u0300-\u036f]/gu,``).replace(/[^A-Za-z0-9._-]+/gu,`-`).replace(/^[._-]+|[._-]+$/gu,``).slice(0,48).replace(/[._-]+$/gu,``);return n===``||n===`.`||n===`..`?t:n}function p(e,n){if(!e)return f(t.basename(n),o);let r=t.basename(e);return f(r===a?t.basename(t.dirname(e)):r,o)}export{s as resolveSkillCacheDirectory,f as sanitizeSyncLabel};
|
|
2
|
+
//# sourceMappingURL=skillCacheLocation.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillCacheLocation.mjs","names":[],"sources":["../../src/adapters/skillCacheLocation.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nconst PI_DIRECTORY = '.pi';\nconst DOOM_CONFIG_DIRECTORY = '.doom';\nconst SYNC_DIRECTORY = 'sync';\nconst WORKTREES_DIRECTORY = 'worktrees';\nconst SKILL_CACHE_SEGMENTS = ['cache', 'skills'];\nconst GIT_DIRECTORY = '.git';\nconst COMMON_DIRECTORY_FILE = 'commondir';\nconst IDENTITY_HEX_LENGTH = 32;\nconst LABEL_MAX_LENGTH = 48;\nconst DEFAULT_REPOSITORY_LABEL = 'repo';\nconst DEFAULT_WORKTREE_LABEL = 'worktree';\n\n/**\n * The home-scoped skill manifest cache for one worktree.\n *\n * This mirrors the namespace the DoomPi launcher publishes into, so a session\n * that stages resources through the launcher and one that stages them through a\n * `/domains` switch hit the same manifests instead of rescanning every tree.\n * Two worktrees of one repository stay separate, and a checkout reached through\n * a symlink resolves to the same identity as the real path.\n */\nexport function resolveSkillCacheDirectory(repositoryRoot: string, homeDirectory: string = os.homedir()): string {\n const root = canonicalPath(repositoryRoot);\n const commonDirectory = gitCommonDirectory(root);\n const repositoryToken = commonDirectory ? `git:${commonDirectory}` : `root:${root}`;\n const repositoryId = identityHash(repositoryToken);\n const worktreeId = identityHash(`${repositoryToken}\\0worktree:${root}`);\n const repoLabel = repositoryLabel(commonDirectory, root);\n const worktreeLabel = sanitizeSyncLabel(path.basename(root), DEFAULT_WORKTREE_LABEL);\n return path.join(\n path.resolve(homeDirectory),\n PI_DIRECTORY,\n DOOM_CONFIG_DIRECTORY,\n SYNC_DIRECTORY,\n `${repoLabel}--${repositoryId}`,\n WORKTREES_DIRECTORY,\n `${worktreeLabel}--${worktreeId}`,\n ...SKILL_CACHE_SEGMENTS,\n );\n}\n\nfunction canonicalPath(target: string): string {\n const absolute = path.resolve(target);\n try {\n return fs.realpathSync.native(absolute);\n } catch {\n return absolute;\n }\n}\n\nfunction readGitDirectory(repositoryRoot: string): string | undefined {\n const gitPath = path.join(repositoryRoot, GIT_DIRECTORY);\n try {\n const stat = fs.statSync(gitPath);\n if (stat.isDirectory()) return canonicalPath(gitPath);\n if (!stat.isFile()) return undefined;\n const match = /^gitdir:\\s*(.+)$/imu.exec(fs.readFileSync(gitPath, 'utf8').trim());\n return match?.[1] ? canonicalPath(path.resolve(repositoryRoot, match[1].trim())) : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction gitCommonDirectory(repositoryRoot: string): string | undefined {\n const gitDirectory = readGitDirectory(repositoryRoot);\n if (!gitDirectory) return undefined;\n try {\n const relative = fs.readFileSync(path.join(gitDirectory, COMMON_DIRECTORY_FILE), 'utf8').trim();\n return relative ? canonicalPath(path.resolve(gitDirectory, relative)) : gitDirectory;\n } catch {\n return gitDirectory;\n }\n}\n\nfunction identityHash(value: string): string {\n return crypto.createHash('sha256').update(value, 'utf8').digest('hex').slice(0, IDENTITY_HEX_LENGTH);\n}\n\n/** Keeps a repository or worktree name usable as one path segment. */\nexport function sanitizeSyncLabel(value: string, fallback: string): string {\n const normalized = value\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/gu, '')\n .replace(/[^A-Za-z0-9._-]+/gu, '-')\n .replace(/^[._-]+|[._-]+$/gu, '')\n .slice(0, LABEL_MAX_LENGTH)\n .replace(/[._-]+$/gu, '');\n return normalized === '' || normalized === '.' || normalized === '..' ? fallback : normalized;\n}\n\nfunction repositoryLabel(commonDirectory: string | undefined, repositoryRoot: string): string {\n if (!commonDirectory) return sanitizeSyncLabel(path.basename(repositoryRoot), DEFAULT_REPOSITORY_LABEL);\n const base = path.basename(commonDirectory);\n const source = base === GIT_DIRECTORY ? path.basename(path.dirname(commonDirectory)) : base;\n return sanitizeSyncLabel(source, DEFAULT_REPOSITORY_LABEL);\n}\n"],"mappings":"kGAKA,MAIM,EAAuB,CAAC,QAAS,QAAQ,EACzC,EAAgB,OAIhB,EAA2B,OAYjC,SAAgB,EAA2B,EAAwB,EAAwB,EAAG,QAAQ,EAAW,CAC/G,IAAM,EAAO,EAAc,CAAc,EACnC,EAAkB,EAAmB,CAAI,EACzC,EAAkB,EAAkB,OAAO,IAAoB,QAAQ,IACvE,EAAe,EAAa,CAAe,EAC3C,EAAa,EAAa,GAAG,EAAgB,aAAa,GAAM,EAChE,EAAY,EAAgB,EAAiB,CAAI,EACjD,EAAgB,EAAkB,EAAK,SAAS,CAAI,EAAG,UAAsB,EACnF,OAAO,EAAK,KACV,EAAK,QAAQ,CAAa,EAC1B,MACA,QACA,OACA,GAAG,EAAU,IAAI,IACjB,YACA,GAAG,EAAc,IAAI,IACrB,GAAG,CACL,CACF,CAEA,SAAS,EAAc,EAAwB,CAC7C,IAAM,EAAW,EAAK,QAAQ,CAAM,EACpC,GAAI,CACF,OAAO,EAAG,aAAa,OAAO,CAAQ,CACxC,MAAQ,CACN,OAAO,CACT,CACF,CAEA,SAAS,EAAiB,EAA4C,CACpE,IAAM,EAAU,EAAK,KAAK,EAAgB,CAAa,EACvD,GAAI,CACF,IAAM,EAAO,EAAG,SAAS,CAAO,EAChC,GAAI,EAAK,YAAY,EAAG,OAAO,EAAc,CAAO,EACpD,GAAI,CAAC,EAAK,OAAO,EAAG,OACpB,IAAM,EAAQ,sBAAsB,KAAK,EAAG,aAAa,EAAS,MAAM,CAAC,CAAC,KAAK,CAAC,EAChF,OAAO,IAAQ,GAAK,EAAc,EAAK,QAAQ,EAAgB,EAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAI,IAAA,EACrF,MAAQ,CACN,MACF,CACF,CAEA,SAAS,EAAmB,EAA4C,CACtE,IAAM,EAAe,EAAiB,CAAc,EAC/C,KACL,GAAI,CACF,IAAM,EAAW,EAAG,aAAa,EAAK,KAAK,EAAc,WAAqB,EAAG,MAAM,CAAC,CAAC,KAAK,EAC9F,OAAO,EAAW,EAAc,EAAK,QAAQ,EAAc,CAAQ,CAAC,EAAI,CAC1E,MAAQ,CACN,OAAO,CACT,CACF,CAEA,SAAS,EAAa,EAAuB,CAC3C,OAAO,EAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,EAAO,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,EAAG,EAAmB,CACrG,CAGA,SAAgB,EAAkB,EAAe,EAA0B,CACzE,IAAM,EAAa,EAChB,UAAU,MAAM,CAAC,CACjB,QAAQ,oBAAqB,EAAE,CAAC,CAChC,QAAQ,qBAAsB,GAAG,CAAC,CAClC,QAAQ,oBAAqB,EAAE,CAAC,CAChC,MAAM,EAAG,EAAgB,CAAC,CAC1B,QAAQ,YAAa,EAAE,EAC1B,OAAO,IAAe,IAAM,IAAe,KAAO,IAAe,KAAO,EAAW,CACrF,CAEA,SAAS,EAAgB,EAAqC,EAAgC,CAC5F,GAAI,CAAC,EAAiB,OAAO,EAAkB,EAAK,SAAS,CAAc,EAAG,CAAwB,EACtG,IAAM,EAAO,EAAK,SAAS,CAAe,EAE1C,OAAO,EADQ,IAAS,EAAgB,EAAK,SAAS,EAAK,QAAQ,CAAe,CAAC,EAAI,EACtD,CAAwB,CAC3D"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("@agimon-ai/doompi-telemetry");function t(t={}){let n=(0,e.createDoomTelemetry)({serviceName:`doom-pi-domain`,packageName:`@agimon-ai/doompi-domain`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordEvent:(e,t)=>n.recordEvent(e,t)}}exports.createDomainTelemetry=t;
|
|
2
|
+
//# sourceMappingURL=logSinkTelemetry.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logSinkTelemetry.cjs","names":["createDoomTelemetry"],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { DomainTelemetry } from '../../types/telemetry.ts';\n\nconst SERVICE_NAME = 'doom-pi-domain';\nconst PACKAGE_NAME = '@agimon-ai/doompi-domain';\n\nexport interface DomainTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createDomainTelemetry(options: DomainTelemetryOptions = {}): DomainTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordEvent: (event, attributes) => telemetry.recordEvent(event, attributes),\n };\n}\n"],"mappings":"6CAcA,SAAgB,EAAsB,EAAkC,CAAC,EAAoB,CAC3F,IAAM,GAAA,EAA2BA,EAAAA,oBAAAA,CAAoB,CACnD,YAAa,iBACb,YAAa,2BACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,CAAU,EACzF,aAAc,EAAO,IAAe,EAAU,YAAY,EAAO,CAAU,CAC7E,CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DomainTelemetry } from "../../types/telemetry.cjs";
|
|
2
|
+
import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
|
|
3
|
+
//#region src/adapters/telemetry/logSinkTelemetry.d.ts
|
|
4
|
+
interface DomainTelemetryOptions {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
workspaceRoot?: string;
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
|
|
9
|
+
warn?: (message: string) => void;
|
|
10
|
+
}
|
|
11
|
+
declare function createDomainTelemetry(options?: DomainTelemetryOptions): DomainTelemetry;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { DomainTelemetryOptions, createDomainTelemetry };
|
|
14
|
+
//# sourceMappingURL=logSinkTelemetry.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logSinkTelemetry.d.cts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;UAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;iBAGM,sBAAsB,UAAS,yBAA8B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DomainTelemetry } from "../../types/telemetry.mjs";
|
|
2
|
+
import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
|
|
3
|
+
//#region src/adapters/telemetry/logSinkTelemetry.d.ts
|
|
4
|
+
interface DomainTelemetryOptions {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
workspaceRoot?: string;
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
|
|
9
|
+
warn?: (message: string) => void;
|
|
10
|
+
}
|
|
11
|
+
declare function createDomainTelemetry(options?: DomainTelemetryOptions): DomainTelemetry;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { DomainTelemetryOptions, createDomainTelemetry };
|
|
14
|
+
//# sourceMappingURL=logSinkTelemetry.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logSinkTelemetry.d.mts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;UAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;iBAGM,sBAAsB,UAAS,yBAA8B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createDoomTelemetry as e}from"@agimon-ai/doompi-telemetry";function t(t={}){let n=e({serviceName:`doom-pi-domain`,packageName:`@agimon-ai/doompi-domain`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordEvent:(e,t)=>n.recordEvent(e,t)}}export{t as createDomainTelemetry};
|
|
2
|
+
//# sourceMappingURL=logSinkTelemetry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logSinkTelemetry.mjs","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { DomainTelemetry } from '../../types/telemetry.ts';\n\nconst SERVICE_NAME = 'doom-pi-domain';\nconst PACKAGE_NAME = '@agimon-ai/doompi-domain';\n\nexport interface DomainTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createDomainTelemetry(options: DomainTelemetryOptions = {}): DomainTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordEvent: (event, attributes) => telemetry.recordEvent(event, attributes),\n };\n}\n"],"mappings":"kEAcA,SAAgB,EAAsB,EAAkC,CAAC,EAAoB,CAC3F,IAAM,EAA2B,EAAoB,CACnD,YAAa,iBACb,YAAa,2BACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,CAAU,EACzF,aAAc,EAAO,IAAe,EAAU,YAAY,EAAO,CAAU,CAC7E,CACF"}
|
package/dist/apply.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/applyDomains.cjs");exports.applyDomains=e.applyDomains;
|
package/dist/apply.d.cts
ADDED
package/dist/apply.d.mts
ADDED
package/dist/apply.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{applyDomains as e}from"./adapters/applyDomains.mjs";export{e as applyDomains};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../services/domainText.cjs"),t=require("../types/telemetry.cjs");let n=require("@agimon-ai/doompi-config/harnessStore"),r=require("@agimon-ai/doompi-config/piContext"),i=require("@agimon-ai/doompi-extension-contracts/voice-tools"),a=require("@agimon-ai/doompi-extension-contracts/transition");const o=`info`;function s(e){return e instanceof AggregateError?e.errors.map(s).join(`; `):e instanceof Error?e.message:String(e)}function c(e,t,n){return Error(`${e} compensation failed: ${s(n)}`,{cause:t})}function l(e,t){if(!t.commit(e.reloadHandoffToken,{sessionId:e.sessionId,hostGeneration:e.hostGeneration}))throw Error(`The voice reload handoff is stale or was already consumed.`)}async function u(t,n){let r=await n.catalog.list(t),[{MatrixPickerComponent:i},a]=await Promise.all([n.loadPicker(),n.catalog.describe(t)]);return t.ui.custom((t,n,o,s)=>new i({title:e.pickerTitle(r),items:e.domainItems(r.available,a),selected:[...r.effective],multi:!0},n,o,s))}function d(s,d,f){s.registerCommand(e.DOMAIN_COMMAND,{description:`Show the selected domains and pick a different set`,handler:async(p,m)=>{let h=f.cordisContext(),g=(0,r.requireDoomConfigContext)(h).harness,_,v,y,b,x=!1;try{let r=e.voiceSwitchToken(p);if(r){let e=m.sessionManager.getSessionId(),t=(0,i.readDoomVoiceToolsService)(h)?.readSession(e);if(t&&(_={sessionId:e,hostGeneration:t.hostGeneration}),v=_?f.handoffs.consume(r,_):void 0,!v)throw Error(`The voice domain switch token is stale or belongs to another session.`)}let S=v?[...v.domains]:e.splitDomains(p),C=!1;if(!v&&S.length===0&&m.mode===`tui`){let e=await u(m,f);if(e===void 0)return;S=e,C=!0}if(!v&&S.length===0&&!C){m.ui.notify(e.domainSummary(await f.catalog.list(m)),o);return}S=await f.catalog.validate(m,S);let w=(0,a.requireDoomTransitionCoordinator)(h),T=v?`voice`:C?`ui`:`command`,E=await w.execute({sessionId:m.sessionManager.getSessionId(),hostGeneration:w.hostGeneration,operationId:v?.operationId??crypto.randomUUID(),source:T,target:{axis:`domains`,domains:S}},async(r,i)=>{await m.waitForIdle(),y=(0,a.prepareMinorModeReloadHandoff)(h,m.sessionManager.getSessionId(),w.hostGeneration,i.operationId,i.previous.minorModes);let{persistHarnessSelection:u}=await f.loadConfigJournal(),p=(0,n.snapshotHarnessState)(),_={agentDirectories:process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS,skillDirectories:process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS},C=e=>{let t=[];try{(0,n.restoreHarnessStateSnapshot)(p)}catch(e){t.push(e)}let r=(e,t)=>{t===void 0?delete process.env[e]:process.env[e]=t};if(r(`PI_SUBAGENT_EXTRA_AGENT_DIRS`,_.agentDirectories),r(`PI_SUBAGENT_EXTRA_SKILL_DIRS`,_.skillDirectories),e)try{u(s,p.state)}catch(e){t.push(e)}if(t.length>0)throw AggregateError(t,`Could not restore the previous domain selection`)},E,D=!1;try{E=await f.applyDomains(S,g),v&&l(v,f.reloadHandoffs),u(s,E),D=!0,b=()=>C(!0)}catch(e){try{C(D)}catch(n){d.recordError(t.DOMAIN_EVENT.domainsSwitchFailed,c(`Domain switch`,e,n))}throw e}return d.recordEvent(t.DOMAIN_EVENT.domainsSwitched,{"harness.domains.previous":g.domains.join(`,`),"harness.domains":S.join(`,`),"harness.transition.source":T,"harness.transition.disposition":i.disposition,"harness.transition.operation_id":i.operationId}),m.ui.notify(e.switchedSummary(S),o),x=!0,`queued`});if(E.outcome===`unchanged`)m.ui.notify(e.unchangedSummary(S),o),v&&(l(v,f.reloadHandoffs),await m.waitForIdle(),x=!0);else if(E.outcome===`rejected`||E.outcome===`stale`)throw e.transitionError(E)}catch(n){if(x=!1,b){try{b()}catch(e){d.recordError(t.DOMAIN_EVENT.domainsSwitchFailed,c(`Domain switch`,n,e))}b=void 0}y?.discard(),y=void 0,v&&_&&(f.handoffs.discard(v.token,_),f.reloadHandoffs.discard(v.reloadHandoffToken,{sessionId:v.sessionId,hostGeneration:v.hostGeneration})),d.recordError(t.DOMAIN_EVENT.domainsSwitchFailed,n),m.ui.notify(e.errorMessage(n),`error`)}if(x)try{await m.reload()}catch(e){if(b){try{b()}catch(n){d.recordError(t.DOMAIN_EVENT.domainsSwitchFailed,c(`Domain reload`,e,n))}b=void 0}throw y?.discard(),v&&_&&(f.handoffs.discard(v.token,_),f.reloadHandoffs.discard(v.reloadHandoffToken,{sessionId:v.sessionId,hostGeneration:v.hostGeneration})),e}}})}exports.registerDomainsCommand=d;
|
|
2
|
+
//# sourceMappingURL=domainsCommand.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domainsCommand.cjs","names":["pickerTitle","domainItems","DOMAIN_COMMAND","requireDoomConfigContext","voiceSwitchToken","readDoomVoiceToolsService","splitDomains","domainSummary","requireDoomTransitionCoordinator","prepareMinorModeReloadHandoff","snapshotHarnessState","DOMAIN_EVENT","switchedSummary","unchangedSummary","transitionError","errorMessage"],"sources":["../../src/commands/domainsCommand.ts"],"sourcesContent":["import type { DoomHarnessContext, HarnessState } from '@agimon-ai/doompi-config/types';\nimport { restoreHarnessStateSnapshot, snapshotHarnessState } from '@agimon-ai/doompi-config/harnessStore';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport {\n type MinorModeReloadHandoffHandle,\n prepareMinorModeReloadHandoff,\n requireDoomTransitionCoordinator,\n type TransitionSource,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { VoiceReloadHandoffStore } from '@agimon-ai/doompi-extension-contracts/voice-reload-handoff';\nimport { readDoomVoiceToolsService } from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { Context } from '@deepseek-ai/cordis';\nimport {\n DOMAIN_COMMAND,\n domainItems,\n domainSummary,\n errorMessage,\n pickerTitle,\n splitDomains,\n switchedSummary,\n transitionError,\n unchangedSummary,\n voiceSwitchToken,\n} from '../services/domainText.ts';\nimport type { DomainCompletion, DomainListing } from '../types/domains.ts';\nimport type { DomainSwitchHandoff, DomainSwitchHandoffIdentity, DomainSwitchHandoffStore } from '../types/handoff.ts';\nimport { DOMAIN_EVENT, type DomainTelemetry } from '../types/telemetry.ts';\n\nconst INFO = 'info';\nconst ERROR = 'error';\n\nfunction failureDetail(error: unknown): string {\n if (error instanceof AggregateError) return error.errors.map(failureDetail).join('; ');\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction compensationDiagnostic(operation: string, error: unknown, compensationError: unknown): Error {\n return new Error(`${operation} compensation failed: ${failureDetail(compensationError)}`, { cause: error });\n}\n\n/** Everything the manifest reader gives the command, resolved lazily behind it. */\nexport interface DomainCatalogPort {\n list(ctx: ExtensionContext): Promise<DomainListing>;\n validate(ctx: ExtensionContext, values: readonly string[]): Promise<string[]>;\n describe(ctx: ExtensionContext): Promise<Record<string, string | undefined>>;\n completions(root: string, textBeforeCursor: string): Promise<DomainCompletion | undefined>;\n}\n\nexport interface DomainsCommandDependencies {\n readonly cordisContext: () => Context;\n readonly catalog: DomainCatalogPort;\n readonly handoffs: DomainSwitchHandoffStore;\n readonly reloadHandoffs: VoiceReloadHandoffStore;\n readonly applyDomains: (domains: string[], state: DoomHarnessContext) => Promise<HarnessState>;\n readonly loadConfigJournal: () => Promise<typeof import('@agimon-ai/doompi-config/piContext')>;\n readonly loadPicker: () => Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')>;\n}\n\n/** Confirms the parked voice reload handoff, which the reload then acts on. */\nfunction commitReloadHandoff(queued: DomainSwitchHandoff, reloadHandoffs: VoiceReloadHandoffStore): void {\n const committed = reloadHandoffs.commit(queued.reloadHandoffToken, {\n sessionId: queued.sessionId,\n hostGeneration: queued.hostGeneration,\n });\n if (!committed) throw new Error('The voice reload handoff is stale or was already consumed.');\n}\n\nasync function pickDomains(\n ctx: ExtensionContext,\n dependencies: DomainsCommandDependencies,\n): Promise<string[] | undefined> {\n const listing = await dependencies.catalog.list(ctx);\n const [{ MatrixPickerComponent }, descriptions] = await Promise.all([\n dependencies.loadPicker(),\n dependencies.catalog.describe(ctx),\n ]);\n // Domains compose, unlike a layer base, so this picker toggles with space and\n // confirms the whole set rather than replacing one value.\n return ctx.ui.custom<string[] | undefined>(\n (_tui, theme, keybindings, done) =>\n new MatrixPickerComponent(\n {\n title: pickerTitle(listing),\n items: domainItems(listing.available, descriptions),\n selected: [...listing.effective],\n multi: true,\n },\n theme,\n keybindings,\n done,\n ),\n );\n}\n\nexport function registerDomainsCommand(\n pi: ExtensionAPI,\n telemetry: DomainTelemetry,\n dependencies: DomainsCommandDependencies,\n): void {\n pi.registerCommand(DOMAIN_COMMAND, {\n description: 'Show the selected domains and pick a different set',\n handler: async (args, ctx) => {\n const cordis = dependencies.cordisContext();\n const state = requireDoomConfigContext(cordis).harness;\n let sessionIdentity: DomainSwitchHandoffIdentity | undefined;\n let queued: DomainSwitchHandoff | undefined;\n let minorModeReloadHandoff: MinorModeReloadHandoffHandle | undefined;\n let rollbackAppliedSwitch: (() => void) | undefined;\n let reloadRequested = false;\n try {\n const token = voiceSwitchToken(args);\n if (token) {\n const sessionId = ctx.sessionManager.getSessionId();\n const voiceSession = readDoomVoiceToolsService(cordis)?.readSession(sessionId);\n if (voiceSession) sessionIdentity = { sessionId, hostGeneration: voiceSession.hostGeneration };\n queued = sessionIdentity ? dependencies.handoffs.consume(token, sessionIdentity) : undefined;\n if (!queued) throw new Error('The voice domain switch token is stale or belongs to another session.');\n }\n\n let requested = queued ? [...queued.domains] : splitDomains(args);\n let pickerConfirmed = false;\n if (!queued && requested.length === 0 && ctx.mode === 'tui') {\n const chosen = await pickDomains(ctx, dependencies);\n if (chosen === undefined) return;\n requested = chosen;\n pickerConfirmed = true;\n }\n\n if (!queued && requested.length === 0 && !pickerConfirmed) {\n ctx.ui.notify(domainSummary(await dependencies.catalog.list(ctx)), INFO);\n return;\n }\n\n requested = await dependencies.catalog.validate(ctx, requested);\n const coordinator = requireDoomTransitionCoordinator(cordis);\n const source: TransitionSource = queued ? 'voice' : pickerConfirmed ? 'ui' : 'command';\n const result = await coordinator.execute(\n {\n sessionId: ctx.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: queued?.operationId ?? crypto.randomUUID(),\n source,\n target: { axis: 'domains', domains: requested },\n },\n async (_request, plan) => {\n await ctx.waitForIdle();\n minorModeReloadHandoff = prepareMinorModeReloadHandoff(\n cordis,\n ctx.sessionManager.getSessionId(),\n coordinator.hostGeneration,\n plan.operationId,\n plan.previous.minorModes,\n );\n const { persistHarnessSelection } = await dependencies.loadConfigJournal();\n const snapshot = snapshotHarnessState();\n const subagentEnvironment = {\n agentDirectories: process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS,\n skillDirectories: process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS,\n };\n const restoreCandidate = (compensateJournal: boolean): void => {\n const failures: unknown[] = [];\n try {\n restoreHarnessStateSnapshot(snapshot);\n } catch (error) {\n failures.push(error);\n }\n const restoreEnvironment = (key: string, value: string | undefined): void => {\n if (value === undefined) delete process.env[key];\n else process.env[key] = value;\n };\n restoreEnvironment('PI_SUBAGENT_EXTRA_AGENT_DIRS', subagentEnvironment.agentDirectories);\n restoreEnvironment('PI_SUBAGENT_EXTRA_SKILL_DIRS', subagentEnvironment.skillDirectories);\n if (compensateJournal) {\n try {\n // Pi's selection journal is append-only. Once B has been\n // recorded, restoring A means appending A as the newest\n // authoritative selection rather than trying to erase B.\n persistHarnessSelection(pi, snapshot.state);\n } catch (error) {\n failures.push(error);\n }\n }\n if (failures.length > 0) {\n throw new AggregateError(failures, 'Could not restore the previous domain selection');\n }\n };\n let updated: HarnessState;\n let selectionJournaled = false;\n try {\n updated = await dependencies.applyDomains(requested, state);\n if (queued) commitReloadHandoff(queued, dependencies.reloadHandoffs);\n persistHarnessSelection(pi, updated);\n selectionJournaled = true;\n rollbackAppliedSwitch = () => restoreCandidate(true);\n } catch (error) {\n try {\n restoreCandidate(selectionJournaled);\n } catch (compensationError) {\n void telemetry.recordError(\n DOMAIN_EVENT.domainsSwitchFailed,\n compensationDiagnostic('Domain switch', error, compensationError),\n );\n }\n throw error;\n }\n\n void telemetry.recordEvent(DOMAIN_EVENT.domainsSwitched, {\n 'harness.domains.previous': state.domains.join(','),\n 'harness.domains': requested.join(','),\n 'harness.transition.source': source,\n 'harness.transition.disposition': plan.disposition,\n 'harness.transition.operation_id': plan.operationId,\n });\n ctx.ui.notify(switchedSummary(requested), INFO);\n reloadRequested = true;\n // A structural switch is not live until Pi replaces this session.\n // Keeping it queued prevents the old coordinator from treating B\n // as committed if that terminal reload rejects and we restore A.\n return 'queued';\n },\n );\n if (result.outcome === 'unchanged') {\n ctx.ui.notify(unchangedSummary(requested), INFO);\n // A voice switch still has to reload: the follow-up command is the\n // only thing that consumes the handoff the tool already committed to.\n if (queued) {\n commitReloadHandoff(queued, dependencies.reloadHandoffs);\n await ctx.waitForIdle();\n reloadRequested = true;\n }\n } else if (result.outcome === 'rejected' || result.outcome === 'stale') {\n throw transitionError(result);\n }\n } catch (error) {\n reloadRequested = false;\n if (rollbackAppliedSwitch) {\n try {\n rollbackAppliedSwitch();\n } catch (compensationError) {\n void telemetry.recordError(\n DOMAIN_EVENT.domainsSwitchFailed,\n compensationDiagnostic('Domain switch', error, compensationError),\n );\n }\n rollbackAppliedSwitch = undefined;\n }\n minorModeReloadHandoff?.discard();\n minorModeReloadHandoff = undefined;\n if (queued && sessionIdentity) {\n dependencies.handoffs.discard(queued.token, sessionIdentity);\n dependencies.reloadHandoffs.discard(queued.reloadHandoffToken, {\n sessionId: queued.sessionId,\n hostGeneration: queued.hostGeneration,\n });\n }\n void telemetry.recordError(DOMAIN_EVENT.domainsSwitchFailed, error);\n ctx.ui.notify(errorMessage(error), ERROR);\n }\n\n if (reloadRequested) {\n try {\n // Reload must be the handler's terminal action: Pi invalidates this\n // command context as soon as the replacement session is active.\n await ctx.reload();\n } catch (error) {\n if (rollbackAppliedSwitch) {\n try {\n rollbackAppliedSwitch();\n } catch (compensationError) {\n void telemetry.recordError(\n DOMAIN_EVENT.domainsSwitchFailed,\n compensationDiagnostic('Domain reload', error, compensationError),\n );\n }\n rollbackAppliedSwitch = undefined;\n }\n minorModeReloadHandoff?.discard();\n if (queued && sessionIdentity) {\n dependencies.handoffs.discard(queued.token, sessionIdentity);\n dependencies.reloadHandoffs.discard(queued.reloadHandoffToken, {\n sessionId: queued.sessionId,\n hostGeneration: queued.hostGeneration,\n });\n }\n throw error;\n }\n }\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DomainTelemetry } from "../types/telemetry.cjs";
|
|
2
|
+
import { DomainCompletion, DomainListing } from "../types/domains.cjs";
|
|
3
|
+
import { DomainSwitchHandoffStore } from "../types/handoff.cjs";
|
|
4
|
+
import { DoomHarnessContext, HarnessState } from "@agimon-ai/doompi-config/types";
|
|
5
|
+
import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
7
|
+
import { VoiceReloadHandoffStore } from "@agimon-ai/doompi-extension-contracts/voice-reload-handoff";
|
|
8
|
+
//#region src/commands/domainsCommand.d.ts
|
|
9
|
+
/** Everything the manifest reader gives the command, resolved lazily behind it. */
|
|
10
|
+
interface DomainCatalogPort {
|
|
11
|
+
list(ctx: ExtensionContext): Promise<DomainListing>;
|
|
12
|
+
validate(ctx: ExtensionContext, values: readonly string[]): Promise<string[]>;
|
|
13
|
+
describe(ctx: ExtensionContext): Promise<Record<string, string | undefined>>;
|
|
14
|
+
completions(root: string, textBeforeCursor: string): Promise<DomainCompletion | undefined>;
|
|
15
|
+
}
|
|
16
|
+
interface DomainsCommandDependencies {
|
|
17
|
+
readonly cordisContext: () => Context;
|
|
18
|
+
readonly catalog: DomainCatalogPort;
|
|
19
|
+
readonly handoffs: DomainSwitchHandoffStore;
|
|
20
|
+
readonly reloadHandoffs: VoiceReloadHandoffStore;
|
|
21
|
+
readonly applyDomains: (domains: string[], state: DoomHarnessContext) => Promise<HarnessState>;
|
|
22
|
+
readonly loadConfigJournal: () => Promise<typeof import('@agimon-ai/doompi-config/piContext')>;
|
|
23
|
+
readonly loadPicker: () => Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')>;
|
|
24
|
+
}
|
|
25
|
+
declare function registerDomainsCommand(pi: ExtensionAPI, telemetry: DomainTelemetry, dependencies: DomainsCommandDependencies): void;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { DomainCatalogPort, DomainsCommandDependencies, registerDomainsCommand };
|
|
28
|
+
//# sourceMappingURL=domainsCommand.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domainsCommand.d.cts","names":[],"sources":["../../src/commands/domainsCommand.ts"],"mappings":";;;;;;;;;UA0CiB;EACf,KAAK,KAAK,mBAAmB,QAAQ;EACrC,SAAS,KAAK,kBAAkB,4BAA4B;EAC5D,SAAS,KAAK,mBAAmB,QAAQ;EACzC,YAAY,cAAc,2BAA2B,QAAQ;;UAG9C;WACN,qBAAqB;WACrB,SAAS;WACT,UAAU;WACV,gBAAgB;WAChB,eAAe,mBAAmB,OAAO,uBAAuB,QAAQ;WACxE,yBAAyB;WACzB,kBAAkB;;iBAuCb,uBACd,IAAI,cACJ,WAAW,iBACX,cAAc"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DomainTelemetry } from "../types/telemetry.mjs";
|
|
2
|
+
import { DomainCompletion, DomainListing } from "../types/domains.mjs";
|
|
3
|
+
import { DomainSwitchHandoffStore } from "../types/handoff.mjs";
|
|
4
|
+
import { VoiceReloadHandoffStore } from "@agimon-ai/doompi-extension-contracts/voice-reload-handoff";
|
|
5
|
+
import { DoomHarnessContext, HarnessState } from "@agimon-ai/doompi-config/types";
|
|
6
|
+
import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
8
|
+
//#region src/commands/domainsCommand.d.ts
|
|
9
|
+
/** Everything the manifest reader gives the command, resolved lazily behind it. */
|
|
10
|
+
interface DomainCatalogPort {
|
|
11
|
+
list(ctx: ExtensionContext): Promise<DomainListing>;
|
|
12
|
+
validate(ctx: ExtensionContext, values: readonly string[]): Promise<string[]>;
|
|
13
|
+
describe(ctx: ExtensionContext): Promise<Record<string, string | undefined>>;
|
|
14
|
+
completions(root: string, textBeforeCursor: string): Promise<DomainCompletion | undefined>;
|
|
15
|
+
}
|
|
16
|
+
interface DomainsCommandDependencies {
|
|
17
|
+
readonly cordisContext: () => Context;
|
|
18
|
+
readonly catalog: DomainCatalogPort;
|
|
19
|
+
readonly handoffs: DomainSwitchHandoffStore;
|
|
20
|
+
readonly reloadHandoffs: VoiceReloadHandoffStore;
|
|
21
|
+
readonly applyDomains: (domains: string[], state: DoomHarnessContext) => Promise<HarnessState>;
|
|
22
|
+
readonly loadConfigJournal: () => Promise<typeof import('@agimon-ai/doompi-config/piContext')>;
|
|
23
|
+
readonly loadPicker: () => Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')>;
|
|
24
|
+
}
|
|
25
|
+
declare function registerDomainsCommand(pi: ExtensionAPI, telemetry: DomainTelemetry, dependencies: DomainsCommandDependencies): void;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { DomainCatalogPort, DomainsCommandDependencies, registerDomainsCommand };
|
|
28
|
+
//# sourceMappingURL=domainsCommand.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domainsCommand.d.mts","names":[],"sources":["../../src/commands/domainsCommand.ts"],"mappings":";;;;;;;;;UA0CiB;EACf,KAAK,KAAK,mBAAmB,QAAQ;EACrC,SAAS,KAAK,kBAAkB,4BAA4B;EAC5D,SAAS,KAAK,mBAAmB,QAAQ;EACzC,YAAY,cAAc,2BAA2B,QAAQ;;UAG9C;WACN,qBAAqB;WACrB,SAAS;WACT,UAAU;WACV,gBAAgB;WAChB,eAAe,mBAAmB,OAAO,uBAAuB,QAAQ;WACxE,yBAAyB;WACzB,kBAAkB;;iBAuCb,uBACd,IAAI,cACJ,WAAW,iBACX,cAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{DOMAIN_COMMAND as e,domainItems as t,domainSummary as n,errorMessage as r,pickerTitle as i,splitDomains as a,switchedSummary as o,transitionError as s,unchangedSummary as c,voiceSwitchToken as l}from"../services/domainText.mjs";import{DOMAIN_EVENT as u}from"../types/telemetry.mjs";import{restoreHarnessStateSnapshot as d,snapshotHarnessState as f}from"@agimon-ai/doompi-config/harnessStore";import{requireDoomConfigContext as p}from"@agimon-ai/doompi-config/piContext";import{readDoomVoiceToolsService as m}from"@agimon-ai/doompi-extension-contracts/voice-tools";import{prepareMinorModeReloadHandoff as h,requireDoomTransitionCoordinator as g}from"@agimon-ai/doompi-extension-contracts/transition";const _=`info`;function v(e){return e instanceof AggregateError?e.errors.map(v).join(`; `):e instanceof Error?e.message:String(e)}function y(e,t,n){return Error(`${e} compensation failed: ${v(n)}`,{cause:t})}function b(e,t){if(!t.commit(e.reloadHandoffToken,{sessionId:e.sessionId,hostGeneration:e.hostGeneration}))throw Error(`The voice reload handoff is stale or was already consumed.`)}async function x(e,n){let r=await n.catalog.list(e),[{MatrixPickerComponent:a},o]=await Promise.all([n.loadPicker(),n.catalog.describe(e)]);return e.ui.custom((e,n,s,c)=>new a({title:i(r),items:t(r.available,o),selected:[...r.effective],multi:!0},n,s,c))}function S(t,i,v){t.registerCommand(e,{description:`Show the selected domains and pick a different set`,handler:async(e,S)=>{let C=v.cordisContext(),w=p(C).harness,T,E,D,O,k=!1;try{let r=l(e);if(r){let e=S.sessionManager.getSessionId(),t=m(C)?.readSession(e);if(t&&(T={sessionId:e,hostGeneration:t.hostGeneration}),E=T?v.handoffs.consume(r,T):void 0,!E)throw Error(`The voice domain switch token is stale or belongs to another session.`)}let p=E?[...E.domains]:a(e),A=!1;if(!E&&p.length===0&&S.mode===`tui`){let e=await x(S,v);if(e===void 0)return;p=e,A=!0}if(!E&&p.length===0&&!A){S.ui.notify(n(await v.catalog.list(S)),_);return}p=await v.catalog.validate(S,p);let j=g(C),M=E?`voice`:A?`ui`:`command`,N=await j.execute({sessionId:S.sessionManager.getSessionId(),hostGeneration:j.hostGeneration,operationId:E?.operationId??crypto.randomUUID(),source:M,target:{axis:`domains`,domains:p}},async(e,n)=>{await S.waitForIdle(),D=h(C,S.sessionManager.getSessionId(),j.hostGeneration,n.operationId,n.previous.minorModes);let{persistHarnessSelection:r}=await v.loadConfigJournal(),a=f(),s={agentDirectories:process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS,skillDirectories:process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS},c=e=>{let n=[];try{d(a)}catch(e){n.push(e)}let i=(e,t)=>{t===void 0?delete process.env[e]:process.env[e]=t};if(i(`PI_SUBAGENT_EXTRA_AGENT_DIRS`,s.agentDirectories),i(`PI_SUBAGENT_EXTRA_SKILL_DIRS`,s.skillDirectories),e)try{r(t,a.state)}catch(e){n.push(e)}if(n.length>0)throw AggregateError(n,`Could not restore the previous domain selection`)},l,m=!1;try{l=await v.applyDomains(p,w),E&&b(E,v.reloadHandoffs),r(t,l),m=!0,O=()=>c(!0)}catch(e){try{c(m)}catch(t){i.recordError(u.domainsSwitchFailed,y(`Domain switch`,e,t))}throw e}return i.recordEvent(u.domainsSwitched,{"harness.domains.previous":w.domains.join(`,`),"harness.domains":p.join(`,`),"harness.transition.source":M,"harness.transition.disposition":n.disposition,"harness.transition.operation_id":n.operationId}),S.ui.notify(o(p),_),k=!0,`queued`});if(N.outcome===`unchanged`)S.ui.notify(c(p),_),E&&(b(E,v.reloadHandoffs),await S.waitForIdle(),k=!0);else if(N.outcome===`rejected`||N.outcome===`stale`)throw s(N)}catch(e){if(k=!1,O){try{O()}catch(t){i.recordError(u.domainsSwitchFailed,y(`Domain switch`,e,t))}O=void 0}D?.discard(),D=void 0,E&&T&&(v.handoffs.discard(E.token,T),v.reloadHandoffs.discard(E.reloadHandoffToken,{sessionId:E.sessionId,hostGeneration:E.hostGeneration})),i.recordError(u.domainsSwitchFailed,e),S.ui.notify(r(e),`error`)}if(k)try{await S.reload()}catch(e){if(O){try{O()}catch(t){i.recordError(u.domainsSwitchFailed,y(`Domain reload`,e,t))}O=void 0}throw D?.discard(),E&&T&&(v.handoffs.discard(E.token,T),v.reloadHandoffs.discard(E.reloadHandoffToken,{sessionId:E.sessionId,hostGeneration:E.hostGeneration})),e}}})}export{S as registerDomainsCommand};
|
|
2
|
+
//# sourceMappingURL=domainsCommand.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domainsCommand.mjs","names":[],"sources":["../../src/commands/domainsCommand.ts"],"sourcesContent":["import type { DoomHarnessContext, HarnessState } from '@agimon-ai/doompi-config/types';\nimport { restoreHarnessStateSnapshot, snapshotHarnessState } from '@agimon-ai/doompi-config/harnessStore';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport {\n type MinorModeReloadHandoffHandle,\n prepareMinorModeReloadHandoff,\n requireDoomTransitionCoordinator,\n type TransitionSource,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { VoiceReloadHandoffStore } from '@agimon-ai/doompi-extension-contracts/voice-reload-handoff';\nimport { readDoomVoiceToolsService } from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { Context } from '@deepseek-ai/cordis';\nimport {\n DOMAIN_COMMAND,\n domainItems,\n domainSummary,\n errorMessage,\n pickerTitle,\n splitDomains,\n switchedSummary,\n transitionError,\n unchangedSummary,\n voiceSwitchToken,\n} from '../services/domainText.ts';\nimport type { DomainCompletion, DomainListing } from '../types/domains.ts';\nimport type { DomainSwitchHandoff, DomainSwitchHandoffIdentity, DomainSwitchHandoffStore } from '../types/handoff.ts';\nimport { DOMAIN_EVENT, type DomainTelemetry } from '../types/telemetry.ts';\n\nconst INFO = 'info';\nconst ERROR = 'error';\n\nfunction failureDetail(error: unknown): string {\n if (error instanceof AggregateError) return error.errors.map(failureDetail).join('; ');\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction compensationDiagnostic(operation: string, error: unknown, compensationError: unknown): Error {\n return new Error(`${operation} compensation failed: ${failureDetail(compensationError)}`, { cause: error });\n}\n\n/** Everything the manifest reader gives the command, resolved lazily behind it. */\nexport interface DomainCatalogPort {\n list(ctx: ExtensionContext): Promise<DomainListing>;\n validate(ctx: ExtensionContext, values: readonly string[]): Promise<string[]>;\n describe(ctx: ExtensionContext): Promise<Record<string, string | undefined>>;\n completions(root: string, textBeforeCursor: string): Promise<DomainCompletion | undefined>;\n}\n\nexport interface DomainsCommandDependencies {\n readonly cordisContext: () => Context;\n readonly catalog: DomainCatalogPort;\n readonly handoffs: DomainSwitchHandoffStore;\n readonly reloadHandoffs: VoiceReloadHandoffStore;\n readonly applyDomains: (domains: string[], state: DoomHarnessContext) => Promise<HarnessState>;\n readonly loadConfigJournal: () => Promise<typeof import('@agimon-ai/doompi-config/piContext')>;\n readonly loadPicker: () => Promise<typeof import('@agimon-ai/doompi-ui/components/matrixPicker')>;\n}\n\n/** Confirms the parked voice reload handoff, which the reload then acts on. */\nfunction commitReloadHandoff(queued: DomainSwitchHandoff, reloadHandoffs: VoiceReloadHandoffStore): void {\n const committed = reloadHandoffs.commit(queued.reloadHandoffToken, {\n sessionId: queued.sessionId,\n hostGeneration: queued.hostGeneration,\n });\n if (!committed) throw new Error('The voice reload handoff is stale or was already consumed.');\n}\n\nasync function pickDomains(\n ctx: ExtensionContext,\n dependencies: DomainsCommandDependencies,\n): Promise<string[] | undefined> {\n const listing = await dependencies.catalog.list(ctx);\n const [{ MatrixPickerComponent }, descriptions] = await Promise.all([\n dependencies.loadPicker(),\n dependencies.catalog.describe(ctx),\n ]);\n // Domains compose, unlike a layer base, so this picker toggles with space and\n // confirms the whole set rather than replacing one value.\n return ctx.ui.custom<string[] | undefined>(\n (_tui, theme, keybindings, done) =>\n new MatrixPickerComponent(\n {\n title: pickerTitle(listing),\n items: domainItems(listing.available, descriptions),\n selected: [...listing.effective],\n multi: true,\n },\n theme,\n keybindings,\n done,\n ),\n );\n}\n\nexport function registerDomainsCommand(\n pi: ExtensionAPI,\n telemetry: DomainTelemetry,\n dependencies: DomainsCommandDependencies,\n): void {\n pi.registerCommand(DOMAIN_COMMAND, {\n description: 'Show the selected domains and pick a different set',\n handler: async (args, ctx) => {\n const cordis = dependencies.cordisContext();\n const state = requireDoomConfigContext(cordis).harness;\n let sessionIdentity: DomainSwitchHandoffIdentity | undefined;\n let queued: DomainSwitchHandoff | undefined;\n let minorModeReloadHandoff: MinorModeReloadHandoffHandle | undefined;\n let rollbackAppliedSwitch: (() => void) | undefined;\n let reloadRequested = false;\n try {\n const token = voiceSwitchToken(args);\n if (token) {\n const sessionId = ctx.sessionManager.getSessionId();\n const voiceSession = readDoomVoiceToolsService(cordis)?.readSession(sessionId);\n if (voiceSession) sessionIdentity = { sessionId, hostGeneration: voiceSession.hostGeneration };\n queued = sessionIdentity ? dependencies.handoffs.consume(token, sessionIdentity) : undefined;\n if (!queued) throw new Error('The voice domain switch token is stale or belongs to another session.');\n }\n\n let requested = queued ? [...queued.domains] : splitDomains(args);\n let pickerConfirmed = false;\n if (!queued && requested.length === 0 && ctx.mode === 'tui') {\n const chosen = await pickDomains(ctx, dependencies);\n if (chosen === undefined) return;\n requested = chosen;\n pickerConfirmed = true;\n }\n\n if (!queued && requested.length === 0 && !pickerConfirmed) {\n ctx.ui.notify(domainSummary(await dependencies.catalog.list(ctx)), INFO);\n return;\n }\n\n requested = await dependencies.catalog.validate(ctx, requested);\n const coordinator = requireDoomTransitionCoordinator(cordis);\n const source: TransitionSource = queued ? 'voice' : pickerConfirmed ? 'ui' : 'command';\n const result = await coordinator.execute(\n {\n sessionId: ctx.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: queued?.operationId ?? crypto.randomUUID(),\n source,\n target: { axis: 'domains', domains: requested },\n },\n async (_request, plan) => {\n await ctx.waitForIdle();\n minorModeReloadHandoff = prepareMinorModeReloadHandoff(\n cordis,\n ctx.sessionManager.getSessionId(),\n coordinator.hostGeneration,\n plan.operationId,\n plan.previous.minorModes,\n );\n const { persistHarnessSelection } = await dependencies.loadConfigJournal();\n const snapshot = snapshotHarnessState();\n const subagentEnvironment = {\n agentDirectories: process.env.PI_SUBAGENT_EXTRA_AGENT_DIRS,\n skillDirectories: process.env.PI_SUBAGENT_EXTRA_SKILL_DIRS,\n };\n const restoreCandidate = (compensateJournal: boolean): void => {\n const failures: unknown[] = [];\n try {\n restoreHarnessStateSnapshot(snapshot);\n } catch (error) {\n failures.push(error);\n }\n const restoreEnvironment = (key: string, value: string | undefined): void => {\n if (value === undefined) delete process.env[key];\n else process.env[key] = value;\n };\n restoreEnvironment('PI_SUBAGENT_EXTRA_AGENT_DIRS', subagentEnvironment.agentDirectories);\n restoreEnvironment('PI_SUBAGENT_EXTRA_SKILL_DIRS', subagentEnvironment.skillDirectories);\n if (compensateJournal) {\n try {\n // Pi's selection journal is append-only. Once B has been\n // recorded, restoring A means appending A as the newest\n // authoritative selection rather than trying to erase B.\n persistHarnessSelection(pi, snapshot.state);\n } catch (error) {\n failures.push(error);\n }\n }\n if (failures.length > 0) {\n throw new AggregateError(failures, 'Could not restore the previous domain selection');\n }\n };\n let updated: HarnessState;\n let selectionJournaled = false;\n try {\n updated = await dependencies.applyDomains(requested, state);\n if (queued) commitReloadHandoff(queued, dependencies.reloadHandoffs);\n persistHarnessSelection(pi, updated);\n selectionJournaled = true;\n rollbackAppliedSwitch = () => restoreCandidate(true);\n } catch (error) {\n try {\n restoreCandidate(selectionJournaled);\n } catch (compensationError) {\n void telemetry.recordError(\n DOMAIN_EVENT.domainsSwitchFailed,\n compensationDiagnostic('Domain switch', error, compensationError),\n );\n }\n throw error;\n }\n\n void telemetry.recordEvent(DOMAIN_EVENT.domainsSwitched, {\n 'harness.domains.previous': state.domains.join(','),\n 'harness.domains': requested.join(','),\n 'harness.transition.source': source,\n 'harness.transition.disposition': plan.disposition,\n 'harness.transition.operation_id': plan.operationId,\n });\n ctx.ui.notify(switchedSummary(requested), INFO);\n reloadRequested = true;\n // A structural switch is not live until Pi replaces this session.\n // Keeping it queued prevents the old coordinator from treating B\n // as committed if that terminal reload rejects and we restore A.\n return 'queued';\n },\n );\n if (result.outcome === 'unchanged') {\n ctx.ui.notify(unchangedSummary(requested), INFO);\n // A voice switch still has to reload: the follow-up command is the\n // only thing that consumes the handoff the tool already committed to.\n if (queued) {\n commitReloadHandoff(queued, dependencies.reloadHandoffs);\n await ctx.waitForIdle();\n reloadRequested = true;\n }\n } else if (result.outcome === 'rejected' || result.outcome === 'stale') {\n throw transitionError(result);\n }\n } catch (error) {\n reloadRequested = false;\n if (rollbackAppliedSwitch) {\n try {\n rollbackAppliedSwitch();\n } catch (compensationError) {\n void telemetry.recordError(\n DOMAIN_EVENT.domainsSwitchFailed,\n compensationDiagnostic('Domain switch', error, compensationError),\n );\n }\n rollbackAppliedSwitch = undefined;\n }\n minorModeReloadHandoff?.discard();\n minorModeReloadHandoff = undefined;\n if (queued && sessionIdentity) {\n dependencies.handoffs.discard(queued.token, sessionIdentity);\n dependencies.reloadHandoffs.discard(queued.reloadHandoffToken, {\n sessionId: queued.sessionId,\n hostGeneration: queued.hostGeneration,\n });\n }\n void telemetry.recordError(DOMAIN_EVENT.domainsSwitchFailed, error);\n ctx.ui.notify(errorMessage(error), ERROR);\n }\n\n if (reloadRequested) {\n try {\n // Reload must be the handler's terminal action: Pi invalidates this\n // command context as soon as the replacement session is active.\n await ctx.reload();\n } catch (error) {\n if (rollbackAppliedSwitch) {\n try {\n rollbackAppliedSwitch();\n } catch (compensationError) {\n void telemetry.recordError(\n DOMAIN_EVENT.domainsSwitchFailed,\n compensationDiagnostic('Domain reload', error, compensationError),\n );\n }\n rollbackAppliedSwitch = undefined;\n }\n minorModeReloadHandoff?.discard();\n if (queued && sessionIdentity) {\n dependencies.handoffs.discard(queued.token, sessionIdentity);\n dependencies.reloadHandoffs.discard(queued.reloadHandoffToken, {\n sessionId: queued.sessionId,\n hostGeneration: queued.hostGeneration,\n });\n }\n throw error;\n }\n }\n },\n });\n}\n"],"mappings":"ksBA6BA,MAAM,EAAO,OAGb,SAAS,EAAc,EAAwB,CAE7C,OADI,aAAiB,eAAuB,EAAM,OAAO,IAAI,CAAa,CAAC,CAAC,KAAK,IAAI,EAC9E,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAEA,SAAS,EAAuB,EAAmB,EAAgB,EAAmC,CACpG,OAAW,MAAM,GAAG,EAAU,wBAAwB,EAAc,CAAiB,IAAK,CAAE,MAAO,CAAM,CAAC,CAC5G,CAqBA,SAAS,EAAoB,EAA6B,EAA+C,CAKvG,GAAI,CAJc,EAAe,OAAO,EAAO,mBAAoB,CACjE,UAAW,EAAO,UAClB,eAAgB,EAAO,cACzB,CACa,EAAG,MAAU,MAAM,4DAA4D,CAC9F,CAEA,eAAe,EACb,EACA,EAC+B,CAC/B,IAAM,EAAU,MAAM,EAAa,QAAQ,KAAK,CAAG,EAC7C,CAAC,CAAE,yBAAyB,GAAgB,MAAM,QAAQ,IAAI,CAClE,EAAa,WAAW,EACxB,EAAa,QAAQ,SAAS,CAAG,CACnC,CAAC,EAGD,OAAO,EAAI,GAAG,QACX,EAAM,EAAO,EAAa,IACzB,IAAI,EACF,CACE,MAAO,EAAY,CAAO,EAC1B,MAAO,EAAY,EAAQ,UAAW,CAAY,EAClD,SAAU,CAAC,GAAG,EAAQ,SAAS,EAC/B,MAAO,EACT,EACA,EACA,EACA,CACF,CACJ,CACF,CAEA,SAAgB,EACd,EACA,EACA,EACM,CACN,EAAG,gBAAgB,EAAgB,CACjC,YAAa,qDACb,QAAS,MAAO,EAAM,IAAQ,CAC5B,IAAM,EAAS,EAAa,cAAc,EACpC,EAAQ,EAAyB,CAAM,CAAC,CAAC,QAC3C,EACA,EACA,EACA,EACA,EAAkB,GACtB,GAAI,CACF,IAAM,EAAQ,EAAiB,CAAI,EACnC,GAAI,EAAO,CACT,IAAM,EAAY,EAAI,eAAe,aAAa,EAC5C,EAAe,EAA0B,CAAM,CAAC,EAAE,YAAY,CAAS,EAG7E,GAFI,IAAc,EAAkB,CAAE,YAAW,eAAgB,EAAa,cAAe,GAC7F,EAAS,EAAkB,EAAa,SAAS,QAAQ,EAAO,CAAe,EAAI,IAAA,GAC/E,CAAC,EAAQ,MAAU,MAAM,uEAAuE,CACtG,CAEA,IAAI,EAAY,EAAS,CAAC,GAAG,EAAO,OAAO,EAAI,EAAa,CAAI,EAC5D,EAAkB,GACtB,GAAI,CAAC,GAAU,EAAU,SAAW,GAAK,EAAI,OAAS,MAAO,CAC3D,IAAM,EAAS,MAAM,EAAY,EAAK,CAAY,EAClD,GAAI,IAAW,IAAA,GAAW,OAC1B,EAAY,EACZ,EAAkB,EACpB,CAEA,GAAI,CAAC,GAAU,EAAU,SAAW,GAAK,CAAC,EAAiB,CACzD,EAAI,GAAG,OAAO,EAAc,MAAM,EAAa,QAAQ,KAAK,CAAG,CAAC,EAAG,CAAI,EACvE,MACF,CAEA,EAAY,MAAM,EAAa,QAAQ,SAAS,EAAK,CAAS,EAC9D,IAAM,EAAc,EAAiC,CAAM,EACrD,EAA2B,EAAS,QAAU,EAAkB,KAAO,UACvE,EAAS,MAAM,EAAY,QAC/B,CACE,UAAW,EAAI,eAAe,aAAa,EAC3C,eAAgB,EAAY,eAC5B,YAAa,GAAQ,aAAe,OAAO,WAAW,EACtD,SACA,OAAQ,CAAE,KAAM,UAAW,QAAS,CAAU,CAChD,EACA,MAAO,EAAU,IAAS,CACxB,MAAM,EAAI,YAAY,EACtB,EAAyB,EACvB,EACA,EAAI,eAAe,aAAa,EAChC,EAAY,eACZ,EAAK,YACL,EAAK,SAAS,UAChB,EACA,GAAM,CAAE,2BAA4B,MAAM,EAAa,kBAAkB,EACnE,EAAW,EAAqB,EAChC,EAAsB,CAC1B,iBAAkB,QAAQ,IAAI,6BAC9B,iBAAkB,QAAQ,IAAI,4BAChC,EACM,EAAoB,GAAqC,CAC7D,IAAM,EAAsB,CAAC,EAC7B,GAAI,CACF,EAA4B,CAAQ,CACtC,OAAS,EAAO,CACd,EAAS,KAAK,CAAK,CACrB,CACA,IAAM,GAAsB,EAAa,IAAoC,CACvE,IAAU,IAAA,GAAW,OAAO,QAAQ,IAAI,GACvC,QAAQ,IAAI,GAAO,CAC1B,EAGA,GAFA,EAAmB,+BAAgC,EAAoB,gBAAgB,EACvF,EAAmB,+BAAgC,EAAoB,gBAAgB,EACnF,EACF,GAAI,CAIF,EAAwB,EAAI,EAAS,KAAK,CAC5C,OAAS,EAAO,CACd,EAAS,KAAK,CAAK,CACrB,CAEF,GAAI,EAAS,OAAS,EACpB,MAAU,eAAe,EAAU,iDAAiD,CAExF,EACI,EACA,EAAqB,GACzB,GAAI,CACF,EAAU,MAAM,EAAa,aAAa,EAAW,CAAK,EACtD,GAAQ,EAAoB,EAAQ,EAAa,cAAc,EACnE,EAAwB,EAAI,CAAO,EACnC,EAAqB,GACrB,MAA8B,EAAiB,EAAI,CACrD,OAAS,EAAO,CACd,GAAI,CACF,EAAiB,CAAkB,CACrC,OAAS,EAAmB,CAC1B,EAAe,YACb,EAAa,oBACb,EAAuB,gBAAiB,EAAO,CAAiB,CAClE,CACF,CACA,MAAM,CACR,CAcA,OAZA,EAAe,YAAY,EAAa,gBAAiB,CACvD,2BAA4B,EAAM,QAAQ,KAAK,GAAG,EAClD,kBAAmB,EAAU,KAAK,GAAG,EACrC,4BAA6B,EAC7B,iCAAkC,EAAK,YACvC,kCAAmC,EAAK,WAC1C,CAAC,EACD,EAAI,GAAG,OAAO,EAAgB,CAAS,EAAG,CAAI,EAC9C,EAAkB,GAIX,QACT,CACF,EACA,GAAI,EAAO,UAAY,YACrB,EAAI,GAAG,OAAO,EAAiB,CAAS,EAAG,CAAI,EAG3C,IACF,EAAoB,EAAQ,EAAa,cAAc,EACvD,MAAM,EAAI,YAAY,EACtB,EAAkB,SAEf,GAAI,EAAO,UAAY,YAAc,EAAO,UAAY,QAC7D,MAAM,EAAgB,CAAM,CAEhC,OAAS,EAAO,CAEd,GADA,EAAkB,GACd,EAAuB,CACzB,GAAI,CACF,EAAsB,CACxB,OAAS,EAAmB,CAC1B,EAAe,YACb,EAAa,oBACb,EAAuB,gBAAiB,EAAO,CAAiB,CAClE,CACF,CACA,EAAwB,IAAA,EAC1B,CACA,GAAwB,QAAQ,EAChC,EAAyB,IAAA,GACrB,GAAU,IACZ,EAAa,SAAS,QAAQ,EAAO,MAAO,CAAe,EAC3D,EAAa,eAAe,QAAQ,EAAO,mBAAoB,CAC7D,UAAW,EAAO,UAClB,eAAgB,EAAO,cACzB,CAAC,GAEH,EAAe,YAAY,EAAa,oBAAqB,CAAK,EAClE,EAAI,GAAG,OAAO,EAAa,CAAK,EAAG,OAAK,CAC1C,CAEA,GAAI,EACF,GAAI,CAGF,MAAM,EAAI,OAAO,CACnB,OAAS,EAAO,CACd,GAAI,EAAuB,CACzB,GAAI,CACF,EAAsB,CACxB,OAAS,EAAmB,CAC1B,EAAe,YACb,EAAa,oBACb,EAAuB,gBAAiB,EAAO,CAAiB,CAClE,CACF,CACA,EAAwB,IAAA,EAC1B,CASA,MARA,GAAwB,QAAQ,EAC5B,GAAU,IACZ,EAAa,SAAS,QAAQ,EAAO,MAAO,CAAe,EAC3D,EAAa,eAAe,QAAQ,EAAO,mBAAoB,CAC7D,UAAW,EAAO,UAClB,eAAgB,EAAO,cACzB,CAAC,GAEG,CACR,CAEJ,CACF,CAAC,CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/pi/extension.cjs");exports.default=e.default,exports.domainsExtension=e.default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"../adapters/pi/extension.mjs";export{e as default,e as domainsExtension};
|