holycodex 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,8 +21,11 @@ bunx holycodex remove
21
21
 
22
22
  `--plan` selects routing only. `--tier` is independent and controls service
23
23
  handling without changing routes or authority. Optional selections are
24
- `--work`, `--frontend`, `--security`, and `--computer-use`; unavailable
25
- selections fail closed. `--json` emits one machine-readable result.
24
+ `--work`, `--frontend`, `--security`, and `--computer-use`; explicit
25
+ selections and additional plugins fail closed when unavailable. Omitted
26
+ Frontend and Security defaults may be recorded as missing or uncertain on a
27
+ first install and retried on reinstall. `--json` emits one machine-readable
28
+ result.
26
29
 
27
30
  The development entry point is:
28
31
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "Root-directed capabilities and deterministic installed assets for HolyCodex.",
5
5
  "author": {
6
6
  "name": "David Basile Filho",
package/dist/index.js CHANGED
@@ -21548,8 +21548,10 @@ async function installHolyCodex(request = {}, options = {}, environment = proces
21548
21548
  const plan = choosePlan(request.plan, previous?.plan);
21549
21549
  const tier = chooseTier(request.tier, previous?.tier);
21550
21550
  const optional = chooseOptional(request.optional, previous?.optional_selections);
21551
- const explicitOptional = request.optional ?? previous?.explicit_optional_selections ?? {};
21552
- const providerPlugins = pluginIdsForOptionalCapabilities(toCoreSelections(optional), request.officialPlugins ?? previous?.official_plugins ?? []);
21551
+ const explicitOptional = mergeExplicitOptionalSelections(previous?.explicit_optional_selections, request.optional);
21552
+ const explicitAdditionalPlugins = new Set(request.officialPlugins ?? []);
21553
+ const additionalPlugins = request.officialPlugins ?? additionalPluginsFromPrevious(previous);
21554
+ const providerPlugins = pluginIdsForOptionalCapabilities(toCoreSelections(optional), additionalPlugins);
21553
21555
  let manager;
21554
21556
  try {
21555
21557
  manager = options.officialPluginManager ?? await CodexOfficialPluginManager.discover({
@@ -21560,12 +21562,33 @@ async function installHolyCodex(request = {}, options = {}, environment = proces
21560
21562
  throw new InstallerError("capability_denied", "Native Codex plugin installation is unavailable.", error, { recovery: "Install or expose Codex, then retry." });
21561
21563
  }
21562
21564
  if (!manager.addMarketplace || !manager.add || !manager.list) throw new InstallerError("install_failed", "Native Codex plugin installation and verification are unavailable.");
21565
+ let nativeCapabilityFailures = /* @__PURE__ */ new Map();
21566
+ let nativeWarnings = [];
21563
21567
  try {
21564
21568
  await manager.addMarketplace(HOLYCODEX_MARKETPLACE);
21565
- await installAndVerify({
21569
+ const nativeManager = {
21566
21570
  list: () => manager.list(),
21567
21571
  add: (id) => manager.add(id)
21568
- }, [HOLYCODEX_PLUGIN, ...providerPlugins]);
21572
+ };
21573
+ await installAndVerify(nativeManager, [HOLYCODEX_PLUGIN]);
21574
+ const unavailable = /* @__PURE__ */ new Map();
21575
+ const warnings = [];
21576
+ for (const pluginId of providerPlugins) {
21577
+ const capability = optionalCapabilityForPlugin(pluginId);
21578
+ const canFailOpen = capability !== void 0 && isImplicitDefault(capability, optional, explicitOptional) && !explicitAdditionalPlugins.has(pluginId);
21579
+ try {
21580
+ await installAndVerify(nativeManager, [pluginId]);
21581
+ } catch (error) {
21582
+ if (!canFailOpen) throw error;
21583
+ const status = capabilityFailureStatus(error);
21584
+ if (status === void 0) throw error;
21585
+ const previousStatus = unavailable.get(capability);
21586
+ unavailable.set(capability, previousStatus === "uncertain" || status === "uncertain" ? "uncertain" : status);
21587
+ warnings.push(`optional capability ${capability} unavailable; skipped plugin ${pluginId} (${status})`);
21588
+ }
21589
+ }
21590
+ nativeCapabilityFailures = unavailable;
21591
+ nativeWarnings = warnings;
21569
21592
  } catch (error) {
21570
21593
  throw new InstallerError("capability_denied", `Codex native plugin installation did not converge: ${safeMessage$1(error)}`, error, { recovery: "Retry install; Codex owns plugin installation state." });
21571
21594
  }
@@ -21577,7 +21600,7 @@ async function installHolyCodex(request = {}, options = {}, environment = proces
21577
21600
  if (error instanceof PathBoundaryError) throw error;
21578
21601
  throw new InstallerError("install_failed", safeMessage$1(error), error);
21579
21602
  }
21580
- const capabilityState = capabilityStateFor(optional);
21603
+ const capabilityState = capabilityStateFor(optional, nativeCapabilityFailures);
21581
21604
  const version = await readCanonicalBaseVersion();
21582
21605
  const installedAt = (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
21583
21606
  const digest = await installRecordDigest({
@@ -21613,7 +21636,7 @@ async function installHolyCodex(request = {}, options = {}, environment = proces
21613
21636
  record,
21614
21637
  optional_plugins: providerPlugins,
21615
21638
  preserved: native.preserved,
21616
- warnings: native.preserved.length === 0 ? [] : ["modified managed files were preserved"]
21639
+ warnings: [...nativeWarnings, ...native.preserved.length === 0 ? [] : ["modified managed files were preserved"]]
21617
21640
  };
21618
21641
  }
21619
21642
  async function readActiveInstallRecord(paths) {
@@ -21627,14 +21650,64 @@ function toCoreSelections(value) {
21627
21650
  security: value.security
21628
21651
  };
21629
21652
  }
21653
+ function mergeExplicitOptionalSelections(previous, requested) {
21654
+ const merged = {};
21655
+ for (const name of [
21656
+ "computer_use",
21657
+ "work",
21658
+ "frontend",
21659
+ "security"
21660
+ ]) {
21661
+ const value = requested?.[name] ?? previous?.[name];
21662
+ if (value !== void 0) merged[name] = value;
21663
+ }
21664
+ return merged;
21665
+ }
21666
+ function optionalCapabilityForPlugin(pluginId) {
21667
+ return [
21668
+ "computer_use",
21669
+ "work",
21670
+ "frontend",
21671
+ "security"
21672
+ ].find((name) => CAPABILITY_REGISTRY[name].pluginIds.includes(pluginId));
21673
+ }
21674
+ function additionalPluginsFromPrevious(previous) {
21675
+ return (previous?.official_plugins ?? []).filter((pluginId) => {
21676
+ const capability = optionalCapabilityForPlugin(pluginId);
21677
+ return capability === void 0 || previous?.optional_selections[capability] !== true;
21678
+ });
21679
+ }
21680
+ function isImplicitDefault(name, selections, explicit) {
21681
+ return (name === "frontend" || name === "security") && selections[name] && explicit[name] === void 0;
21682
+ }
21683
+ function capabilityFailureStatus(error) {
21684
+ if (error instanceof PluginVerificationError && error.status === "missing") return "missing";
21685
+ if (error instanceof OfficialPluginManagerError && error.code === "plugin_missing") return "missing";
21686
+ if (error instanceof PluginVerificationError) return "uncertain";
21687
+ if (error instanceof OfficialPluginManagerError) return "uncertain";
21688
+ }
21630
21689
  async function installAndVerify(manager, ids) {
21631
21690
  for (const id of ids) {
21632
21691
  const before = findPlugin(await manager.list(), id);
21633
- if (!(before?.installed && before.enabled)) await manager.add(id);
21692
+ if (!(before?.installed && before.enabled)) try {
21693
+ await manager.add(id);
21694
+ } catch (error) {
21695
+ if (error instanceof OfficialPluginManagerError || error instanceof PluginVerificationError) throw error;
21696
+ throw new PluginVerificationError("uncertain", `${id} could not be added`);
21697
+ }
21634
21698
  const after = findPlugin(await manager.list(), id);
21635
- if (!after?.installed || !after.enabled) throw new Error(`${id} is ${after?.installed ? "disabled" : "not installed"} after add`);
21699
+ if (!after?.installed) throw new PluginVerificationError("missing", `${id} is not installed after add`);
21700
+ if (!after.enabled) throw new PluginVerificationError("uncertain", `${id} is disabled after add`);
21636
21701
  }
21637
21702
  }
21703
+ var PluginVerificationError = class extends Error {
21704
+ status;
21705
+ constructor(status, message) {
21706
+ super(message);
21707
+ this.name = "PluginVerificationError";
21708
+ this.status = status;
21709
+ }
21710
+ };
21638
21711
  function findPlugin(live, id) {
21639
21712
  return [...live.installed, ...live.available].find((entry) => entry.pluginId === id);
21640
21713
  }
@@ -21664,7 +21737,7 @@ function chooseOptional(requested, previous) {
21664
21737
  coding: true
21665
21738
  };
21666
21739
  }
21667
- function capabilityStateFor(selections) {
21740
+ function capabilityStateFor(selections, failures = /* @__PURE__ */ new Map()) {
21668
21741
  return Object.fromEntries([
21669
21742
  "computer_use",
21670
21743
  "work",
@@ -21674,7 +21747,7 @@ function capabilityStateFor(selections) {
21674
21747
  const selected = selections[name];
21675
21748
  return [name, {
21676
21749
  selected,
21677
- status: selected ? "healthy" : "disabled",
21750
+ status: selected ? failures.get(name) ?? "healthy" : "disabled",
21678
21751
  plugin_ids: [...CAPABILITY_REGISTRY[name].pluginIds]
21679
21752
  }];
21680
21753
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "bin": {
5
5
  "holycodex": "./dist/index.js"
6
6
  },
@@ -22,6 +22,6 @@
22
22
  "release": {
23
23
  "schemaVersion": "holycodex-release-v1",
24
24
  "channel": "stable",
25
- "sourceSha": "e7bc6a8fffeb71e74f321f90a2e0af2d482ea86e"
25
+ "sourceSha": "5d207d8c2784ea36e9ca9761fa82e619f39aaf39"
26
26
  }
27
27
  }