@acidicsoil/portable-capabilities 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3541,9 +3541,9 @@ function normalizeDigestValue(value) {
3541
3541
  function stableManifestDigest(value) {
3542
3542
  return digestBytes(new TextEncoder().encode(JSON.stringify(normalizeDigestValue(value))));
3543
3543
  }
3544
- function packageEntriesDigest(entries2, packageIdentities = []) {
3544
+ function packageEntriesDigest(entries, packageIdentities = []) {
3545
3545
  return stableManifestDigest({
3546
- entries: [...entries2].sort((left, right) => left.path.localeCompare(right.path)).map((entry) => ({ path: entry.path, digest: entry.digest, mode: entry.mode })),
3546
+ entries: [...entries].sort((left, right) => left.path.localeCompare(right.path)).map((entry) => ({ path: entry.path, digest: entry.digest, mode: entry.mode })),
3547
3547
  packageIdentities: [...packageIdentities].sort(
3548
3548
  (left, right) => left.lockPath.localeCompare(right.lockPath)
3549
3549
  )
@@ -3792,9 +3792,9 @@ async function copyAtomically(source3, target, mode) {
3792
3792
  await rename2(temporary, target);
3793
3793
  }
3794
3794
  async function desiredEntries(sourceRoot, files) {
3795
- const entries2 = [];
3796
- for (const file of files) entries2.push(await entryFor(join3(sourceRoot, file), file));
3797
- return entries2;
3795
+ const entries = [];
3796
+ for (const file of files) entries.push(await entryFor(join3(sourceRoot, file), file));
3797
+ return entries;
3798
3798
  }
3799
3799
  async function selectedPackageFiles(options) {
3800
3800
  const files = await listPackageFiles(options.sourceRoot);
@@ -3860,9 +3860,9 @@ async function unselectedPackageRoots(options) {
3860
3860
  }
3861
3861
  return Object.freeze(roots);
3862
3862
  }
3863
- async function installedPackageIdentities(sourceRoot, entries2) {
3863
+ async function installedPackageIdentities(sourceRoot, entries) {
3864
3864
  const identities = [];
3865
- for (const entry of entries2.filter((item) => item.path.endsWith("/capability.lock.json"))) {
3865
+ for (const entry of entries.filter((item) => item.path.endsWith("/capability.lock.json"))) {
3866
3866
  const lock = JSON.parse(await readFile2(join3(sourceRoot, entry.path), "utf8"));
3867
3867
  if (lock.schemaVersion !== "2.0.0" || !lock.integrity?.package?.digest || lock.generatedDigest !== lock.integrity.package.digest) {
3868
3868
  throw new Error(`Invalid capability package identity: ${entry.path}`);
@@ -4155,6 +4155,19 @@ async function assertPlanPathsSafe(targetRoot, plan) {
4155
4155
  }
4156
4156
  async function executePreparedInstallation(options) {
4157
4157
  const manifest = await readInstallationManifest(options.targetRoot);
4158
+ const operation = options.preparedOperation ?? "install";
4159
+ if (options.preparedDiagnostics?.length) {
4160
+ return result(operation, "degraded", {
4161
+ ok: false,
4162
+ diagnostics: options.preparedDiagnostics
4163
+ });
4164
+ }
4165
+ if (options.preparedMutations.length === 0) {
4166
+ return result(operation, "degraded", {
4167
+ ok: false,
4168
+ diagnostics: ["No prepared mutations can be installed"]
4169
+ });
4170
+ }
4158
4171
  const duplicatePaths = /* @__PURE__ */ new Set();
4159
4172
  for (const mutation of options.preparedMutations) {
4160
4173
  if (duplicatePaths.has(mutation.path)) {
@@ -4229,7 +4242,6 @@ async function executePreparedInstallation(options) {
4229
4242
  packageIdentities,
4230
4243
  entries: nextEntries
4231
4244
  };
4232
- const operation = options.preparedOperation ?? "install";
4233
4245
  if (options.dryRun)
4234
4246
  return result(operation, manifest ? "healthy" : "missing", {
4235
4247
  dryRun: true,
@@ -4338,12 +4350,12 @@ async function removeInstallation(targetRoot, faultInjector, capabilityIds) {
4338
4350
  const removes = manifest.entries.filter((entry) => unchanged.has(entry.path)).map((entry) => entry.path);
4339
4351
  const preserved = manifest.entries.filter((entry) => !unchanged.has(entry.path));
4340
4352
  const nextManifest = preserved.length ? (() => {
4341
- const entries2 = Object.freeze(preserved);
4342
- const preservedPaths = new Set(entries2.map((entry) => entry.path));
4353
+ const entries = Object.freeze(preserved);
4354
+ const preservedPaths = new Set(entries.map((entry) => entry.path));
4343
4355
  const packageIdentities = Object.freeze(
4344
4356
  manifest.packageIdentities.filter((identity3) => preservedPaths.has(identity3.lockPath))
4345
4357
  );
4346
- const packageDigest = packageEntriesDigest(entries2, packageIdentities);
4358
+ const packageDigest = packageEntriesDigest(entries, packageIdentities);
4347
4359
  const base = {
4348
4360
  runtimeId: manifest.runtimeId,
4349
4361
  packageVersion: manifest.packageVersion,
@@ -4351,7 +4363,7 @@ async function removeInstallation(targetRoot, faultInjector, capabilityIds) {
4351
4363
  journalVersion: manifest.journalVersion,
4352
4364
  lifecycleState: "modified",
4353
4365
  packageIdentities,
4354
- entries: entries2
4366
+ entries
4355
4367
  };
4356
4368
  return {
4357
4369
  ...manifest,
@@ -11762,8 +11774,8 @@ async function assertNoSymlinks(current) {
11762
11774
  async function treeDigest(root) {
11763
11775
  const hash = createHash3("sha256");
11764
11776
  async function visit(current, relative5 = "") {
11765
- const entries2 = await readdir2(current, { withFileTypes: true });
11766
- for (const entry of entries2.sort((left, right) => left.name.localeCompare(right.name))) {
11777
+ const entries = await readdir2(current, { withFileTypes: true });
11778
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
11767
11779
  if ([".git", "node_modules", ".turbo"].includes(entry.name)) continue;
11768
11780
  const path9 = join4(current, entry.name);
11769
11781
  const child = relative5 ? `${relative5}/${entry.name}` : entry.name;
@@ -12051,10 +12063,81 @@ import { parse } from "yaml";
12051
12063
  import { parseDocument } from "yaml";
12052
12064
 
12053
12065
  // packages/compiler/src/evidence/runtime-claims.ts
12066
+ function parseVersion(value) {
12067
+ const match = value.match(/(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/u);
12068
+ if (!match) return void 0;
12069
+ return {
12070
+ major: Number(match[1]),
12071
+ minor: Number(match[2]),
12072
+ patch: Number(match[3]),
12073
+ prerelease: match[4] ? match[4].split(".").map((part) => /^\d+$/u.test(part) ? Number(part) : part) : []
12074
+ };
12075
+ }
12076
+ function compareVersions(left, right) {
12077
+ for (const key of ["major", "minor", "patch"]) {
12078
+ if (left[key] !== right[key]) return left[key] > right[key] ? 1 : -1;
12079
+ }
12080
+ if (left.prerelease.length === 0 && right.prerelease.length === 0) return 0;
12081
+ if (left.prerelease.length === 0) return 1;
12082
+ if (right.prerelease.length === 0) return -1;
12083
+ for (let index = 0; index < Math.max(left.prerelease.length, right.prerelease.length); index += 1) {
12084
+ const leftPart = left.prerelease[index];
12085
+ const rightPart = right.prerelease[index];
12086
+ if (leftPart === void 0) return -1;
12087
+ if (rightPart === void 0) return 1;
12088
+ if (leftPart === rightPart) continue;
12089
+ if (typeof leftPart === "number" && typeof rightPart === "string") return -1;
12090
+ if (typeof leftPart === "string" && typeof rightPart === "number") return 1;
12091
+ return leftPart > rightPart ? 1 : -1;
12092
+ }
12093
+ return 0;
12094
+ }
12095
+ function caretUpperBound(version) {
12096
+ if (version.major > 0) return { major: version.major + 1, minor: 0, patch: 0, prerelease: [] };
12097
+ if (version.minor > 0) return { major: 0, minor: version.minor + 1, patch: 0, prerelease: [] };
12098
+ return { major: 0, minor: 0, patch: version.patch + 1, prerelease: [] };
12099
+ }
12100
+ function tildeUpperBound(version) {
12101
+ return { major: version.major, minor: version.minor + 1, patch: 0, prerelease: [] };
12102
+ }
12103
+ function matchesConstraint(actual, operator, expected) {
12104
+ if (actual.prerelease.length > 0 && expected.prerelease.length === 0) return false;
12105
+ const comparison = compareVersions(actual, expected);
12106
+ switch (operator ?? "=") {
12107
+ case ">=":
12108
+ return comparison >= 0;
12109
+ case "<=":
12110
+ return comparison <= 0;
12111
+ case ">":
12112
+ return comparison > 0;
12113
+ case "<":
12114
+ return comparison < 0;
12115
+ case "^":
12116
+ return comparison >= 0 && compareVersions(actual, caretUpperBound(expected)) < 0;
12117
+ case "~":
12118
+ return comparison >= 0 && compareVersions(actual, tildeUpperBound(expected)) < 0;
12119
+ default:
12120
+ return comparison === 0;
12121
+ }
12122
+ }
12123
+ function isRuntimeVersionInRange(range, runtimeVersion) {
12124
+ const normalizedRange = range.trim();
12125
+ if (normalizedRange === "*") return true;
12126
+ const actual = parseVersion(runtimeVersion);
12127
+ if (!actual) return false;
12128
+ const expression = normalizedRange.includes(";") ? normalizedRange.slice(normalizedRange.lastIndexOf(";") + 1).trim() : normalizedRange;
12129
+ const constraints = expression.split(/\s+/u).map((token) => {
12130
+ const match = token.match(/^(>=|<=|>|<|=|\^|~)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/u);
12131
+ if (!match || !match[2]) return void 0;
12132
+ const version = parseVersion(match[2]);
12133
+ return version ? { operator: match[1], version } : void 0;
12134
+ });
12135
+ return constraints.length > 0 && constraints.every(
12136
+ (constraint) => constraint?.version && matchesConstraint(actual, constraint.operator, constraint.version)
12137
+ );
12138
+ }
12054
12139
  function resolveRuntimeEvidence(claim4, runtimeVersion) {
12055
- const rangeMajor = claim4.versionRange.match(/\d+/)?.[0];
12056
- const runtimeMajor = runtimeVersion.match(/^\d+/)?.[0];
12057
- const applicable = claim4.versionRange === "*" || rangeMajor !== void 0 && rangeMajor === runtimeMajor;
12140
+ const applicable = isRuntimeVersionInRange(claim4.versionRange, runtimeVersion);
12058
12141
  const sufficientState = ["documented", "source-observed", "runtime-observed"].includes(
12059
12142
  claim4.state
12060
12143
  );
@@ -12072,85 +12155,26 @@ function resolveRuntimeEvidence(claim4, runtimeVersion) {
12072
12155
  }
12073
12156
 
12074
12157
  // packages/compiler/src/negotiation/adapter-registry.ts
12075
- var entries = [
12076
- {
12077
- id: "materialize-markdown",
12078
- operationKinds: ["MaterializeArtifact"],
12079
- purityClass: "pure",
12080
- effectClass: "filesystem",
12081
- requiredEvidenceCategories: ["location", "discovery"]
12082
- },
12083
- {
12084
- id: "patch-structured-config",
12085
- operationKinds: ["PatchStructuredConfig"],
12086
- purityClass: "planned-effect",
12087
- effectClass: "configuration",
12088
- requiredEvidenceCategories: ["configuration"]
12089
- },
12090
- {
12091
- id: "pi-extension-registration",
12092
- operationKinds: ["InstallExtension"],
12093
- purityClass: "planned-effect",
12094
- effectClass: "registration",
12095
- requiredEvidenceCategories: ["configuration"]
12096
- },
12097
- {
12098
- id: "oh-my-pi-code-as-hooks",
12099
- operationKinds: ["InstallExtension"],
12100
- purityClass: "planned-effect",
12101
- effectClass: "registration",
12102
- requiredEvidenceCategories: ["hooks", "configuration"]
12103
- },
12104
- {
12105
- id: "antigravity-plugin-registration",
12106
- operationKinds: ["RegisterPlugin"],
12107
- purityClass: "planned-effect",
12108
- effectClass: "registration",
12109
- requiredEvidenceCategories: ["plugin", "location"]
12110
- },
12111
- {
12112
- id: "antigravity-hook-registration",
12113
- operationKinds: ["RegisterHook"],
12114
- purityClass: "planned-effect",
12115
- effectClass: "registration",
12116
- requiredEvidenceCategories: ["hooks", "location"]
12117
- },
12118
- {
12119
- id: "antigravity-mcp-registration",
12120
- operationKinds: ["RegisterMcpServer"],
12121
- purityClass: "planned-effect",
12122
- effectClass: "registration",
12123
- requiredEvidenceCategories: ["mcp", "location"]
12124
- },
12125
- {
12126
- id: "opencode-custom-tool",
12127
- operationKinds: ["InstallExtension"],
12128
- purityClass: "planned-effect",
12129
- effectClass: "registration",
12130
- requiredEvidenceCategories: ["location", "discovery"]
12131
- },
12132
- {
12133
- id: "opencode-plugin",
12134
- operationKinds: ["RegisterPlugin"],
12135
- purityClass: "planned-effect",
12136
- effectClass: "registration",
12137
- requiredEvidenceCategories: ["plugin", "discovery"]
12138
- }
12139
- ];
12140
- var adapterRegistry = new Map(
12141
- entries.map((x) => [x.id, x])
12142
- );
12158
+ var adapterIds = Object.freeze([
12159
+ "materialize-markdown",
12160
+ "patch-structured-config",
12161
+ "pi-extension-registration",
12162
+ "oh-my-pi-code-as-hooks",
12163
+ "antigravity-plugin-registration",
12164
+ "antigravity-hook-registration",
12165
+ "antigravity-mcp-registration",
12166
+ "opencode-custom-tool",
12167
+ "opencode-plugin"
12168
+ ]);
12143
12169
  function requireAdapter(id) {
12144
- const item = adapterRegistry.get(id);
12145
- if (!item) throw new Error(`Unknown adapter ID: ${id}`);
12146
- return item;
12170
+ if (!adapterIds.includes(id)) throw new Error(`Unknown adapter ID: ${id}`);
12147
12171
  }
12148
12172
 
12149
12173
  // packages/compiler/src/negotiation/negotiate-capability.ts
12150
12174
  function negotiateCapability(artifact, descriptor, claims, version) {
12151
12175
  return artifact.invocationIntents.map((intent) => {
12152
12176
  const surface = descriptor.surfaces.find(
12153
- (x) => x.semanticKind === intent && x.evidenceClaimIds.some((claimId) => {
12177
+ (x) => x.semanticKind === intent && (x.versionRange === void 0 || isRuntimeVersionInRange(x.versionRange, version)) && x.evidenceClaimIds.some((claimId) => {
12154
12178
  const claim4 = claims.find((candidate) => candidate.id === claimId);
12155
12179
  return claim4 !== void 0 && resolveRuntimeEvidence(claim4, version).reason !== "version-inapplicable";
12156
12180
  })
@@ -12206,8 +12230,8 @@ var operationalSectionNames = Object.freeze([
12206
12230
  ]);
12207
12231
  function validateOperationalSkillContract(contract) {
12208
12232
  for (const section of operationalSectionNames) {
12209
- const entries2 = contract[section];
12210
- if (!Array.isArray(entries2) || entries2.length === 0 || entries2.some((entry) => !entry.trim())) {
12233
+ const entries = contract[section];
12234
+ if (!Array.isArray(entries) || entries.length === 0 || entries.some((entry) => !entry.trim())) {
12211
12235
  throw new Error(`Missing operational section: ${section}`);
12212
12236
  }
12213
12237
  }
@@ -12227,13 +12251,26 @@ var headings = {
12227
12251
  function renderOperationalSkillContract(contract) {
12228
12252
  validateOperationalSkillContract(contract);
12229
12253
  return operationalSectionNames.map((section) => {
12230
- const entries2 = contract[section].map((entry, index) => `${index + 1}. ${entry}`).join("\n");
12254
+ const entries = contract[section].map((entry, index) => `${index + 1}. ${entry}`).join("\n");
12231
12255
  return `## ${headings[section]}
12232
12256
 
12233
- ${entries2}`;
12257
+ ${entries}`;
12234
12258
  }).join("\n\n");
12235
12259
  }
12236
12260
 
12261
+ // packages/contracts/src/skill-document.ts
12262
+ function renderSkillDocument(input) {
12263
+ const description = input.description.replace(/[\r\n\t]+/gu, " ").replace(/\s{2,}/gu, " ").trim();
12264
+ if (!description) throw new Error(`Skill ${input.name} requires a non-empty description`);
12265
+ return `---
12266
+ name: ${JSON.stringify(input.name)}
12267
+ description: ${JSON.stringify(description)}
12268
+ ---
12269
+ ${input.marker}
12270
+ ${input.content}
12271
+ `;
12272
+ }
12273
+
12237
12274
  // packages/contracts/src/structured-config.ts
12238
12275
  import { existsSync, readFileSync as readFileSync4 } from "node:fs";
12239
12276
  import { parse as parse2, stringify } from "yaml";
@@ -12266,6 +12303,7 @@ function planProjection(artifact, runtimeId, scope, negotiations) {
12266
12303
  id: `materialize:${n4.intent}`,
12267
12304
  artifactId: artifact.id,
12268
12305
  logicalDestination: `${n4.intent}/${artifact.id}`,
12306
+ description: artifact.title,
12269
12307
  content: artifact.operationalContract ? renderOperationalSkillContract(artifact.operationalContract) : artifact.title
12270
12308
  });
12271
12309
  for (const resource2 of artifact.resourceFiles ?? [])
@@ -12301,14 +12339,14 @@ function planProjection(artifact, runtimeId, scope, negotiations) {
12301
12339
 
12302
12340
  // packages/compiler/src/planning/plan-installation.ts
12303
12341
  import { createHash as createHash6 } from "node:crypto";
12304
- function planInstallation(plan, descriptor) {
12342
+ function planInstallation(plan, descriptor, runtimeVersion) {
12305
12343
  const operations = [];
12306
12344
  for (const op of plan.operations) {
12307
12345
  if (op.kind === "MaterializeArtifact") {
12308
12346
  const location = descriptor.locations.find(
12309
- (x) => x.scope === plan.scope && (x.artifactKind === "skill" || x.artifactKind === op.logicalDestination.split("/")[0])
12347
+ (x) => x.scope === plan.scope && (x.artifactKind === "skill" || x.artifactKind === op.logicalDestination.split("/")[0]) && (!x.versionRange || isRuntimeVersionInRange(x.versionRange, runtimeVersion))
12310
12348
  );
12311
- if (!location || !location.pathTemplate || location.installation === "manual") {
12349
+ if (!location?.pathTemplate || location.installation === "manual") {
12312
12350
  operations.push({
12313
12351
  kind: "EmitManualStep",
12314
12352
  id: `manual:${op.id}`,
@@ -12336,14 +12374,15 @@ function planInstallation(plan, descriptor) {
12336
12374
  uninstall: "remove-owned-only",
12337
12375
  ownershipIntent: "own",
12338
12376
  destination: `${location.pathTemplate}/${op.logicalDestination}`,
12377
+ description: op.description,
12339
12378
  content: op.content
12340
12379
  });
12341
12380
  }
12342
12381
  if (op.kind === "IncludeResource") {
12343
12382
  const location = descriptor.locations.find(
12344
- (candidate) => candidate.scope === plan.scope && candidate.artifactKind === "skill"
12383
+ (candidate) => candidate.scope === plan.scope && candidate.artifactKind === "skill" && (!candidate.versionRange || isRuntimeVersionInRange(candidate.versionRange, runtimeVersion))
12345
12384
  );
12346
- if (!location || !location.pathTemplate || location.installation === "manual") {
12385
+ if (!location?.pathTemplate || location.installation === "manual") {
12347
12386
  operations.push({
12348
12387
  kind: "EmitManualStep",
12349
12388
  id: `manual:${op.id}`,
@@ -12415,7 +12454,7 @@ function planSetup(request, artifact, descriptor, claims, ownershipManifest) {
12415
12454
  request.runtimeVersion
12416
12455
  );
12417
12456
  const projectionPlan = planProjection(artifact, descriptor.id, request.scope, negotiations);
12418
- const baseInstallationPlan = planInstallation(projectionPlan, descriptor);
12457
+ const baseInstallationPlan = planInstallation(projectionPlan, descriptor, request.runtimeVersion);
12419
12458
  const mutatingIntent = request.intent === "setup" || request.intent === "update";
12420
12459
  let installationPlan = mutatingIntent ? baseInstallationPlan : { ...baseInstallationPlan, operations: [] };
12421
12460
  if (request.intent === "remove") {
@@ -12486,7 +12525,7 @@ function planSetup(request, artifact, descriptor, claims, ownershipManifest) {
12486
12525
  approvals: request.approvalPolicy === "preapproved" ? [] : approvals,
12487
12526
  manualSteps: installationPlan.operations.filter((operation) => operation.kind === "EmitManualStep").map((operation) => operation.id),
12488
12527
  verificationExpectations: projectionPlan.operations.filter((operation) => operation.kind === "ExpectVerification").map((operation) => operation.expectation),
12489
- nativeUsageInputs: negotiations.filter((outcome) => outcome.surfaceId).map((outcome) => outcome.surfaceId)
12528
+ nativeUsageInputs: negotiations.flatMap(({ surfaceId }) => surfaceId ? [surfaceId] : [])
12490
12529
  };
12491
12530
  }
12492
12531
 
@@ -12601,9 +12640,9 @@ async function resolveVerifiedCapabilityEntrypoint(options) {
12601
12640
  }
12602
12641
 
12603
12642
  // packages/cli/src/release.ts
12604
- var cliVersion = true ? "0.1.8" : createRequire(import.meta.url)("../../../package.json").version;
12643
+ var cliVersion = true ? "0.1.10" : createRequire(import.meta.url)("../../../package.json").version;
12605
12644
 
12606
- // packages/adapters/antigravity/src/materialize.ts
12645
+ // packages/adapters/src/antigravity/materialize.ts
12607
12646
  import { resolve as resolve4 } from "node:path";
12608
12647
  var marker = "<!-- portable-capabilities:owned antigravity -->";
12609
12648
  function destination(value) {
@@ -12634,15 +12673,15 @@ function diagnostic(operation, kind, message) {
12634
12673
  }
12635
12674
  function render(operation) {
12636
12675
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
12637
- if (!skill) return `${marker}
12676
+ const name = skill?.[1];
12677
+ if (!name) return `${marker}
12638
12678
  ${operation.content}`;
12639
- return `---
12640
- name: ${skill[1]}
12641
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
12642
- ---
12643
- ${marker}
12644
- ${operation.content}
12645
- `;
12679
+ return renderSkillDocument({
12680
+ name,
12681
+ description: operation.description,
12682
+ marker,
12683
+ content: operation.content
12684
+ });
12646
12685
  }
12647
12686
  function registration(operation) {
12648
12687
  return `${JSON.stringify({ adapterId: operation.adapterId, kind: operation.kind, target: operation.target }, null, 2)}
@@ -12751,7 +12790,7 @@ function prepareAntigravityMaterialization(plan, root) {
12751
12790
  });
12752
12791
  }
12753
12792
 
12754
- // packages/adapters/antigravity/src/runtime-descriptor.ts
12793
+ // packages/adapters/src/antigravity/runtime-descriptor.ts
12755
12794
  var markdown = "materialize-markdown";
12756
12795
  var plugin = "antigravity-plugin-registration";
12757
12796
  var hook = "antigravity-hook-registration";
@@ -12944,7 +12983,7 @@ var antigravityRuntimeDescriptor = {
12944
12983
  ]
12945
12984
  };
12946
12985
 
12947
- // packages/adapters/antigravity/src/runtime-evidence.ts
12986
+ // packages/adapters/src/antigravity/runtime-evidence.ts
12948
12987
  import { createHash as createHash9 } from "node:crypto";
12949
12988
  var digest2 = (value) => createHash9("sha256").update(value).digest("hex");
12950
12989
  var retrievedAt = "2026-08-10T00:00:00.000Z";
@@ -13092,7 +13131,7 @@ var antigravityRuntimeEvidence = [
13092
13131
  )
13093
13132
  ];
13094
13133
 
13095
- // packages/adapters/claude-code/src/materialize.ts
13134
+ // packages/adapters/src/claude-code/materialize.ts
13096
13135
  import { resolve as resolve5 } from "node:path";
13097
13136
  var marker2 = "<!-- portable-capabilities:owned claude-code -->";
13098
13137
  function destination2(value) {
@@ -13127,15 +13166,15 @@ function diagnostic2(operation, kind, message) {
13127
13166
  }
13128
13167
  function render2(operation) {
13129
13168
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
13130
- if (!skill) return `${marker2}
13169
+ const name = skill?.[1];
13170
+ if (!name) return `${marker2}
13131
13171
  ${operation.content}`;
13132
- return `---
13133
- name: ${skill[1]}
13134
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
13135
- ---
13136
- ${marker2}
13137
- ${operation.content}
13138
- `;
13172
+ return renderSkillDocument({
13173
+ name,
13174
+ description: operation.description,
13175
+ marker: marker2,
13176
+ content: operation.content
13177
+ });
13139
13178
  }
13140
13179
  function config(operation, root, path9) {
13141
13180
  if (operation.format !== "json")
@@ -13249,7 +13288,7 @@ function prepareClaudeCodeMaterialization(plan, root) {
13249
13288
  });
13250
13289
  }
13251
13290
 
13252
- // packages/adapters/claude-code/src/runtime-descriptor.ts
13291
+ // packages/adapters/src/claude-code/runtime-descriptor.ts
13253
13292
  var markdown2 = "materialize-markdown";
13254
13293
  var claudeCodeRuntimeDescriptor = {
13255
13294
  schemaVersion: "1.0",
@@ -13451,7 +13490,7 @@ var claudeCodeRuntimeDescriptor = {
13451
13490
  ]
13452
13491
  };
13453
13492
 
13454
- // packages/adapters/claude-code/src/runtime-evidence.ts
13493
+ // packages/adapters/src/claude-code/runtime-evidence.ts
13455
13494
  import { createHash as createHash10 } from "node:crypto";
13456
13495
  var digest3 = (value) => createHash10("sha256").update(value).digest("hex");
13457
13496
  var retrievedAt2 = "2026-08-10T00:00:00.000Z";
@@ -13622,18 +13661,20 @@ var claudeCodeRuntimeEvidence = Object.freeze([
13622
13661
  }))
13623
13662
  ]);
13624
13663
 
13625
- // packages/adapters/codex/src/materialize.ts
13664
+ // packages/adapters/src/codex/materialize.ts
13626
13665
  import { resolve as resolve6 } from "node:path";
13627
13666
  var marker3 = "<!-- portable-capabilities:owned codex -->";
13628
13667
  function destination3(value) {
13629
13668
  const project = value.match(/^\.codex\/skills\/skill\/(.+)$/);
13630
13669
  if (project) return `.codex/skills/${project[1]}/SKILL.md`;
13670
+ const currentProject = value.match(/^\.agents\/skills\/skill\/(.+)$/);
13671
+ if (currentProject) return `.agents/skills/${currentProject[1]}/SKILL.md`;
13631
13672
  const user = value.match(/^\$CODEX_HOME\/skills\/skill\/(.+)$/);
13632
13673
  if (user) return `.codex-user/skills/${user[1]}/SKILL.md`;
13633
13674
  return value.replace(/^\$CODEX_HOME\//, ".codex-user/");
13634
13675
  }
13635
13676
  function resourceDestination3(value) {
13636
- return value.replace(/^\.codex\/skills\/skill\//u, ".codex/skills/").replace(/^\$CODEX_HOME\/skills\/skill\//u, ".codex-user/skills/");
13677
+ return value.replace(/^\.codex\/skills\/skill\//u, ".codex/skills/").replace(/^\.agents\/skills\/skill\//u, ".agents/skills/").replace(/^\$CODEX_HOME\/skills\/skill\//u, ".codex-user/skills/");
13637
13678
  }
13638
13679
  function confined3(root, path9) {
13639
13680
  const target = resolve6(root, path9);
@@ -13643,15 +13684,15 @@ function confined3(root, path9) {
13643
13684
  }
13644
13685
  function render3(operation) {
13645
13686
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
13646
- if (!skill) return `${marker3}
13687
+ const name = skill?.[1];
13688
+ if (!name) return `${marker3}
13647
13689
  ${operation.content}`;
13648
- return `---
13649
- name: ${skill[1]}
13650
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
13651
- ---
13652
- ${marker3}
13653
- ${operation.content}
13654
- `;
13690
+ return renderSkillDocument({
13691
+ name,
13692
+ description: operation.description,
13693
+ marker: marker3,
13694
+ content: operation.content
13695
+ });
13655
13696
  }
13656
13697
  function transform(operation) {
13657
13698
  if (operation.format !== "json")
@@ -13715,25 +13756,48 @@ function prepareCodexMaterialization(plan, root, ..._options) {
13715
13756
  });
13716
13757
  }
13717
13758
 
13718
- // packages/adapters/codex/src/runtime-descriptor.ts
13759
+ // packages/adapters/src/codex/runtime-descriptor.ts
13719
13760
  var codexRuntimeDescriptor = {
13720
13761
  schemaVersion: "1.0",
13721
13762
  id: "codex",
13722
13763
  aliases: ["codex-cli"],
13723
- supportedVersions: [">=0.146.0"],
13764
+ supportedVersions: ["=0.146.0", ">=0.147.0 <0.148.0"],
13724
13765
  locations: [
13725
13766
  {
13726
- id: "codex-project-skills",
13767
+ id: "codex-project-skills-0146",
13727
13768
  artifactKind: "skill",
13728
13769
  scope: "project",
13729
13770
  pathTemplate: ".codex/skills",
13730
13771
  evidenceClaimIds: ["codex.location.project-skills"],
13772
+ versionRange: "=0.146.0",
13773
+ installation: "automatic",
13774
+ registration: "discovery",
13775
+ uninstall: "automatic"
13776
+ },
13777
+ {
13778
+ id: "codex-project-skills-0147",
13779
+ artifactKind: "skill",
13780
+ scope: "project",
13781
+ pathTemplate: ".agents/skills",
13782
+ evidenceClaimIds: ["codex.location.project-skills-agents"],
13783
+ versionRange: ">=0.147.0 <0.148.0",
13731
13784
  installation: "automatic",
13732
13785
  registration: "discovery",
13733
13786
  uninstall: "automatic"
13734
13787
  },
13735
13788
  {
13736
- id: "codex-user-skills",
13789
+ id: "codex-user-skills-0147",
13790
+ artifactKind: "skill",
13791
+ scope: "user",
13792
+ pathTemplate: ".agents/skills",
13793
+ evidenceClaimIds: ["codex.location.user-skills-agents"],
13794
+ versionRange: ">=0.147.0 <0.148.0",
13795
+ installation: "automatic",
13796
+ registration: "discovery",
13797
+ uninstall: "automatic"
13798
+ },
13799
+ {
13800
+ id: "codex-user-skills-0146",
13737
13801
  artifactKind: "skill",
13738
13802
  scope: "user",
13739
13803
  pathTemplate: "$CODEX_HOME/skills",
@@ -13746,16 +13810,30 @@ var codexRuntimeDescriptor = {
13746
13810
  ],
13747
13811
  surfaces: [
13748
13812
  {
13749
- id: "codex-direct-skill",
13813
+ id: "codex-direct-skill-0146",
13750
13814
  semanticKind: "skill",
13751
13815
  integrationMode: "declarative",
13752
13816
  adapterId: "materialize-markdown",
13753
- discovery: "Codex discovers project and user skills from its native skills roots.",
13754
- invocation: "Invoke the installed skill through Codex's native skill mechanism.",
13817
+ discovery: "Codex 0.146.x discovers project skills from .codex/skills.",
13818
+ invocation: "Invoke the installed skill through Codex 0.146.x native skill selection.",
13755
13819
  precedence: ["project", "user"],
13756
13820
  evidenceClaimIds: ["codex.discovery.skills", "codex.invocation.skills"],
13757
- stability: "stable",
13821
+ versionRange: "=0.146.0",
13822
+ stability: "version-gated",
13758
13823
  evidenceState: "runtime-observed"
13824
+ },
13825
+ {
13826
+ id: "codex-direct-skill-0147",
13827
+ semanticKind: "skill",
13828
+ integrationMode: "declarative",
13829
+ adapterId: "materialize-markdown",
13830
+ discovery: "Codex 0.147.x discovers project skills from .agents/skills.",
13831
+ invocation: "Invoke the installed skill through Codex 0.147.x native skill selection.",
13832
+ precedence: ["project", "user"],
13833
+ evidenceClaimIds: ["codex.discovery.skills-0147", "codex.invocation.skills-0147"],
13834
+ versionRange: ">=0.147.0 <0.148.0",
13835
+ stability: "version-gated",
13836
+ evidenceState: "source-observed"
13759
13837
  }
13760
13838
  ],
13761
13839
  configuration: [],
@@ -13765,10 +13843,37 @@ var codexRuntimeDescriptor = {
13765
13843
  degradation: []
13766
13844
  };
13767
13845
 
13768
- // packages/adapters/codex/src/runtime-evidence.ts
13846
+ // packages/adapters/src/codex/runtime-evidence.ts
13769
13847
  import { createHash as createHash11 } from "node:crypto";
13770
13848
  var digest4 = (value) => createHash11("sha256").update(value).digest("hex");
13771
13849
  var observedAt = "2026-08-08T00:00:00.000Z";
13850
+ var sourceObservedAt = "2026-08-15T00:00:00.000Z";
13851
+ var codexSource = "https://github.com/openai/codex";
13852
+ var codexSkillRootsSource = "https://github.com/openai/codex/blob/53f3fa749659498fa24c81da8fde5440fa7bba7f/codex-rs/ext/skills/src/host_roots.rs";
13853
+ var codexCurrentRange = ">=0.147.0 <0.148.0";
13854
+ var projectSkillRootExcerpt = 'const AGENTS_DIR_NAME: &str = ".agents";\nconst SKILLS_DIR_NAME: &str = "skills";';
13855
+ var userSkillRootExcerpt = "home_dir.join(AGENTS_DIR_NAME).join(SKILLS_DIR_NAME), SkillScope::User";
13856
+ var discoveryExcerpt = "let agents_skills = directory.join(AGENTS_DIR_NAME).join(SKILLS_DIR_NAME);";
13857
+ var invocationExcerpt = 'UserInput::Skill {\n name: "demo".to_string(),';
13858
+ var sourceClaim2 = (id, subject, assertion, sourceLocator, sourceExcerpt) => ({
13859
+ schemaVersion: "1.0",
13860
+ id,
13861
+ runtimeId: "codex",
13862
+ category: id.includes("location") ? "location" : id.includes("discovery") ? "discovery" : "invocation",
13863
+ subject,
13864
+ assertion,
13865
+ versionRange: codexCurrentRange,
13866
+ sourceType: "official-source",
13867
+ source: codexSource,
13868
+ sourceLocator,
13869
+ sourceExcerpt,
13870
+ sourceDigest: digest4(sourceExcerpt),
13871
+ state: "source-observed",
13872
+ confidence: "high",
13873
+ verificationStatus: "verified",
13874
+ stability: "version-gated",
13875
+ verifiedAt: sourceObservedAt
13876
+ });
13772
13877
  var codexRuntimeEvidence = Object.freeze([
13773
13878
  {
13774
13879
  schemaVersion: "1.0",
@@ -13776,54 +13881,82 @@ var codexRuntimeEvidence = Object.freeze([
13776
13881
  runtimeId: "codex",
13777
13882
  category: "location",
13778
13883
  subject: "project skill root",
13779
- assertion: "Codex project skills are materialized beneath .codex/skills.",
13780
- versionRange: ">=0.146.0",
13884
+ assertion: "Codex 0.146.x project skills are materialized beneath .codex/skills.",
13885
+ versionRange: "=0.146.0",
13781
13886
  sourceType: "runtime-probe",
13782
13887
  source: "codex-cli",
13783
- sourceLocator: "native vertical tracer",
13888
+ sourceLocator: "packages/conformance/src/tracer/codex-native-evidence.json",
13784
13889
  sourceExcerpt: ".codex/skills",
13785
- sourceDigest: digest4("codex project skills .codex/skills"),
13890
+ sourceDigest: digest4("codex 0.146 project skills .codex/skills"),
13786
13891
  state: "runtime-observed",
13787
13892
  confidence: "high",
13788
13893
  verificationStatus: "verified",
13789
- stability: "stable",
13894
+ stability: "version-gated",
13790
13895
  verifiedAt: observedAt
13791
13896
  },
13897
+ sourceClaim2(
13898
+ "codex.location.project-skills-agents",
13899
+ "project skill root",
13900
+ "Codex 0.147.x project skills are discovered beneath .agents/skills.",
13901
+ `${codexSkillRootsSource}#L92-L101`,
13902
+ projectSkillRootExcerpt
13903
+ ),
13904
+ sourceClaim2(
13905
+ "codex.location.user-skills-agents",
13906
+ "user skill root",
13907
+ "Codex 0.147.x user skills are discovered beneath ~/.agents/skills.",
13908
+ `${codexSkillRootsSource}#L107-L119`,
13909
+ userSkillRootExcerpt
13910
+ ),
13792
13911
  {
13793
13912
  schemaVersion: "1.0",
13794
13913
  id: "codex.location.user-skills",
13795
13914
  runtimeId: "codex",
13796
13915
  category: "location",
13797
13916
  subject: "user skill root",
13798
- assertion: "Codex user skills are materialized beneath CODEX_HOME/skills.",
13799
- versionRange: ">=0.146.0",
13917
+ assertion: "Codex 0.146.x user skills are materialized beneath CODEX_HOME/skills.",
13918
+ versionRange: "=0.146.0",
13800
13919
  sourceType: "runtime-probe",
13801
13920
  source: "codex-cli",
13802
13921
  sourceLocator: "native vertical tracer",
13803
13922
  sourceExcerpt: "CODEX_HOME/skills",
13804
- sourceDigest: digest4("codex user skills CODEX_HOME/skills"),
13923
+ sourceDigest: digest4("codex 0.146 user skills CODEX_HOME/skills"),
13805
13924
  state: "runtime-observed",
13806
13925
  confidence: "high",
13807
13926
  verificationStatus: "verified",
13808
- stability: "stable",
13927
+ stability: "version-gated",
13809
13928
  verifiedAt: observedAt
13810
13929
  },
13930
+ sourceClaim2(
13931
+ "codex.discovery.skills-0147",
13932
+ "native skill discovery",
13933
+ "Codex 0.147.x discovers Agent Skills from .agents/skills.",
13934
+ `${codexSkillRootsSource}#L139-L161`,
13935
+ discoveryExcerpt
13936
+ ),
13937
+ sourceClaim2(
13938
+ "codex.invocation.skills-0147",
13939
+ "native skill invocation",
13940
+ "Codex 0.147.x invokes a discovered Agent Skill through its native skill selection.",
13941
+ "https://github.com/openai/codex/blob/53f3fa749659498fa24c81da8fde5440fa7bba7f/codex-rs/core/tests/suite/skills.rs",
13942
+ invocationExcerpt
13943
+ ),
13811
13944
  {
13812
13945
  schemaVersion: "1.0",
13813
13946
  id: "codex.discovery.skills",
13814
13947
  runtimeId: "codex",
13815
13948
  category: "discovery",
13816
13949
  subject: "native skill discovery",
13817
- assertion: "Codex natively discovers a skill installed in its project skill root.",
13818
- versionRange: ">=0.146.0",
13950
+ assertion: "Codex 0.146.x natively discovers a skill installed in its project skill root.",
13951
+ versionRange: "=0.146.0",
13819
13952
  sourceType: "runtime-probe",
13820
13953
  source: "codex-cli",
13821
13954
  sourceLocator: "packages/conformance/src/tracer/codex-native-evidence.json",
13822
- sourceDigest: digest4("codex native discovery"),
13955
+ sourceDigest: digest4("codex 0.146 native discovery"),
13823
13956
  state: "runtime-observed",
13824
13957
  confidence: "high",
13825
13958
  verificationStatus: "verified",
13826
- stability: "stable",
13959
+ stability: "version-gated",
13827
13960
  verifiedAt: observedAt
13828
13961
  },
13829
13962
  {
@@ -13832,21 +13965,22 @@ var codexRuntimeEvidence = Object.freeze([
13832
13965
  runtimeId: "codex",
13833
13966
  category: "invocation",
13834
13967
  subject: "native skill invocation",
13835
- assertion: "Codex can invoke an installed skill through the native client.",
13836
- versionRange: ">=0.146.0",
13968
+ assertion: "Codex 0.146.x can invoke an installed skill through the native client.",
13969
+ versionRange: "=0.146.0",
13837
13970
  sourceType: "runtime-probe",
13838
13971
  source: "codex-cli",
13839
13972
  sourceLocator: "packages/conformance/src/tracer/codex-native-evidence.json",
13840
- sourceDigest: digest4("codex native invocation"),
13973
+ sourceDigest: digest4("codex 0.146 native invocation"),
13841
13974
  state: "runtime-observed",
13842
13975
  confidence: "high",
13843
13976
  verificationStatus: "verified",
13844
- stability: "stable",
13977
+ stability: "version-gated",
13845
13978
  verifiedAt: observedAt
13846
13979
  }
13847
13980
  ]);
13848
13981
 
13849
- // packages/adapters/dcode/src/materialize.ts
13982
+ // packages/adapters/src/dcode/materialize.ts
13983
+ import { readFile as readFile5 } from "node:fs/promises";
13850
13984
  import { resolve as resolve7 } from "node:path";
13851
13985
  var marker4 = "<!-- portable-capabilities:owned dcode -->";
13852
13986
  function destination4(value) {
@@ -13878,21 +14012,46 @@ function diagnostic3(operation, kind, message) {
13878
14012
  }
13879
14013
  function render4(operation) {
13880
14014
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
13881
- if (!skill) return `${marker4}
14015
+ const name = skill?.[1];
14016
+ if (!name) return `${marker4}
13882
14017
  ${operation.content}`;
13883
- return `---
13884
- name: ${skill[1]}
13885
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
13886
- ---
13887
- ${marker4}
13888
- ${operation.content}
13889
- `;
14018
+ return renderSkillDocument({
14019
+ name,
14020
+ description: operation.description,
14021
+ marker: marker4,
14022
+ content: operation.content
14023
+ });
13890
14024
  }
13891
14025
  function registration3(operation) {
13892
14026
  return `${JSON.stringify({ adapterId: operation.adapterId, kind: operation.kind, target: operation.target }, null, 2)}
13893
14027
  `;
13894
14028
  }
13895
- function prepareDCodeMaterialization(plan, root) {
14029
+ async function mergedInstructions(root, path9, operations, removedIds) {
14030
+ let existing;
14031
+ try {
14032
+ existing = await readFile5(resolve7(root, path9), "utf8");
14033
+ } catch (error) {
14034
+ if (error.code !== "ENOENT") throw error;
14035
+ }
14036
+ if (!existing && operations.length === 0) return void 0;
14037
+ const selectedIds = new Set(operations.map((operation) => operation.id));
14038
+ const existingText = existing ?? "";
14039
+ const firstHeading = existingText.search(/^## .+$/mu);
14040
+ const preamble = firstHeading >= 0 ? existingText.slice(0, firstHeading).trim() : existingText.trim();
14041
+ const sections = firstHeading >= 0 ? existingText.slice(firstHeading).split(/(?=^## .+$)/mu) : [];
14042
+ const retained = sections.filter((section) => {
14043
+ const id = section.match(/^## ([^\n]+)/u)?.[1] ?? "";
14044
+ return !selectedIds.has(id) && !removedIds.some((removedId) => id.startsWith(`${removedId}:`));
14045
+ }).map((section) => section.trim());
14046
+ const generated = operations.slice().sort((left, right) => left.id.localeCompare(right.id)).map((operation) => `## ${operation.id}
14047
+
14048
+ ${operation.content.trim()}`);
14049
+ const sectionsToWrite = [...retained, ...generated];
14050
+ return sectionsToWrite.length > 0 ? `${preamble || marker4}
14051
+ ${sectionsToWrite.join("\n\n")}
14052
+ ` : void 0;
14053
+ }
14054
+ async function prepareDCodeMaterialization(plan, root) {
13896
14055
  if (plan.runtimeId !== "dcode") throw new Error(`DCode adapter cannot prepare ${plan.runtimeId}`);
13897
14056
  const mutations = [];
13898
14057
  const diagnostics = [];
@@ -13994,28 +14153,39 @@ function prepareDCodeMaterialization(plan, root) {
13994
14153
  );
13995
14154
  }
13996
14155
  }
13997
- if (instructionOperations.length > 0) {
14156
+ const instructionRemovals = plan.operations.filter(
14157
+ (operation) => operation.kind === "RemoveOwnedArtifact" && /^\.deepagents\/skills\/[^/]+\/SKILL\.md$/u.test(destination4(operation.detail))
14158
+ );
14159
+ if (instructionOperations.length > 0 || instructionRemovals.length > 0) {
13998
14160
  const instructionPath = ".deepagents/AGENTS.md";
13999
14161
  confined4(root, instructionPath);
14000
- const content = instructionOperations.sort((left, right) => left.id.localeCompare(right.id)).map((operation) => `## ${operation.id}
14001
-
14002
- ${operation.content.trim()}`).join("\n\n");
14003
- const first = instructionOperations[0];
14004
- mutations.push({
14005
- path: instructionPath,
14006
- kind: "write",
14007
- content: `<!-- portable-capabilities:owned dcode -->
14008
- ${content}
14009
- `,
14010
- mode: 420,
14011
- operationId: "dcode:shared-instructions",
14012
- sourceProjectionOperationId: first.sourceProjectionOperationId,
14013
- ownershipIntent: first.ownershipIntent,
14014
- approval: first.approval,
14015
- rollback: first.rollback,
14016
- upgrade: first.upgrade,
14017
- uninstall: first.uninstall
14162
+ const first = instructionOperations[0] ?? instructionRemovals[0];
14163
+ if (!first) throw new Error("DCode shared instruction operation is missing");
14164
+ const removedIds = instructionRemovals.flatMap((operation) => {
14165
+ const match = operation.detail.match(/^\.deepagents\/skills\/([^/]+)\/SKILL\.md$/u);
14166
+ return match?.[1] ? [match[1]] : [];
14018
14167
  });
14168
+ const content = await mergedInstructions(
14169
+ root,
14170
+ instructionPath,
14171
+ instructionOperations,
14172
+ removedIds
14173
+ );
14174
+ mutations.push(
14175
+ content ? {
14176
+ path: instructionPath,
14177
+ kind: "write",
14178
+ content,
14179
+ mode: 420,
14180
+ operationId: "dcode:shared-instructions",
14181
+ sourceProjectionOperationId: first.sourceProjectionOperationId,
14182
+ ownershipIntent: first.ownershipIntent,
14183
+ approval: first.approval,
14184
+ rollback: first.rollback,
14185
+ upgrade: first.upgrade,
14186
+ uninstall: first.uninstall
14187
+ } : { path: instructionPath, kind: "remove", ...metadata3(first) }
14188
+ );
14019
14189
  }
14020
14190
  return Object.freeze({
14021
14191
  runtimeId: plan.runtimeId,
@@ -14025,7 +14195,7 @@ ${content}
14025
14195
  });
14026
14196
  }
14027
14197
 
14028
- // packages/adapters/dcode/src/runtime-descriptor.ts
14198
+ // packages/adapters/src/dcode/runtime-descriptor.ts
14029
14199
  var markdown3 = "materialize-markdown";
14030
14200
  var source2 = "source-observed";
14031
14201
  var dcodeRuntimeDescriptor = {
@@ -14230,7 +14400,7 @@ var dcodeRuntimeDescriptor = {
14230
14400
  ]
14231
14401
  };
14232
14402
 
14233
- // packages/adapters/dcode/src/runtime-evidence.ts
14403
+ // packages/adapters/src/dcode/runtime-evidence.ts
14234
14404
  import { createHash as createHash12 } from "node:crypto";
14235
14405
  var digest5 = (value) => createHash12("sha256").update(value).digest("hex");
14236
14406
  var verifiedAt = "2026-08-10T00:00:00.000Z";
@@ -14413,7 +14583,7 @@ var dcodeRuntimeEvidence = Object.freeze([
14413
14583
  })
14414
14584
  ]);
14415
14585
 
14416
- // packages/adapters/oh-my-pi/src/materialize.ts
14586
+ // packages/adapters/src/oh-my-pi/materialize.ts
14417
14587
  import { resolve as resolve8 } from "node:path";
14418
14588
  var marker5 = "<!-- portable-capabilities:owned oh-my-pi -->";
14419
14589
  function resolveOhMyPiProfile(input) {
@@ -14471,13 +14641,13 @@ function diagnostic4(operation, kind, message) {
14471
14641
  }
14472
14642
  function render5(operation) {
14473
14643
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
14474
- return skill ? `---
14475
- name: ${skill[1]}
14476
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
14477
- ---
14478
- ${marker5}
14479
- ${operation.content}
14480
- ` : `${marker5}
14644
+ const name = skill?.[1];
14645
+ return name ? renderSkillDocument({
14646
+ name,
14647
+ description: operation.description,
14648
+ marker: marker5,
14649
+ content: operation.content
14650
+ }) : `${marker5}
14481
14651
  ${operation.content}`;
14482
14652
  }
14483
14653
  function registration4(operation) {
@@ -14586,7 +14756,7 @@ async function prepareOhMyPiMaterialization(plan, root, profile = { home: root }
14586
14756
  });
14587
14757
  }
14588
14758
 
14589
- // packages/adapters/oh-my-pi/src/runtime-descriptor.ts
14759
+ // packages/adapters/src/oh-my-pi/runtime-descriptor.ts
14590
14760
  var markdown4 = "materialize-markdown";
14591
14761
  var hooks = "oh-my-pi-code-as-hooks";
14592
14762
  var config2 = "patch-structured-config";
@@ -14834,7 +15004,7 @@ var ohMyPiRuntimeDescriptor = {
14834
15004
  ]
14835
15005
  };
14836
15006
 
14837
- // packages/adapters/oh-my-pi/src/runtime-evidence.ts
15007
+ // packages/adapters/src/oh-my-pi/runtime-evidence.ts
14838
15008
  import { createHash as createHash13 } from "node:crypto";
14839
15009
  var digest6 = (value) => createHash13("sha256").update(value).digest("hex");
14840
15010
  var verifiedAt2 = "2026-08-10T00:00:00.000Z";
@@ -14984,7 +15154,7 @@ var ohMyPiRuntimeEvidence = [
14984
15154
  }
14985
15155
  ];
14986
15156
 
14987
- // packages/adapters/opencode/src/materialize.ts
15157
+ // packages/adapters/src/opencode/materialize.ts
14988
15158
  import { resolve as resolve9 } from "node:path";
14989
15159
  var marker6 = "<!-- portable-capabilities:owned opencode -->";
14990
15160
  function destination5(value) {
@@ -15021,15 +15191,15 @@ function diagnostic5(operation, kind, message) {
15021
15191
  }
15022
15192
  function render6(operation) {
15023
15193
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
15024
- if (!skill) return `${marker6}
15194
+ const name = skill?.[1];
15195
+ if (!name) return `${marker6}
15025
15196
  ${operation.content}`;
15026
- return `---
15027
- name: ${skill[1]}
15028
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
15029
- ---
15030
- ${marker6}
15031
- ${operation.content}
15032
- `;
15197
+ return renderSkillDocument({
15198
+ name,
15199
+ description: operation.description,
15200
+ marker: marker6,
15201
+ content: operation.content
15202
+ });
15033
15203
  }
15034
15204
  function config3(operation, root, path9) {
15035
15205
  if (operation.format !== "json")
@@ -15137,7 +15307,7 @@ async function prepareOpencodeMaterialization(plan, root) {
15137
15307
  });
15138
15308
  }
15139
15309
 
15140
- // packages/adapters/opencode/src/runtime-descriptor.ts
15310
+ // packages/adapters/src/opencode/runtime-descriptor.ts
15141
15311
  var native = "opencode.stable";
15142
15312
  var beta = "opencode.v2-beta";
15143
15313
  var opencodeRuntimeDescriptor = {
@@ -15419,7 +15589,7 @@ var opencodeRuntimeDescriptor = {
15419
15589
  ]
15420
15590
  };
15421
15591
 
15422
- // packages/adapters/opencode/src/runtime-evidence.ts
15592
+ // packages/adapters/src/opencode/runtime-evidence.ts
15423
15593
  import { createHash as createHash14 } from "node:crypto";
15424
15594
  var retrievedAt3 = "2026-08-10T00:00:00.000Z";
15425
15595
  var docs2 = "docs/RFC/runtime-capability-profiles-revised.md";
@@ -15503,14 +15673,14 @@ var sourceClaims = [
15503
15673
  "discovery",
15504
15674
  "stable skill discovery",
15505
15675
  "OpenCode discovers native project and user skills.",
15506
- "runtime-observed"
15676
+ "source-observed"
15507
15677
  ],
15508
15678
  [
15509
15679
  "invocation.skills",
15510
15680
  "invocation",
15511
15681
  "stable skill invocation",
15512
15682
  "OpenCode invokes a discovered skill through its native skill tool.",
15513
- "runtime-observed"
15683
+ "source-observed"
15514
15684
  ],
15515
15685
  [
15516
15686
  "discovery.agents",
@@ -15648,7 +15818,7 @@ var opencodeRuntimeEvidence = Object.freeze([
15648
15818
  ...betaClaims
15649
15819
  ]);
15650
15820
 
15651
- // packages/adapters/pi/src/materialize.ts
15821
+ // packages/adapters/src/pi/materialize.ts
15652
15822
  import { resolve as resolve10 } from "node:path";
15653
15823
  var marker7 = "<!-- portable-capabilities:owned pi -->";
15654
15824
  function destination6(value) {
@@ -15669,15 +15839,15 @@ function confined7(root, path9) {
15669
15839
  }
15670
15840
  function render7(operation) {
15671
15841
  const skill = operation.destination.match(/skills\/skill\/([^/]+)$/);
15672
- if (!skill) return `${marker7}
15842
+ const name = skill?.[1];
15843
+ if (!name) return `${marker7}
15673
15844
  ${operation.content}`;
15674
- return `---
15675
- name: ${skill[1]}
15676
- description: ${operation.content.replace(/[\r\n]+/g, " ").trim()}
15677
- ---
15678
- ${marker7}
15679
- ${operation.content}
15680
- `;
15845
+ return renderSkillDocument({
15846
+ name,
15847
+ description: operation.description,
15848
+ marker: marker7,
15849
+ content: operation.content
15850
+ });
15681
15851
  }
15682
15852
  function transform2(operation) {
15683
15853
  if (operation.format !== "json")
@@ -15741,7 +15911,7 @@ function preparePiMaterialization(plan, root, ..._options) {
15741
15911
  });
15742
15912
  }
15743
15913
 
15744
- // packages/adapters/pi/src/runtime-descriptor.ts
15914
+ // packages/adapters/src/pi/runtime-descriptor.ts
15745
15915
  var piRuntimeDescriptor = {
15746
15916
  schemaVersion: "1.0",
15747
15917
  id: "pi",
@@ -15819,7 +15989,7 @@ var piRuntimeDescriptor = {
15819
15989
  ]
15820
15990
  };
15821
15991
 
15822
- // packages/adapters/pi/src/runtime-evidence.ts
15992
+ // packages/adapters/src/pi/runtime-evidence.ts
15823
15993
  import { createHash as createHash15 } from "node:crypto";
15824
15994
  var digest8 = (value) => createHash15("sha256").update(value).digest("hex");
15825
15995
  var observedAt2 = "2026-08-08T04:24:00-05:00";
@@ -15885,7 +16055,7 @@ var piRuntimeEvidence = [
15885
16055
  category: "discovery",
15886
16056
  subject: "native skill discovery",
15887
16057
  assertion: "Pi natively discovers a project skill with extensions disabled.",
15888
- versionRange: ">=0.64.0",
16058
+ versionRange: "=0.64.0",
15889
16059
  sourceType: "runtime-probe",
15890
16060
  source: "pi",
15891
16061
  sourceLocator: "packages/conformance/src/tracer/pi-native-evidence.json",
@@ -15903,7 +16073,7 @@ var piRuntimeEvidence = [
15903
16073
  category: "invocation",
15904
16074
  subject: "native skill invocation",
15905
16075
  assertion: "Pi invokes a discovered project skill with extensions disabled.",
15906
- versionRange: ">=0.64.0",
16076
+ versionRange: "=0.64.0",
15907
16077
  sourceType: "runtime-probe",
15908
16078
  source: "pi",
15909
16079
  sourceLocator: "packages/conformance/src/tracer/pi-native-evidence.json",
@@ -16027,7 +16197,7 @@ function normalizeSetupRequest(input) {
16027
16197
  // packages/cli/src/setup/service.ts
16028
16198
  import { createHash as createHash16 } from "node:crypto";
16029
16199
  import { existsSync as existsSync2 } from "node:fs";
16030
- import { readdir as readdir4, readFile as readFile5 } from "node:fs/promises";
16200
+ import { readdir as readdir4, readFile as readFile6 } from "node:fs/promises";
16031
16201
  import { dirname as dirname5, isAbsolute as isAbsolute3, relative as relative4, resolve as resolve12 } from "node:path";
16032
16202
  import { fileURLToPath as fileURLToPath4 } from "node:url";
16033
16203
  import { parse as parse3 } from "yaml";
@@ -16089,7 +16259,7 @@ async function loadCanonicalArtifact(catalogRoot, capabilityId) {
16089
16259
  if (!capabilityId || /[\\/]/u.test(capabilityId))
16090
16260
  throw new Error("capability IDs must be single path segments");
16091
16261
  const file = resolve12(catalogRoot, "roles", `${capabilityId}.yaml`);
16092
- const role = parse3(await readFile5(file, "utf8"));
16262
+ const role = parse3(await readFile6(file, "utf8"));
16093
16263
  if (role.schemaVersion !== "1.0" || role.id !== capabilityId || !role.purpose || !Array.isArray(role.inputs) || !role.output || !role.family || !role.taxonomy || !Array.isArray(role.precedence) || !Array.isArray(role.requiredBehavior) || !Array.isArray(role.forbiddenBehavior) || !Array.isArray(role.evaluation?.criteria)) {
16094
16264
  throw new Error(`Invalid canonical capability: ${file}`);
16095
16265
  }
@@ -16098,7 +16268,7 @@ async function loadCanonicalArtifact(catalogRoot, capabilityId) {
16098
16268
  const schemaRelativePath = relative4(resolve12(catalogRoot), schemaFile);
16099
16269
  if (isAbsolute3(schemaRelativePath) || schemaRelativePath.startsWith(".."))
16100
16270
  throw new Error(`Canonical output schema escapes catalog: ${role.output.schema}`);
16101
- const schemaContent = await readFile5(schemaFile, "utf8");
16271
+ const schemaContent = await readFile6(schemaFile, "utf8");
16102
16272
  const contract = operationalContract(role);
16103
16273
  const contractContent = `${JSON.stringify(
16104
16274
  { ...role, output: { ...role.output, schema: "resources/output.schema.json" } },
@@ -16182,6 +16352,27 @@ function renderVerifiedUsage(preview, descriptor, claims, runtimeVersion) {
16182
16352
  return verified ? `${descriptor.id}: ${surface.invocation}` : `${descriptor.id}: native usage unavailable; use manual guidance`;
16183
16353
  });
16184
16354
  }
16355
+ function composeInstallationPlan(previews, artifacts, runtimeId) {
16356
+ const first = previews[0]?.installationPlan;
16357
+ if (!first) throw new Error("at least one installation plan is required");
16358
+ const operations = previews.flatMap((preview, index) => {
16359
+ const capabilityId = artifacts[index]?.id;
16360
+ if (!capabilityId) throw new Error("installation plan is missing its capability");
16361
+ return preview.installationPlan.operations.map((operation) => ({
16362
+ ...operation,
16363
+ id: `${capabilityId}:${operation.id}`,
16364
+ sourceProjectionOperationId: `${capabilityId}:${operation.sourceProjectionOperationId}`
16365
+ }));
16366
+ });
16367
+ const base = {
16368
+ schemaVersion: first.schemaVersion,
16369
+ id: `installation:${runtimeId}:${artifacts.map((artifact) => artifact.id).join(",")}`,
16370
+ runtimeId,
16371
+ scope: first.scope,
16372
+ operations
16373
+ };
16374
+ return { ...base, digest: stableDigest(base) };
16375
+ }
16185
16376
  function defaultCatalogRoot() {
16186
16377
  const moduleDir = dirname5(fileURLToPath4(import.meta.url));
16187
16378
  const packagedCatalog = [resolve12(moduleDir, "catalog"), resolve12(moduleDir, "../catalog")].find(
@@ -16240,30 +16431,41 @@ async function executeSetupSelection(request, artifacts, descriptor, claims, con
16240
16431
  ...context.faultInjector ? { faultInjector: context.faultInjector } : {}
16241
16432
  };
16242
16433
  const runtime = resolveProductionRuntime(executionRequest.runtimeId);
16243
- const lifecycle = executionRequest.intent === "setup" || executionRequest.intent === "update" ? await executePreparedInstallation({
16244
- ...lifecycleOptions,
16245
- preparedOperation: executionRequest.intent === "update" ? "upgrade" : "install",
16246
- preparedMutations: (await Promise.all(
16247
- previews.map((preview) => runtime.prepare(preview.installationPlan, targetRoot))
16248
- )).flatMap((prepared) => prepared.mutations)
16249
- }) : executionRequest.intent === "remove" ? await removeInstallation(
16250
- targetRoot,
16251
- context.faultInjector,
16252
- executionRequest.capabilityIds
16253
- ) : await statusInstallation(targetRoot);
16434
+ const lifecycle = executionRequest.intent === "setup" || executionRequest.intent === "update" || executionRequest.intent === "remove" ? await (async () => {
16435
+ const installationPlan = composeInstallationPlan(
16436
+ previews,
16437
+ planningArtifacts,
16438
+ executionRequest.runtimeId
16439
+ );
16440
+ const prepared = await runtime.prepare(installationPlan, targetRoot);
16441
+ if (prepared.runtimeId !== installationPlan.runtimeId || prepared.planId !== installationPlan.id) {
16442
+ throw new Error(`Materializer returned an invalid ${executionRequest.runtimeId} plan`);
16443
+ }
16444
+ const duplicatePath = prepared.mutations.map((mutation) => mutation.path).find((path9, index, paths) => paths.indexOf(path9) !== index);
16445
+ if (duplicatePath)
16446
+ throw new Error(`Selection produced duplicate prepared path: ${duplicatePath}`);
16447
+ return executePreparedInstallation({
16448
+ ...lifecycleOptions,
16449
+ preparedOperation: executionRequest.intent === "update" ? "upgrade" : executionRequest.intent === "remove" ? "remove" : "install",
16450
+ preparedMutations: prepared.mutations,
16451
+ ...prepared.diagnostics ? {
16452
+ preparedDiagnostics: prepared.diagnostics.map(
16453
+ (diagnostic6) => `${diagnostic6.kind}: ${diagnostic6.message}`
16454
+ )
16455
+ } : {}
16456
+ });
16457
+ })() : await statusInstallation(targetRoot);
16254
16458
  return { request, previews, lifecycle };
16255
16459
  }
16256
16460
  async function executeSetupLifecycle(request, artifact, descriptor, claims, context) {
16257
16461
  const result2 = await executeSetupSelection(request, [artifact], descriptor, claims, context);
16258
16462
  const preview = result2.previews[0];
16463
+ if (!preview) throw new Error("at least one capability is required");
16259
16464
  if (!result2.lifecycle)
16260
16465
  throw new Error("approval required; rerun with approvalPolicy=preapproved");
16261
16466
  return { request, preview, lifecycle: result2.lifecycle };
16262
16467
  }
16263
16468
 
16264
- // packages/cli/src/wizard.ts
16265
- import { execFileSync } from "node:child_process";
16266
-
16267
16469
  // node_modules/.pnpm/@clack+core@1.4.3/node_modules/@clack/core/dist/index.mjs
16268
16470
  import { styleText } from "node:util";
16269
16471
  import { stdout, stdin } from "node:process";
@@ -17471,6 +17673,73 @@ ${r2}
17471
17673
  }
17472
17674
  }).prompt();
17473
17675
 
17676
+ // packages/cli/src/setup/probe.ts
17677
+ import { execFileSync } from "node:child_process";
17678
+ var executables = Object.freeze({
17679
+ antigravity: "agy",
17680
+ "claude-code": "claude",
17681
+ codex: "codex",
17682
+ dcode: "dcode",
17683
+ "oh-my-pi": "omp",
17684
+ opencode: "opencode",
17685
+ pi: "pi"
17686
+ });
17687
+ function resolveRuntimeProbe(runtimeId) {
17688
+ const runtime = resolveProductionRuntime(runtimeId);
17689
+ const canonicalId = runtime.descriptor.id;
17690
+ const executable = executables[canonicalId];
17691
+ if (!executable) throw new Error(`No runtime probe configured for ${canonicalId}`);
17692
+ return {
17693
+ runtimeId: canonicalId,
17694
+ executable,
17695
+ args: ["--version"],
17696
+ supportedVersions: runtime.descriptor.supportedVersions
17697
+ };
17698
+ }
17699
+ function parseVersion2(output) {
17700
+ return output.match(/\bv?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\b/u)?.[1];
17701
+ }
17702
+ function defaultRun(probe) {
17703
+ return execFileSync(probe.executable, probe.args, {
17704
+ encoding: "utf8",
17705
+ stdio: ["ignore", "pipe", "pipe"],
17706
+ timeout: 5e3
17707
+ });
17708
+ }
17709
+ function probeRuntimeVersion(runtimeId, options = {}) {
17710
+ const probe = resolveRuntimeProbe(runtimeId);
17711
+ let output;
17712
+ try {
17713
+ output = (options.run ?? defaultRun)(probe);
17714
+ } catch (error) {
17715
+ const code = error.code;
17716
+ const unavailable = code === "ENOENT" || code === "EACCES";
17717
+ return {
17718
+ status: unavailable ? "unavailable" : "failed",
17719
+ runtimeId: probe.runtimeId,
17720
+ executable: probe.executable,
17721
+ reason: unavailable ? `${probe.executable} is not installed or is not executable` : error instanceof Error ? error.message : String(error)
17722
+ };
17723
+ }
17724
+ const version = parseVersion2(output);
17725
+ if (!version)
17726
+ return {
17727
+ status: "unknown-version",
17728
+ runtimeId: probe.runtimeId,
17729
+ executable: probe.executable,
17730
+ reason: "version probe returned no parseable semantic version"
17731
+ };
17732
+ if (!probe.supportedVersions.some((range) => isRuntimeVersionInRange(range, version)))
17733
+ return {
17734
+ status: "unsupported-version",
17735
+ runtimeId: probe.runtimeId,
17736
+ executable: probe.executable,
17737
+ version,
17738
+ reason: `version ${version} is outside the supported runtime ranges`
17739
+ };
17740
+ return { status: "detected", runtimeId: probe.runtimeId, executable: probe.executable, version };
17741
+ }
17742
+
17474
17743
  // packages/cli/src/wizard.ts
17475
17744
  var supportedRuntimes = [...productionRuntimeRegistry.keys()];
17476
17745
  function unwrap(value) {
@@ -17481,17 +17750,6 @@ function unwrap(value) {
17481
17750
  }
17482
17751
  return value;
17483
17752
  }
17484
- function detectRuntimeVersion(runtime) {
17485
- try {
17486
- const output = execFileSync(runtime, ["--version"], {
17487
- encoding: "utf8",
17488
- stdio: ["ignore", "pipe", "pipe"]
17489
- });
17490
- return output.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0] ?? "unknown";
17491
- } catch {
17492
- return "unknown";
17493
- }
17494
- }
17495
17753
  async function runInstallWizard() {
17496
17754
  intro("Portable Capabilities setup");
17497
17755
  try {
@@ -17511,6 +17769,12 @@ async function runInstallWizard() {
17511
17769
  options: supportedRuntimes.map((value) => ({ value, label: value }))
17512
17770
  })
17513
17771
  );
17772
+ const probe = probeRuntimeVersion(runtime);
17773
+ if (probe.status !== "detected" || !probe.version) {
17774
+ log.error(`${runtime}: ${probe.reason ?? probe.status}`);
17775
+ process.exitCode = 4;
17776
+ return;
17777
+ }
17514
17778
  const target = String(
17515
17779
  unwrap(
17516
17780
  await text({
@@ -17528,7 +17792,7 @@ async function runInstallWizard() {
17528
17792
  );
17529
17793
  const request = normalizeSetupRequest({
17530
17794
  runtimeId: runtime,
17531
- runtimeVersion: detectRuntimeVersion(runtime),
17795
+ runtimeVersion: probe.version,
17532
17796
  scope: "project",
17533
17797
  projectDirectory: target,
17534
17798
  capabilityIds,
@@ -17550,7 +17814,7 @@ async function runInstallWizard() {
17550
17814
  runtimeEntry.claims,
17551
17815
  { sourceRoot: process.cwd(), packageVersion: cliVersion }
17552
17816
  );
17553
- if (!result2.lifecycle || !result2.lifecycle.ok) {
17817
+ if (!result2.lifecycle?.ok) {
17554
17818
  for (const diagnostic6 of result2.lifecycle?.diagnostics ?? ["Approval required."])
17555
17819
  log.error(diagnostic6);
17556
17820
  process.exitCode = 4;
@@ -17755,11 +18019,13 @@ export {
17755
18019
  normalizeSetupRequest,
17756
18020
  persistInvocation,
17757
18021
  previewSetup,
18022
+ probeRuntimeVersion,
17758
18023
  productionRuntimeRegistry,
17759
18024
  recoverInstallation,
17760
18025
  removeInstallation,
17761
18026
  renderVerifiedUsage,
17762
18027
  resolveProductionRuntime,
18028
+ resolveRuntimeProbe,
17763
18029
  statusInstallation,
17764
18030
  structuredLog,
17765
18031
  upgradePackage,