{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/pack/import.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pack import — data-type parts (S1).\n *\n * Maps a pack's data-type contents (skills, prompts) to bundle-relative\n * DraftChanges. This module is the pure mapping layer: it produces the file\n * changes and reports which bundle assets were added, so the integration layer\n * can update policy.json (prompt order / managed sources) and stage a data\n * proposal against the current stable bundle.\n *\n * Skills and prompts are pure-additive bundle assets. Structured preference\n * memory is parsed, merged append-only with the parent bundle, and rewritten\n * with pack provenance. Code-type parts (components, workflows) are handled by\n * the ABI activation path, not here.\n */\n\nimport { cp, lstat, mkdir, mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { loadCompiledBundle } from \"../bundle/compile.ts\";\nimport { parseBundlePolicy } from \"../bundle/schema.ts\";\nimport {\n\ttype InspectedEvoComponentArtifact,\n\tinspectEvoComponentArtifact,\n\tpublishInspectedEvoComponentArtifact,\n\tvalidateEvoComponentSelection,\n} from \"../components/artifact.ts\";\nimport { type EvoCapabilityGrant, parseEvoCapabilityGrants } from \"../components/capabilities/broker.ts\";\nimport { EvoComponentProcess } from \"../components/process-runtime.ts\";\nimport { createDefaultEvoAbiRegistry } from \"../components/registry.ts\";\nimport { validateComponentCandidate } from \"../evolve/retry.ts\";\nimport { createUnknownAbiBuilderRequestsFromPack, type UnknownAbiBuilderRequest } from \"../evolve/unknown-abi.ts\";\nimport {\n\tPREFERENCES_PATH,\n\ttype PreferenceMemory,\n\tparsePreferenceMemory,\n\treadBundlePreferenceMemory,\n} from \"../memory/preferences.ts\";\nimport { type EvoPaths, ensureEvoLayout, getEvoPaths } from \"../paths.ts\";\nimport {\n\tattachProposalArtifact,\n\ttype DraftChange,\n\ttype DraftProposal,\n\tproposalApproval,\n\trejectProposal,\n\tstageProposal,\n} from \"../proposal.ts\";\nimport { copyRegularFileNoFollow, readRegularDirectoryNoFollow, resolveRegularDirectory } from \"../secure-file.ts\";\nimport type { BundlePolicy, Proposal } from \"../types.ts\";\nimport {\n\tcomputeEvoPackIntegrity,\n\ttype EvoPackComponent,\n\ttype EvoPackManifest,\n\ttype EvoPackWorkflow,\n\tloadEvoPack,\n} from \"./pack.ts\";\n\nconst ASSET_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\n/** Derive a bundle-legal asset name (ASSET_NAME_PATTERN) from arbitrary text. */\nfunction sanitizeAssetName(raw: string): string {\n\tconst cleaned = raw.replace(/[^A-Za-z0-9._-]/g, \"-\").replace(/^[^A-Za-z0-9]+/, \"\");\n\treturn cleaned.length > 0 ? cleaned.slice(0, 64) : \"pack\";\n}\n\nexport interface PackDataChanges {\n\t/** Bundle-relative file changes to stage in a data proposal. */\n\tchanges: DraftChange[];\n\t/** Bundle paths of prompt assets added (for policy promptOrder update). */\n\taddedPromptPaths: string[];\n\t/** Bundle paths of skill assets added. */\n\taddedSkillPaths: string[];\n\t/** Number of new durable preferences appended from memory parts. */\n\taddedMemoryPreferences: number;\n}\n\n/**\n * Build the bundle DraftChanges for a pack's data-type contents. Reads each\n * referenced file from `packDir`. Pure w.r.t. the registry: no bundle is\n * mutated; the caller stages these as a proposal.\n */\nexport async function buildPackDataChanges(\n\tpackDir: string,\n\tmanifest: EvoPackManifest,\n\tparentMemory: PreferenceMemory = { schemaVersion: 1, preferences: [] },\n): Promise<PackDataChanges> {\n\tconst changes: DraftChange[] = [];\n\tconst addedPromptPaths: string[] = [];\n\tconst addedSkillPaths: string[] = [];\n\tconst usedPaths = new Set<string>();\n\n\t// Skills — pure-additive `skills/<name>/SKILL.md`.\n\tfor (const skill of manifest.contents.skills) {\n\t\tif (!ASSET_NAME_PATTERN.test(skill.name)) {\n\t\t\tthrow new Error(`pack skill name is not a valid bundle asset name: ${skill.name}`);\n\t\t}\n\t\tconst path = `skills/${skill.name}/SKILL.md`;\n\t\tif (usedPaths.has(path)) throw new Error(`pack has duplicate skill target: ${path}`);\n\t\tusedPaths.add(path);\n\t\tconst content = await readFile(join(packDir, skill.dir, \"SKILL.md\"), \"utf8\");\n\t\tchanges.push({ path, content });\n\t\taddedSkillPaths.push(path);\n\t}\n\n\t// Prompts — mapped to uniquely-named `prompts/<name>.md` assets.\n\tconst usedNames = new Set<string>();\n\tfor (const [index, prompt] of manifest.contents.prompts.entries()) {\n\t\tlet name = sanitizeAssetName(`${manifest.name}-${prompt.target}-${index + 1}`);\n\t\twhile (usedNames.has(name)) name = sanitizeAssetName(`${name}-x`);\n\t\tusedNames.add(name);\n\t\tif (!ASSET_NAME_PATTERN.test(name)) throw new Error(`derived prompt asset name is invalid: ${name}`);\n\t\tconst path = `prompts/${name}.md`;\n\t\tif (usedPaths.has(path)) throw new Error(`pack has duplicate prompt target: ${path}`);\n\t\tusedPaths.add(path);\n\t\tconst content = await readFile(join(packDir, prompt.file), \"utf8\");\n\t\tchanges.push({ path, content });\n\t\taddedPromptPaths.push(path);\n\t}\n\n\tconst mergedMemory: PreferenceMemory = {\n\t\tschemaVersion: 1,\n\t\tpreferences: [...parentMemory.preferences],\n\t};\n\tlet addedMemoryPreferences = 0;\n\tconst integrity = manifest.integrity ?? (await computeEvoPackIntegrity(packDir, manifest));\n\tfor (const memory of manifest.contents.memory) {\n\t\tconst fragment = parsePreferenceMemory(JSON.parse(await readFile(join(packDir, memory.file), \"utf8\")) as unknown);\n\t\tfor (const preference of fragment.preferences) {\n\t\t\tconst existingId = mergedMemory.preferences.find((entry) => entry.id === preference.id);\n\t\t\tif (existingId) {\n\t\t\t\tif (existingId.instruction !== preference.instruction) {\n\t\t\t\t\tthrow new Error(`pack preference id conflicts with the active bundle: ${preference.id}`);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (mergedMemory.preferences.some((entry) => entry.instruction === preference.instruction)) continue;\n\t\t\tmergedMemory.preferences.push({\n\t\t\t\t...preference,\n\t\t\t\tsource: {\n\t\t\t\t\tpackName: manifest.name,\n\t\t\t\t\tpackVersion: manifest.version,\n\t\t\t\t\tintegrity,\n\t\t\t\t\tfile: memory.file,\n\t\t\t\t},\n\t\t\t});\n\t\t\taddedMemoryPreferences += 1;\n\t\t}\n\t}\n\tif (addedMemoryPreferences > 0) {\n\t\tconst validated = parsePreferenceMemory(mergedMemory);\n\t\tchanges.push({ path: PREFERENCES_PATH, content: `${JSON.stringify(validated, undefined, \"\\t\")}\\n` });\n\t}\n\n\treturn {\n\t\tchanges,\n\t\taddedPromptPaths,\n\t\taddedSkillPaths,\n\t\taddedMemoryPreferences,\n\t};\n}\n\nexport interface PackImportResult {\n\tmanifest: EvoPackManifest;\n\t/** The staged data proposal, or undefined when the pack has no data-type parts. */\n\tproposal: Proposal | undefined;\n\taddedSkillPaths: string[];\n\taddedPromptPaths: string[];\n\taddedMemoryPreferences: number;\n\t/** Code-type parts (components + workflows) not handled by the data path. */\n\tskippedCode: number;\n}\n\nfunction createPackDataDraft(manifest: EvoPackManifest, data: PackDataChanges): DraftProposal | undefined {\n\tif (data.changes.length === 0) return undefined;\n\treturn {\n\t\tmotivation: `Import optimization pack \"${manifest.name}\"`,\n\t\texpectedEffect: `Add ${data.addedSkillPaths.length} skill(s), ${data.addedPromptPaths.length} prompt(s), and ${data.addedMemoryPreferences} preference(s) from pack ${manifest.name}@${manifest.version}`,\n\t\trisk: \"Data-only bundle additions (skills/prompts/preferences); reversible via trial/rollback.\",\n\t\tverifyPlan: \"bundle-compile\",\n\t\ttrialPlan: \"Activate in a reversible data trial, then keep or rollback.\",\n\t\tsource: \"explicit-request\",\n\t\tevidence: [],\n\t\tinboxReferences: [],\n\t\treplayScenarios: [],\n\t\tchanges: data.changes,\n\t};\n}\n\n/**\n * Import a pack's data-type parts against the current stable bundle: verify\n * integrity, map skills/prompts to bundle changes, and stage a reversible data\n * proposal (T0/T1) via the existing proposal pipeline. Skills load from the\n * bundle `skills/` directory and prompts from `prompts/` automatically, so no\n * policy edit is required. Code-type parts (components/workflows) are counted\n * and left to the ABI activation path.\n */\nexport async function importPackData(options: {\n\tpaths: EvoPaths;\n\tparentDigest: string;\n\tpackDir: string;\n\t/** Reject if the pack changed after a caller's read-only preflight. */\n\texpectedIntegrity?: string;\n}): Promise<PackImportResult> {\n\tconst { manifest, integrity } = await loadEvoPack(options.packDir);\n\tif (!integrity.ok) {\n\t\tthrow new Error(\n\t\t\t`pack integrity check failed: expected ${integrity.expected ?? \"(none declared)\"}, got ${integrity.actual}`,\n\t\t);\n\t}\n\tif (options.expectedIntegrity !== undefined && integrity.actual !== options.expectedIntegrity) {\n\t\tthrow new Error(`pack changed after preflight: expected ${options.expectedIntegrity}, got ${integrity.actual}`);\n\t}\n\tconst snapshotDirectory = await createVerifiedPackSnapshot({\n\t\tpaths: options.paths,\n\t\tpackDir: options.packDir,\n\t\tmanifest,\n\t\texpectedIntegrity: integrity.actual,\n\t});\n\ttry {\n\t\tconst parent = await loadCompiledBundle(options.paths, options.parentDigest);\n\t\tconst data = await buildPackDataChanges(snapshotDirectory, manifest, await readBundlePreferenceMemory(parent));\n\t\tconst skippedCode = manifest.contents.components.length + manifest.contents.workflows.length;\n\t\tconst draft = createPackDataDraft(manifest, data);\n\t\tif (!draft) {\n\t\t\treturn {\n\t\t\t\tmanifest,\n\t\t\t\tproposal: undefined,\n\t\t\t\taddedSkillPaths: [],\n\t\t\t\taddedPromptPaths: [],\n\t\t\t\taddedMemoryPreferences: data.addedMemoryPreferences,\n\t\t\t\tskippedCode,\n\t\t\t};\n\t\t}\n\t\tconst proposal = await stageProposal({\n\t\t\tpaths: options.paths,\n\t\t\tparentDigest: options.parentDigest,\n\t\t\tdraft,\n\t\t\tobservationsMarkdown: `Imported from optimization pack ${manifest.name}@${manifest.version}.`,\n\t\t});\n\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tproposal,\n\t\t\taddedSkillPaths: data.addedSkillPaths,\n\t\t\taddedPromptPaths: data.addedPromptPaths,\n\t\t\taddedMemoryPreferences: data.addedMemoryPreferences,\n\t\t\tskippedCode,\n\t\t};\n\t} finally {\n\t\tawait rm(snapshotDirectory, { recursive: true, force: true });\n\t}\n}\n\nexport interface ImportedPackComponent {\n\tsurface: string;\n\tabi: string;\n\tid: string;\n\ttrigger?: string;\n\tartifactDigest: string;\n\tproposal: Proposal;\n}\n\nexport interface EvoPackImportResult extends PackImportResult {\n\timportedComponents: ImportedPackComponent[];\n\t/** ABIs that require a T2 host-wiring proposal before their parts can activate. */\n\tunregisteredAbis: string[];\n\t/** Workflow parts whose ABI is not registered and therefore cannot be staged yet. */\n\tpendingWorkflows: number;\n\t/** Frozen, fully validated Builder inputs for code parts whose ABI is not registered. */\n\tunknownAbiRequests: UnknownAbiBuilderRequest[];\n}\n\nexport interface EvoPackImportPreflight {\n\tmanifest: EvoPackManifest;\n\tintegrity: string;\n\t/** Private verified snapshot; valid only until the beforeStage callback returns. */\n\tpackDirectory: string;\n\tunregisteredAbis: string[];\n\tpendingWorkflows: number;\n\tunknownAbiRequests: UnknownAbiBuilderRequest[];\n}\n\ntype EvoPackCodePart = { kind: \"component\"; part: EvoPackComponent } | { kind: \"workflow\"; part: EvoPackWorkflow };\n\nfunction referencedPackPaths(manifest: EvoPackManifest): string[] {\n\treturn [\n\t\t...manifest.contents.prompts.map((part) => part.file),\n\t\t...manifest.contents.skills.map((part) => part.dir),\n\t\t...manifest.contents.memory.map((part) => part.file),\n\t\t...manifest.contents.components.map((part) => part.artifact),\n\t\t...manifest.contents.workflows.map((part) => part.artifact),\n\t];\n}\n\nasync function copyPackSnapshotPath(sourceRoot: string, targetRoot: string, relativePath: string): Promise<void> {\n\tconst source = join(sourceRoot, relativePath);\n\tconst target = join(targetRoot, relativePath);\n\tconst metadata = await lstat(source);\n\tif (metadata.isSymbolicLink()) throw new Error(`pack path is a symlink: ${relativePath}`);\n\tif (metadata.isDirectory()) {\n\t\tawait mkdir(target, { recursive: true, mode: 0o700 });\n\t\tconst entries = (await readRegularDirectoryNoFollow(source, `pack directory ${relativePath}`)).sort(\n\t\t\t(left, right) => left.name.localeCompare(right.name),\n\t\t);\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.isSymbolicLink()) throw new Error(`pack path is a symlink: ${relativePath}/${entry.name}`);\n\t\t\tawait copyPackSnapshotPath(sourceRoot, targetRoot, `${relativePath}/${entry.name}`);\n\t\t}\n\t\treturn;\n\t}\n\tif (!metadata.isFile()) throw new Error(`pack path is neither file nor directory: ${relativePath}`);\n\tawait mkdir(dirname(target), { recursive: true, mode: 0o700 });\n\tawait copyRegularFileNoFollow(source, target, `pack file ${relativePath}`);\n}\n\nasync function createVerifiedPackSnapshot(options: {\n\tpaths: EvoPaths;\n\tpackDir: string;\n\tmanifest: EvoPackManifest;\n\texpectedIntegrity: string;\n}): Promise<string> {\n\tconst snapshotDirectory = await mkdtemp(join(options.paths.root, \".pack-import-\"));\n\ttry {\n\t\tconst sourceRoot = await resolveRegularDirectory(options.packDir, \"pack directory\");\n\t\tfor (const relativePath of new Set(referencedPackPaths(options.manifest))) {\n\t\t\tawait copyPackSnapshotPath(sourceRoot, snapshotDirectory, relativePath);\n\t\t}\n\t\tawait writeFile(join(snapshotDirectory, \"pack.json\"), `${JSON.stringify(options.manifest, undefined, \"\\t\")}\\n`, {\n\t\t\tmode: 0o600,\n\t\t});\n\t\tconst snapshot = await loadEvoPack(snapshotDirectory);\n\t\tif (!snapshot.integrity.ok || snapshot.integrity.actual !== options.expectedIntegrity) {\n\t\t\tthrow new Error(\n\t\t\t\t`pack changed while creating import snapshot: expected ${options.expectedIntegrity}, got ${snapshot.integrity.actual}`,\n\t\t\t);\n\t\t}\n\t\treturn snapshotDirectory;\n\t} catch (error) {\n\t\tawait rm(snapshotDirectory, { recursive: true, force: true });\n\t\tthrow error;\n\t}\n}\n\nfunction sameStringSet(left: readonly string[], right: readonly string[]): boolean {\n\treturn [...left].sort().join(\"\\n\") === [...right].sort().join(\"\\n\");\n}\n\nfunction preflightPackGrants(\n\tcodeParts: readonly EvoPackCodePart[],\n\tgrantsByComponent: Readonly<Record<string, readonly EvoCapabilityGrant[]>> | undefined,\n): Readonly<Record<string, readonly EvoCapabilityGrant[]>> {\n\tconst codePartIds = new Set(codeParts.map((codePart) => codePart.part.id));\n\tfor (const id of Object.keys(grantsByComponent ?? {})) {\n\t\tif (!codePartIds.has(id)) throw new Error(`Capability grants reference an unknown pack component: ${id}`);\n\t}\n\tconst normalized: Record<string, readonly EvoCapabilityGrant[]> = {};\n\tfor (const codePart of codeParts) {\n\t\tconst part = codePart.part;\n\t\tconst grants = parseEvoCapabilityGrants(grantsByComponent?.[part.id] ?? [], `grants for ${part.id}`);\n\t\tif (\n\t\t\t!sameStringSet(\n\t\t\t\tpart.capabilities,\n\t\t\t\tgrants.map((grant) => grant.capability),\n\t\t\t)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Component ${part.id} requires an explicit grant for every declared capability: ${part.capabilities.join(\", \") || \"(none)\"}`,\n\t\t\t);\n\t\t}\n\t\tnormalized[part.id] = grants;\n\t}\n\treturn normalized;\n}\n\ninterface PreparedPackCodePart {\n\tcodePart: EvoPackCodePart;\n\tsurface: string;\n\tabi: string;\n\tartifact: InspectedEvoComponentArtifact;\n\tpolicy: BundlePolicy;\n}\n\nfunction addCodeSelectionToPolicy(\n\tpolicy: BundlePolicy,\n\tcodePart: EvoPackCodePart,\n\tsurface: string,\n\tselection: {\n\t\tid: string;\n\t\tabi: string;\n\t\tartifactDigest: string;\n\t\tconfig: Record<string, unknown>;\n\t\tgrants?: EvoCapabilityGrant[];\n\t},\n): BundlePolicy {\n\treturn parseBundlePolicy(\n\t\tcodePart.kind === \"workflow\"\n\t\t\t? {\n\t\t\t\t\t...policy,\n\t\t\t\t\tworkflows: [...(policy.workflows ?? []), { ...selection, trigger: codePart.part.trigger }],\n\t\t\t\t}\n\t\t\t: surface === \"tool\"\n\t\t\t\t? {\n\t\t\t\t\t\t...policy,\n\t\t\t\t\t\t...(policy.enabledTools === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { enabledTools: [...new Set([...policy.enabledTools, selection.id])] }),\n\t\t\t\t\t\ttools: [...(policy.tools ?? []), selection],\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\t...policy,\n\t\t\t\t\t\tcomponents: {\n\t\t\t\t\t\t\t...(policy.components ?? {}),\n\t\t\t\t\t\t\t[surface]: selection,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t);\n}\n\nasync function prepareRegisteredCodeParts(options: {\n\tpackDirectory: string;\n\tcodeParts: readonly EvoPackCodePart[];\n\tgrantsByComponent: Readonly<Record<string, readonly EvoCapabilityGrant[]>>;\n\tparentPolicy: BundlePolicy;\n}): Promise<{ prepared: PreparedPackCodePart[]; unregisteredAbis: string[]; pendingWorkflows: number }> {\n\tconst registry = createDefaultEvoAbiRegistry();\n\tconst prepared: PreparedPackCodePart[] = [];\n\tconst unregisteredAbis = new Set<string>();\n\tlet pendingWorkflows = 0;\n\tlet policy = options.parentPolicy;\n\tfor (const codePart of options.codeParts) {\n\t\tconst part = codePart.part;\n\t\tconst abi = registry.get(part.abi);\n\t\tif (!abi) {\n\t\t\tunregisteredAbis.add(part.abi);\n\t\t\tif (codePart.kind === \"workflow\") pendingWorkflows += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst surface = codePart.kind === \"workflow\" ? \"workflow\" : codePart.part.surface;\n\t\tif (abi.surface !== surface) {\n\t\t\tthrow new Error(\n\t\t\t\t`Pack component ${part.id} declares surface ${surface}, but ${abi.id} belongs to ${abi.surface}`,\n\t\t\t);\n\t\t}\n\t\tconst artifact = await inspectEvoComponentArtifact(join(options.packDirectory, part.artifact), registry);\n\t\tif (\n\t\t\tartifact.manifest.id !== part.id ||\n\t\t\tartifact.manifest.abi !== part.abi ||\n\t\t\t!sameStringSet(artifact.manifest.capabilities, part.capabilities)\n\t\t) {\n\t\t\tthrow new Error(`Pack component declaration does not match imported artifact: ${part.id}`);\n\t\t}\n\t\tconst grants = [...(options.grantsByComponent[part.id] ?? [])];\n\t\tconst selectionWithoutConfig = {\n\t\t\tid: artifact.manifest.id,\n\t\t\tabi: artifact.manifest.abi,\n\t\t\tartifactDigest: artifact.manifest.artifactDigest,\n\t\t\t...(grants.length === 0 ? {} : { grants }),\n\t\t};\n\t\tconst config = registry.validateSelection(surface, { ...selectionWithoutConfig, config: {} }) as Record<\n\t\t\tstring,\n\t\t\tunknown\n\t\t>;\n\t\tpolicy = addCodeSelectionToPolicy(policy, codePart, surface, { ...selectionWithoutConfig, config });\n\t\tprepared.push({ codePart, surface, abi: abi.id, artifact, policy });\n\t}\n\treturn { prepared, unregisteredAbis: [...unregisteredAbis].sort(), pendingWorkflows };\n}\n\n/**\n * Executable validation for an imported component proposal. Workflows run the\n * full protocol dry run and compaction components their deterministic fixture;\n * other host ABIs have no fixture, so they get the generic runtime check: the\n * exact artifact must start under the component runtime and answer the health\n * probe. Semantic behavior always remains Canary evidence.\n */\nconst IMPORT_VALIDATION_REQUEST_TIMEOUT_MS = 30_000;\n\nasync function validateImportedComponentCandidate(\n\tpaths: EvoPaths,\n\tproposal: Proposal,\n\tcomponentId: string,\n\toptions: { sandbox?: boolean },\n): Promise<string> {\n\tif (!proposal.candidateDigest || !proposal.targetAbi) {\n\t\tthrow new Error(\"Imported component proposal is not a component selection\");\n\t}\n\tconst registry = createDefaultEvoAbiRegistry();\n\tconst abi = registry.require(proposal.targetAbi);\n\tif (abi.id === \"workflow/v1\" || abi.id === \"compaction/v1\") {\n\t\treturn validateComponentCandidate(paths, proposal, {\n\t\t\t...options,\n\t\t\trequestTimeoutMs: IMPORT_VALIDATION_REQUEST_TIMEOUT_MS,\n\t\t});\n\t}\n\tconst bundle = await loadCompiledBundle(paths, proposal.candidateDigest);\n\t// Plural surfaces (tool/v1) select into an array; singular surfaces into\n\t// policy.components keyed by surface name.\n\tconst selection =\n\t\tabi.id === \"tool/v1\"\n\t\t\t? (bundle.policy.tools ?? []).find((entry) => entry.id === componentId)\n\t\t\t: bundle.policy.components?.[abi.surface];\n\tif (!selection) throw new Error(`Candidate bundle does not select ${componentId} on ${abi.surface}`);\n\tconst config = registry.validateSelection(abi.surface, selection);\n\tconst artifact = await validateEvoComponentSelection(paths, abi.surface, selection, registry);\n\tconst process = new EvoComponentProcess(artifact, abi, config, {\n\t\trequestTimeoutMs: IMPORT_VALIDATION_REQUEST_TIMEOUT_MS,\n\t\t...(options.sandbox === undefined ? {} : { sandbox: options.sandbox }),\n\t});\n\ttry {\n\t\tawait process.start();\n\t\tawait process.health();\n\t} finally {\n\t\tawait process.shutdown().catch(() => undefined);\n\t}\n\treturn [\n\t\t\"# Imported component executable validation\",\n\t\t\"\",\n\t\t`- ABI: ${abi.id}`,\n\t\t`- Artifact: ${selection.artifactDigest}`,\n\t\t\"- The exact content-addressed artifact started under the component runtime and answered the health probe.\",\n\t\t`- ${abi.id} declares no deterministic fixture; semantic behavior remains Canary evidence.`,\n\t\t\"\",\n\t].join(\"\\n\");\n}\n\n/**\n * Attach the approval-gating artifacts to a freshly staged pack proposal.\n * Imports never run an evolution cycle, so without these the staged proposal\n * could never pass the tiered approval checks. The executable validation is\n * real (workflow dry run, deterministic fixture, or runtime health probe);\n * the review and replay artifacts document exactly which trust anchors\n * replace the model critic.\n */\nasync function attachImportApprovalArtifacts(options: {\n\tpaths: EvoPaths;\n\tpackName: string;\n\tpackVersion: string;\n\tproposal: Proposal;\n\tcomponentId: string;\n\tsandbox?: boolean;\n}): Promise<Proposal> {\n\tconst validation = await validateImportedComponentCandidate(options.paths, options.proposal, options.componentId, {\n\t\t...(options.sandbox === undefined ? {} : { sandbox: options.sandbox }),\n\t});\n\tlet reviewed = await attachProposalArtifact({\n\t\tpaths: options.paths,\n\t\tproposalId: options.proposal.id,\n\t\texpected: proposalApproval(options.proposal),\n\t\tkind: \"validation\",\n\t\tcontent: validation,\n\t\tallowedStatuses: [\"pending\"],\n\t});\n\treviewed = await attachProposalArtifact({\n\t\tpaths: options.paths,\n\t\tproposalId: reviewed.id,\n\t\texpected: proposalApproval(reviewed),\n\t\tkind: \"replay\",\n\t\tcontent: `${validation}\\nThis trusted executable component replay replaces the unavailable pre-validation model replay. Provider and live-session effects remain Canary evidence.\\n`,\n\t\tallowedStatuses: [\"pending\"],\n\t});\n\treturn attachProposalArtifact({\n\t\tpaths: options.paths,\n\t\tproposalId: reviewed.id,\n\t\texpected: proposalApproval(reviewed),\n\t\tkind: \"review\",\n\t\tcontent: [\n\t\t\t\"# Pack import review\",\n\t\t\t\"\",\n\t\t\t\"## Origin\",\n\t\t\t\"\",\n\t\t\t`Imported from optimization pack \"${options.packName}@${options.packVersion}\". No independent model critic ran; trust derives from the pack integrity digest, the explicitly persisted capability grants, sandboxed execution, and the reversible Canary.`,\n\t\t\t\"\",\n\t\t\t\"## Trusted executable-validation addendum\",\n\t\t\t\"\",\n\t\t\t\"The exact content-addressed artifact passed executable ABI protocol validation (workflow dry run or deterministic fixture). Benefit and semantic quality remain unverified, so activation is limited to the reversible Canary trial.\",\n\t\t\t\"\",\n\t\t\t\"Recommendation: needs-evidence\",\n\t\t\t\"\",\n\t\t].join(\"\\n\"),\n\t\tallowedStatuses: [\"pending\"],\n\t});\n}\n\nasync function stagePreparedCodePart(options: {\n\tpaths: EvoPaths;\n\tparentDigest: string;\n\tpackName: string;\n\tpackVersion: string;\n\tprepared: PreparedPackCodePart;\n\t/** Skipped during the shadow preflight; the real staging pass validates. */\n\tvalidate: boolean;\n\tsandbox?: boolean;\n}): Promise<ImportedPackComponent> {\n\tconst part = options.prepared.codePart.part;\n\tconst artifact = await publishInspectedEvoComponentArtifact(options.paths, options.prepared.artifact);\n\tconst staged = await stageProposal({\n\t\tpaths: options.paths,\n\t\tparentDigest: options.parentDigest,\n\t\tdraft: {\n\t\t\tmotivation: `Import component ${part.id} from optimization pack \"${options.packName}\"`,\n\t\t\texpectedEffect: `Register ${part.id} on the registered ${options.prepared.abi} host ABI`,\n\t\t\trisk: \"Sandboxed empty-ceiling component selection; activation is limited to a reversible Canary trial.\",\n\t\t\tverifyPlan: `Verify artifact identity and execute the deterministic ${options.prepared.abi} fixture before Canary approval.`,\n\t\t\ttrialPlan: \"Activate for new sessions as a reversible Canary; keep or rollback after focused review.\",\n\t\t\tsource: \"explicit-request\",\n\t\t\tevidence: [],\n\t\t\tinboxReferences: [],\n\t\t\treplayScenarios: [],\n\t\t\ttargetAbi: options.prepared.abi,\n\t\t\trequiresNewAbi: false,\n\t\t\tchanges: [{ path: \"policy.json\", content: `${JSON.stringify(options.prepared.policy, undefined, \"\\t\")}\\n` }],\n\t\t},\n\t\tobservationsMarkdown: `Imported component from optimization pack ${options.packName}@${options.packVersion}.`,\n\t});\n\tlet proposal = staged;\n\tif (options.validate) {\n\t\ttry {\n\t\t\tproposal = await attachImportApprovalArtifacts({\n\t\t\t\tpaths: options.paths,\n\t\t\t\tpackName: options.packName,\n\t\t\t\tpackVersion: options.packVersion,\n\t\t\t\tproposal: staged,\n\t\t\t\tcomponentId: part.id,\n\t\t\t\t...(options.sandbox === undefined ? {} : { sandbox: options.sandbox }),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t// Fail closed without leaving an unapprovable pending proposal behind.\n\t\t\tawait rejectProposal(options.paths, staged.id, `Pack import executable validation failed: ${message}`).catch(\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t\tthrow new Error(`Imported component ${part.id} failed executable validation: ${message}`);\n\t\t}\n\t}\n\treturn {\n\t\tsurface: options.prepared.surface,\n\t\tabi: options.prepared.abi,\n\t\tid: artifact.manifest.id,\n\t\t...(options.prepared.codePart.kind === \"workflow\" ? { trigger: options.prepared.codePart.part.trigger } : {}),\n\t\tartifactDigest: artifact.manifest.artifactDigest,\n\t\tproposal,\n\t};\n}\n\nasync function preflightPackStages(options: {\n\ttargetPaths: EvoPaths;\n\tsnapshotDirectory: string;\n\tparentDigest: string;\n\tparentPolicy: BundlePolicy;\n\tparentDirectory: string;\n\tmanifest: EvoPackManifest;\n\tdataDraft?: DraftProposal;\n\tpreparedCode: readonly PreparedPackCodePart[];\n}): Promise<void> {\n\tconst shadowPaths = getEvoPaths(join(options.snapshotDirectory, \".staging-preflight\"));\n\tawait ensureEvoLayout(shadowPaths);\n\tawait cp(options.parentDirectory, join(shadowPaths.bundles, options.parentDigest), { recursive: true });\n\tfor (const selection of Object.values(options.parentPolicy.components ?? {})) {\n\t\tawait cp(\n\t\t\tjoin(options.targetPaths.components, selection.artifactDigest),\n\t\t\tjoin(shadowPaths.components, selection.artifactDigest),\n\t\t\t{ recursive: true },\n\t\t);\n\t}\n\tlet candidateParentDigest = options.parentDigest;\n\tif (options.dataDraft) {\n\t\tconst proposal = await stageProposal({\n\t\t\tpaths: shadowPaths,\n\t\t\tparentDigest: candidateParentDigest,\n\t\t\tdraft: options.dataDraft,\n\t\t\tobservationsMarkdown: `Preflight optimization pack ${options.manifest.name}@${options.manifest.version}.`,\n\t\t});\n\t\tif (!proposal.candidateDigest) throw new Error(\"Pack data preflight proposal has no candidate bundle\");\n\t\tcandidateParentDigest = proposal.candidateDigest;\n\t}\n\tfor (const prepared of options.preparedCode) {\n\t\tconst imported = await stagePreparedCodePart({\n\t\t\tpaths: shadowPaths,\n\t\t\tparentDigest: candidateParentDigest,\n\t\t\tpackName: options.manifest.name,\n\t\t\tpackVersion: options.manifest.version,\n\t\t\tprepared,\n\t\t\tvalidate: false,\n\t\t});\n\t\tif (!imported.proposal.candidateDigest) {\n\t\t\tthrow new Error(`Pack component preflight proposal has no candidate bundle: ${prepared.codePart.part.id}`);\n\t\t}\n\t\tcandidateParentDigest = imported.proposal.candidateDigest;\n\t}\n}\n\n/**\n * Full pack staging entry point. Data assets use the existing reversible data\n * proposal. Registered, empty-ceiling components are verified into the local\n * content-addressed store and each receives its own focused selection proposal.\n * Unknown ABIs are reported for the later T2 Builder path; nothing activates\n * during import.\n */\nexport async function importEvoPack(options: {\n\tpaths: EvoPaths;\n\tparentDigest: string;\n\tpackDir: string;\n\t/** Reject if the pack changed after a caller's read-only approval preview. */\n\texpectedIntegrity?: string;\n\t/** Explicit artifact grants keyed by the pack's globally unique component id. */\n\tgrantsByComponent?: Readonly<Record<string, readonly EvoCapabilityGrant[]>>;\n\t/**\n\t * Runs after the entire pack is validated but before this importer publishes\n\t * artifacts or stages proposals. A failure leaves no pack-owned durable state.\n\t * Side effects created inside the callback belong to that independent\n\t * transaction and are not deleted by this importer.\n\t */\n\tbeforeStage?: (preflight: EvoPackImportPreflight) => Promise<void>;\n\t/**\n\t * Sandbox mode for the post-stage executable validation of imported\n\t * components (workflow dry run / deterministic fixture). Pass false only\n\t * after an explicit one-time direct-execution permission.\n\t */\n\tsandbox?: boolean;\n}): Promise<EvoPackImportResult> {\n\tconst preflight = await loadEvoPack(options.packDir);\n\tif (!preflight.integrity.ok) {\n\t\tthrow new Error(\n\t\t\t`pack integrity check failed: expected ${preflight.integrity.expected ?? \"(none declared)\"}, got ${preflight.integrity.actual}`,\n\t\t);\n\t}\n\tif (options.expectedIntegrity !== undefined && preflight.integrity.actual !== options.expectedIntegrity) {\n\t\tthrow new Error(\n\t\t\t`pack changed after preflight: expected ${options.expectedIntegrity}, got ${preflight.integrity.actual}`,\n\t\t);\n\t}\n\tconst codeParts: EvoPackCodePart[] = [\n\t\t...preflight.manifest.contents.components.map((part): EvoPackCodePart => ({ kind: \"component\", part })),\n\t\t...preflight.manifest.contents.workflows.map((part): EvoPackCodePart => ({ kind: \"workflow\", part })),\n\t];\n\tconst grantsByComponent = preflightPackGrants(codeParts, options.grantsByComponent);\n\tconst snapshotDirectory = await createVerifiedPackSnapshot({\n\t\tpaths: options.paths,\n\t\tpackDir: options.packDir,\n\t\tmanifest: preflight.manifest,\n\t\texpectedIntegrity: preflight.integrity.actual,\n\t});\n\ttry {\n\t\tconst parent = await loadCompiledBundle(options.paths, options.parentDigest);\n\t\tconst data = await buildPackDataChanges(\n\t\t\tsnapshotDirectory,\n\t\t\tpreflight.manifest,\n\t\t\tawait readBundlePreferenceMemory(parent),\n\t\t);\n\t\tconst dataDraft = createPackDataDraft(preflight.manifest, data);\n\t\tconst preparedCode = await prepareRegisteredCodeParts({\n\t\t\tpackDirectory: snapshotDirectory,\n\t\t\tcodeParts,\n\t\t\tgrantsByComponent,\n\t\t\tparentPolicy: parent.policy,\n\t\t});\n\t\tconst unknownAbiRequests = await createUnknownAbiBuilderRequestsFromPack({\n\t\t\tpackDirectory: snapshotDirectory,\n\t\t\tgrantsByComponent,\n\t\t});\n\t\tif (\n\t\t\tunknownAbiRequests\n\t\t\t\t.map((request) => request.targetAbi)\n\t\t\t\t.sort()\n\t\t\t\t.join(\"\\n\") !== preparedCode.unregisteredAbis.join(\"\\n\")\n\t\t) {\n\t\t\tthrow new Error(\"Pack registered and unknown-ABI preflight disagreed\");\n\t\t}\n\t\tawait preflightPackStages({\n\t\t\ttargetPaths: options.paths,\n\t\t\tsnapshotDirectory,\n\t\t\tparentDigest: options.parentDigest,\n\t\t\tparentPolicy: parent.policy,\n\t\t\tparentDirectory: parent.directory,\n\t\t\tmanifest: preflight.manifest,\n\t\t\t...(dataDraft ? { dataDraft } : {}),\n\t\t\tpreparedCode: preparedCode.prepared,\n\t\t});\n\t\tawait rm(join(snapshotDirectory, \".staging-preflight\"), { recursive: true, force: true });\n\t\tawait options.beforeStage?.({\n\t\t\tmanifest: preflight.manifest,\n\t\t\tintegrity: preflight.integrity.actual,\n\t\t\tpackDirectory: snapshotDirectory,\n\t\t\tunregisteredAbis: preparedCode.unregisteredAbis,\n\t\t\tpendingWorkflows: preparedCode.pendingWorkflows,\n\t\t\tunknownAbiRequests,\n\t\t});\n\n\t\tconst proposal = dataDraft\n\t\t\t? await stageProposal({\n\t\t\t\t\tpaths: options.paths,\n\t\t\t\t\tparentDigest: options.parentDigest,\n\t\t\t\t\tdraft: dataDraft,\n\t\t\t\t\tobservationsMarkdown: `Imported from optimization pack ${preflight.manifest.name}@${preflight.manifest.version}.`,\n\t\t\t\t})\n\t\t\t: undefined;\n\t\tconst importedComponents: ImportedPackComponent[] = [];\n\t\tlet candidateParentDigest = proposal?.candidateDigest ?? options.parentDigest;\n\t\tfor (const prepared of preparedCode.prepared) {\n\t\t\tconst imported = await stagePreparedCodePart({\n\t\t\t\tpaths: options.paths,\n\t\t\t\tparentDigest: candidateParentDigest,\n\t\t\t\tpackName: preflight.manifest.name,\n\t\t\t\tpackVersion: preflight.manifest.version,\n\t\t\t\tprepared,\n\t\t\t\tvalidate: true,\n\t\t\t\t...(options.sandbox === undefined ? {} : { sandbox: options.sandbox }),\n\t\t\t});\n\t\t\timportedComponents.push(imported);\n\t\t\tif (!imported.proposal.candidateDigest) {\n\t\t\t\tthrow new Error(`Imported component proposal has no candidate bundle: ${prepared.codePart.part.id}`);\n\t\t\t}\n\t\t\tcandidateParentDigest = imported.proposal.candidateDigest;\n\t\t}\n\t\treturn {\n\t\t\tmanifest: preflight.manifest,\n\t\t\tproposal,\n\t\t\taddedSkillPaths: data.addedSkillPaths,\n\t\t\taddedPromptPaths: data.addedPromptPaths,\n\t\t\taddedMemoryPreferences: data.addedMemoryPreferences,\n\t\t\tskippedCode: codeParts.length,\n\t\t\timportedComponents,\n\t\t\tunregisteredAbis: preparedCode.unregisteredAbis,\n\t\t\tpendingWorkflows: preparedCode.pendingWorkflows,\n\t\t\tunknownAbiRequests,\n\t\t};\n\t} finally {\n\t\tawait rm(snapshotDirectory, { recursive: true, force: true });\n\t}\n}\n"]}