@agimon-ai/doompi-domain 0.0.1-alpha.13 → 0.0.1-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +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("@agimon-ai/doompi-config/domains"),i=require("node:child_process");const a=`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`,o=`.doompi-plugin.json`;function s(e,t){let n=e+t.toString(`utf8`);return n.length<=65536?n:n.slice(-65536)}function c(e,t,n={}){return new Promise((r,a)=>{let o=(0,i.spawn)(e,t,{cwd:n.cwd,env:n.environment??process.env,stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;o.stdout.on(`data`,e=>{c=s(c,e)}),o.stderr.on(`data`,e=>{l=s(l,e)}),o.once(`error`,t=>{a(Error(`Failed to run ${e}: ${t.message}`,{cause:t}))}),o.once(`close`,(n,i)=>{if(n===0){r(c.trim());return}let o=i?`signal ${i}`:`exit code ${n??`unknown`}`,s=l.trim()||c.trim();a(Error(`${e} ${t.join(` `)} failed with ${o}${s?`\n${s}`:``}`))})})}function l(e,t,r){let i=n.default.relative(e,t);if(!(i===``||!i.startsWith(`..`)&&!n.default.isAbsolute(i)))throw Error(`${r} resolves outside ${e}`)}async function u(e,t){let r=n.default.join(t,`checkout`),i=[`clone`,`--filter=blob:none`];e.path&&i.push(`--sparse`,`--no-checkout`),i.push(e.url,r);let a={...process.env,GIT_TERMINAL_PROMPT:`0`};if(await c(`git`,i,{environment:a}),e.path&&await c(`git`,[`sparse-checkout`,`set`,`--no-cone`,`--`,e.path],{cwd:r,environment:a}),e.sha){await c(`git`,[`checkout`,e.sha],{cwd:r,environment:a});let t=await c(`git`,[`rev-parse`,`HEAD`],{cwd:r,environment:a});if(t.toLowerCase()!==e.sha.toLowerCase())throw Error(`Checked out Git SHA ${t} does not match requested SHA ${e.sha}`)}else e.ref?await c(`git`,[`checkout`,e.ref],{cwd:r,environment:a}):e.path&&await c(`git`,[`checkout`],{cwd:r,environment:a});let o=e.path?n.default.resolve(r,e.path):r;return l(r,o,`Git plugin path`),o}async function d(e,t){let r=n.default.join(t,`npm`),i=[`install`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--package-lock=false`,`--prefix`,r,e.version?`${e.package}@${e.version}`:e.package];e.registry&&i.push(`--registry`,e.registry),await c(`npm`,i,{environment:{...process.env,NPM_CONFIG_AUDIT:`false`,NPM_CONFIG_FUND:`false`,NPM_CONFIG_IGNORE_SCRIPTS:`true`}});let a=n.default.resolve(r,`node_modules`,...e.package.split(`/`));return l(n.default.join(r,`node_modules`),a,`npm plugin package`),a}const f={git:u,npm:d};async function p(e){try{return(await t.default.promises.lstat(e)).isDirectory()?`directory`:`other`}catch(e){if(e.code===`ENOENT`)return`missing`;throw e}}function m(e,t){let n=e[t];return typeof n==`string`&&n.trim()?n.trim():void 0}function h(e,r){try{let i=JSON.parse(t.default.readFileSync(r,`utf8`));if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`manifest must contain a JSON object`);let o=i,s=r===n.default.join(e,`plugin.json`)&&o.$schema===a?a:void 0,c=m(o,`name`),l=m(o,`version`),u=m(o,`description`);return{skillDiscovery:s?`direct-children`:`recursive`,manifest:{path:r,...c?{name:c}:{},...l?{version:l}:{},...u?{description:u}:{},...s?{agentPluginSchema:s}:{}}}}catch(e){throw Error(`Invalid plugin manifest ${r}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}async function g(e){let i=await p(e.directory);if(i===`missing`)return!1;if(i!==`directory`)throw Error(`Remote plugin cache path is not a directory: ${e.directory}`);if(!e.source||!(0,r.isRemotePluginSource)(e.source))throw Error(`Remote plugin entry is missing its source: ${e.name??e.directory}`);let a;try{a=JSON.parse(await t.default.promises.readFile(n.default.join(e.directory,o),`utf8`))}catch(t){throw Error(`Remote plugin cache is not managed by DoomPi: ${e.directory}`,{cause:t})}if(a.version!==1||JSON.stringify(a.source)!==JSON.stringify(e.source))throw Error(`Remote plugin cache metadata does not match ${e.name??e.directory}: ${e.directory}`);let s=(0,r.findPluginManifestPath)(e.directory);if(!s)throw Error(`Remote plugin cache is missing a supported plugin manifest: ${e.directory}`);return h(e.directory,s)}async function _(e,r){if(await p(e)!==`directory`)throw Error(`Materialized plugin source is not a directory: ${e}`);await t.default.promises.cp(e,r,{recursive:!0,filter:e=>n.default.basename(e)!==`.git`})}function v(e){let t=e.code;return t===`EEXIST`||t===`ENOTEMPTY`}async function y(e,i){if(!e.source||!(0,r.isRemotePluginSource)(e.source))return e;let a=await g(e);if(a)return{...e,...a};let s=n.default.dirname(e.directory);if(await t.default.promises.mkdir(s,{recursive:!0,mode:448}),await p(s)!==`directory`)throw Error(`Remote plugin cache root is not a directory: ${s}`);await t.default.promises.chmod(s,448);let c=await t.default.promises.mkdtemp(n.default.join(s,`.plugin-staging-`)),l=n.default.join(c,`installation`);try{await _(e.source.type===`git`?await i.git(e.source,c):await i.npm(e.source,c),l);let a=(0,r.findPluginManifestPath)(l);if(!a)throw Error(`Remote plugin ${e.name??e.directory} does not contain a supported plugin manifest`);h(l,a);let s=n.default.join(l,o);if(await p(s)!==`missing`)throw Error(`Remote plugin contains reserved cache metadata path: ${o}`);let u={version:1,source:e.source};await t.default.promises.writeFile(s,`${JSON.stringify(u,null,2)}\n`,{flag:`wx`,mode:384});try{await t.default.promises.rename(l,e.directory)}catch(n){if(!v(n))throw n;await t.default.promises.rm(l,{recursive:!0,force:!0});let r=await g(e);if(!r)throw Error(`Remote plugin installation race left no cache: ${e.directory}`);return{...e,...r}}let d=await g(e);if(!d)throw Error(`Remote plugin installation left no cache: ${e.directory}`);return{...e,...d}}catch(t){throw Error(`Failed to install remote plugin ${e.name??e.directory}: ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{await t.default.promises.rm(c,{recursive:!0,force:!0})}}async function b(e,t={}){let n={git:t.materializers?.git??f.git,npm:t.materializers?.npm??f.npm};return Promise.all(e.map(e=>y(e,n)))}exports.materializePluginEntries=b;
1
+ const e=require("../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("@agimon-ai/doompi-config/domains"),i=require("node:child_process");const a=`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`,o=`.doompi-plugin.json`;function s(e,t){let n=e+t.toString(`utf8`);return n.length<=65536?n:n.slice(-65536)}function c(e,t,n={}){return new Promise((r,a)=>{let o=(0,i.spawn)(e,t,{cwd:n.cwd,env:n.environment??process.env,stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;o.stdout.on(`data`,e=>{c=s(c,e)}),o.stderr.on(`data`,e=>{l=s(l,e)}),o.once(`error`,t=>{a(Error(`Failed to run ${e}: ${t.message}`,{cause:t}))}),o.once(`close`,(n,i)=>{if(n===0){r(c.trim());return}let o=i?`signal ${i}`:`exit code ${n??`unknown`}`,s=l.trim()||c.trim();a(Error(`${e} ${t.join(` `)} failed with ${o}${s?`\n${s}`:``}`))})})}function l(e,t,r){let i=n.default.relative(e,t);if(!(i===``||!i.startsWith(`..`)&&!n.default.isAbsolute(i)))throw Error(`${r} resolves outside ${e}`)}async function u(e,t){let r=n.default.join(t,`checkout`),i=e.path?n.default.resolve(r,e.path):r;e.path&&l(r,i,`Git plugin path`);let a=[`clone`,`--filter=blob:none`];e.path&&a.push(`--sparse`,`--no-checkout`),a.push(e.url,r);let o={...process.env,GIT_TERMINAL_PROMPT:`0`};if(await c(`git`,a,{environment:o}),e.path&&await c(`git`,[`sparse-checkout`,`set`,`--no-cone`,`--`,e.path],{cwd:r,environment:o}),e.sha){await c(`git`,[`checkout`,e.sha],{cwd:r,environment:o});let t=await c(`git`,[`rev-parse`,`HEAD`],{cwd:r,environment:o});if(t.toLowerCase()!==e.sha.toLowerCase())throw Error(`Checked out Git SHA ${t} does not match requested SHA ${e.sha}`)}else e.ref?await c(`git`,[`checkout`,e.ref],{cwd:r,environment:o}):e.path&&await c(`git`,[`checkout`],{cwd:r,environment:o});return i}async function d(e,t){let r=n.default.join(t,`npm`),i=[`install`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--package-lock=false`,`--prefix`,r,e.version?`${e.package}@${e.version}`:e.package];e.registry&&i.push(`--registry`,e.registry),await c(`npm`,i,{environment:{...process.env,NPM_CONFIG_AUDIT:`false`,NPM_CONFIG_FUND:`false`,NPM_CONFIG_IGNORE_SCRIPTS:`true`}});let a=n.default.resolve(r,`node_modules`,...e.package.split(`/`));return l(n.default.join(r,`node_modules`),a,`npm plugin package`),a}const f={git:u,npm:d};async function p(e){try{return(await t.default.promises.lstat(e)).isDirectory()?`directory`:`other`}catch(e){if(e.code===`ENOENT`)return`missing`;throw e}}function m(e,t){let n=e[t];return typeof n==`string`&&n.trim()?n.trim():void 0}function h(e,r){try{let i=JSON.parse(t.default.readFileSync(r,`utf8`));if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`manifest must contain a JSON object`);let o=i,s=r===n.default.join(e,`plugin.json`)&&o.$schema===a?a:void 0,c=m(o,`name`),l=m(o,`version`),u=m(o,`description`);return{skillDiscovery:s?`direct-children`:`recursive`,manifest:{path:r,...c?{name:c}:{},...l?{version:l}:{},...u?{description:u}:{},...s?{agentPluginSchema:s}:{}}}}catch(e){throw Error(`Invalid plugin manifest ${r}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}async function g(e){let i=await p(e.directory);if(i===`missing`)return!1;if(i!==`directory`)throw Error(`Remote plugin cache path is not a directory: ${e.directory}`);if(!e.source||!(0,r.isRemotePluginSource)(e.source))throw Error(`Remote plugin entry is missing its source: ${e.name??e.directory}`);let a;try{a=JSON.parse(await t.default.promises.readFile(n.default.join(e.directory,o),`utf8`))}catch(t){throw Error(`Remote plugin cache is not managed by DoomPi: ${e.directory}`,{cause:t})}if(a.version!==1||JSON.stringify(a.source)!==JSON.stringify(e.source))throw Error(`Remote plugin cache metadata does not match ${e.name??e.directory}: ${e.directory}`);let s=(0,r.findPluginManifestPath)(e.directory);if(!s)throw Error(`Remote plugin cache is missing a supported plugin manifest: ${e.directory}`);return h(e.directory,s)}async function _(e,r){if(await p(e)!==`directory`)throw Error(`Materialized plugin source is not a directory: ${e}`);await t.default.promises.cp(e,r,{recursive:!0,filter:e=>n.default.basename(e)!==`.git`})}function v(e){let t=e.code;return t===`EEXIST`||t===`ENOTEMPTY`}async function y(e,i){if(!e.source||!(0,r.isRemotePluginSource)(e.source))return e;let a=await g(e);if(a)return{...e,...a};let s=n.default.dirname(e.directory);if(await t.default.promises.mkdir(s,{recursive:!0,mode:448}),await p(s)!==`directory`)throw Error(`Remote plugin cache root is not a directory: ${s}`);await t.default.promises.chmod(s,448);let c=await t.default.promises.mkdtemp(n.default.join(s,`.plugin-staging-`)),l=n.default.join(c,`installation`);try{await _(e.source.type===`git`?await i.git(e.source,c):await i.npm(e.source,c),l);let a=(0,r.findPluginManifestPath)(l);if(!a)throw Error(`Remote plugin ${e.name??e.directory} does not contain a supported plugin manifest`);h(l,a);let s=n.default.join(l,o);if(await p(s)!==`missing`)throw Error(`Remote plugin contains reserved cache metadata path: ${o}`);let u={version:1,source:e.source};await t.default.promises.writeFile(s,`${JSON.stringify(u,null,2)}\n`,{flag:`wx`,mode:384});try{await t.default.promises.rename(l,e.directory)}catch(n){if(!v(n))throw n;await t.default.promises.rm(l,{recursive:!0,force:!0});let r=await g(e);if(!r)throw Error(`Remote plugin installation race left no cache: ${e.directory}`);return{...e,...r}}let d=await g(e);if(!d)throw Error(`Remote plugin installation left no cache: ${e.directory}`);return{...e,...d}}catch(t){throw Error(`Failed to install remote plugin ${e.name??e.directory}: ${t instanceof Error?t.message:String(t)}`,{cause:t})}finally{await t.default.promises.rm(c,{recursive:!0,force:!0})}}async function b(e,t={}){let n={git:t.materializers?.git??f.git,npm:t.materializers?.npm??f.npm};return Promise.all(e.map(e=>y(e,n)))}exports.materializePluginEntries=b;
2
2
  //# sourceMappingURL=pluginMaterializer.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pluginMaterializer.cjs","names":["spawn","path","fs","isRemotePluginSource","findPluginManifestPath"],"sources":["../../src/adapters/pluginMaterializer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n findPluginManifestPath,\n type GitPluginSource,\n isRemotePluginSource,\n type NpmPluginSource,\n type PluginEntry,\n type PluginManifestMetadata,\n type PluginSkillDiscovery,\n} from '@agimon-ai/doompi-config/domains';\n\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst INSTALL_MARKER = '.doompi-plugin.json';\nconst INSTALL_MARKER_VERSION = 1;\nconst OUTPUT_LIMIT = 64 * 1024;\n\ninterface CommandOptions {\n cwd?: string;\n environment?: NodeJS.ProcessEnv;\n}\n\ninterface InstallMarker {\n version: number;\n source: GitPluginSource | NpmPluginSource;\n}\n\ninterface InspectedPluginManifest {\n skillDiscovery: PluginSkillDiscovery;\n manifest: PluginManifestMetadata;\n}\n\nexport interface PluginSourceMaterializers {\n git: (source: GitPluginSource, workspace: string) => Promise<string>;\n npm: (source: NpmPluginSource, workspace: string) => Promise<string>;\n}\n\nexport interface PluginMaterializerOptions {\n materializers?: Partial<PluginSourceMaterializers>;\n}\n\nfunction appendOutput(current: string, chunk: Buffer): string {\n const next = current + chunk.toString('utf8');\n return next.length <= OUTPUT_LIMIT ? next : next.slice(-OUTPUT_LIMIT);\n}\n\nfunction runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.environment ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout = appendOutput(stdout, chunk);\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr = appendOutput(stderr, chunk);\n });\n child.once('error', (error) => {\n reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error }));\n });\n child.once('close', (code, signal) => {\n if (code === 0) {\n resolve(stdout.trim());\n return;\n }\n const outcome = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const details = stderr.trim() || stdout.trim();\n reject(new Error(`${command} ${args.join(' ')} failed with ${outcome}${details ? `\\n${details}` : ''}`));\n });\n });\n}\n\nfunction assertContained(root: string, candidate: string, label: string): void {\n const relative = path.relative(root, candidate);\n if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;\n throw new Error(`${label} resolves outside ${root}`);\n}\n\nasync function materializeGitSource(source: GitPluginSource, workspace: string): Promise<string> {\n const checkout = path.join(workspace, 'checkout');\n const cloneArgs = ['clone', '--filter=blob:none'];\n if (source.path) cloneArgs.push('--sparse', '--no-checkout');\n cloneArgs.push(source.url, checkout);\n const environment = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n await runCommand('git', cloneArgs, { environment });\n\n if (source.path) {\n await runCommand('git', ['sparse-checkout', 'set', '--no-cone', '--', source.path], {\n cwd: checkout,\n environment,\n });\n }\n if (source.sha) {\n await runCommand('git', ['checkout', source.sha], { cwd: checkout, environment });\n const checkedOutSha = await runCommand('git', ['rev-parse', 'HEAD'], { cwd: checkout, environment });\n if (checkedOutSha.toLowerCase() !== source.sha.toLowerCase()) {\n throw new Error(`Checked out Git SHA ${checkedOutSha} does not match requested SHA ${source.sha}`);\n }\n } else if (source.ref) {\n await runCommand('git', ['checkout', source.ref], { cwd: checkout, environment });\n } else if (source.path) {\n await runCommand('git', ['checkout'], { cwd: checkout, environment });\n }\n\n const pluginRoot = source.path ? path.resolve(checkout, source.path) : checkout;\n assertContained(checkout, pluginRoot, 'Git plugin path');\n return pluginRoot;\n}\n\nasync function materializeNpmSource(source: NpmPluginSource, workspace: string): Promise<string> {\n const prefix = path.join(workspace, 'npm');\n const packageSpecifier = source.version ? `${source.package}@${source.version}` : source.package;\n const args = [\n 'install',\n '--ignore-scripts',\n '--no-audit',\n '--no-fund',\n '--package-lock=false',\n '--prefix',\n prefix,\n packageSpecifier,\n ];\n if (source.registry) args.push('--registry', source.registry);\n await runCommand('npm', args, {\n environment: {\n ...process.env,\n NPM_CONFIG_AUDIT: 'false',\n NPM_CONFIG_FUND: 'false',\n NPM_CONFIG_IGNORE_SCRIPTS: 'true',\n },\n });\n const pluginRoot = path.resolve(prefix, 'node_modules', ...source.package.split('/'));\n assertContained(path.join(prefix, 'node_modules'), pluginRoot, 'npm plugin package');\n return pluginRoot;\n}\n\nconst DEFAULT_MATERIALIZERS: PluginSourceMaterializers = {\n git: materializeGitSource,\n npm: materializeNpmSource,\n};\n\nasync function pathType(target: string): Promise<'directory' | 'missing' | 'other'> {\n try {\n const stat = await fs.promises.lstat(target);\n return stat.isDirectory() ? 'directory' : 'other';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';\n throw error;\n }\n}\n\nfunction optionalManifestString(manifest: Record<string, unknown>, key: string): string | undefined {\n const value = manifest[key];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction validatePluginManifest(pluginRoot: string, manifestPath: string): InspectedPluginManifest {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {\n throw new Error('manifest must contain a JSON object');\n }\n const record = manifest as Record<string, unknown>;\n const agentPluginSchema =\n manifestPath === path.join(pluginRoot, 'plugin.json') && record.$schema === AGENT_PLUGIN_SCHEMA\n ? AGENT_PLUGIN_SCHEMA\n : undefined;\n const name = optionalManifestString(record, 'name');\n const version = optionalManifestString(record, 'version');\n const description = optionalManifestString(record, 'description');\n return {\n skillDiscovery: agentPluginSchema ? 'direct-children' : 'recursive',\n manifest: {\n path: manifestPath,\n ...(name ? { name } : {}),\n ...(version ? { version } : {}),\n ...(description ? { description } : {}),\n ...(agentPluginSchema ? { agentPluginSchema } : {}),\n },\n };\n } catch (error) {\n throw new Error(\n `Invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\nasync function inspectInstallation(entry: PluginEntry): Promise<InspectedPluginManifest | false> {\n const type = await pathType(entry.directory);\n if (type === 'missing') return false;\n if (type !== 'directory') throw new Error(`Remote plugin cache path is not a directory: ${entry.directory}`);\n if (!entry.source || !isRemotePluginSource(entry.source)) {\n throw new Error(`Remote plugin entry is missing its source: ${entry.name ?? entry.directory}`);\n }\n\n let marker: InstallMarker;\n try {\n marker = JSON.parse(\n await fs.promises.readFile(path.join(entry.directory, INSTALL_MARKER), 'utf8'),\n ) as InstallMarker;\n } catch (error) {\n throw new Error(`Remote plugin cache is not managed by DoomPi: ${entry.directory}`, { cause: error });\n }\n if (marker.version !== INSTALL_MARKER_VERSION || JSON.stringify(marker.source) !== JSON.stringify(entry.source)) {\n throw new Error(`Remote plugin cache metadata does not match ${entry.name ?? entry.directory}: ${entry.directory}`);\n }\n const manifestPath = findPluginManifestPath(entry.directory);\n if (!manifestPath) {\n throw new Error(`Remote plugin cache is missing a supported plugin manifest: ${entry.directory}`);\n }\n return validatePluginManifest(entry.directory, manifestPath);\n}\n\nasync function copyPluginSource(sourceRoot: string, destination: string): Promise<void> {\n if ((await pathType(sourceRoot)) !== 'directory') {\n throw new Error(`Materialized plugin source is not a directory: ${sourceRoot}`);\n }\n await fs.promises.cp(sourceRoot, destination, {\n recursive: true,\n filter: (candidate) => path.basename(candidate) !== '.git',\n });\n}\n\nfunction isRenameRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'EEXIST' || code === 'ENOTEMPTY';\n}\n\nasync function installRemotePlugin(entry: PluginEntry, materializers: PluginSourceMaterializers): Promise<PluginEntry> {\n if (!entry.source || !isRemotePluginSource(entry.source)) return entry;\n const existingManifest = await inspectInstallation(entry);\n if (existingManifest) return { ...entry, ...existingManifest };\n\n const parent = path.dirname(entry.directory);\n await fs.promises.mkdir(parent, { recursive: true, mode: 0o700 });\n if ((await pathType(parent)) !== 'directory') {\n throw new Error(`Remote plugin cache root is not a directory: ${parent}`);\n }\n await fs.promises.chmod(parent, 0o700);\n const workspace = await fs.promises.mkdtemp(path.join(parent, '.plugin-staging-'));\n const installation = path.join(workspace, 'installation');\n try {\n const sourceRoot =\n entry.source.type === 'git'\n ? await materializers.git(entry.source, workspace)\n : await materializers.npm(entry.source, workspace);\n await copyPluginSource(sourceRoot, installation);\n const manifestPath = findPluginManifestPath(installation);\n if (!manifestPath) {\n throw new Error(`Remote plugin ${entry.name ?? entry.directory} does not contain a supported plugin manifest`);\n }\n validatePluginManifest(installation, manifestPath);\n const markerPath = path.join(installation, INSTALL_MARKER);\n if ((await pathType(markerPath)) !== 'missing') {\n throw new Error(`Remote plugin contains reserved cache metadata path: ${INSTALL_MARKER}`);\n }\n const marker: InstallMarker = { version: INSTALL_MARKER_VERSION, source: entry.source };\n await fs.promises.writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n try {\n await fs.promises.rename(installation, entry.directory);\n } catch (error) {\n if (!isRenameRace(error)) throw error;\n await fs.promises.rm(installation, { recursive: true, force: true });\n const racedManifest = await inspectInstallation(entry);\n if (!racedManifest) throw new Error(`Remote plugin installation race left no cache: ${entry.directory}`);\n return { ...entry, ...racedManifest };\n }\n const installedManifest = await inspectInstallation(entry);\n if (!installedManifest) throw new Error(`Remote plugin installation left no cache: ${entry.directory}`);\n return { ...entry, ...installedManifest };\n } catch (error) {\n throw new Error(\n `Failed to install remote plugin ${entry.name ?? entry.directory}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n } finally {\n await fs.promises.rm(workspace, { recursive: true, force: true });\n }\n}\n\n/** Downloads selected remote plugins once into their content-addressed cache directories. */\nexport async function materializePluginEntries(\n entries: readonly PluginEntry[],\n options: PluginMaterializerOptions = {},\n): Promise<PluginEntry[]> {\n const materializers: PluginSourceMaterializers = {\n git: options.materializers?.git ?? DEFAULT_MATERIALIZERS.git,\n npm: options.materializers?.npm ?? DEFAULT_MATERIALIZERS.npm,\n };\n return Promise.all(entries.map((entry) => installRemotePlugin(entry, materializers)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pluginMaterializer.cjs","names":["spawn","path","fs","isRemotePluginSource","findPluginManifestPath"],"sources":["../../src/adapters/pluginMaterializer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n findPluginManifestPath,\n type GitPluginSource,\n isRemotePluginSource,\n type NpmPluginSource,\n type PluginEntry,\n type PluginManifestMetadata,\n type PluginSkillDiscovery,\n} from '@agimon-ai/doompi-config/domains';\n\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst INSTALL_MARKER = '.doompi-plugin.json';\nconst INSTALL_MARKER_VERSION = 1;\nconst OUTPUT_LIMIT = 64 * 1024;\n\ninterface CommandOptions {\n cwd?: string;\n environment?: NodeJS.ProcessEnv;\n}\n\ninterface InstallMarker {\n version: number;\n source: GitPluginSource | NpmPluginSource;\n}\n\ninterface InspectedPluginManifest {\n skillDiscovery: PluginSkillDiscovery;\n manifest: PluginManifestMetadata;\n}\n\nexport interface PluginSourceMaterializers {\n git: (source: GitPluginSource, workspace: string) => Promise<string>;\n npm: (source: NpmPluginSource, workspace: string) => Promise<string>;\n}\n\nexport interface PluginMaterializerOptions {\n materializers?: Partial<PluginSourceMaterializers>;\n}\n\nfunction appendOutput(current: string, chunk: Buffer): string {\n const next = current + chunk.toString('utf8');\n return next.length <= OUTPUT_LIMIT ? next : next.slice(-OUTPUT_LIMIT);\n}\n\nfunction runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.environment ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout = appendOutput(stdout, chunk);\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr = appendOutput(stderr, chunk);\n });\n child.once('error', (error) => {\n reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error }));\n });\n child.once('close', (code, signal) => {\n if (code === 0) {\n resolve(stdout.trim());\n return;\n }\n const outcome = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const details = stderr.trim() || stdout.trim();\n reject(new Error(`${command} ${args.join(' ')} failed with ${outcome}${details ? `\\n${details}` : ''}`));\n });\n });\n}\n\nfunction assertContained(root: string, candidate: string, label: string): void {\n const relative = path.relative(root, candidate);\n if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;\n throw new Error(`${label} resolves outside ${root}`);\n}\n\nasync function materializeGitSource(source: GitPluginSource, workspace: string): Promise<string> {\n const checkout = path.join(workspace, 'checkout');\n const pluginRoot = source.path ? path.resolve(checkout, source.path) : checkout;\n if (source.path) assertContained(checkout, pluginRoot, 'Git plugin path');\n const cloneArgs = ['clone', '--filter=blob:none'];\n if (source.path) cloneArgs.push('--sparse', '--no-checkout');\n cloneArgs.push(source.url, checkout);\n const environment = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n await runCommand('git', cloneArgs, { environment });\n\n if (source.path) {\n await runCommand('git', ['sparse-checkout', 'set', '--no-cone', '--', source.path], {\n cwd: checkout,\n environment,\n });\n }\n if (source.sha) {\n await runCommand('git', ['checkout', source.sha], { cwd: checkout, environment });\n const checkedOutSha = await runCommand('git', ['rev-parse', 'HEAD'], { cwd: checkout, environment });\n if (checkedOutSha.toLowerCase() !== source.sha.toLowerCase()) {\n throw new Error(`Checked out Git SHA ${checkedOutSha} does not match requested SHA ${source.sha}`);\n }\n } else if (source.ref) {\n await runCommand('git', ['checkout', source.ref], { cwd: checkout, environment });\n } else if (source.path) {\n await runCommand('git', ['checkout'], { cwd: checkout, environment });\n }\n\n return pluginRoot;\n}\n\nasync function materializeNpmSource(source: NpmPluginSource, workspace: string): Promise<string> {\n const prefix = path.join(workspace, 'npm');\n const packageSpecifier = source.version ? `${source.package}@${source.version}` : source.package;\n const args = [\n 'install',\n '--ignore-scripts',\n '--no-audit',\n '--no-fund',\n '--package-lock=false',\n '--prefix',\n prefix,\n packageSpecifier,\n ];\n if (source.registry) args.push('--registry', source.registry);\n await runCommand('npm', args, {\n environment: {\n ...process.env,\n NPM_CONFIG_AUDIT: 'false',\n NPM_CONFIG_FUND: 'false',\n NPM_CONFIG_IGNORE_SCRIPTS: 'true',\n },\n });\n const pluginRoot = path.resolve(prefix, 'node_modules', ...source.package.split('/'));\n assertContained(path.join(prefix, 'node_modules'), pluginRoot, 'npm plugin package');\n return pluginRoot;\n}\n\nconst DEFAULT_MATERIALIZERS: PluginSourceMaterializers = {\n git: materializeGitSource,\n npm: materializeNpmSource,\n};\n\nasync function pathType(target: string): Promise<'directory' | 'missing' | 'other'> {\n try {\n const stat = await fs.promises.lstat(target);\n return stat.isDirectory() ? 'directory' : 'other';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';\n throw error;\n }\n}\n\nfunction optionalManifestString(manifest: Record<string, unknown>, key: string): string | undefined {\n const value = manifest[key];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction validatePluginManifest(pluginRoot: string, manifestPath: string): InspectedPluginManifest {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {\n throw new Error('manifest must contain a JSON object');\n }\n const record = manifest as Record<string, unknown>;\n const agentPluginSchema =\n manifestPath === path.join(pluginRoot, 'plugin.json') && record.$schema === AGENT_PLUGIN_SCHEMA\n ? AGENT_PLUGIN_SCHEMA\n : undefined;\n const name = optionalManifestString(record, 'name');\n const version = optionalManifestString(record, 'version');\n const description = optionalManifestString(record, 'description');\n return {\n skillDiscovery: agentPluginSchema ? 'direct-children' : 'recursive',\n manifest: {\n path: manifestPath,\n ...(name ? { name } : {}),\n ...(version ? { version } : {}),\n ...(description ? { description } : {}),\n ...(agentPluginSchema ? { agentPluginSchema } : {}),\n },\n };\n } catch (error) {\n throw new Error(\n `Invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\nasync function inspectInstallation(entry: PluginEntry): Promise<InspectedPluginManifest | false> {\n const type = await pathType(entry.directory);\n if (type === 'missing') return false;\n if (type !== 'directory') throw new Error(`Remote plugin cache path is not a directory: ${entry.directory}`);\n if (!entry.source || !isRemotePluginSource(entry.source)) {\n throw new Error(`Remote plugin entry is missing its source: ${entry.name ?? entry.directory}`);\n }\n\n let marker: InstallMarker;\n try {\n marker = JSON.parse(\n await fs.promises.readFile(path.join(entry.directory, INSTALL_MARKER), 'utf8'),\n ) as InstallMarker;\n } catch (error) {\n throw new Error(`Remote plugin cache is not managed by DoomPi: ${entry.directory}`, { cause: error });\n }\n if (marker.version !== INSTALL_MARKER_VERSION || JSON.stringify(marker.source) !== JSON.stringify(entry.source)) {\n throw new Error(`Remote plugin cache metadata does not match ${entry.name ?? entry.directory}: ${entry.directory}`);\n }\n const manifestPath = findPluginManifestPath(entry.directory);\n if (!manifestPath) {\n throw new Error(`Remote plugin cache is missing a supported plugin manifest: ${entry.directory}`);\n }\n return validatePluginManifest(entry.directory, manifestPath);\n}\n\nasync function copyPluginSource(sourceRoot: string, destination: string): Promise<void> {\n if ((await pathType(sourceRoot)) !== 'directory') {\n throw new Error(`Materialized plugin source is not a directory: ${sourceRoot}`);\n }\n await fs.promises.cp(sourceRoot, destination, {\n recursive: true,\n filter: (candidate) => path.basename(candidate) !== '.git',\n });\n}\n\nfunction isRenameRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'EEXIST' || code === 'ENOTEMPTY';\n}\n\nasync function installRemotePlugin(entry: PluginEntry, materializers: PluginSourceMaterializers): Promise<PluginEntry> {\n if (!entry.source || !isRemotePluginSource(entry.source)) return entry;\n const existingManifest = await inspectInstallation(entry);\n if (existingManifest) return { ...entry, ...existingManifest };\n\n const parent = path.dirname(entry.directory);\n await fs.promises.mkdir(parent, { recursive: true, mode: 0o700 });\n if ((await pathType(parent)) !== 'directory') {\n throw new Error(`Remote plugin cache root is not a directory: ${parent}`);\n }\n await fs.promises.chmod(parent, 0o700);\n const workspace = await fs.promises.mkdtemp(path.join(parent, '.plugin-staging-'));\n const installation = path.join(workspace, 'installation');\n try {\n const sourceRoot =\n entry.source.type === 'git'\n ? await materializers.git(entry.source, workspace)\n : await materializers.npm(entry.source, workspace);\n await copyPluginSource(sourceRoot, installation);\n const manifestPath = findPluginManifestPath(installation);\n if (!manifestPath) {\n throw new Error(`Remote plugin ${entry.name ?? entry.directory} does not contain a supported plugin manifest`);\n }\n validatePluginManifest(installation, manifestPath);\n const markerPath = path.join(installation, INSTALL_MARKER);\n if ((await pathType(markerPath)) !== 'missing') {\n throw new Error(`Remote plugin contains reserved cache metadata path: ${INSTALL_MARKER}`);\n }\n const marker: InstallMarker = { version: INSTALL_MARKER_VERSION, source: entry.source };\n await fs.promises.writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n try {\n await fs.promises.rename(installation, entry.directory);\n } catch (error) {\n if (!isRenameRace(error)) throw error;\n await fs.promises.rm(installation, { recursive: true, force: true });\n const racedManifest = await inspectInstallation(entry);\n if (!racedManifest) throw new Error(`Remote plugin installation race left no cache: ${entry.directory}`);\n return { ...entry, ...racedManifest };\n }\n const installedManifest = await inspectInstallation(entry);\n if (!installedManifest) throw new Error(`Remote plugin installation left no cache: ${entry.directory}`);\n return { ...entry, ...installedManifest };\n } catch (error) {\n throw new Error(\n `Failed to install remote plugin ${entry.name ?? entry.directory}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n } finally {\n await fs.promises.rm(workspace, { recursive: true, force: true });\n }\n}\n\n/** Downloads selected remote plugins once into their content-addressed cache directories. */\nexport async function materializePluginEntries(\n entries: readonly PluginEntry[],\n options: PluginMaterializerOptions = {},\n): Promise<PluginEntry[]> {\n const materializers: PluginSourceMaterializers = {\n git: options.materializers?.git ?? DEFAULT_MATERIALIZERS.git,\n npm: options.materializers?.npm ?? DEFAULT_MATERIALIZERS.npm,\n };\n return Promise.all(entries.map((entry) => installRemotePlugin(entry, materializers)));\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"node:fs";import t from"node:path";import{findPluginManifestPath as n,isRemotePluginSource as r}from"@agimon-ai/doompi-config/domains";import{spawn as i}from"node:child_process";const a=`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`,o=`.doompi-plugin.json`;function s(e,t){let n=e+t.toString(`utf8`);return n.length<=65536?n:n.slice(-65536)}function c(e,t,n={}){return new Promise((r,a)=>{let o=i(e,t,{cwd:n.cwd,env:n.environment??process.env,stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;o.stdout.on(`data`,e=>{c=s(c,e)}),o.stderr.on(`data`,e=>{l=s(l,e)}),o.once(`error`,t=>{a(Error(`Failed to run ${e}: ${t.message}`,{cause:t}))}),o.once(`close`,(n,i)=>{if(n===0){r(c.trim());return}let o=i?`signal ${i}`:`exit code ${n??`unknown`}`,s=l.trim()||c.trim();a(Error(`${e} ${t.join(` `)} failed with ${o}${s?`\n${s}`:``}`))})})}function l(e,n,r){let i=t.relative(e,n);if(!(i===``||!i.startsWith(`..`)&&!t.isAbsolute(i)))throw Error(`${r} resolves outside ${e}`)}async function u(e,n){let r=t.join(n,`checkout`),i=[`clone`,`--filter=blob:none`];e.path&&i.push(`--sparse`,`--no-checkout`),i.push(e.url,r);let a={...process.env,GIT_TERMINAL_PROMPT:`0`};if(await c(`git`,i,{environment:a}),e.path&&await c(`git`,[`sparse-checkout`,`set`,`--no-cone`,`--`,e.path],{cwd:r,environment:a}),e.sha){await c(`git`,[`checkout`,e.sha],{cwd:r,environment:a});let t=await c(`git`,[`rev-parse`,`HEAD`],{cwd:r,environment:a});if(t.toLowerCase()!==e.sha.toLowerCase())throw Error(`Checked out Git SHA ${t} does not match requested SHA ${e.sha}`)}else e.ref?await c(`git`,[`checkout`,e.ref],{cwd:r,environment:a}):e.path&&await c(`git`,[`checkout`],{cwd:r,environment:a});let o=e.path?t.resolve(r,e.path):r;return l(r,o,`Git plugin path`),o}async function d(e,n){let r=t.join(n,`npm`),i=[`install`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--package-lock=false`,`--prefix`,r,e.version?`${e.package}@${e.version}`:e.package];e.registry&&i.push(`--registry`,e.registry),await c(`npm`,i,{environment:{...process.env,NPM_CONFIG_AUDIT:`false`,NPM_CONFIG_FUND:`false`,NPM_CONFIG_IGNORE_SCRIPTS:`true`}});let a=t.resolve(r,`node_modules`,...e.package.split(`/`));return l(t.join(r,`node_modules`),a,`npm plugin package`),a}const f={git:u,npm:d};async function p(t){try{return(await e.promises.lstat(t)).isDirectory()?`directory`:`other`}catch(e){if(e.code===`ENOENT`)return`missing`;throw e}}function m(e,t){let n=e[t];return typeof n==`string`&&n.trim()?n.trim():void 0}function h(n,r){try{let i=JSON.parse(e.readFileSync(r,`utf8`));if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`manifest must contain a JSON object`);let o=i,s=r===t.join(n,`plugin.json`)&&o.$schema===a?a:void 0,c=m(o,`name`),l=m(o,`version`),u=m(o,`description`);return{skillDiscovery:s?`direct-children`:`recursive`,manifest:{path:r,...c?{name:c}:{},...l?{version:l}:{},...u?{description:u}:{},...s?{agentPluginSchema:s}:{}}}}catch(e){throw Error(`Invalid plugin manifest ${r}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}async function g(i){let a=await p(i.directory);if(a===`missing`)return!1;if(a!==`directory`)throw Error(`Remote plugin cache path is not a directory: ${i.directory}`);if(!i.source||!r(i.source))throw Error(`Remote plugin entry is missing its source: ${i.name??i.directory}`);let s;try{s=JSON.parse(await e.promises.readFile(t.join(i.directory,o),`utf8`))}catch(e){throw Error(`Remote plugin cache is not managed by DoomPi: ${i.directory}`,{cause:e})}if(s.version!==1||JSON.stringify(s.source)!==JSON.stringify(i.source))throw Error(`Remote plugin cache metadata does not match ${i.name??i.directory}: ${i.directory}`);let c=n(i.directory);if(!c)throw Error(`Remote plugin cache is missing a supported plugin manifest: ${i.directory}`);return h(i.directory,c)}async function _(n,r){if(await p(n)!==`directory`)throw Error(`Materialized plugin source is not a directory: ${n}`);await e.promises.cp(n,r,{recursive:!0,filter:e=>t.basename(e)!==`.git`})}function v(e){let t=e.code;return t===`EEXIST`||t===`ENOTEMPTY`}async function y(i,a){if(!i.source||!r(i.source))return i;let s=await g(i);if(s)return{...i,...s};let c=t.dirname(i.directory);if(await e.promises.mkdir(c,{recursive:!0,mode:448}),await p(c)!==`directory`)throw Error(`Remote plugin cache root is not a directory: ${c}`);await e.promises.chmod(c,448);let l=await e.promises.mkdtemp(t.join(c,`.plugin-staging-`)),u=t.join(l,`installation`);try{await _(i.source.type===`git`?await a.git(i.source,l):await a.npm(i.source,l),u);let r=n(u);if(!r)throw Error(`Remote plugin ${i.name??i.directory} does not contain a supported plugin manifest`);h(u,r);let s=t.join(u,o);if(await p(s)!==`missing`)throw Error(`Remote plugin contains reserved cache metadata path: ${o}`);let c={version:1,source:i.source};await e.promises.writeFile(s,`${JSON.stringify(c,null,2)}\n`,{flag:`wx`,mode:384});try{await e.promises.rename(u,i.directory)}catch(t){if(!v(t))throw t;await e.promises.rm(u,{recursive:!0,force:!0});let n=await g(i);if(!n)throw Error(`Remote plugin installation race left no cache: ${i.directory}`);return{...i,...n}}let d=await g(i);if(!d)throw Error(`Remote plugin installation left no cache: ${i.directory}`);return{...i,...d}}catch(e){throw Error(`Failed to install remote plugin ${i.name??i.directory}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{await e.promises.rm(l,{recursive:!0,force:!0})}}async function b(e,t={}){let n={git:t.materializers?.git??f.git,npm:t.materializers?.npm??f.npm};return Promise.all(e.map(e=>y(e,n)))}export{b as materializePluginEntries};
1
+ import e from"node:fs";import t from"node:path";import{findPluginManifestPath as n,isRemotePluginSource as r}from"@agimon-ai/doompi-config/domains";import{spawn as i}from"node:child_process";const a=`https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`,o=`.doompi-plugin.json`;function s(e,t){let n=e+t.toString(`utf8`);return n.length<=65536?n:n.slice(-65536)}function c(e,t,n={}){return new Promise((r,a)=>{let o=i(e,t,{cwd:n.cwd,env:n.environment??process.env,stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;o.stdout.on(`data`,e=>{c=s(c,e)}),o.stderr.on(`data`,e=>{l=s(l,e)}),o.once(`error`,t=>{a(Error(`Failed to run ${e}: ${t.message}`,{cause:t}))}),o.once(`close`,(n,i)=>{if(n===0){r(c.trim());return}let o=i?`signal ${i}`:`exit code ${n??`unknown`}`,s=l.trim()||c.trim();a(Error(`${e} ${t.join(` `)} failed with ${o}${s?`\n${s}`:``}`))})})}function l(e,n,r){let i=t.relative(e,n);if(!(i===``||!i.startsWith(`..`)&&!t.isAbsolute(i)))throw Error(`${r} resolves outside ${e}`)}async function u(e,n){let r=t.join(n,`checkout`),i=e.path?t.resolve(r,e.path):r;e.path&&l(r,i,`Git plugin path`);let a=[`clone`,`--filter=blob:none`];e.path&&a.push(`--sparse`,`--no-checkout`),a.push(e.url,r);let o={...process.env,GIT_TERMINAL_PROMPT:`0`};if(await c(`git`,a,{environment:o}),e.path&&await c(`git`,[`sparse-checkout`,`set`,`--no-cone`,`--`,e.path],{cwd:r,environment:o}),e.sha){await c(`git`,[`checkout`,e.sha],{cwd:r,environment:o});let t=await c(`git`,[`rev-parse`,`HEAD`],{cwd:r,environment:o});if(t.toLowerCase()!==e.sha.toLowerCase())throw Error(`Checked out Git SHA ${t} does not match requested SHA ${e.sha}`)}else e.ref?await c(`git`,[`checkout`,e.ref],{cwd:r,environment:o}):e.path&&await c(`git`,[`checkout`],{cwd:r,environment:o});return i}async function d(e,n){let r=t.join(n,`npm`),i=[`install`,`--ignore-scripts`,`--no-audit`,`--no-fund`,`--package-lock=false`,`--prefix`,r,e.version?`${e.package}@${e.version}`:e.package];e.registry&&i.push(`--registry`,e.registry),await c(`npm`,i,{environment:{...process.env,NPM_CONFIG_AUDIT:`false`,NPM_CONFIG_FUND:`false`,NPM_CONFIG_IGNORE_SCRIPTS:`true`}});let a=t.resolve(r,`node_modules`,...e.package.split(`/`));return l(t.join(r,`node_modules`),a,`npm plugin package`),a}const f={git:u,npm:d};async function p(t){try{return(await e.promises.lstat(t)).isDirectory()?`directory`:`other`}catch(e){if(e.code===`ENOENT`)return`missing`;throw e}}function m(e,t){let n=e[t];return typeof n==`string`&&n.trim()?n.trim():void 0}function h(n,r){try{let i=JSON.parse(e.readFileSync(r,`utf8`));if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`manifest must contain a JSON object`);let o=i,s=r===t.join(n,`plugin.json`)&&o.$schema===a?a:void 0,c=m(o,`name`),l=m(o,`version`),u=m(o,`description`);return{skillDiscovery:s?`direct-children`:`recursive`,manifest:{path:r,...c?{name:c}:{},...l?{version:l}:{},...u?{description:u}:{},...s?{agentPluginSchema:s}:{}}}}catch(e){throw Error(`Invalid plugin manifest ${r}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}async function g(i){let a=await p(i.directory);if(a===`missing`)return!1;if(a!==`directory`)throw Error(`Remote plugin cache path is not a directory: ${i.directory}`);if(!i.source||!r(i.source))throw Error(`Remote plugin entry is missing its source: ${i.name??i.directory}`);let s;try{s=JSON.parse(await e.promises.readFile(t.join(i.directory,o),`utf8`))}catch(e){throw Error(`Remote plugin cache is not managed by DoomPi: ${i.directory}`,{cause:e})}if(s.version!==1||JSON.stringify(s.source)!==JSON.stringify(i.source))throw Error(`Remote plugin cache metadata does not match ${i.name??i.directory}: ${i.directory}`);let c=n(i.directory);if(!c)throw Error(`Remote plugin cache is missing a supported plugin manifest: ${i.directory}`);return h(i.directory,c)}async function _(n,r){if(await p(n)!==`directory`)throw Error(`Materialized plugin source is not a directory: ${n}`);await e.promises.cp(n,r,{recursive:!0,filter:e=>t.basename(e)!==`.git`})}function v(e){let t=e.code;return t===`EEXIST`||t===`ENOTEMPTY`}async function y(i,a){if(!i.source||!r(i.source))return i;let s=await g(i);if(s)return{...i,...s};let c=t.dirname(i.directory);if(await e.promises.mkdir(c,{recursive:!0,mode:448}),await p(c)!==`directory`)throw Error(`Remote plugin cache root is not a directory: ${c}`);await e.promises.chmod(c,448);let l=await e.promises.mkdtemp(t.join(c,`.plugin-staging-`)),u=t.join(l,`installation`);try{await _(i.source.type===`git`?await a.git(i.source,l):await a.npm(i.source,l),u);let r=n(u);if(!r)throw Error(`Remote plugin ${i.name??i.directory} does not contain a supported plugin manifest`);h(u,r);let s=t.join(u,o);if(await p(s)!==`missing`)throw Error(`Remote plugin contains reserved cache metadata path: ${o}`);let c={version:1,source:i.source};await e.promises.writeFile(s,`${JSON.stringify(c,null,2)}\n`,{flag:`wx`,mode:384});try{await e.promises.rename(u,i.directory)}catch(t){if(!v(t))throw t;await e.promises.rm(u,{recursive:!0,force:!0});let n=await g(i);if(!n)throw Error(`Remote plugin installation race left no cache: ${i.directory}`);return{...i,...n}}let d=await g(i);if(!d)throw Error(`Remote plugin installation left no cache: ${i.directory}`);return{...i,...d}}catch(e){throw Error(`Failed to install remote plugin ${i.name??i.directory}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}finally{await e.promises.rm(l,{recursive:!0,force:!0})}}async function b(e,t={}){let n={git:t.materializers?.git??f.git,npm:t.materializers?.npm??f.npm};return Promise.all(e.map(e=>y(e,n)))}export{b as materializePluginEntries};
2
2
  //# sourceMappingURL=pluginMaterializer.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pluginMaterializer.mjs","names":[],"sources":["../../src/adapters/pluginMaterializer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n findPluginManifestPath,\n type GitPluginSource,\n isRemotePluginSource,\n type NpmPluginSource,\n type PluginEntry,\n type PluginManifestMetadata,\n type PluginSkillDiscovery,\n} from '@agimon-ai/doompi-config/domains';\n\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst INSTALL_MARKER = '.doompi-plugin.json';\nconst INSTALL_MARKER_VERSION = 1;\nconst OUTPUT_LIMIT = 64 * 1024;\n\ninterface CommandOptions {\n cwd?: string;\n environment?: NodeJS.ProcessEnv;\n}\n\ninterface InstallMarker {\n version: number;\n source: GitPluginSource | NpmPluginSource;\n}\n\ninterface InspectedPluginManifest {\n skillDiscovery: PluginSkillDiscovery;\n manifest: PluginManifestMetadata;\n}\n\nexport interface PluginSourceMaterializers {\n git: (source: GitPluginSource, workspace: string) => Promise<string>;\n npm: (source: NpmPluginSource, workspace: string) => Promise<string>;\n}\n\nexport interface PluginMaterializerOptions {\n materializers?: Partial<PluginSourceMaterializers>;\n}\n\nfunction appendOutput(current: string, chunk: Buffer): string {\n const next = current + chunk.toString('utf8');\n return next.length <= OUTPUT_LIMIT ? next : next.slice(-OUTPUT_LIMIT);\n}\n\nfunction runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.environment ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout = appendOutput(stdout, chunk);\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr = appendOutput(stderr, chunk);\n });\n child.once('error', (error) => {\n reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error }));\n });\n child.once('close', (code, signal) => {\n if (code === 0) {\n resolve(stdout.trim());\n return;\n }\n const outcome = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const details = stderr.trim() || stdout.trim();\n reject(new Error(`${command} ${args.join(' ')} failed with ${outcome}${details ? `\\n${details}` : ''}`));\n });\n });\n}\n\nfunction assertContained(root: string, candidate: string, label: string): void {\n const relative = path.relative(root, candidate);\n if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;\n throw new Error(`${label} resolves outside ${root}`);\n}\n\nasync function materializeGitSource(source: GitPluginSource, workspace: string): Promise<string> {\n const checkout = path.join(workspace, 'checkout');\n const cloneArgs = ['clone', '--filter=blob:none'];\n if (source.path) cloneArgs.push('--sparse', '--no-checkout');\n cloneArgs.push(source.url, checkout);\n const environment = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n await runCommand('git', cloneArgs, { environment });\n\n if (source.path) {\n await runCommand('git', ['sparse-checkout', 'set', '--no-cone', '--', source.path], {\n cwd: checkout,\n environment,\n });\n }\n if (source.sha) {\n await runCommand('git', ['checkout', source.sha], { cwd: checkout, environment });\n const checkedOutSha = await runCommand('git', ['rev-parse', 'HEAD'], { cwd: checkout, environment });\n if (checkedOutSha.toLowerCase() !== source.sha.toLowerCase()) {\n throw new Error(`Checked out Git SHA ${checkedOutSha} does not match requested SHA ${source.sha}`);\n }\n } else if (source.ref) {\n await runCommand('git', ['checkout', source.ref], { cwd: checkout, environment });\n } else if (source.path) {\n await runCommand('git', ['checkout'], { cwd: checkout, environment });\n }\n\n const pluginRoot = source.path ? path.resolve(checkout, source.path) : checkout;\n assertContained(checkout, pluginRoot, 'Git plugin path');\n return pluginRoot;\n}\n\nasync function materializeNpmSource(source: NpmPluginSource, workspace: string): Promise<string> {\n const prefix = path.join(workspace, 'npm');\n const packageSpecifier = source.version ? `${source.package}@${source.version}` : source.package;\n const args = [\n 'install',\n '--ignore-scripts',\n '--no-audit',\n '--no-fund',\n '--package-lock=false',\n '--prefix',\n prefix,\n packageSpecifier,\n ];\n if (source.registry) args.push('--registry', source.registry);\n await runCommand('npm', args, {\n environment: {\n ...process.env,\n NPM_CONFIG_AUDIT: 'false',\n NPM_CONFIG_FUND: 'false',\n NPM_CONFIG_IGNORE_SCRIPTS: 'true',\n },\n });\n const pluginRoot = path.resolve(prefix, 'node_modules', ...source.package.split('/'));\n assertContained(path.join(prefix, 'node_modules'), pluginRoot, 'npm plugin package');\n return pluginRoot;\n}\n\nconst DEFAULT_MATERIALIZERS: PluginSourceMaterializers = {\n git: materializeGitSource,\n npm: materializeNpmSource,\n};\n\nasync function pathType(target: string): Promise<'directory' | 'missing' | 'other'> {\n try {\n const stat = await fs.promises.lstat(target);\n return stat.isDirectory() ? 'directory' : 'other';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';\n throw error;\n }\n}\n\nfunction optionalManifestString(manifest: Record<string, unknown>, key: string): string | undefined {\n const value = manifest[key];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction validatePluginManifest(pluginRoot: string, manifestPath: string): InspectedPluginManifest {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {\n throw new Error('manifest must contain a JSON object');\n }\n const record = manifest as Record<string, unknown>;\n const agentPluginSchema =\n manifestPath === path.join(pluginRoot, 'plugin.json') && record.$schema === AGENT_PLUGIN_SCHEMA\n ? AGENT_PLUGIN_SCHEMA\n : undefined;\n const name = optionalManifestString(record, 'name');\n const version = optionalManifestString(record, 'version');\n const description = optionalManifestString(record, 'description');\n return {\n skillDiscovery: agentPluginSchema ? 'direct-children' : 'recursive',\n manifest: {\n path: manifestPath,\n ...(name ? { name } : {}),\n ...(version ? { version } : {}),\n ...(description ? { description } : {}),\n ...(agentPluginSchema ? { agentPluginSchema } : {}),\n },\n };\n } catch (error) {\n throw new Error(\n `Invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\nasync function inspectInstallation(entry: PluginEntry): Promise<InspectedPluginManifest | false> {\n const type = await pathType(entry.directory);\n if (type === 'missing') return false;\n if (type !== 'directory') throw new Error(`Remote plugin cache path is not a directory: ${entry.directory}`);\n if (!entry.source || !isRemotePluginSource(entry.source)) {\n throw new Error(`Remote plugin entry is missing its source: ${entry.name ?? entry.directory}`);\n }\n\n let marker: InstallMarker;\n try {\n marker = JSON.parse(\n await fs.promises.readFile(path.join(entry.directory, INSTALL_MARKER), 'utf8'),\n ) as InstallMarker;\n } catch (error) {\n throw new Error(`Remote plugin cache is not managed by DoomPi: ${entry.directory}`, { cause: error });\n }\n if (marker.version !== INSTALL_MARKER_VERSION || JSON.stringify(marker.source) !== JSON.stringify(entry.source)) {\n throw new Error(`Remote plugin cache metadata does not match ${entry.name ?? entry.directory}: ${entry.directory}`);\n }\n const manifestPath = findPluginManifestPath(entry.directory);\n if (!manifestPath) {\n throw new Error(`Remote plugin cache is missing a supported plugin manifest: ${entry.directory}`);\n }\n return validatePluginManifest(entry.directory, manifestPath);\n}\n\nasync function copyPluginSource(sourceRoot: string, destination: string): Promise<void> {\n if ((await pathType(sourceRoot)) !== 'directory') {\n throw new Error(`Materialized plugin source is not a directory: ${sourceRoot}`);\n }\n await fs.promises.cp(sourceRoot, destination, {\n recursive: true,\n filter: (candidate) => path.basename(candidate) !== '.git',\n });\n}\n\nfunction isRenameRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'EEXIST' || code === 'ENOTEMPTY';\n}\n\nasync function installRemotePlugin(entry: PluginEntry, materializers: PluginSourceMaterializers): Promise<PluginEntry> {\n if (!entry.source || !isRemotePluginSource(entry.source)) return entry;\n const existingManifest = await inspectInstallation(entry);\n if (existingManifest) return { ...entry, ...existingManifest };\n\n const parent = path.dirname(entry.directory);\n await fs.promises.mkdir(parent, { recursive: true, mode: 0o700 });\n if ((await pathType(parent)) !== 'directory') {\n throw new Error(`Remote plugin cache root is not a directory: ${parent}`);\n }\n await fs.promises.chmod(parent, 0o700);\n const workspace = await fs.promises.mkdtemp(path.join(parent, '.plugin-staging-'));\n const installation = path.join(workspace, 'installation');\n try {\n const sourceRoot =\n entry.source.type === 'git'\n ? await materializers.git(entry.source, workspace)\n : await materializers.npm(entry.source, workspace);\n await copyPluginSource(sourceRoot, installation);\n const manifestPath = findPluginManifestPath(installation);\n if (!manifestPath) {\n throw new Error(`Remote plugin ${entry.name ?? entry.directory} does not contain a supported plugin manifest`);\n }\n validatePluginManifest(installation, manifestPath);\n const markerPath = path.join(installation, INSTALL_MARKER);\n if ((await pathType(markerPath)) !== 'missing') {\n throw new Error(`Remote plugin contains reserved cache metadata path: ${INSTALL_MARKER}`);\n }\n const marker: InstallMarker = { version: INSTALL_MARKER_VERSION, source: entry.source };\n await fs.promises.writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n try {\n await fs.promises.rename(installation, entry.directory);\n } catch (error) {\n if (!isRenameRace(error)) throw error;\n await fs.promises.rm(installation, { recursive: true, force: true });\n const racedManifest = await inspectInstallation(entry);\n if (!racedManifest) throw new Error(`Remote plugin installation race left no cache: ${entry.directory}`);\n return { ...entry, ...racedManifest };\n }\n const installedManifest = await inspectInstallation(entry);\n if (!installedManifest) throw new Error(`Remote plugin installation left no cache: ${entry.directory}`);\n return { ...entry, ...installedManifest };\n } catch (error) {\n throw new Error(\n `Failed to install remote plugin ${entry.name ?? entry.directory}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n } finally {\n await fs.promises.rm(workspace, { recursive: true, force: true });\n }\n}\n\n/** Downloads selected remote plugins once into their content-addressed cache directories. */\nexport async function materializePluginEntries(\n entries: readonly PluginEntry[],\n options: PluginMaterializerOptions = {},\n): Promise<PluginEntry[]> {\n const materializers: PluginSourceMaterializers = {\n git: options.materializers?.git ?? DEFAULT_MATERIALIZERS.git,\n npm: options.materializers?.npm ?? DEFAULT_MATERIALIZERS.npm,\n };\n return Promise.all(entries.map((entry) => installRemotePlugin(entry, materializers)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pluginMaterializer.mjs","names":[],"sources":["../../src/adapters/pluginMaterializer.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n findPluginManifestPath,\n type GitPluginSource,\n isRemotePluginSource,\n type NpmPluginSource,\n type PluginEntry,\n type PluginManifestMetadata,\n type PluginSkillDiscovery,\n} from '@agimon-ai/doompi-config/domains';\n\nconst AGENT_PLUGIN_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';\nconst INSTALL_MARKER = '.doompi-plugin.json';\nconst INSTALL_MARKER_VERSION = 1;\nconst OUTPUT_LIMIT = 64 * 1024;\n\ninterface CommandOptions {\n cwd?: string;\n environment?: NodeJS.ProcessEnv;\n}\n\ninterface InstallMarker {\n version: number;\n source: GitPluginSource | NpmPluginSource;\n}\n\ninterface InspectedPluginManifest {\n skillDiscovery: PluginSkillDiscovery;\n manifest: PluginManifestMetadata;\n}\n\nexport interface PluginSourceMaterializers {\n git: (source: GitPluginSource, workspace: string) => Promise<string>;\n npm: (source: NpmPluginSource, workspace: string) => Promise<string>;\n}\n\nexport interface PluginMaterializerOptions {\n materializers?: Partial<PluginSourceMaterializers>;\n}\n\nfunction appendOutput(current: string, chunk: Buffer): string {\n const next = current + chunk.toString('utf8');\n return next.length <= OUTPUT_LIMIT ? next : next.slice(-OUTPUT_LIMIT);\n}\n\nfunction runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n env: options.environment ?? process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (chunk: Buffer) => {\n stdout = appendOutput(stdout, chunk);\n });\n child.stderr.on('data', (chunk: Buffer) => {\n stderr = appendOutput(stderr, chunk);\n });\n child.once('error', (error) => {\n reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error }));\n });\n child.once('close', (code, signal) => {\n if (code === 0) {\n resolve(stdout.trim());\n return;\n }\n const outcome = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const details = stderr.trim() || stdout.trim();\n reject(new Error(`${command} ${args.join(' ')} failed with ${outcome}${details ? `\\n${details}` : ''}`));\n });\n });\n}\n\nfunction assertContained(root: string, candidate: string, label: string): void {\n const relative = path.relative(root, candidate);\n if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;\n throw new Error(`${label} resolves outside ${root}`);\n}\n\nasync function materializeGitSource(source: GitPluginSource, workspace: string): Promise<string> {\n const checkout = path.join(workspace, 'checkout');\n const pluginRoot = source.path ? path.resolve(checkout, source.path) : checkout;\n if (source.path) assertContained(checkout, pluginRoot, 'Git plugin path');\n const cloneArgs = ['clone', '--filter=blob:none'];\n if (source.path) cloneArgs.push('--sparse', '--no-checkout');\n cloneArgs.push(source.url, checkout);\n const environment = { ...process.env, GIT_TERMINAL_PROMPT: '0' };\n await runCommand('git', cloneArgs, { environment });\n\n if (source.path) {\n await runCommand('git', ['sparse-checkout', 'set', '--no-cone', '--', source.path], {\n cwd: checkout,\n environment,\n });\n }\n if (source.sha) {\n await runCommand('git', ['checkout', source.sha], { cwd: checkout, environment });\n const checkedOutSha = await runCommand('git', ['rev-parse', 'HEAD'], { cwd: checkout, environment });\n if (checkedOutSha.toLowerCase() !== source.sha.toLowerCase()) {\n throw new Error(`Checked out Git SHA ${checkedOutSha} does not match requested SHA ${source.sha}`);\n }\n } else if (source.ref) {\n await runCommand('git', ['checkout', source.ref], { cwd: checkout, environment });\n } else if (source.path) {\n await runCommand('git', ['checkout'], { cwd: checkout, environment });\n }\n\n return pluginRoot;\n}\n\nasync function materializeNpmSource(source: NpmPluginSource, workspace: string): Promise<string> {\n const prefix = path.join(workspace, 'npm');\n const packageSpecifier = source.version ? `${source.package}@${source.version}` : source.package;\n const args = [\n 'install',\n '--ignore-scripts',\n '--no-audit',\n '--no-fund',\n '--package-lock=false',\n '--prefix',\n prefix,\n packageSpecifier,\n ];\n if (source.registry) args.push('--registry', source.registry);\n await runCommand('npm', args, {\n environment: {\n ...process.env,\n NPM_CONFIG_AUDIT: 'false',\n NPM_CONFIG_FUND: 'false',\n NPM_CONFIG_IGNORE_SCRIPTS: 'true',\n },\n });\n const pluginRoot = path.resolve(prefix, 'node_modules', ...source.package.split('/'));\n assertContained(path.join(prefix, 'node_modules'), pluginRoot, 'npm plugin package');\n return pluginRoot;\n}\n\nconst DEFAULT_MATERIALIZERS: PluginSourceMaterializers = {\n git: materializeGitSource,\n npm: materializeNpmSource,\n};\n\nasync function pathType(target: string): Promise<'directory' | 'missing' | 'other'> {\n try {\n const stat = await fs.promises.lstat(target);\n return stat.isDirectory() ? 'directory' : 'other';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return 'missing';\n throw error;\n }\n}\n\nfunction optionalManifestString(manifest: Record<string, unknown>, key: string): string | undefined {\n const value = manifest[key];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction validatePluginManifest(pluginRoot: string, manifestPath: string): InspectedPluginManifest {\n try {\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as unknown;\n if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {\n throw new Error('manifest must contain a JSON object');\n }\n const record = manifest as Record<string, unknown>;\n const agentPluginSchema =\n manifestPath === path.join(pluginRoot, 'plugin.json') && record.$schema === AGENT_PLUGIN_SCHEMA\n ? AGENT_PLUGIN_SCHEMA\n : undefined;\n const name = optionalManifestString(record, 'name');\n const version = optionalManifestString(record, 'version');\n const description = optionalManifestString(record, 'description');\n return {\n skillDiscovery: agentPluginSchema ? 'direct-children' : 'recursive',\n manifest: {\n path: manifestPath,\n ...(name ? { name } : {}),\n ...(version ? { version } : {}),\n ...(description ? { description } : {}),\n ...(agentPluginSchema ? { agentPluginSchema } : {}),\n },\n };\n } catch (error) {\n throw new Error(\n `Invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n }\n}\n\nasync function inspectInstallation(entry: PluginEntry): Promise<InspectedPluginManifest | false> {\n const type = await pathType(entry.directory);\n if (type === 'missing') return false;\n if (type !== 'directory') throw new Error(`Remote plugin cache path is not a directory: ${entry.directory}`);\n if (!entry.source || !isRemotePluginSource(entry.source)) {\n throw new Error(`Remote plugin entry is missing its source: ${entry.name ?? entry.directory}`);\n }\n\n let marker: InstallMarker;\n try {\n marker = JSON.parse(\n await fs.promises.readFile(path.join(entry.directory, INSTALL_MARKER), 'utf8'),\n ) as InstallMarker;\n } catch (error) {\n throw new Error(`Remote plugin cache is not managed by DoomPi: ${entry.directory}`, { cause: error });\n }\n if (marker.version !== INSTALL_MARKER_VERSION || JSON.stringify(marker.source) !== JSON.stringify(entry.source)) {\n throw new Error(`Remote plugin cache metadata does not match ${entry.name ?? entry.directory}: ${entry.directory}`);\n }\n const manifestPath = findPluginManifestPath(entry.directory);\n if (!manifestPath) {\n throw new Error(`Remote plugin cache is missing a supported plugin manifest: ${entry.directory}`);\n }\n return validatePluginManifest(entry.directory, manifestPath);\n}\n\nasync function copyPluginSource(sourceRoot: string, destination: string): Promise<void> {\n if ((await pathType(sourceRoot)) !== 'directory') {\n throw new Error(`Materialized plugin source is not a directory: ${sourceRoot}`);\n }\n await fs.promises.cp(sourceRoot, destination, {\n recursive: true,\n filter: (candidate) => path.basename(candidate) !== '.git',\n });\n}\n\nfunction isRenameRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'EEXIST' || code === 'ENOTEMPTY';\n}\n\nasync function installRemotePlugin(entry: PluginEntry, materializers: PluginSourceMaterializers): Promise<PluginEntry> {\n if (!entry.source || !isRemotePluginSource(entry.source)) return entry;\n const existingManifest = await inspectInstallation(entry);\n if (existingManifest) return { ...entry, ...existingManifest };\n\n const parent = path.dirname(entry.directory);\n await fs.promises.mkdir(parent, { recursive: true, mode: 0o700 });\n if ((await pathType(parent)) !== 'directory') {\n throw new Error(`Remote plugin cache root is not a directory: ${parent}`);\n }\n await fs.promises.chmod(parent, 0o700);\n const workspace = await fs.promises.mkdtemp(path.join(parent, '.plugin-staging-'));\n const installation = path.join(workspace, 'installation');\n try {\n const sourceRoot =\n entry.source.type === 'git'\n ? await materializers.git(entry.source, workspace)\n : await materializers.npm(entry.source, workspace);\n await copyPluginSource(sourceRoot, installation);\n const manifestPath = findPluginManifestPath(installation);\n if (!manifestPath) {\n throw new Error(`Remote plugin ${entry.name ?? entry.directory} does not contain a supported plugin manifest`);\n }\n validatePluginManifest(installation, manifestPath);\n const markerPath = path.join(installation, INSTALL_MARKER);\n if ((await pathType(markerPath)) !== 'missing') {\n throw new Error(`Remote plugin contains reserved cache metadata path: ${INSTALL_MARKER}`);\n }\n const marker: InstallMarker = { version: INSTALL_MARKER_VERSION, source: entry.source };\n await fs.promises.writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, {\n flag: 'wx',\n mode: 0o600,\n });\n try {\n await fs.promises.rename(installation, entry.directory);\n } catch (error) {\n if (!isRenameRace(error)) throw error;\n await fs.promises.rm(installation, { recursive: true, force: true });\n const racedManifest = await inspectInstallation(entry);\n if (!racedManifest) throw new Error(`Remote plugin installation race left no cache: ${entry.directory}`);\n return { ...entry, ...racedManifest };\n }\n const installedManifest = await inspectInstallation(entry);\n if (!installedManifest) throw new Error(`Remote plugin installation left no cache: ${entry.directory}`);\n return { ...entry, ...installedManifest };\n } catch (error) {\n throw new Error(\n `Failed to install remote plugin ${entry.name ?? entry.directory}: ${error instanceof Error ? error.message : String(error)}`,\n {\n cause: error,\n },\n );\n } finally {\n await fs.promises.rm(workspace, { recursive: true, force: true });\n }\n}\n\n/** Downloads selected remote plugins once into their content-addressed cache directories. */\nexport async function materializePluginEntries(\n entries: readonly PluginEntry[],\n options: PluginMaterializerOptions = {},\n): Promise<PluginEntry[]> {\n const materializers: PluginSourceMaterializers = {\n git: options.materializers?.git ?? DEFAULT_MATERIALIZERS.git,\n npm: options.materializers?.npm ?? DEFAULT_MATERIALIZERS.npm,\n };\n return Promise.all(entries.map((entry) => installRemotePlugin(entry, materializers)));\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-domain",
3
- "version": "0.0.1-alpha.13",
3
+ "version": "0.0.1-alpha.14",
4
4
  "description": "Domain selection, resource staging, and MCP scoping for DoomPi sessions.",
5
5
  "keywords": [
6
6
  "ai",
@@ -17,8 +17,16 @@
17
17
  "skills"
18
18
  ],
19
19
  "homepage": "https://agimon.ai",
20
+ "bugs": {
21
+ "url": "https://github.com/AgiFlow/doompi/issues"
22
+ },
20
23
  "license": "MIT",
21
24
  "author": "Vuong Ngo",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/AgiFlow/doompi.git",
28
+ "directory": "packages/core/doompi-domain"
29
+ },
22
30
  "files": [
23
31
  "dist",
24
32
  "llms.txt",
@@ -71,10 +79,10 @@
71
79
  "@deepseek-ai/cordis": "4.0.1",
72
80
  "typebox": "1.3.16",
73
81
  "yaml": "2.9.0",
74
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.35",
75
- "@agimon-ai/doompi-config": "0.0.1-alpha.35",
76
- "@agimon-ai/doompi-telemetry": "0.0.1-alpha.35",
77
- "@agimon-ai/doompi-ui": "0.0.1-alpha.35"
82
+ "@agimon-ai/doompi-config": "0.0.1-alpha.36",
83
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.36",
84
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.36",
85
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.36"
78
86
  },
79
87
  "devDependencies": {
80
88
  "@deepseek-ai/cordis": "4.0.1",
@@ -85,7 +93,7 @@
85
93
  "tsdown": "0.22.14",
86
94
  "typescript": "7.0.2",
87
95
  "vitest": "4.1.11",
88
- "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.33"
96
+ "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.34"
89
97
  },
90
98
  "peerDependencies": {
91
99
  "@earendil-works/pi-coding-agent": "0.84.2",