@wairon/cli 5.1.1-dev.70 → 5.1.1-dev.72

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/dist/index.js CHANGED
@@ -3539,11 +3539,7 @@ __export(src_exports, {
3539
3539
  defaultNarrativeDetail: () => defaultNarrativeDetail,
3540
3540
  defaultPackSelections: () => defaultPackSelections,
3541
3541
  defaultTargetConfig: () => defaultTargetConfig,
3542
- deleteComponentSpec: () => deleteComponentSpec,
3543
- deleteImplementationSpec: () => deleteImplementationSpec,
3544
- deleteInterfaceSpec: () => deleteInterfaceSpec,
3545
- deleteSubsystemSpec: () => deleteSubsystemSpec,
3546
- deleteTypeSpec: () => deleteTypeSpec,
3542
+ deleteSpec: () => deleteSpec,
3547
3543
  deregisterPackRef: () => deregisterPackRef,
3548
3544
  deriveExecutionProfile: () => deriveExecutionProfile,
3549
3545
  derivedDocPaths: () => derivedDocPaths,
@@ -3612,6 +3608,7 @@ __export(src_exports, {
3612
3608
  loadProjectConfig: () => loadProjectConfig4,
3613
3609
  loadProjectExtensions: () => loadProjectExtensions,
3614
3610
  loadRegistry: () => loadRegistry,
3611
+ loadSpec: () => loadSpec,
3615
3612
  loadSpecGraph: () => loadSpecGraph,
3616
3613
  loadSubsystemSpec: () => loadSubsystemSpec,
3617
3614
  loadSubsystemSpecs: () => loadSubsystemSpecs,
@@ -3670,13 +3667,8 @@ __export(src_exports, {
3670
3667
  runWithProjectBinding: () => runWithProjectBinding,
3671
3668
  runWithProjectRoot: () => runWithProjectRoot,
3672
3669
  sameContract: () => sameContract,
3673
- saveComponentSpec: () => saveComponentSpec,
3674
- saveImplementationSpec: () => saveImplementationSpec,
3675
- saveInterfaceSpec: () => saveInterfaceSpec,
3676
- saveSubsystemSpec: () => saveSubsystemSpec,
3677
- saveSystemSpec: () => saveSystemSpec,
3670
+ saveSpec: () => saveSpec,
3678
3671
  saveTopologyConfig: () => saveTopologyConfig,
3679
- saveTypeSpec: () => saveTypeSpec,
3680
3672
  serializeYaml: () => serializeYaml,
3681
3673
  setExecutionTier: () => setExecutionTier,
3682
3674
  setLogLevel: () => setLogLevel,
@@ -5203,7 +5195,13 @@ var PublicInterfaceSchema = import_zod8.z.object({
5203
5195
  /** The L2 component that realizes this public interface (the subsystem's published surface). */
5204
5196
  component: SpecIdSchema.optional(),
5205
5197
  /** Optional L3 interface on that component backing this entry. */
5206
- interface: SpecIdSchema.optional()
5198
+ interface: SpecIdSchema.optional(),
5199
+ /**
5200
+ * The subsystems this surface is published to. Absent, anyone may depend on
5201
+ * it; present, only these subsystems may — when every entry publishing the
5202
+ * component names consumers, the union of those lists is the whole set.
5203
+ */
5204
+ consumers: import_zod8.z.array(SpecIdSchema).optional()
5207
5205
  });
5208
5206
  var TrustedLinkSchema = import_zod8.z.object({
5209
5207
  /** The peer subsystem id this link sanctions tight coupling with. */
@@ -11593,7 +11591,7 @@ function defaultTargetConfig(type) {
11593
11591
  enabled: true
11594
11592
  };
11595
11593
  }
11596
- var WAIRON_VERSION = "5.1.1-dev.70";
11594
+ var WAIRON_VERSION = "5.1.1-dev.72";
11597
11595
  var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
11598
11596
  var ARCHITECT_AGENT_ID = "agent-architect";
11599
11597
  var ARCHITECT_TEMPLATE_ID = "architect";
@@ -12776,6 +12774,32 @@ var publicSurfaceBindingRule = {
12776
12774
  }
12777
12775
  };
12778
12776
 
12777
+ // src/core/rules/integrity/public-surface-consumers.ts
12778
+ var publicSurfaceConsumersRule = {
12779
+ name: "public-surface-consumers",
12780
+ description: "Every subsystem a published surface names as its consumer must exist in the tree. A consumers list restricts who may depend on the surface, so an id that names nothing locks the surface against a caller nobody can be \u2014 and a typo there silently locks out the caller that was meant, which the boundary rule would then report against the wrong party.",
12781
+ codes: [
12782
+ { code: "PUBLIC_INTERFACE_UNKNOWN_CONSUMER", defaultSeverity: "error", summary: "A published surface names as its consumer a subsystem the tree does not have" }
12783
+ ],
12784
+ check(ctx) {
12785
+ const known = new Set(ctx.subsystems.map((s) => s.id));
12786
+ for (const sub of ctx.subsystems) {
12787
+ for (const pi of sub.publicInterfaces) {
12788
+ for (const consumer of pi.consumers ?? []) {
12789
+ if (known.has(consumer)) continue;
12790
+ ctx.addIssue(
12791
+ "error",
12792
+ "PUBLIC_INTERFACE_UNKNOWN_CONSUMER",
12793
+ `Subsystem "${sub.id}" publishes "${pi.component ?? `${pi.type} ${pi.details}`}" to consumer "${consumer}", which names no subsystem of this tree. Name an existing subsystem, or drop the id \u2014 a consumers list admits only the subsystems it names.`,
12794
+ sub.id,
12795
+ isDraftSubsystem(sub)
12796
+ );
12797
+ }
12798
+ }
12799
+ }
12800
+ }
12801
+ };
12802
+
12779
12803
  // src/core/rules/integrity/public-surface-declared-type.ts
12780
12804
  var pubTypeMatches = (piType, ct, portalType) => {
12781
12805
  switch (piType) {
@@ -14145,14 +14169,15 @@ var authSourceWiringRule = {
14145
14169
  // src/core/rules/doctrine/subsystem-boundary-dependencies.ts
14146
14170
  var subsystemBoundaryDepsRule = {
14147
14171
  name: "subsystem-boundary-dependencies",
14148
- description: "Judges every dependsOn edge that leaves its own subsystem, and every one that resolves nowhere. Across subsystems the shape is client Adapter \u2192 published remote Portal, OR a direct in-process edge licensed by a trustedLink declared on the SOURCE subsystem (the published-Portal target requirement applies either way). A reference that names nothing in this tree is resolved against the stored surface snapshots: a hit is a DECLARED remote portal and the same Adapter requirement applies to it, snapshots of several providers that disagree make the reference ambiguous, and a reference authored to leave this root that no snapshot covers warns instead of erroring. Boundary rules are never relaxed by a pack profile.",
14172
+ description: "Judges every dependsOn edge that leaves its own subsystem, and every one that resolves nowhere. Across subsystems the shape is client Adapter \u2192 published remote Portal, OR a direct in-process edge licensed by a trustedLink declared on the SOURCE subsystem (the published-Portal target requirement applies either way). A published surface may also name the subsystems it serves (a publicInterfaces entry's consumers): a component every one of whose entries names consumers may be depended on only from those subsystems, which is how a provider keeps a surface \u2014 the raw spec writes \u2014 away from a door that must not reach it. A reference that names nothing in this tree is resolved against the stored surface snapshots: a hit is a DECLARED remote portal and the same Adapter requirement applies to it, snapshots of several providers that disagree make the reference ambiguous, and a reference authored to leave this root that no snapshot covers warns instead of erroring. Boundary rules are never relaxed by a pack profile.",
14149
14173
  codes: [
14150
14174
  { code: "INVALID_DEPENDENCY_REFERENCE", defaultSeverity: "error", summary: "dependsOn names a non-existent component" },
14151
14175
  { code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree dependsOn (super::/:: form) with no surface snapshot covering it" },
14152
14176
  { code: "SURFACE_REF_AMBIGUOUS", defaultSeverity: "error", summary: "Cross-tree dependsOn matched by surface snapshots of several providers with different contracts" },
14153
14177
  { code: "CROSS_SUBSYSTEM_NON_ADAPTER", defaultSeverity: "error", summary: "Non-Adapter component crossing a subsystem boundary" },
14154
14178
  { code: "CROSS_SUBSYSTEM_PRIVATE_ACCESS", defaultSeverity: "error", summary: "Cross-subsystem dependency on an unpublished component" },
14155
- { code: "CROSS_SUBSYSTEM_TARGET_NON_PORTAL", defaultSeverity: "error", summary: "Cross-subsystem hop entering through a non-Portal" }
14179
+ { code: "CROSS_SUBSYSTEM_TARGET_NON_PORTAL", defaultSeverity: "error", summary: "Cross-subsystem hop entering through a non-Portal" },
14180
+ { code: "CROSS_SUBSYSTEM_UNLISTED_CONSUMER", defaultSeverity: "error", summary: "Cross-subsystem dependency on a surface published only to other subsystems" }
14156
14181
  ],
14157
14182
  check(ctx) {
14158
14183
  for (const edge of ctx.dependencyEdges().all) {
@@ -14235,9 +14260,24 @@ var subsystemBoundaryDepsRule = {
14235
14260
  edge.draftContext
14236
14261
  );
14237
14262
  }
14263
+ const publishedTo = restrictedConsumers(ctx, depComp.subsystem, depComp.id);
14264
+ if (publishedTo && !publishedTo.includes(comp.subsystem)) {
14265
+ ctx.addIssue(
14266
+ "error",
14267
+ "CROSS_SUBSYSTEM_UNLISTED_CONSUMER",
14268
+ `Boundary violation: "${comp.id}" (subsystem "${comp.subsystem}") depends on "${depComp.id}", which subsystem "${depComp.subsystem}" publishes only to ${publishedTo.map((s) => `"${s}"`).join(", ")}. Depend on a surface published to "${comp.subsystem}" instead, or \u2014 when "${comp.subsystem}" really is a caller the provider meant to serve \u2014 add it to the entry's consumers.`,
14269
+ comp.id,
14270
+ edge.draftContext
14271
+ );
14272
+ }
14238
14273
  }
14239
14274
  }
14240
14275
  };
14276
+ function restrictedConsumers(ctx, subsystemId, componentId) {
14277
+ const entries = (ctx.subsystems.find((s) => s.id === subsystemId)?.publicInterfaces ?? []).filter((pi) => pi.component === componentId);
14278
+ if (entries.length === 0 || entries.some((pi) => pi.consumers === void 0)) return null;
14279
+ return [...new Set(entries.flatMap((pi) => pi.consumers ?? []))];
14280
+ }
14241
14281
 
14242
14282
  // src/core/rules/doctrine/stereotype-terms.ts
14243
14283
  var NEVER_INLINE_STATE = " Never resolve this by merging the store's state into the consuming component \u2014 state hidden inside a logic block is invisible to the spec and unrecoverable.";
@@ -18730,10 +18770,11 @@ var SDD_RULES = [
18730
18770
  assertionForbiddenEdgesRule,
18731
18771
  assertionRequiredFieldsRule,
18732
18772
  assertionEndpointShapesRule,
18733
- // The published surface in three questions: what backs the entry, whether
18734
- // that component's stereotype can realize the type it declares, and whether
18735
- // the contract it binds is that component's own.
18773
+ // The published surface in four questions: what backs the entry, who it is
18774
+ // published to, whether that component's stereotype can realize the type it
18775
+ // declares, and whether the contract it binds is that component's own.
18736
18776
  publicSurfaceBindingRule,
18777
+ publicSurfaceConsumersRule,
18737
18778
  publicSurfaceDeclaredTypeRule,
18738
18779
  publicSurfaceBoundContractRule,
18739
18780
  cyclesRule,
@@ -21438,7 +21479,10 @@ function stripNamespaceFromSubsystem(spec, prefix) {
21438
21479
  publicInterfaces: spec.publicInterfaces.map((pi) => ({
21439
21480
  ...pi,
21440
21481
  component: pi.component ? relMember(pi.component) : void 0,
21441
- interface: pi.interface ? relMember(pi.interface) : void 0
21482
+ interface: pi.interface ? relMember(pi.interface) : void 0,
21483
+ // consumers name SUBSYSTEMS — peers of this one, so they are relative to
21484
+ // the namespace the subsystem itself is declared in, never its members'.
21485
+ ...pi.consumers ? { consumers: pi.consumers.map((c) => c.includes("::") ? relativizeId(c, prefix) : c) } : {}
21442
21486
  })),
21443
21487
  lifecycle: spec.lifecycle?.map((le) => ({
21444
21488
  ...le,
@@ -21663,6 +21707,8 @@ function identityKeyOf(field, item) {
21663
21707
  const o = item;
21664
21708
  const str = (v) => typeof v === "string" && v.length > 0 ? v : null;
21665
21709
  switch (field) {
21710
+ case "publicInterfaces":
21711
+ return publicInterfaceKey(o);
21666
21712
  case "dispatch":
21667
21713
  return str(o.capability);
21668
21714
  // A listener mounts each portal once, so the portal IS the mount's identity.
@@ -21708,6 +21754,13 @@ function identityKeyOf(field, item) {
21708
21754
  return str(o.name) ?? str(o.id);
21709
21755
  }
21710
21756
  }
21757
+ function publicInterfaceKey(o) {
21758
+ const str = (v) => typeof v === "string" && v.length > 0 ? v : null;
21759
+ const component = str(o.component);
21760
+ if (component) return str(o.interface) ? `${component}.${String(o.interface)}` : component;
21761
+ if (typeof o.type === "string" && typeof o.details === "string") return `${o.type} ${o.details}`;
21762
+ return null;
21763
+ }
21711
21764
  function reportIdentityOf(field, item) {
21712
21765
  if (item !== null && typeof item === "object") {
21713
21766
  const step = item.stepNumber;
@@ -21769,6 +21822,9 @@ function identityFieldsOf(field) {
21769
21822
  switch (field) {
21770
21823
  case "dispatch":
21771
21824
  return ["capability"];
21825
+ // Bound: component + interface; not yet bound: type + details.
21826
+ case "publicInterfaces":
21827
+ return ["component", "interface", "type", "details"];
21772
21828
  case "lifecycle":
21773
21829
  return ["phase", "component", "method"];
21774
21830
  case "emits":
@@ -22034,7 +22090,10 @@ var SpecWorkspace = class {
22034
22090
  publicInterfaces: sub.publicInterfaces.map((p) => ({
22035
22091
  ...p,
22036
22092
  component: p.component ? qualifyId(p.component, componentPrefix, this.rootSubsystems) : void 0,
22037
- interface: p.interface ? qualifyId(p.interface, componentPrefix, this.rootSubsystems) : void 0
22093
+ interface: p.interface ? qualifyId(p.interface, componentPrefix, this.rootSubsystems) : void 0,
22094
+ // Each consumer is a subsystem reference: qualified into the namespace
22095
+ // this subsystem is declared in, like a component's `subsystem` field.
22096
+ ...p.consumers ? { consumers: p.consumers.map((c) => qualifySubsystemRef(c, namespacePrefix, this.rootSubsystems)) } : {}
22038
22097
  })),
22039
22098
  lifecycle: sub.lifecycle?.map((le) => ({
22040
22099
  ...le,
@@ -22934,6 +22993,76 @@ var SpecWorkspace = class {
22934
22993
  return true;
22935
22994
  }
22936
22995
  // -------------------------------------------------------------------------
22996
+ // Kind-generic access (spec_index.load, spec_registry.save / delete)
22997
+ //
22998
+ // The one place a kind held as DATA becomes the typed loader, writer or
22999
+ // delete of that kind. Every caller that holds the kind as a value — the
23000
+ // gated whole-spec write, a delete by kind, the delta update, the method
23001
+ // move — used to repeat this switch, and each copy could drift from the
23002
+ // others (one of them forgot that a type's writer takes no status).
23003
+ // -------------------------------------------------------------------------
23004
+ /** One stored spec of the named kind, or null. The L0 is a singleton: its id is informational. */
23005
+ load(kind, id) {
23006
+ switch (kind) {
23007
+ case "system":
23008
+ return this.loadSystemSpec();
23009
+ case "subsystem":
23010
+ return this.loadSubsystemSpec(id);
23011
+ case "component":
23012
+ return this.loadComponentSpec(id);
23013
+ case "interface":
23014
+ return this.loadInterfaceSpec(id);
23015
+ case "implementation":
23016
+ return this.loadImplementationSpec(id);
23017
+ case "type":
23018
+ return this.loadTypeSpec(id);
23019
+ }
23020
+ }
23021
+ /**
23022
+ * Persist one spec through the typed writer of its kind, answering with that
23023
+ * writer's placement notices (none for the L0 and a subsystem). A draft or
23024
+ * status-less save keeps the stored status, exactly as the typed writers do.
23025
+ */
23026
+ save(kind, spec) {
23027
+ return this.saveOfKind(kind, spec);
23028
+ }
23029
+ /** The typed writer of a kind, with the caller's save options — the delta update and the move state a demotion. */
23030
+ saveOfKind(kind, spec, opts) {
23031
+ switch (kind) {
23032
+ case "system":
23033
+ this.saveSystemSpec(spec);
23034
+ return [];
23035
+ case "subsystem":
23036
+ this.saveSubsystemSpec(spec, opts);
23037
+ return [];
23038
+ case "component":
23039
+ return this.saveComponentSpec(spec, opts);
23040
+ case "interface":
23041
+ return this.saveInterfaceSpec(spec, opts);
23042
+ case "implementation":
23043
+ return this.saveImplementationSpec(spec, opts);
23044
+ case "type":
23045
+ return this.saveTypeSpec(spec, opts);
23046
+ }
23047
+ }
23048
+ /** Delete one spec document of the named kind; false when none was stored. The L0 cannot be deleted. */
23049
+ delete(kind, id) {
23050
+ switch (kind) {
23051
+ case "system":
23052
+ throw new Error("The L0 system spec cannot be deleted: it is the root every other spec hangs from.");
23053
+ case "subsystem":
23054
+ return this.deleteSubsystemSpec(id);
23055
+ case "component":
23056
+ return this.deleteComponentSpec(id);
23057
+ case "interface":
23058
+ return this.deleteInterfaceSpec(id);
23059
+ case "implementation":
23060
+ return this.deleteImplementationSpec(id);
23061
+ case "type":
23062
+ return this.deleteTypeSpec(id);
23063
+ }
23064
+ }
23065
+ // -------------------------------------------------------------------------
22937
23066
  // Spec status promotion (draft/design → complete)
22938
23067
  // -------------------------------------------------------------------------
22939
23068
  /** Every spec whose status is not yet 'complete', with its current status captured. */
@@ -23154,23 +23283,7 @@ var SpecWorkspace = class {
23154
23283
  */
23155
23284
  updateSpec(kind, id, delta, hooks, dryRun = false) {
23156
23285
  const notices = [];
23157
- const result = (() => {
23158
- switch (kind) {
23159
- case "system":
23160
- return this.loadSystemSpec();
23161
- // singleton — id is informational
23162
- case "subsystem":
23163
- return this.loadSubsystemSpec(id);
23164
- case "component":
23165
- return this.loadComponentSpec(id);
23166
- case "interface":
23167
- return this.loadInterfaceSpec(id);
23168
- case "implementation":
23169
- return this.loadImplementationSpec(id);
23170
- case "type":
23171
- return this.loadTypeSpec(id);
23172
- }
23173
- })();
23286
+ const result = this.load(kind, id);
23174
23287
  if (!result) {
23175
23288
  throw new Error(`Spec of kind "${kind}" with ID "${id}" does not exist. Define it first.`);
23176
23289
  }
@@ -23502,9 +23615,10 @@ var SpecWorkspace = class {
23502
23615
  const mergePublicInterfaces = (existing, delta2) => {
23503
23616
  const merged = [...existing];
23504
23617
  for (const deltaItem of delta2) {
23505
- const piKey = (i) => `${i?.component}.${i?.interface}`;
23618
+ const piKey = (i) => String(identityKeyOf("publicInterfaces", i));
23506
23619
  assertDeltaMarkers(deltaItem, `publicInterface "${piKey(deltaItem)}"`);
23507
- const idx = merged.findIndex((item) => item.component === deltaItem.component && item.interface === deltaItem.interface);
23620
+ const key = identityKeyOf("publicInterfaces", deltaItem);
23621
+ const idx = key === null ? -1 : merged.findIndex((item) => identityKeyOf("publicInterfaces", item) === key);
23508
23622
  if (idx !== -1) {
23509
23623
  if (deltaItem.remove === true || deltaItem.action === "delete") {
23510
23624
  merged.splice(idx, 1);
@@ -23593,7 +23707,8 @@ var SpecWorkspace = class {
23593
23707
  out.publicInterfaces = out.publicInterfaces.map((pi) => ({
23594
23708
  ...pi,
23595
23709
  ...typeof pi?.component === "string" ? { component: qm(pi.component) } : {},
23596
- ...typeof pi?.interface === "string" ? { interface: qm(pi.interface) } : {}
23710
+ ...typeof pi?.interface === "string" ? { interface: qm(pi.interface) } : {},
23711
+ ...Array.isArray(pi?.consumers) ? { consumers: pi.consumers.map((c) => typeof c === "string" ? qualifySubsystemRef(c, prefix, this.rootSubsystems) : c) } : {}
23597
23712
  }));
23598
23713
  }
23599
23714
  if (Array.isArray(out.lifecycle)) {
@@ -23693,26 +23808,7 @@ var SpecWorkspace = class {
23693
23808
  const opts = {
23694
23809
  allowStatusDemotion: Object.prototype.hasOwnProperty.call(delta, "status")
23695
23810
  };
23696
- switch (kind) {
23697
- case "system":
23698
- this.saveSystemSpec(mergedResult);
23699
- break;
23700
- case "subsystem":
23701
- this.saveSubsystemSpec(mergedResult, opts);
23702
- break;
23703
- case "component":
23704
- notices.push(...this.saveComponentSpec(mergedResult, opts));
23705
- break;
23706
- case "interface":
23707
- notices.push(...this.saveInterfaceSpec(mergedResult, opts));
23708
- break;
23709
- case "implementation":
23710
- notices.push(...this.saveImplementationSpec(mergedResult, opts));
23711
- break;
23712
- case "type":
23713
- notices.push(...this.saveTypeSpec(mergedResult));
23714
- break;
23715
- }
23811
+ notices.push(...this.saveOfKind(kind, mergedResult, opts));
23716
23812
  return {
23717
23813
  kind,
23718
23814
  id,
@@ -24073,23 +24169,7 @@ var SpecWorkspace = class {
24073
24169
  }
24074
24170
  /** Persist one moved spec through the store's own writer, and answer with its placement notices. */
24075
24171
  saveMovedSpec(kind, spec) {
24076
- const opts = { allowStatusDemotion: true };
24077
- switch (kind) {
24078
- case "system":
24079
- this.saveSystemSpec(spec);
24080
- return [];
24081
- case "subsystem":
24082
- this.saveSubsystemSpec(spec, opts);
24083
- return [];
24084
- case "component":
24085
- return this.saveComponentSpec(spec, opts);
24086
- case "interface":
24087
- return this.saveInterfaceSpec(spec, opts);
24088
- case "implementation":
24089
- return this.saveImplementationSpec(spec, opts);
24090
- case "type":
24091
- return this.saveTypeSpec(spec);
24092
- }
24172
+ return this.saveOfKind(kind, spec, { allowStatusDemotion: true });
24093
24173
  }
24094
24174
  };
24095
24175
  var DEFAULT_DEPENDENCY_LIMIT = 8;
@@ -24239,9 +24319,6 @@ function loadSubsystemSpec(id) {
24239
24319
  function saveSubsystemSpec(spec) {
24240
24320
  current().saveSubsystemSpec(spec);
24241
24321
  }
24242
- function deleteSubsystemSpec(id) {
24243
- return current().deleteSubsystemSpec(id);
24244
- }
24245
24322
  function loadComponentSpecs() {
24246
24323
  return current().loadComponentSpecs();
24247
24324
  }
@@ -24251,9 +24328,6 @@ function loadComponentSpec(id) {
24251
24328
  function saveComponentSpec(spec, opts) {
24252
24329
  return current().saveComponentSpec(spec, opts);
24253
24330
  }
24254
- function deleteComponentSpec(id) {
24255
- return current().deleteComponentSpec(id);
24256
- }
24257
24331
  function loadInterfaceSpecs() {
24258
24332
  return current().loadInterfaceSpecs();
24259
24333
  }
@@ -24263,9 +24337,6 @@ function loadInterfaceSpec(id) {
24263
24337
  function saveInterfaceSpec(spec, opts) {
24264
24338
  return current().saveInterfaceSpec(spec, opts);
24265
24339
  }
24266
- function deleteInterfaceSpec(id) {
24267
- return current().deleteInterfaceSpec(id);
24268
- }
24269
24340
  function loadImplementationSpecs() {
24270
24341
  return current().loadImplementationSpecs();
24271
24342
  }
@@ -24275,18 +24346,12 @@ function loadImplementationSpec(id) {
24275
24346
  function saveImplementationSpec(spec, opts) {
24276
24347
  return current().saveImplementationSpec(spec, opts);
24277
24348
  }
24278
- function deleteImplementationSpec(id) {
24279
- return current().deleteImplementationSpec(id);
24280
- }
24281
24349
  function loadTypeSpecs() {
24282
24350
  return current().loadTypeSpecs();
24283
24351
  }
24284
24352
  function loadTypeSpec(id) {
24285
24353
  return current().loadTypeSpec(id);
24286
24354
  }
24287
- function saveTypeSpec(spec) {
24288
- return current().saveTypeSpec(spec);
24289
- }
24290
24355
  function dryRunSerializeSpecs(include) {
24291
24356
  return current().dryRunSerializeSpecs(include);
24292
24357
  }
@@ -24362,15 +24427,24 @@ function computeStateIdAt(root) {
24362
24427
  return `${s.algorithm}:${s.digest}`;
24363
24428
  });
24364
24429
  }
24365
- function deleteTypeSpec(id) {
24366
- return current().deleteTypeSpec(id);
24367
- }
24368
24430
  function specPathsInScope(scopeSubsystem) {
24369
24431
  return current().specPathsInScope(scopeSubsystem);
24370
24432
  }
24371
24433
  function snapshotSpecFiles() {
24372
24434
  return current().snapshotSpecFiles();
24373
24435
  }
24436
+ function loadSpec(kind, id) {
24437
+ const workspace = current();
24438
+ return workspace.load(kind, id);
24439
+ }
24440
+ function saveSpec(kind, spec) {
24441
+ const workspace = current();
24442
+ return workspace.save(kind, spec);
24443
+ }
24444
+ function deleteSpec(kind, id) {
24445
+ const workspace = current();
24446
+ return workspace.delete(kind, id);
24447
+ }
24374
24448
  function updateSpec(kind, id, delta, hooks, dryRun) {
24375
24449
  return current().updateSpec(kind, id, delta, hooks, dryRun);
24376
24450
  }
@@ -27072,11 +27146,7 @@ function loadProjectConfig4() {
27072
27146
  defaultNarrativeDetail,
27073
27147
  defaultPackSelections,
27074
27148
  defaultTargetConfig,
27075
- deleteComponentSpec,
27076
- deleteImplementationSpec,
27077
- deleteInterfaceSpec,
27078
- deleteSubsystemSpec,
27079
- deleteTypeSpec,
27149
+ deleteSpec,
27080
27150
  deregisterPackRef,
27081
27151
  deriveExecutionProfile,
27082
27152
  derivedDocPaths,
@@ -27145,6 +27215,7 @@ function loadProjectConfig4() {
27145
27215
  loadProjectConfig,
27146
27216
  loadProjectExtensions,
27147
27217
  loadRegistry,
27218
+ loadSpec,
27148
27219
  loadSpecGraph,
27149
27220
  loadSubsystemSpec,
27150
27221
  loadSubsystemSpecs,
@@ -27203,13 +27274,8 @@ function loadProjectConfig4() {
27203
27274
  runWithProjectBinding,
27204
27275
  runWithProjectRoot,
27205
27276
  sameContract,
27206
- saveComponentSpec,
27207
- saveImplementationSpec,
27208
- saveInterfaceSpec,
27209
- saveSubsystemSpec,
27210
- saveSystemSpec,
27277
+ saveSpec,
27211
27278
  saveTopologyConfig,
27212
- saveTypeSpec,
27213
27279
  serializeYaml,
27214
27280
  setExecutionTier,
27215
27281
  setLogLevel,