@elevasis/sdk 1.48.0 → 1.50.0

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.
Files changed (56) hide show
  1. package/dist/chunk-MGZZ4HL4.js +4399 -0
  2. package/dist/chunk-VYWGWJRW.js +130 -0
  3. package/dist/chunk-YJDXRHNP.js +7901 -0
  4. package/dist/cli.cjs +949 -281
  5. package/dist/index.d.ts +1031 -48
  6. package/dist/index.js +2 -7597
  7. package/dist/node/index.d.ts +3 -3675
  8. package/dist/node/index.js +2 -124
  9. package/dist/test-utils/index.d.ts +2 -12051
  10. package/dist/test-utils/index.js +113 -27891
  11. package/dist/worker/index.d.ts +548 -12264
  12. package/dist/worker/index.js +3 -7400
  13. package/package.json +12 -4
  14. package/reference/_navigation.md +4 -4
  15. package/reference/_reference-manifest.json +1 -1
  16. package/reference/core/index.mdx +6 -4
  17. package/reference/index.mdx +11 -5
  18. package/reference/packages/core/src/README.md +46 -44
  19. package/reference/packages/core/src/content/README.md +16 -12
  20. package/reference/rules/agent-start-here.md +1 -1
  21. package/reference/rules/frontend.md +3 -1
  22. package/reference/rules/package-taxonomy.md +7 -5
  23. package/reference/rules/ui.md +31 -5
  24. package/reference/rules/vibe-intents.md +2 -2
  25. package/reference/rules/vibe.md +30 -10
  26. package/reference/scaffold/recipes/extend-content.md +82 -3
  27. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +8 -6
  28. package/reference/scaffold/ui/feature-flags-and-gating.md +11 -1
  29. package/reference/sdk/cli-management.mdx +284 -139
  30. package/reference/sdk/cli.mdx +136 -88
  31. package/reference/sdk/define-builders.mdx +1 -1
  32. package/reference/sdk/deployment/command-center.mdx +2 -2
  33. package/reference/sdk/deployment/index.mdx +24 -7
  34. package/reference/sdk/exports.mdx +4 -4
  35. package/reference/sdk/framework/agent.mdx +4 -3
  36. package/reference/sdk/framework/index.mdx +1 -1
  37. package/reference/sdk/framework/project-structure.mdx +34 -23
  38. package/reference/sdk/framework/tutorial-system.mdx +1 -1
  39. package/reference/sdk/getting-started.mdx +25 -52
  40. package/reference/sdk/index.mdx +3 -3
  41. package/reference/sdk/platform-tools/adapters-integration.mdx +1 -1
  42. package/reference/sdk/platform-tools/adapters-platform.mdx +1 -1
  43. package/reference/sdk/platform-tools/type-safety.mdx +1 -1
  44. package/reference/sdk/resources/patterns.mdx +10 -11
  45. package/reference/sdk/resources/types.mdx +15 -9
  46. package/reference/sdk/templates/data-enrichment.mdx +1 -1
  47. package/reference/sdk/templates/email-sender.mdx +1 -1
  48. package/reference/sdk/templates/index.mdx +47 -47
  49. package/reference/sdk/templates/lead-scorer.mdx +1 -1
  50. package/reference/sdk/templates/pdf-generator.mdx +42 -24
  51. package/reference/sdk/templates/recurring-job.mdx +20 -15
  52. package/reference/sdk/templates/text-classifier.mdx +1 -1
  53. package/reference/sdk/templates/web-scraper.mdx +9 -5
  54. package/reference/sdk/troubleshooting.mdx +72 -1
  55. package/reference/ui/exports.mdx +1 -1
  56. package/reference/ui/index.mdx +2 -2
package/dist/cli.cjs CHANGED
@@ -22654,44 +22654,64 @@ var init_ontology = __esm({
22654
22654
  }).passthrough();
22655
22655
  OntologyObjectTypeSchema = OntologyRecordBaseSchema.extend({
22656
22656
  properties: external_exports.record(external_exports.string().trim().min(1).max(200), external_exports.unknown()).optional(),
22657
- storage: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
22658
- });
22657
+ storage: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
22658
+ // Carried by the legacy entity projection (`addLegacyEntityProjections`); not
22659
+ // authored directly, but a real key an authored record must not collide with.
22660
+ rowSchema: external_exports.string().trim().min(1).optional(),
22661
+ stateCatalogId: external_exports.string().trim().min(1).optional()
22662
+ }).strict();
22659
22663
  OntologyLinkTypeSchema = OntologyRecordBaseSchema.extend({
22660
22664
  from: OntologyIdSchema,
22661
22665
  to: OntologyIdSchema,
22662
22666
  cardinality: external_exports.string().trim().min(1).max(80).optional(),
22663
22667
  via: external_exports.string().trim().min(1).max(255).optional()
22664
- });
22668
+ }).strict();
22665
22669
  OntologyActionTypeSchema = OntologyRecordBaseSchema.extend({
22666
22670
  actsOn: OntologyReferenceListSchema,
22667
22671
  input: external_exports.record(external_exports.string().trim().min(1).max(200), external_exports.unknown()).optional(),
22668
- effects: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())).optional()
22669
- });
22672
+ effects: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())).optional(),
22673
+ resourceId: external_exports.string().trim().min(1).optional(),
22674
+ invocations: external_exports.array(external_exports.unknown()).optional(),
22675
+ lifecycle: external_exports.string().trim().min(1).optional(),
22676
+ // Carried by the legacy action projection (`addLegacyActionProjections`); not
22677
+ // authored directly, but a real key an authored record must not collide with.
22678
+ legacyActionId: external_exports.string().trim().min(1).optional()
22679
+ }).strict();
22670
22680
  OntologyCatalogTypeSchema = OntologyRecordBaseSchema.extend({
22671
22681
  kind: external_exports.string().trim().min(1).max(120).optional(),
22672
22682
  appliesTo: OntologyIdSchema.optional(),
22673
- entries: external_exports.record(external_exports.string().trim().min(1).max(200), external_exports.unknown()).optional()
22674
- });
22683
+ entries: external_exports.record(external_exports.string().trim().min(1).max(200), external_exports.unknown()).optional(),
22684
+ // Carried by lead-gen's legacy stage-catalog projection
22685
+ // (`createLeadGenStageCatalog`); not authored directly, but a real key an
22686
+ // authored record must not collide with.
22687
+ legacyCatalogKey: external_exports.string().trim().min(1).optional(),
22688
+ // Carried in live tenant configs (Elevasis, `nirvana-marketing`, and the
22689
+ // `_template` scaffold all author these on `sales.crm:catalog/crm.pipeline`)
22690
+ // as a cross-reference to the pre-ontology CRM pipeline key/entity id. No
22691
+ // code currently reads them back — do not silently normalize them away.
22692
+ legacyPipelineKey: external_exports.string().trim().min(1).optional(),
22693
+ legacyEntityKey: external_exports.string().trim().min(1).optional()
22694
+ }).strict();
22675
22695
  OntologyEventTypeSchema = OntologyRecordBaseSchema.extend({
22676
22696
  payload: external_exports.record(external_exports.string().trim().min(1).max(200), external_exports.unknown()).optional()
22677
- });
22697
+ }).strict();
22678
22698
  OntologyInterfaceTypeSchema = OntologyRecordBaseSchema.extend({
22679
22699
  properties: external_exports.record(external_exports.string().trim().min(1).max(200), external_exports.unknown()).optional()
22680
- });
22700
+ }).strict();
22681
22701
  OntologyValueTypeSchema = OntologyRecordBaseSchema.extend({
22682
22702
  primitive: external_exports.string().trim().min(1).max(120).optional()
22683
- });
22703
+ }).strict();
22684
22704
  OntologySharedPropertySchema = OntologyRecordBaseSchema.extend({
22685
22705
  valueType: OntologyIdSchema.optional(),
22686
22706
  searchable: external_exports.boolean().optional(),
22687
22707
  pii: external_exports.boolean().optional()
22688
- });
22708
+ }).strict();
22689
22709
  OntologyGroupSchema = OntologyRecordBaseSchema.extend({
22690
22710
  members: OntologyReferenceListSchema
22691
- });
22711
+ }).strict();
22692
22712
  OntologyEndpointTypeSchema = OntologyRecordBaseSchema.extend({
22693
22713
  route: external_exports.string().trim().min(1).max(500).optional()
22694
- });
22714
+ }).strict();
22695
22715
  OntologyScopeSchema = external_exports.object({
22696
22716
  objectTypes: external_exports.record(OntologyIdSchema, OntologyObjectTypeSchema).default({}).optional(),
22697
22717
  linkTypes: external_exports.record(OntologyIdSchema, OntologyLinkTypeSchema).default({}).optional(),
@@ -23550,6 +23570,10 @@ var init_profile_registry = __esm({
23550
23570
  });
23551
23571
 
23552
23572
  // ../core/src/organization-model/domains/systems.ts
23573
+ function isSystemLifecycleVisible(lifecycle, enabled) {
23574
+ if (enabled === false) return false;
23575
+ return lifecycle !== "draft" && lifecycle !== "deprecated" && lifecycle !== "archived";
23576
+ }
23553
23577
  function isReservedPlatformProfileId(profileId) {
23554
23578
  return BUILT_IN_VALIDATED_PROFILE_IDS.includes(profileId);
23555
23579
  }
@@ -23566,7 +23590,10 @@ var init_systems = __esm({
23566
23590
  init_ontology();
23567
23591
  init_profile_registry();
23568
23592
  SystemKindSchema = external_exports.enum(["product", "operational", "platform", "diagnostic"]).meta({ label: "System kind", color: "blue" });
23569
- SystemLifecycleSchema = external_exports.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" });
23593
+ SystemLifecycleSchema = external_exports.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({
23594
+ label: "Lifecycle",
23595
+ color: "teal"
23596
+ });
23570
23597
  SystemIdSchema = ModelIdSchema;
23571
23598
  SystemPathSchema = external_exports.string().trim().min(1).regex(
23572
23599
  /^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/,
@@ -23686,8 +23713,13 @@ var init_systems = __esm({
23686
23713
  parentSystemId: SystemIdSchema.optional(),
23687
23714
  /** Optional UI presence. Systems without UI omit this. */
23688
23715
  ui: SystemUiSchema.optional(),
23689
- /** Canonical lifecycle state. `beta` is what gates a System to dev-mode viewers. */
23690
- lifecycle: SystemLifecycleSchema.optional(),
23716
+ /**
23717
+ * Canonical lifecycle state. `beta` is what gates a System to dev-mode
23718
+ * viewers. Defaults to `active` (not `.optional()`) so an omitted field
23719
+ * never reaches a consumer as `undefined` -- see `isSystemLifecycleVisible`
23720
+ * and `systemLifecycleAllowsAccess` above.
23721
+ */
23722
+ lifecycle: SystemLifecycleSchema.default("active"),
23691
23723
  /** Optional role responsible for this system. */
23692
23724
  responsibleRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
23693
23725
  /** Optional knowledge nodes that govern this system. */
@@ -24209,10 +24241,6 @@ function addIssue(ctx, path3, message) {
24209
24241
  message
24210
24242
  });
24211
24243
  }
24212
- function isLifecycleEnabled(lifecycle, enabled) {
24213
- if (enabled === false) return false;
24214
- return lifecycle !== "deprecated" && lifecycle !== "archived";
24215
- }
24216
24244
  function defaultSystemPathFor(id) {
24217
24245
  return `/${id.replaceAll(".", "/")}`;
24218
24246
  }
@@ -24283,11 +24311,11 @@ function refineOrganizationModel(model, ctx) {
24283
24311
  systemIdsByEffectivePath.set(effectivePath, path3);
24284
24312
  }
24285
24313
  }
24286
- if (hasChildren && isLifecycleEnabled(system.lifecycle, system.enabled)) {
24314
+ if (hasChildren && isSystemLifecycleVisible(system.lifecycle, system.enabled)) {
24287
24315
  const hasEnabledDescendant = Object.values(system.systems ?? system.subsystems ?? {}).some(
24288
- (candidate) => isLifecycleEnabled(candidate.lifecycle, candidate.enabled)
24316
+ (candidate) => isSystemLifecycleVisible(candidate.lifecycle, candidate.enabled)
24289
24317
  ) || allSystems.some(
24290
- (candidate) => candidate.path.startsWith(`${path3}.`) && !candidate.path.slice(path3.length + 1).includes(".") && isLifecycleEnabled(candidate.system.lifecycle, candidate.system.enabled)
24318
+ (candidate) => candidate.path.startsWith(`${path3}.`) && !candidate.path.slice(path3.length + 1).includes(".") && isSystemLifecycleVisible(candidate.system.lifecycle, candidate.system.enabled)
24291
24319
  );
24292
24320
  if (!hasEnabledDescendant) {
24293
24321
  addIssue(ctx, [...schemaPath, "lifecycle"], `System "${path3}" is active but has no active descendants`);
@@ -24702,6 +24730,7 @@ var init_schema_refinements = __esm({
24702
24730
  "use strict";
24703
24731
  init_zod();
24704
24732
  init_resources();
24733
+ init_systems();
24705
24734
  init_cross_ref();
24706
24735
  init_ontology();
24707
24736
  }
@@ -25034,8 +25063,8 @@ var init_content = __esm({
25034
25063
  "../core/src/organization-model/catalogs/content.ts"() {
25035
25064
  "use strict";
25036
25065
  init_zod();
25037
- ContentPipelineStepActorSchema = external_exports.enum(["workflow", "agent", "vendor"]);
25038
- ContentPipelineStepReviewModeSchema = external_exports.enum(["live", "queued", "none"]);
25066
+ ContentPipelineStepActorSchema = external_exports.enum(["workflow", "agent", "vendor", "human"]);
25067
+ ContentPipelineStepReviewModeSchema = external_exports.enum(["none", "required"]);
25039
25068
  ContentPayloadFieldTypeSchema = external_exports.enum(["string", "text", "number", "boolean", "url", "string-array"]);
25040
25069
  ContentPayloadFieldDeclarationSchema = external_exports.object({
25041
25070
  key: external_exports.string().trim().min(1).max(200),
@@ -26271,6 +26300,63 @@ var init_lead_gen = __esm({
26271
26300
  }
26272
26301
  });
26273
26302
 
26303
+ // ../core/src/organization-model/catalogs/content-producer-factory.ts
26304
+ var init_content_producer_factory = __esm({
26305
+ "../core/src/organization-model/catalogs/content-producer-factory.ts"() {
26306
+ "use strict";
26307
+ }
26308
+ });
26309
+
26310
+ // ../core/src/organization-model/catalogs/define-content-pipeline.ts
26311
+ var init_define_content_pipeline = __esm({
26312
+ "../core/src/organization-model/catalogs/define-content-pipeline.ts"() {
26313
+ "use strict";
26314
+ }
26315
+ });
26316
+
26317
+ // ../core/src/organization-model/catalogs/define-system-api-interface.ts
26318
+ function formatAdoptableProfiles() {
26319
+ return SYSTEM_INTERFACE_PROFILES.map((profile) => `"${profile.readinessProfile}"`).join(", ");
26320
+ }
26321
+ function defineSystemApiInterface(input) {
26322
+ const interfaceKey = input.interfaceKey ?? "api";
26323
+ const identity = `${input.systemPath}/${interfaceKey}`;
26324
+ const catalogEntry = SYSTEM_INTERFACE_PROFILES.find((profile) => profile.readinessProfile === input.readinessProfile);
26325
+ if (catalogEntry === void 0) {
26326
+ throw new Error(
26327
+ `System Interface "${identity}" declares readinessProfile "${input.readinessProfile}", which is not a member of SYSTEM_INTERFACE_PROFILES. Adoptable profiles: ${formatAdoptableProfiles()}. An uncataloged id names no route platform code actually serves -- it computes as ready and answers every request with a 503. Add an entry to SYSTEM_INTERFACE_PROFILES (packages/core/src/organization-model/domains/systems.ts) before declaring it on System "${input.systemPath}", or use one of the ids above.`
26328
+ );
26329
+ }
26330
+ if (input.resourceIds.length === 0) {
26331
+ throw new Error(
26332
+ `System Interface "${identity}" declares an empty resourceIds list. An interface with no scoped active resource computes as ready and answers every route with a 503 -- scope at least one active resource for System "${input.systemPath}".`
26333
+ );
26334
+ }
26335
+ const isBuiltIn = catalogEntry.validation === "built-in";
26336
+ if (!isBuiltIn && input.readinessContract === void 0) {
26337
+ throw new Error(
26338
+ `System Interface "${identity}" adopts contract-validated profile "${input.readinessProfile}" but declares no readinessContract. Contract-validated profiles have no registered platform validator -- each adopter's structural requirements differ, so System "${input.systemPath}" must pass a readinessContract with at least one requiredCatalogs entry.`
26339
+ );
26340
+ }
26341
+ if (isBuiltIn && input.readinessContract !== void 0) {
26342
+ throw new Error(
26343
+ `System Interface "${identity}" declares a readinessContract against built-in profile "${input.readinessProfile}". Built-in profiles derive their requirements from platform code registered via registerBuiltInReadinessProfile, and the readiness engine never reads an authored contract against one -- it is silently ignored (the "else if (readinessContract)" branch in readiness/engine.ts is unreachable for a built-in profile). Delete the readinessContract on System "${input.systemPath}"; it asserts nothing today.`
26344
+ );
26345
+ }
26346
+ return {
26347
+ lifecycle: input.lifecycle ?? "active",
26348
+ readinessProfile: input.readinessProfile,
26349
+ resourceIds: input.resourceIds,
26350
+ ...input.readinessContract !== void 0 ? { readinessContract: input.readinessContract } : {}
26351
+ };
26352
+ }
26353
+ var init_define_system_api_interface = __esm({
26354
+ "../core/src/organization-model/catalogs/define-system-api-interface.ts"() {
26355
+ "use strict";
26356
+ init_systems();
26357
+ }
26358
+ });
26359
+
26274
26360
  // ../core/src/organization-model/readiness/engine.ts
26275
26361
  function addReadinessIssue(issues, family, code, message, details = {}) {
26276
26362
  issues.push({
@@ -26611,6 +26697,9 @@ var init_organization_model = __esm({
26611
26697
  init_graph();
26612
26698
  init_lead_gen();
26613
26699
  init_content();
26700
+ init_content_producer_factory();
26701
+ init_define_content_pipeline();
26702
+ init_define_system_api_interface();
26614
26703
  init_branding();
26615
26704
  init_systems();
26616
26705
  init_resources();
@@ -44095,7 +44184,7 @@ function getModelInfo(model) {
44095
44184
  return MODEL_INFO[model];
44096
44185
  }
44097
44186
  for (const knownModel of MODEL_KEYS_BY_SPECIFICITY) {
44098
- if (model.startsWith(knownModel)) {
44187
+ if (model.startsWith(`${knownModel}-`)) {
44099
44188
  return MODEL_INFO[knownModel];
44100
44189
  }
44101
44190
  }
@@ -44121,7 +44210,7 @@ function validateModelConfig(config3) {
44121
44210
  throw new ModelConfigError(`Invalid config for ${model}: ${firstError.message}`, fieldName, model);
44122
44211
  }
44123
44212
  }
44124
- var GPT5OptionsSchema, GPT5ConfigSchema, MockConfigSchema, OpenRouterOptionsSchema, OpenRouterConfigSchema, AnthropicOptionsSchema, AnthropicStandardConfigSchema, AnthropicClaude5ConfigSchema, AnthropicConfigSchema, MODEL_INFO, MODEL_KEYS_BY_SPECIFICITY;
44213
+ var GPT5OptionsSchema, GPT5ConfigSchema, GPT56OptionsSchema, GPT56ConfigSchema, MockConfigSchema, OpenRouterOptionsSchema, OpenRouterConfigSchema, AnthropicOptionsSchema, AnthropicStandardConfigSchema, AnthropicClaude5ConfigSchema, AnthropicConfigSchema, GPT56_CACHE_READ_RATE_MULTIPLIER, CACHE_CREATION_RATE_MULTIPLIER, MODEL_INFO, MODEL_KEYS_BY_SPECIFICITY;
44125
44214
  var init_model_info = __esm({
44126
44215
  "../core/src/execution/engine/llm/model-info.ts"() {
44127
44216
  "use strict";
@@ -44141,6 +44230,19 @@ var init_model_info = __esm({
44141
44230
  topP: external_exports.number().min(0).max(1).optional(),
44142
44231
  modelOptions: GPT5OptionsSchema.optional()
44143
44232
  });
44233
+ GPT56OptionsSchema = external_exports.object({
44234
+ reasoning_effort: external_exports.enum(["none", "low", "medium", "high", "xhigh", "max"]).optional(),
44235
+ verbosity: external_exports.enum(["low", "medium", "high"]).optional()
44236
+ });
44237
+ GPT56ConfigSchema = external_exports.object({
44238
+ model: external_exports.enum(["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"]),
44239
+ provider: external_exports.enum(["openai"]),
44240
+ apiKey: external_exports.string(),
44241
+ temperature: external_exports.literal(1).optional(),
44242
+ maxOutputTokens: external_exports.number().min(4e3).optional(),
44243
+ topP: external_exports.number().min(0).max(1).optional(),
44244
+ modelOptions: GPT56OptionsSchema.optional()
44245
+ });
44144
44246
  MockConfigSchema = external_exports.object({
44145
44247
  model: external_exports.enum(["mock"]),
44146
44248
  provider: external_exports.enum(["mock"]),
@@ -44193,9 +44295,12 @@ var init_model_info = __esm({
44193
44295
  AnthropicClaude5ConfigSchema,
44194
44296
  AnthropicStandardConfigSchema
44195
44297
  ]);
44298
+ GPT56_CACHE_READ_RATE_MULTIPLIER = 0.1;
44299
+ CACHE_CREATION_RATE_MULTIPLIER = 1.25;
44196
44300
  MODEL_INFO = {
44197
44301
  // OpenAI GPT-5 (Reasoning Models)
44198
44302
  "gpt-5": {
44303
+ provider: "openai",
44199
44304
  inputCostPer1M: 125,
44200
44305
  // $1.25 per 1M tokens
44201
44306
  outputCostPer1M: 1e3,
@@ -44209,6 +44314,7 @@ var init_model_info = __esm({
44209
44314
  configSchema: GPT5ConfigSchema
44210
44315
  },
44211
44316
  "gpt-5.4-mini": {
44317
+ provider: "openai",
44212
44318
  inputCostPer1M: 75,
44213
44319
  // $0.75 per 1M tokens
44214
44320
  outputCostPer1M: 450,
@@ -44222,6 +44328,7 @@ var init_model_info = __esm({
44222
44328
  configSchema: GPT5ConfigSchema
44223
44329
  },
44224
44330
  "gpt-5.4-nano": {
44331
+ provider: "openai",
44225
44332
  inputCostPer1M: 20,
44226
44333
  // $0.20 per 1M tokens
44227
44334
  outputCostPer1M: 125,
@@ -44233,8 +44340,60 @@ var init_model_info = __esm({
44233
44340
  category: "standard",
44234
44341
  configSchema: GPT5ConfigSchema
44235
44342
  },
44343
+ // OpenAI GPT-5.6 family (GA 2026-07-09). All three tiers share 1.05M context, 128K max output,
44344
+ // image input, tool use, structured outputs, and prompt caching -- they differ in reasoning depth
44345
+ // and price, not capability. The bare `gpt-5.6` alias is deliberately unregistered; see OpenAIModel.
44346
+ "gpt-5.6-sol": {
44347
+ provider: "openai",
44348
+ inputCostPer1M: 500,
44349
+ // $5.00 per 1M tokens
44350
+ outputCostPer1M: 3e3,
44351
+ // $30.00 per 1M tokens
44352
+ minTokens: 4e3,
44353
+ recommendedTokens: 8e3,
44354
+ maxTokens: 105e4,
44355
+ // 1.05M context window
44356
+ maxOutputTokens: 128e3,
44357
+ category: "reasoning",
44358
+ configSchema: GPT56ConfigSchema,
44359
+ cacheReadRateMultiplier: GPT56_CACHE_READ_RATE_MULTIPLIER,
44360
+ cacheCreationRateMultiplier: CACHE_CREATION_RATE_MULTIPLIER
44361
+ },
44362
+ "gpt-5.6-terra": {
44363
+ provider: "openai",
44364
+ inputCostPer1M: 250,
44365
+ // $2.50 per 1M tokens
44366
+ outputCostPer1M: 1500,
44367
+ // $15.00 per 1M tokens
44368
+ minTokens: 4e3,
44369
+ recommendedTokens: 8e3,
44370
+ maxTokens: 105e4,
44371
+ // 1.05M context window
44372
+ maxOutputTokens: 128e3,
44373
+ category: "standard",
44374
+ configSchema: GPT56ConfigSchema,
44375
+ cacheReadRateMultiplier: GPT56_CACHE_READ_RATE_MULTIPLIER,
44376
+ cacheCreationRateMultiplier: CACHE_CREATION_RATE_MULTIPLIER
44377
+ },
44378
+ "gpt-5.6-luna": {
44379
+ provider: "openai",
44380
+ inputCostPer1M: 100,
44381
+ // $1.00 per 1M tokens
44382
+ outputCostPer1M: 600,
44383
+ // $6.00 per 1M tokens
44384
+ minTokens: 4e3,
44385
+ recommendedTokens: 8e3,
44386
+ maxTokens: 105e4,
44387
+ // 1.05M context window
44388
+ maxOutputTokens: 128e3,
44389
+ category: "standard",
44390
+ configSchema: GPT56ConfigSchema,
44391
+ cacheReadRateMultiplier: GPT56_CACHE_READ_RATE_MULTIPLIER,
44392
+ cacheCreationRateMultiplier: CACHE_CREATION_RATE_MULTIPLIER
44393
+ },
44236
44394
  // Mock model for testing
44237
44395
  mock: {
44396
+ provider: "mock",
44238
44397
  inputCostPer1M: 0,
44239
44398
  // Free for tests
44240
44399
  outputCostPer1M: 0,
@@ -44248,6 +44407,7 @@ var init_model_info = __esm({
44248
44407
  },
44249
44408
  // OpenRouter Models (via openrouter.ai)
44250
44409
  "openrouter/z-ai/glm-5": {
44410
+ provider: "openrouter",
44251
44411
  inputCostPer1M: 72,
44252
44412
  // $0.72 per 1M tokens
44253
44413
  outputCostPer1M: 230,
@@ -44261,6 +44421,7 @@ var init_model_info = __esm({
44261
44421
  },
44262
44422
  // Anthropic Claude Models (direct SDK access via @anthropic-ai/sdk)
44263
44423
  "claude-opus-5": {
44424
+ provider: "anthropic",
44264
44425
  inputCostPer1M: 500,
44265
44426
  // $5.00 per 1M tokens
44266
44427
  outputCostPer1M: 2500,
@@ -44274,6 +44435,7 @@ var init_model_info = __esm({
44274
44435
  configSchema: AnthropicConfigSchema
44275
44436
  },
44276
44437
  "claude-sonnet-5": {
44438
+ provider: "anthropic",
44277
44439
  // List pricing. An introductory rate of $2.00/$10.00 runs through 2026-08-31; encoding the
44278
44440
  // temporary rate would make historical cost analytics wrong once it lapses.
44279
44441
  inputCostPer1M: 300,
@@ -44289,6 +44451,7 @@ var init_model_info = __esm({
44289
44451
  configSchema: AnthropicConfigSchema
44290
44452
  },
44291
44453
  "claude-haiku-4-5-20251001": {
44454
+ provider: "anthropic",
44292
44455
  inputCostPer1M: 100,
44293
44456
  // $1.00 per 1M tokens
44294
44457
  outputCostPer1M: 500,
@@ -44302,6 +44465,7 @@ var init_model_info = __esm({
44302
44465
  configSchema: AnthropicConfigSchema
44303
44466
  },
44304
44467
  "claude-haiku-4-5": {
44468
+ provider: "anthropic",
44305
44469
  inputCostPer1M: 100,
44306
44470
  // $1.00 per 1M tokens
44307
44471
  outputCostPer1M: 500,
@@ -44690,6 +44854,138 @@ var init_response_schema = __esm({
44690
44854
  }
44691
44855
  });
44692
44856
 
44857
+ // ../core/src/execution/engine/workflow/types.ts
44858
+ var StepType;
44859
+ var init_types5 = __esm({
44860
+ "../core/src/execution/engine/workflow/types.ts"() {
44861
+ "use strict";
44862
+ StepType = {
44863
+ LINEAR: "linear",
44864
+ CONDITIONAL: "conditional"
44865
+ };
44866
+ }
44867
+ });
44868
+
44869
+ // ../core/src/execution/engine/workflow/errors.ts
44870
+ var WorkflowStepError, WorkflowValidationError;
44871
+ var init_errors5 = __esm({
44872
+ "../core/src/execution/engine/workflow/errors.ts"() {
44873
+ "use strict";
44874
+ init_errors3();
44875
+ WorkflowStepError = class extends ExecutionError {
44876
+ type = "workflow_step_error";
44877
+ severity = "critical";
44878
+ category = "workflow";
44879
+ /**
44880
+ * @param cause - The error the step actually threw. Kept so the original stack and any
44881
+ * non-`ExecutionError` throw survive the wrap; its classification is additionally copied into
44882
+ * `context` by the caller, because `type`/`severity`/`category` are fixed on this class.
44883
+ */
44884
+ constructor(message, context, cause) {
44885
+ super(message, context);
44886
+ if (cause !== void 0) this.cause = cause;
44887
+ }
44888
+ };
44889
+ WorkflowValidationError = class extends ExecutionError {
44890
+ type = "workflow_validation_error";
44891
+ severity = "info";
44892
+ category = "validation";
44893
+ constructor(message, context) {
44894
+ super(message, context);
44895
+ }
44896
+ };
44897
+ }
44898
+ });
44899
+
44900
+ // ../core/src/execution/engine/workflow/utils.ts
44901
+ function validateEntryPoint(steps, entryPoint) {
44902
+ if (!(entryPoint in steps)) {
44903
+ throw new WorkflowValidationError(`Entry point step '${entryPoint}' not found in workflow`, {
44904
+ entryPoint
44905
+ });
44906
+ }
44907
+ }
44908
+ function findTerminalSteps(steps) {
44909
+ return Object.values(steps).filter((step) => step.next === null);
44910
+ }
44911
+ function validateTerminalSteps(steps, workflowId) {
44912
+ const terminalSteps = findTerminalSteps(steps);
44913
+ if (terminalSteps.length === 0) {
44914
+ throw new WorkflowValidationError(`Workflow '${workflowId}' must have at least one terminal step (next: null)`, {
44915
+ workflowId
44916
+ });
44917
+ }
44918
+ }
44919
+ function validateStepReferences(steps) {
44920
+ for (const [id, step] of Object.entries(steps)) {
44921
+ if (step.next === null) {
44922
+ continue;
44923
+ }
44924
+ if (step.next.type === StepType.LINEAR) {
44925
+ if (!(step.next.target in steps)) {
44926
+ throw new WorkflowValidationError(`Step '${id}' references non-existent target '${step.next.target}'`, {
44927
+ stepId: id,
44928
+ target: step.next.target
44929
+ });
44930
+ }
44931
+ } else if (step.next.type === StepType.CONDITIONAL) {
44932
+ const targets = [...step.next.routes.map((r) => r.target), step.next.default];
44933
+ for (const target of targets) {
44934
+ if (!(target in steps)) {
44935
+ throw new WorkflowValidationError(`Step '${id}' references non-existent target '${target}'`, {
44936
+ stepId: id,
44937
+ target
44938
+ });
44939
+ }
44940
+ }
44941
+ }
44942
+ }
44943
+ }
44944
+ function detectCycle(visited, executionPath, currentStepId) {
44945
+ if (visited.has(currentStepId)) {
44946
+ const cycle = executionPath.slice(executionPath.indexOf(currentStepId));
44947
+ throw new WorkflowStepError(`Cycle detected in workflow: ${cycle.join(" -> ")} -> ${currentStepId}`, {
44948
+ stepId: currentStepId,
44949
+ cycle: [...cycle, currentStepId]
44950
+ });
44951
+ }
44952
+ }
44953
+ function validateWorkflowGraph(steps, entryPoint, workflowId) {
44954
+ const onPath = /* @__PURE__ */ new Set();
44955
+ const executionPath = [];
44956
+ const reached = /* @__PURE__ */ new Set();
44957
+ const walk = (stepId) => {
44958
+ detectCycle(onPath, executionPath, stepId);
44959
+ onPath.add(stepId);
44960
+ executionPath.push(stepId);
44961
+ reached.add(stepId);
44962
+ const step = steps[stepId];
44963
+ if (step && step.next !== null) {
44964
+ const targets = step.next.type === StepType.LINEAR ? [step.next.target] : [...step.next.routes.map((route) => route.target), step.next.default];
44965
+ for (const target of targets) {
44966
+ if (target in steps) walk(target);
44967
+ }
44968
+ }
44969
+ executionPath.pop();
44970
+ onPath.delete(stepId);
44971
+ };
44972
+ if (entryPoint in steps) walk(entryPoint);
44973
+ const orphanIds = Object.keys(steps).filter((id) => !reached.has(id));
44974
+ if (orphanIds.length > 0) {
44975
+ throw new WorkflowValidationError(
44976
+ `Workflow '${workflowId}' has step(s) unreachable from entry point '${entryPoint}': ${orphanIds.join(", ")}`,
44977
+ { workflowId, entryPoint, orphanIds }
44978
+ );
44979
+ }
44980
+ }
44981
+ var init_utils3 = __esm({
44982
+ "../core/src/execution/engine/workflow/utils.ts"() {
44983
+ "use strict";
44984
+ init_types5();
44985
+ init_errors5();
44986
+ }
44987
+ });
44988
+
44693
44989
  // ../core/src/platform/registry/validation.ts
44694
44990
  function getResourceValidatorMode(explicitMode) {
44695
44991
  if (explicitMode) return explicitMode;
@@ -44708,7 +45004,14 @@ function emitGovernanceIssues(issues, mode, onWarning) {
44708
45004
  if (issues.length === 0) return;
44709
45005
  if (mode === "strict") {
44710
45006
  const first = issues[0];
44711
- throw new RegistryValidationError(first.orgName, first.resourceId, "organizationModel.resources", first.message);
45007
+ const messages = issues.map((issue2) => issue2.message);
45008
+ throw new RegistryValidationError(
45009
+ first.orgName,
45010
+ first.resourceId,
45011
+ "organizationModel.resources",
45012
+ messages.join("\n"),
45013
+ messages
45014
+ );
44712
45015
  }
44713
45016
  const warn2 = onWarning ?? ((issue2) => console.warn(issue2.message));
44714
45017
  for (const issue2 of issues) {
@@ -44869,7 +45172,7 @@ function addTopologyIssues(issues, orgName, deployment, organizationModel, syste
44869
45172
  if (ref.kind === "humanCheckpoint") return humanCheckpointIds.has(ref.id);
44870
45173
  if (ref.kind === "externalResource") return externalResourceIds.has(ref.id);
44871
45174
  if (ref.kind === "ontology") {
44872
- if (ontologyIndex === void 0) return true;
45175
+ if (ontologyIndex === void 0) return false;
44873
45176
  return Object.values(ontologyIndex).some((records) => records[ref.id] !== void 0);
44874
45177
  }
44875
45178
  return false;
@@ -45034,7 +45337,7 @@ function detectMissingApiInterfaceDeclarations(orgName, organizationModel) {
45034
45337
  for (const resource of Object.values(organizationModel.resources ?? {})) {
45035
45338
  const ontology = resource.ontology;
45036
45339
  if (ontology === void 0) continue;
45037
- const hasOntologyBindings = ontology.actions !== void 0 && ontology.actions.length > 0 || ontology.writes !== void 0 && ontology.writes.length > 0;
45340
+ const hasOntologyBindings = ontology.actions !== void 0 && ontology.actions.length > 0 || ontology.writes !== void 0 && ontology.writes.length > 0 || ontology.reads !== void 0 && ontology.reads.length > 0 || ontology.usesCatalogs !== void 0 && ontology.usesCatalogs.length > 0;
45038
45341
  if (!hasOntologyBindings) continue;
45039
45342
  const existing = apiBoundResourcesBySystemPath.get(resource.systemPath);
45040
45343
  if (existing) {
@@ -45059,25 +45362,23 @@ function detectMissingApiInterfaceDeclarations(orgName, organizationModel) {
45059
45362
  }
45060
45363
  return gaps;
45061
45364
  }
45062
- function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel) {
45365
+ function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel, options = {}) {
45366
+ const mode = getResourceValidatorMode(options.mode);
45063
45367
  const issues = [];
45064
45368
  if (organizationModel === void 0) return { valid: true, issues };
45065
45369
  const model = organizationModel;
45066
45370
  for (const { path: path3, system } of listAllSystems(model)) {
45067
45371
  if (system.apiInterface === void 0) continue;
45068
45372
  const interfaceKey = "api";
45069
- const resourceIds = system.apiInterface.resourceIds ?? [];
45070
- if (resourceIds.length === 0) {
45071
- const readinessProfile = system.apiInterface.readinessProfile;
45072
- if (readinessProfile !== void 0 && !SYSTEM_INTERFACE_PROFILES.some((profile) => profile.readinessProfile === readinessProfile)) {
45073
- addSystemInterfaceIssue(issues, orgName, path3, interfaceKey, {
45074
- family: "SYSTEM_INTERFACE_INVALID",
45075
- code: "unknown-readiness-profile",
45076
- path: `systems.${path3}.apiInterface.readinessProfile`,
45077
- ref: readinessProfile,
45078
- message: `System Interface "${path3}/${interfaceKey}" references unknown readiness profile "${readinessProfile}".`
45079
- });
45080
- }
45373
+ const readinessProfile = system.apiInterface.readinessProfile;
45374
+ if (readinessProfile !== void 0 && !SYSTEM_INTERFACE_PROFILES.some((profile) => profile.readinessProfile === readinessProfile)) {
45375
+ addSystemInterfaceIssue(issues, orgName, path3, interfaceKey, {
45376
+ family: "SYSTEM_INTERFACE_INVALID",
45377
+ code: "unknown-readiness-profile",
45378
+ path: `systems.${path3}.apiInterface.readinessProfile`,
45379
+ ref: readinessProfile,
45380
+ message: `System Interface "${path3}/${interfaceKey}" references unknown readiness profile "${readinessProfile}".`
45381
+ });
45081
45382
  }
45082
45383
  const result = computeInterfaceReadiness(model, { systemPath: path3, interfaceKey });
45083
45384
  for (const issue2 of result.issues) {
@@ -45085,17 +45386,27 @@ function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel) {
45085
45386
  }
45086
45387
  }
45087
45388
  if (issues.length > 0) {
45088
- const first = issues[0];
45089
- throw new RegistryValidationError(
45090
- first.orgName,
45091
- `${first.systemPath}/${first.interfaceKey}`,
45092
- first.path ?? "organizationModel.systems.apiInterface",
45093
- first.message
45094
- );
45389
+ if (mode === "strict") {
45390
+ const first = issues[0];
45391
+ const messages = issues.map((issue2) => issue2.message);
45392
+ throw new RegistryValidationError(
45393
+ first.orgName,
45394
+ `${first.systemPath}/${first.interfaceKey}`,
45395
+ first.path ?? "organizationModel.systems.apiInterface",
45396
+ messages.join("\n"),
45397
+ messages
45398
+ );
45399
+ }
45400
+ const warn2 = options.onWarning ?? ((issue2) => console.warn(issue2.message));
45401
+ for (const issue2 of issues) {
45402
+ warn2(issue2);
45403
+ }
45404
+ return { valid: false, issues };
45095
45405
  }
45096
45406
  return { valid: true, issues };
45097
45407
  }
45098
- function validateDeploymentSpec(orgName, resources) {
45408
+ function validateDeploymentSpec(orgName, resources, options = {}) {
45409
+ const warn2 = options.onWarning ?? ((message) => console.warn(message));
45099
45410
  const seenIds = /* @__PURE__ */ new Set();
45100
45411
  resources.workflows?.forEach((workflow) => {
45101
45412
  const id = workflow.config.resourceId;
@@ -45114,6 +45425,14 @@ function validateDeploymentSpec(orgName, resources) {
45114
45425
  if (workflow.interface) {
45115
45426
  validateExecutionInterface(orgName, id, workflow.interface, workflow.contract.inputSchema);
45116
45427
  }
45428
+ try {
45429
+ validateEntryPoint(workflow.steps, workflow.entryPoint);
45430
+ validateTerminalSteps(workflow.steps, id);
45431
+ validateStepReferences(workflow.steps);
45432
+ validateWorkflowGraph(workflow.steps, workflow.entryPoint, id);
45433
+ } catch (error46) {
45434
+ warn2(`[${orgName}] Workflow '${id}' graph validation: ${error46 instanceof Error ? error46.message : String(error46)}`);
45435
+ }
45117
45436
  });
45118
45437
  resources.agents?.forEach((agent) => {
45119
45438
  const id = agent.config.resourceId;
@@ -45127,14 +45446,20 @@ function validateDeploymentSpec(orgName, resources) {
45127
45446
  }
45128
45447
  seenIds.add(id);
45129
45448
  validateResourceModelConfig(orgName, id, agent.modelConfig);
45130
- validateAgentGrammar(orgName, id, agent);
45131
- validateAgentCheapAssertions(orgName, id, agent);
45449
+ validateAgentGrammar(orgName, id, agent, options.mode);
45450
+ validateAgentCheapAssertions(orgName, id, agent, options.mode);
45132
45451
  if (agent.interface) {
45133
45452
  validateExecutionInterface(orgName, id, agent.interface, agent.contract.inputSchema);
45134
45453
  }
45135
45454
  });
45136
- validateResourceGovernance(orgName, resources);
45137
- validateDeclaredSystemInterfaceReadiness(orgName, resources.organizationModel);
45455
+ validateResourceGovernance(orgName, resources, void 0, {
45456
+ mode: options.mode,
45457
+ onWarning: (issue2) => warn2(issue2.message)
45458
+ });
45459
+ validateDeclaredSystemInterfaceReadiness(orgName, resources.organizationModel, {
45460
+ mode: options.mode,
45461
+ onWarning: (issue2) => warn2(issue2.message)
45462
+ });
45138
45463
  }
45139
45464
  function validateResourceModelConfig(orgName, resourceId, modelConfig) {
45140
45465
  try {
@@ -45209,7 +45534,7 @@ function describeGrammarRefusal(reasons, toolInputSchema) {
45209
45534
  }
45210
45535
  return `refused strict mode: ${reasons.join(", ")}`;
45211
45536
  }
45212
- function validateAgentGrammar(orgName, agentId, agent) {
45537
+ function validateAgentGrammar(orgName, agentId, agent, mode) {
45213
45538
  const dialect = dialectForProvider(agent.modelConfig.provider);
45214
45539
  if (!dialect) return;
45215
45540
  const capabilities = agentCapabilitiesForGrammarCheck(agent.config);
@@ -45230,12 +45555,12 @@ function validateAgentGrammar(orgName, agentId, agent) {
45230
45555
  compileSchema(offending.inputSchema, dialect).refusalReasons,
45231
45556
  offending.inputSchema
45232
45557
  )}. This silently drops strict-mode enforcement for the agent's ENTIRE iteration schema on every call, not just this tool -- compileSchema refuses whole-schema, never per-tool.` : `[${orgName}] Agent '${agentId}' iteration schema refused strict mode for provider '${agent.modelConfig.provider}': ${compiled.refusalReasons.join(", ")}. No single tool is independently responsible -- this is a whole-schema limit (e.g. total optional properties across every tool exceeding the provider's cap).`;
45233
- if (getResourceValidatorMode() === "strict") {
45558
+ if (getResourceValidatorMode(mode) === "strict") {
45234
45559
  throw new RegistryValidationError(orgName, agentId, "tools", message);
45235
45560
  }
45236
45561
  console.warn(message);
45237
45562
  }
45238
- function validateAgentCheapAssertions(orgName, agentId, agent) {
45563
+ function validateAgentCheapAssertions(orgName, agentId, agent, mode) {
45239
45564
  const issues = [];
45240
45565
  const config3 = agent.config;
45241
45566
  if (config3.sessionCapable && config3.securityLevel === "none") {
@@ -45265,7 +45590,7 @@ function validateAgentCheapAssertions(orgName, agentId, agent) {
45265
45590
  }
45266
45591
  if (issues.length === 0) return;
45267
45592
  const message = `[${orgName}] Agent '${agentId}': ${issues.join(" ")}`;
45268
- if (getResourceValidatorMode() === "strict") {
45593
+ if (getResourceValidatorMode(mode) === "strict") {
45269
45594
  throw new RegistryValidationError(orgName, agentId, "config", message);
45270
45595
  }
45271
45596
  console.warn(message);
@@ -45532,34 +45857,24 @@ var init_validation2 = __esm({
45532
45857
  init_compile();
45533
45858
  init_dialect();
45534
45859
  init_response_schema();
45860
+ init_utils3();
45535
45861
  init_helpers();
45536
45862
  init_ontology();
45537
45863
  init_readiness();
45538
45864
  init_systems();
45539
45865
  RegistryValidationError = class extends Error {
45540
- constructor(orgName, resourceId, field2, message) {
45866
+ constructor(orgName, resourceId, field2, message, issues) {
45541
45867
  super(message);
45542
45868
  this.orgName = orgName;
45543
45869
  this.resourceId = resourceId;
45544
45870
  this.field = field2;
45871
+ this.issues = issues;
45545
45872
  this.name = "RegistryValidationError";
45546
45873
  }
45547
45874
  };
45548
45875
  }
45549
45876
  });
45550
45877
 
45551
- // ../core/src/execution/engine/workflow/types.ts
45552
- var StepType;
45553
- var init_types5 = __esm({
45554
- "../core/src/execution/engine/workflow/types.ts"() {
45555
- "use strict";
45556
- StepType = {
45557
- LINEAR: "linear",
45558
- CONDITIONAL: "conditional"
45559
- };
45560
- }
45561
- });
45562
-
45563
45878
  // ../core/src/execution/engine/base/serialization.ts
45564
45879
  function serializeDefinition(definition, options) {
45565
45880
  const opts = {
@@ -47295,7 +47610,7 @@ var init_croner = __esm({
47295
47610
  });
47296
47611
 
47297
47612
  // ../core/src/execution/scheduler/utils.ts
47298
- var init_utils3 = __esm({
47613
+ var init_utils4 = __esm({
47299
47614
  "../core/src/execution/scheduler/utils.ts"() {
47300
47615
  "use strict";
47301
47616
  init_esm2();
@@ -47309,7 +47624,7 @@ var init_scheduler = __esm({
47309
47624
  "use strict";
47310
47625
  init_types8();
47311
47626
  init_schemas3();
47312
- init_utils3();
47627
+ init_utils4();
47313
47628
  }
47314
47629
  });
47315
47630
 
@@ -47404,6 +47719,13 @@ var init_clickup = __esm({
47404
47719
  }
47405
47720
  });
47406
47721
 
47722
+ // ../core/src/execution/engine/tools/integration/types/instagram.ts
47723
+ var init_instagram = __esm({
47724
+ "../core/src/execution/engine/tools/integration/types/instagram.ts"() {
47725
+ "use strict";
47726
+ }
47727
+ });
47728
+
47407
47729
  // ../core/src/execution/engine/tools/integration/types/index.ts
47408
47730
  var init_types9 = __esm({
47409
47731
  "../core/src/execution/engine/tools/integration/types/index.ts"() {
@@ -47421,6 +47743,7 @@ var init_types9 = __esm({
47421
47743
  init_tomba();
47422
47744
  init_millionverifier();
47423
47745
  init_clickup();
47746
+ init_instagram();
47424
47747
  }
47425
47748
  });
47426
47749
 
@@ -47702,7 +48025,7 @@ var init_schemas6 = __esm({
47702
48025
  });
47703
48026
 
47704
48027
  // ../core/src/operations/observability/utils.ts
47705
- var init_utils4 = __esm({
48028
+ var init_utils5 = __esm({
47706
48029
  "../core/src/operations/observability/utils.ts"() {
47707
48030
  "use strict";
47708
48031
  }
@@ -47714,7 +48037,7 @@ var init_observability = __esm({
47714
48037
  "use strict";
47715
48038
  init_types13();
47716
48039
  init_schemas6();
47717
- init_utils4();
48040
+ init_utils5();
47718
48041
  }
47719
48042
  });
47720
48043
 
@@ -48514,7 +48837,14 @@ var init_api_schemas5 = __esm({
48514
48837
  "use strict";
48515
48838
  init_zod();
48516
48839
  init_validation();
48517
- CredentialTypeSchema = external_exports.enum(["oauth", "api-key", "webhook-secret", "api-key-secret", "clickup"]);
48840
+ CredentialTypeSchema = external_exports.enum([
48841
+ "oauth",
48842
+ "api-key",
48843
+ "webhook-secret",
48844
+ "api-key-secret",
48845
+ "clickup",
48846
+ "instagram"
48847
+ ]);
48518
48848
  CredentialValueSchema = external_exports.record(external_exports.string(), external_exports.unknown()).refine((val) => Object.keys(val).length > 0, { message: "Credential value must not be empty" }).refine((val) => Object.keys(val).length <= 50, { message: "Credential value has too many keys (max 50)" }).refine(
48519
48849
  (val) => {
48520
48850
  for (const v of Object.values(val)) {
@@ -48582,6 +48912,21 @@ var init_credentials2 = __esm({
48582
48912
  }
48583
48913
  });
48584
48914
 
48915
+ // ../core/src/integrations/cloud-storage/types.ts
48916
+ var init_types20 = __esm({
48917
+ "../core/src/integrations/cloud-storage/types.ts"() {
48918
+ "use strict";
48919
+ }
48920
+ });
48921
+
48922
+ // ../core/src/integrations/cloud-storage/index.ts
48923
+ var init_cloud_storage = __esm({
48924
+ "../core/src/integrations/cloud-storage/index.ts"() {
48925
+ "use strict";
48926
+ init_types20();
48927
+ }
48928
+ });
48929
+
48585
48930
  // ../core/src/index.ts
48586
48931
  var init_src = __esm({
48587
48932
  "../core/src/index.ts"() {
@@ -48598,6 +48943,7 @@ var init_src = __esm({
48598
48943
  init_forms();
48599
48944
  init_oauth();
48600
48945
  init_credentials2();
48946
+ init_cloud_storage();
48601
48947
  }
48602
48948
  });
48603
48949
 
@@ -48654,6 +49000,12 @@ function resolveApiKey(prod) {
48654
49000
  }
48655
49001
  return process.env.ELEVASIS_PLATFORM_KEY ?? "";
48656
49002
  }
49003
+ function isProdApiUrl(apiUrl) {
49004
+ return !apiUrl.includes("localhost");
49005
+ }
49006
+ function resolveApiKeyForUrl(apiUrl) {
49007
+ return resolveApiKey(isProdApiUrl(apiUrl));
49008
+ }
48657
49009
  function tryFindProjectRoot(startDir) {
48658
49010
  const raw = (0, import_path.resolve)(startDir);
48659
49011
  let dir;
@@ -48738,12 +49090,89 @@ var init_config2 = __esm({
48738
49090
  }
48739
49091
  });
48740
49092
 
49093
+ // src/cli/readiness-failure.ts
49094
+ function isReadinessFailureDetails(details) {
49095
+ if (!details || typeof details !== "object") return false;
49096
+ const candidate = details;
49097
+ return typeof candidate.systemPath === "string" && typeof candidate.interfaceKey === "string" && // Deliberately `string`, not a check against the known families. Narrowing
49098
+ // it here would reject a readiness refusal carrying a family this build has
49099
+ // not learned yet, and `request()` would fall through to the gateway
49100
+ // message -- which tells the operator the API did not reject the request and
49101
+ // it may still be running server-side. That is false for every readiness
49102
+ // refusal, familiar family or not. An unrecognized code is handled where it
49103
+ // can be handled honestly, in `guidanceForFamily`.
49104
+ typeof candidate.readinessCode === "string" && Array.isArray(candidate.issues);
49105
+ }
49106
+ function parseReadinessFailureDetails(errorText) {
49107
+ let parsed;
49108
+ try {
49109
+ parsed = JSON.parse(errorText);
49110
+ } catch {
49111
+ return void 0;
49112
+ }
49113
+ if (parsed.code !== "SERVICE_UNAVAILABLE") return void 0;
49114
+ return isReadinessFailureDetails(parsed.details) ? parsed.details : void 0;
49115
+ }
49116
+ function formatIssue(issue2) {
49117
+ let line = ` - [${issue2.code}] ${issue2.message}`;
49118
+ if (issue2.path) line += ` (path: ${issue2.path})`;
49119
+ if (issue2.ref) line += ` (ref: ${issue2.ref})`;
49120
+ return line;
49121
+ }
49122
+ function describeUnknownFamily(readinessCode) {
49123
+ return `This CLI does not recognize readiness code "${readinessCode}", so it cannot describe the general shape of the fix. The issues below are the API's own explanation and are the authoritative part of this message.
49124
+ The likely cause is version skew -- this @elevasis/sdk is older than the API it just called. Update it (pnpm update @elevasis/sdk) and run this again.`;
49125
+ }
49126
+ function guidanceForFamily(details) {
49127
+ const lookup = FAMILY_GUIDANCE;
49128
+ return lookup[details.readinessCode]?.(details) ?? describeUnknownFamily(details.readinessCode);
49129
+ }
49130
+ function describeReadinessFailure(details, endpoint) {
49131
+ const profileSuffix = details.readinessProfile ? ` (readiness profile: ${details.readinessProfile})` : "";
49132
+ const lines = [
49133
+ `API request refused (503): ${details.systemPath}/${details.interfaceKey} is not ready for this API surface${profileSuffix}.`,
49134
+ `This IS the API rejecting the request -- it is not a gateway hiccup, and re-running it will not help.`,
49135
+ ` Endpoint: ${endpoint}`,
49136
+ ""
49137
+ ];
49138
+ lines.push(
49139
+ details.readinessCode === "STALE_OM_SNAPSHOT" ? details.issues[0]?.message ?? "The deployed organization model snapshot is stale. Deploy again to fix this: elevasis-sdk deploy" : guidanceForFamily(details)
49140
+ );
49141
+ if (details.issues.length > 0) {
49142
+ lines.push("", " Issues:", ...details.issues.map(formatIssue));
49143
+ }
49144
+ lines.push("", ` Run 'elevasis-sdk doctor' to see what else is not ready.`);
49145
+ return lines.join("\n");
49146
+ }
49147
+ var FAMILY_GUIDANCE;
49148
+ var init_readiness_failure = __esm({
49149
+ "src/cli/readiness-failure.ts"() {
49150
+ "use strict";
49151
+ FAMILY_GUIDANCE = {
49152
+ SYSTEM_INTERFACE_MISSING: ({ systemPath }) => `This organization has not adopted the "${systemPath}" System. Declare it in this project's core/config/organization-model/systems.ts with an apiInterface block, then deploy (elevasis-sdk deploy or pnpm operations:deploy).
49153
+ Known trap: an empty apiInterface.resourceIds throws -- omit the apiInterface block entirely for the supported opt-out.`,
49154
+ SYSTEM_INTERFACE_DISABLED: ({ systemPath }) => `The "${systemPath}" System declares an apiInterface but it is not active. Re-enable it (apiInterface.lifecycle: 'active') and redeploy.`,
49155
+ // Two failures share this family and they need opposite advice.
49156
+ //
49157
+ // A validator that rejected a declaration emits a `path`, and pointing at it
49158
+ // is the whole fix. A stored snapshot that would not parse emits no `path` --
49159
+ // the API sets `ref` (a deployment or organization id) and never `path` --
49160
+ // and the broken thing is the deployed copy, not the source the operator
49161
+ // would go and edit. Sending them after a "path" that is not in the payload,
49162
+ // to fix a declaration that may be perfectly fine, was the failure this
49163
+ // wording had before.
49164
+ SYSTEM_INTERFACE_INVALID: ({ systemPath, issues }) => issues.some((issue2) => issue2.path) ? `The "${systemPath}" System's apiInterface / readinessContract declaration is malformed. See the "path" on each issue below for the offending field.` : `The "${systemPath}" System's stored organization model snapshot could not be read. No field of your declaration is known to be wrong -- it is the deployed copy that failed, so deploy again first (elevasis-sdk deploy). If that does not clear it, the declaration is the next place to look.`,
49165
+ SYSTEM_INTERFACE_NOT_READY: ({ systemPath }) => `The "${systemPath}" System's readinessContract is unsatisfied. See the issues below for the missing requiredObjects / requiredCatalogs refs.`,
49166
+ SYSTEM_BRIDGE_NOT_READY: ({ systemPath }) => `The counterpart System of "${systemPath}"'s cross-System handoff is not ready. Check readiness on both sides of the bridge.`
49167
+ };
49168
+ }
49169
+ });
49170
+
48741
49171
  // src/cli/api-client.ts
48742
49172
  function getApiKey(apiUrl) {
48743
- const isProd = !apiUrl.includes("localhost");
48744
- const key = resolveApiKey(isProd);
49173
+ const key = resolveApiKeyForUrl(apiUrl);
48745
49174
  if (!key) {
48746
- const varName = isProd ? "ELEVASIS_PLATFORM_KEY" : "ELEVASIS_PLATFORM_KEY_DEV";
49175
+ const varName = isProdApiUrl(apiUrl) ? "ELEVASIS_PLATFORM_KEY" : "ELEVASIS_PLATFORM_KEY_DEV";
48747
49176
  throw new Error(`${varName} environment variable is required.
48748
49177
  Set it in your .env file: ${varName}=sk_...`);
48749
49178
  }
@@ -48805,6 +49234,10 @@ async function request(method, endpoint, apiUrl, body) {
48805
49234
  if (response.status === 401) {
48806
49235
  throw new Error(`401 Unauthorized: Invalid or missing ELEVASIS_PLATFORM_KEY. Check your .env file.`);
48807
49236
  }
49237
+ const readinessDetails = parseReadinessFailureDetails(errorText);
49238
+ if (readinessDetails) {
49239
+ throw new Error(describeReadinessFailure(readinessDetails, endpoint));
49240
+ }
48808
49241
  if (GATEWAY_STATUSES.has(response.status)) {
48809
49242
  throw new Error(describeGatewayFailure(response.status, endpoint, elapsedMs));
48810
49243
  }
@@ -48832,6 +49265,7 @@ var init_api_client = __esm({
48832
49265
  "src/cli/api-client.ts"() {
48833
49266
  "use strict";
48834
49267
  init_config2();
49268
+ init_readiness_failure();
48835
49269
  DEFAULT_TIMEOUT_MS = 2 * 60 * 60 * 1e3;
48836
49270
  GATEWAY_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
48837
49271
  }
@@ -48864,7 +49298,7 @@ var init_package = __esm({
48864
49298
  "package.json"() {
48865
49299
  package_default = {
48866
49300
  name: "@elevasis/sdk",
48867
- version: "1.48.0",
49301
+ version: "1.50.0",
48868
49302
  description: "SDK for building Elevasis organization resources",
48869
49303
  type: "module",
48870
49304
  bin: {
@@ -48896,6 +49330,7 @@ var init_package = __esm({
48896
49330
  "dist/test-utils/index.js",
48897
49331
  "dist/test-utils/index.d.ts",
48898
49332
  "dist/node/",
49333
+ "dist/chunk-*.js",
48899
49334
  "dist/cli.cjs",
48900
49335
  "reference/"
48901
49336
  ],
@@ -48915,8 +49350,14 @@ var init_package = __esm({
48915
49350
  "remark-gfm": "^4.0.1"
48916
49351
  },
48917
49352
  peerDependencies: {
49353
+ vitest: ">=3",
48918
49354
  zod: "^4.1.0"
48919
49355
  },
49356
+ peerDependenciesMeta: {
49357
+ vitest: {
49358
+ optional: true
49359
+ }
49360
+ },
48920
49361
  devDependencies: {
48921
49362
  "@repo/core": "workspace:*",
48922
49363
  "@repo/eslint-config": "workspace:*",
@@ -48931,6 +49372,7 @@ var init_package = __esm({
48931
49372
  "rollup-plugin-dts": "^6.3.0",
48932
49373
  tsup: "^8.0.0",
48933
49374
  typescript: "5.9.2",
49375
+ vitest: "^3.2.4",
48934
49376
  zod: "^4.1.0"
48935
49377
  }
48936
49378
  };
@@ -49069,7 +49511,15 @@ function extractResourceMetadata(resource, schemaWarnings) {
49069
49511
  return meta;
49070
49512
  }
49071
49513
  function bumpVersion(current, type) {
49072
- const [major, minor, patch] = current.split(".").map(Number);
49514
+ const match = PLAIN_SEMVER_RE.exec(current);
49515
+ if (!match) {
49516
+ throw new Error(
49517
+ `Cannot bump version: "${current}" is not a plain "major.minor.patch" version (e.g. "1.0.0"). Set the deployment spec's version to a plain semver value before using --major/--minor/--patch.`
49518
+ );
49519
+ }
49520
+ const major = Number(match[1]);
49521
+ const minor = Number(match[2]);
49522
+ const patch = Number(match[3]);
49073
49523
  switch (type) {
49074
49524
  case "major":
49075
49525
  return `${major + 1}.0.0`;
@@ -49080,36 +49530,55 @@ function bumpVersion(current, type) {
49080
49530
  }
49081
49531
  }
49082
49532
  function updateDeploymentVersionSource(source, newVersion) {
49083
- let offset = 0;
49533
+ const exportIndex = source.indexOf("export default");
49534
+ if (exportIndex === -1) {
49535
+ throw new Error('Unable to find "export default" in the deployment entry file');
49536
+ }
49537
+ const rootBraceIndex = source.indexOf("{", exportIndex);
49538
+ if (rootBraceIndex === -1) {
49539
+ throw new Error("Unable to find the default-exported object in the deployment entry file");
49540
+ }
49541
+ let depth = 0;
49542
+ let offset = rootBraceIndex;
49084
49543
  while (offset < source.length) {
49085
- const keyIndex = source.indexOf("version", offset);
49086
- if (keyIndex === -1) break;
49087
- const before = source[keyIndex - 1];
49088
- const after = source[keyIndex + "version".length];
49089
- const isIdentifierBoundary = (before === void 0 || !/[A-Za-z0-9_$]/.test(before)) && (after === void 0 || !/[A-Za-z0-9_$]/.test(after));
49090
- if (!isIdentifierBoundary) {
49091
- offset = keyIndex + "version".length;
49544
+ const char = source[offset];
49545
+ if (char === "{" || char === "[" || char === "(") {
49546
+ depth += 1;
49547
+ offset += 1;
49092
49548
  continue;
49093
49549
  }
49094
- let cursor = keyIndex + "version".length;
49095
- while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49096
- if (source[cursor] !== ":") {
49097
- offset = cursor;
49550
+ if (char === "}" || char === "]" || char === ")") {
49551
+ depth -= 1;
49552
+ offset += 1;
49553
+ if (depth === 0) break;
49098
49554
  continue;
49099
49555
  }
49100
- cursor += 1;
49101
- while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49102
- const quote = source[cursor];
49103
- if (quote !== "'" && quote !== '"') {
49104
- offset = cursor;
49105
- continue;
49556
+ if (depth === 1 && char === "v" && source.startsWith("version", offset)) {
49557
+ const before = source[offset - 1];
49558
+ const after = source[offset + "version".length];
49559
+ const isIdentifierBoundary = (before === void 0 || !/[A-Za-z0-9_$]/.test(before)) && (after === void 0 || !/[A-Za-z0-9_$]/.test(after));
49560
+ if (isIdentifierBoundary) {
49561
+ let cursor = offset + "version".length;
49562
+ while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49563
+ if (source[cursor] === ":") {
49564
+ cursor += 1;
49565
+ while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49566
+ const quote = source[cursor];
49567
+ if (quote === "'" || quote === '"') {
49568
+ const valueStart = cursor + 1;
49569
+ const valueEnd = source.indexOf(quote, valueStart);
49570
+ if (valueEnd !== -1) {
49571
+ return `${source.slice(0, valueStart)}${newVersion}${source.slice(valueEnd)}`;
49572
+ }
49573
+ }
49574
+ }
49575
+ }
49106
49576
  }
49107
- const valueStart = cursor + 1;
49108
- const valueEnd = source.indexOf(quote, valueStart);
49109
- if (valueEnd === -1) break;
49110
- return `${source.slice(0, valueStart)}${newVersion}${source.slice(valueEnd)}`;
49577
+ offset += 1;
49111
49578
  }
49112
- throw new Error("Unable to find a quoted version property in the deployment entry file");
49579
+ throw new Error(
49580
+ "Unable to find a quoted version property on the default-exported deployment spec (not nested inside a resource config) in the entry file"
49581
+ );
49113
49582
  }
49114
49583
  function listOrganizationModelContractRefs(org) {
49115
49584
  return Object.values(org.organizationModel?.resources ?? {}).flatMap((resource) => {
@@ -49121,7 +49590,7 @@ function listOrganizationModelContractRefs(org) {
49121
49590
  ].filter((entry) => entry[1] !== void 0).map(([side, ref]) => ({ resourceId: resource.id, side, ref }));
49122
49591
  });
49123
49592
  }
49124
- function validateResourceGovernancePreflight(orgName, org, contractRegistry) {
49593
+ function validateResourceGovernancePreflight(orgName, org, contractRegistry, onWarning = (message) => console.warn(message)) {
49125
49594
  if (org.organizationModel !== void 0) {
49126
49595
  OrganizationModelSchema.parse(org.organizationModel);
49127
49596
  }
@@ -49141,24 +49610,43 @@ Run \`pnpm exec elevasis-sdk om:scaffold:fill --gaps <path>\` to scaffold the mi
49141
49610
  );
49142
49611
  }
49143
49612
  validateDeclaredSystemInterfaceReadiness(orgName, org.organizationModel);
49144
- if (process.env.ELEVASIS_RESOURCE_VALIDATOR === "warn-only") return;
49145
- validateResourceGovernance(orgName, org, org.organizationModel, { mode: "strict" });
49613
+ const mode = process.env.ELEVASIS_RESOURCE_VALIDATOR === "warn-only" ? "warn-only" : "strict";
49614
+ validateResourceGovernance(orgName, org, org.organizationModel, {
49615
+ mode,
49616
+ onWarning: (issue2) => onWarning(issue2.message)
49617
+ });
49146
49618
  const contractRefs = listOrganizationModelContractRefs(org);
49147
- if (contractRefs.length === 0 || contractRegistry === void 0) return;
49619
+ if (contractRefs.length === 0) return;
49620
+ if (contractRegistry === void 0) {
49621
+ onWarning(
49622
+ `[${orgName}] ${contractRefs.length} contract ref${contractRefs.length !== 1 ? "s" : ""} declared in organizationModel but no \`contractRegistry\` (or \`ELEVASIS_CONTRACT_REGISTRY\`) was exported from the entry file -- contract-ref resolution skipped.`
49623
+ );
49624
+ return;
49625
+ }
49148
49626
  for (const { resourceId, side, ref } of contractRefs) {
49149
49627
  try {
49150
49628
  resolveContractRef(ref, contractRegistry);
49151
49629
  } catch (error46) {
49152
49630
  const message = error46 instanceof Error ? error46.message : String(error46);
49153
- throw new RegistryValidationError(
49154
- orgName,
49155
- resourceId,
49156
- `organizationModel.resources.${resourceId}.ontology.contract.${side}`,
49157
- message
49158
- );
49631
+ const field2 = `organizationModel.resources.${resourceId}.ontology.contract.${side}`;
49632
+ if (mode === "warn-only") {
49633
+ onWarning(`[${orgName}] ${field2}: ${message}`);
49634
+ continue;
49635
+ }
49636
+ throw new RegistryValidationError(orgName, resourceId, field2, message);
49159
49637
  }
49160
49638
  }
49161
49639
  }
49640
+ function formatZodValidationError(error46) {
49641
+ return error46.issues.map((issue2) => {
49642
+ const path3 = issue2.path.length > 0 ? issue2.path.join(".") : "(root)";
49643
+ return `${path3}: ${issue2.message}`;
49644
+ });
49645
+ }
49646
+ function formatRegistryValidationError(error46) {
49647
+ if (error46.issues && error46.issues.length > 1) return error46.issues;
49648
+ return [error46.message];
49649
+ }
49162
49650
  function registerDeployCommand(program3) {
49163
49651
  program3.command("deploy").description(
49164
49652
  "Validate, bundle, upload, and deploy project resources\n Example: elevasis-sdk deploy --api-url http://localhost:5170"
@@ -49182,7 +49670,7 @@ function registerDeployCommand(program3) {
49182
49670
  authSpinner.fail(source_default.red("Authentication failed"));
49183
49671
  const errMsg = error46 instanceof Error ? error46.message : String(error46);
49184
49672
  if (errMsg.includes("401") || errMsg.toLowerCase().includes("unauthorized")) {
49185
- const keyVar = !options.prod && process.env.NODE_ENV === "development" && process.env.ELEVASIS_PLATFORM_KEY_DEV ? "ELEVASIS_PLATFORM_KEY_DEV" : "ELEVASIS_PLATFORM_KEY";
49673
+ const keyVar = !isProdApiUrl(apiUrl) && process.env.NODE_ENV === "development" && process.env.ELEVASIS_PLATFORM_KEY_DEV ? "ELEVASIS_PLATFORM_KEY_DEV" : "ELEVASIS_PLATFORM_KEY";
49186
49674
  console.error(source_default.red(" Invalid API key."));
49187
49675
  console.error(source_default.gray(` Your ${keyVar} was rejected by the server.`));
49188
49676
  console.error(source_default.gray(" Check your .env file and verify the key in the Elevasis dashboard."));
@@ -49206,7 +49694,13 @@ function registerDeployCommand(program3) {
49206
49694
  throw new Error("Invalid entry: no default export found");
49207
49695
  }
49208
49696
  const contractRegistry = deploymentModule.contractRegistry ?? deploymentModule.ELEVASIS_CONTRACT_REGISTRY;
49209
- validateResourceGovernancePreflight(orgName, org, contractRegistry);
49697
+ const governanceWarnings = [];
49698
+ validateResourceGovernancePreflight(
49699
+ orgName,
49700
+ org,
49701
+ contractRegistry,
49702
+ (message) => governanceWarnings.push(message)
49703
+ );
49210
49704
  new ResourceRegistry({ [orgName]: org });
49211
49705
  activeWorkflows = (org.workflows ?? []).filter((w) => !w.config.archived);
49212
49706
  activeAgents = (org.agents ?? []).filter((a) => !a.config.archived);
@@ -49215,6 +49709,12 @@ function registerDeployCommand(program3) {
49215
49709
  validateSpinner.succeed(
49216
49710
  source_default.green("Validating...") + source_default.white(" done") + source_default.gray(` (${totalCount} resource${totalCount !== 1 ? "s" : ""}, 0 errors)`)
49217
49711
  );
49712
+ if (governanceWarnings.length > 0) {
49713
+ for (const warning of governanceWarnings) {
49714
+ console.log(source_default.yellow(` warn ${warning}`));
49715
+ }
49716
+ console.log("");
49717
+ }
49218
49718
  if (archivedCount > 0) {
49219
49719
  console.log(source_default.gray(` Skipping ${archivedCount} archived resource${archivedCount !== 1 ? "s" : ""}`));
49220
49720
  }
@@ -49248,12 +49748,30 @@ function registerDeployCommand(program3) {
49248
49748
  if (error46 instanceof RegistryValidationError) {
49249
49749
  validateSpinner.fail(source_default.red("Validation failed"));
49250
49750
  console.error("");
49251
- console.error(source_default.red(` ERROR ${error46.message}`));
49751
+ const issues = formatRegistryValidationError(error46);
49752
+ if (issues.length > 1) {
49753
+ console.error(source_default.red(` ${issues.length} issues:`));
49754
+ for (const issue2 of issues) {
49755
+ console.error(source_default.red(` - ${issue2}`));
49756
+ }
49757
+ } else {
49758
+ console.error(source_default.red(` ERROR ${issues[0]}`));
49759
+ }
49252
49760
  if (error46.resourceId) {
49253
49761
  console.error(source_default.gray(` Resource: ${error46.resourceId}`));
49254
49762
  }
49255
49763
  console.error("");
49256
49764
  console.error(source_default.gray(" Deploy aborted."));
49765
+ } else if (error46 instanceof external_exports.ZodError) {
49766
+ validateSpinner.fail(source_default.red("Validation failed: organization model does not match the expected shape"));
49767
+ console.error("");
49768
+ for (const line of formatZodValidationError(error46)) {
49769
+ console.error(source_default.red(` ERROR ${line}`));
49770
+ }
49771
+ console.error("");
49772
+ console.error(source_default.gray(" Deploy aborted."));
49773
+ } else if (validateSpinner.isSpinning) {
49774
+ validateSpinner.fail(source_default.red("Validation failed"));
49257
49775
  }
49258
49776
  throw error46;
49259
49777
  }
@@ -49318,11 +49836,11 @@ import { startWorker } from '@elevasis/sdk/worker'
49318
49836
  const uploadSpinner = ora("Uploading...").start();
49319
49837
  try {
49320
49838
  const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
49321
- const apiKey = resolveApiKey(options.prod);
49839
+ const apiKey = resolveApiKeyForUrl(apiUrl);
49322
49840
  if (!apiKey) {
49323
49841
  uploadSpinner.fail(source_default.red("Missing API key environment variable"));
49324
49842
  console.error(source_default.gray(" Set it in your .env file or shell environment:"));
49325
- if (!options.prod && process.env.NODE_ENV === "development") {
49843
+ if (!isProdApiUrl(apiUrl) && process.env.NODE_ENV === "development") {
49326
49844
  console.error(
49327
49845
  source_default.gray(" ELEVASIS_PLATFORM_KEY_DEV=sk_... (or ELEVASIS_PLATFORM_KEY as fallback)")
49328
49846
  );
@@ -49390,7 +49908,7 @@ import { startWorker } from '@elevasis/sdk/worker'
49390
49908
  )
49391
49909
  );
49392
49910
  }
49393
- var import_path2, import_promises, import_fs2, import_crypto, import_url, import_module;
49911
+ var import_path2, import_promises, import_fs2, import_crypto, import_url, import_module, PLAIN_SEMVER_RE;
49394
49912
  var init_deploy = __esm({
49395
49913
  "src/cli/commands/deploy.ts"() {
49396
49914
  "use strict";
@@ -49411,6 +49929,7 @@ var init_deploy = __esm({
49411
49929
  init_api_client();
49412
49930
  init_wrap_action();
49413
49931
  init_version();
49932
+ PLAIN_SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;
49414
49933
  }
49415
49934
  });
49416
49935
 
@@ -49554,18 +50073,35 @@ function emitSystemEntry(opts) {
49554
50073
  const order = opts.order ?? 10;
49555
50074
  let apiInterfaceBlock = "";
49556
50075
  let apiInterfaceNote;
50076
+ let importLine;
49557
50077
  if (opts.apiBacked) {
49558
50078
  const cataloged = SYSTEM_INTERFACE_PROFILES.find(
49559
50079
  (profile) => profile.systemPath === opts.id && profile.interfaceKey === "api"
49560
50080
  );
49561
- if (cataloged !== void 0) {
50081
+ const resourceIds = (opts.resourceIds ?? []).filter((id) => id.trim().length > 0);
50082
+ if (cataloged !== void 0 && cataloged.validation === "built-in" && resourceIds.length > 0) {
50083
+ defineSystemApiInterface({
50084
+ systemPath: opts.id,
50085
+ readinessProfile: cataloged.readinessProfile,
50086
+ resourceIds
50087
+ });
50088
+ importLine = `import { defineSystemApiInterface } from '@elevasis/core/organization-model'`;
50089
+ const resourceIdsLines = resourceIds.map((id) => ` '${id}'`).join(",\n");
49562
50090
  apiInterfaceBlock = `
49563
- apiInterface: {
49564
- lifecycle: 'active',
49565
- readinessProfile: '${cataloged.readinessProfile}'
49566
- },`;
50091
+ apiInterface: defineSystemApiInterface({
50092
+ systemPath: '${opts.id}',
50093
+ readinessProfile: '${cataloged.readinessProfile}',
50094
+ resourceIds: [
50095
+ ${resourceIdsLines}
50096
+ ]
50097
+ }),`;
50098
+ } else if (cataloged !== void 0 && cataloged.validation === "built-in") {
50099
+ apiInterfaceNote = `System \`${opts.id}\` is cataloged for readiness profile "${cataloged.readinessProfile}", but a brand-new System has no scoped resources yet to back an \`apiInterface\`. \`apiInterface\` was NOT added. Once real resource ids exist for this system, declare it with \`defineSystemApiInterface\` from '@elevasis/core/organization-model' (or re-run \`om:scaffold:fill\`, which does this for you).`;
50100
+ } else if (cataloged !== void 0) {
50101
+ apiInterfaceNote = `System \`${opts.id}\` adopts contract-validated readiness profile "${cataloged.readinessProfile}". \`apiInterface\` was NOT added \u2014 declare it with \`defineContentSystem\` from '@elevasis/core/organization-model', which derives the readinessContract, content:object/item, and status catalog from your pipelines, item voice, and status vocabulary.`;
49567
50102
  } else {
49568
- apiInterfaceNote = `System \`${opts.id}\` is not on a cataloged readiness profile (only sales.lead-gen and sales.crm ship built-in profiles today). \`apiInterface\` was NOT added. Declare it manually once real resourceIds exist for this system, using either a cataloged profile or a custom \`readinessProfile\` paired with a \`readinessContract\`.`;
50103
+ const adoptable = SYSTEM_INTERFACE_PROFILES.filter((profile) => profile.interfaceKey === "api").map((profile) => `"${profile.systemPath}"`).join(", ");
50104
+ apiInterfaceNote = `System \`${opts.id}\` is not on a cataloged readiness profile (adoptable system paths today: ${adoptable}). \`apiInterface\` was NOT added. A custom System extends behavior through workflows/operations plus ontology, resources, and topology \u2014 omitting apiInterface entirely is the designed opt-out.`;
49569
50105
  }
49570
50106
  }
49571
50107
  const code = ` {
@@ -49581,7 +50117,8 @@ function emitSystemEntry(opts) {
49581
50117
  `;
49582
50118
  const startAnchor = /^(?!\s*(?:\/\/|\*|\/\*)).*\bexport const templateSystems\s*=/m;
49583
50119
  const anchor = /^\] as const\s*$/m;
49584
- return { code, startAnchor, anchor, apiInterfaceNote };
50120
+ const importAnchor = /^\/\/ -{75,}\n\/\/ Feature/m;
50121
+ return { code, startAnchor, anchor, apiInterfaceNote, importLine, importAnchor };
49585
50122
  }
49586
50123
  var init_emit_system = __esm({
49587
50124
  "src/cli/commands/om/emit-system.ts"() {
@@ -49748,10 +50285,20 @@ async function scaffoldSystem(opts) {
49748
50285
  });
49749
50286
  apiBacked = answer.trim().toLowerCase() === "y";
49750
50287
  }
49751
- const { code, anchor, startAnchor, apiInterfaceNote } = emitSystemEntry({ id, title, kind, apiBacked });
50288
+ const { code, anchor, startAnchor, apiInterfaceNote, importLine, importAnchor } = emitSystemEntry({
50289
+ id,
50290
+ title,
50291
+ kind,
50292
+ apiBacked,
50293
+ resourceIds: options.resourceIds
50294
+ });
49752
50295
  const shouldWrite = options.write === true || options.dryRun === false;
49753
50296
  if (!shouldWrite) {
49754
50297
  console.log(source_default.cyan("Dry-run mode (default) \u2014 no files written. Pass --write to apply.\n"));
50298
+ if (importLine !== void 0) {
50299
+ console.log(source_default.gray("Import line to add near the top of core/config/organization-model/systems.ts:"));
50300
+ console.log(importLine);
50301
+ }
49755
50302
  console.log(source_default.gray("Proposed addition to core/config/organization-model/systems.ts:"));
49756
50303
  console.log(code);
49757
50304
  if (apiInterfaceNote !== void 0) {
@@ -49762,6 +50309,9 @@ async function scaffoldSystem(opts) {
49762
50309
  const systemsFilePath = (0, import_node_path13.join)(getOrganizationModelDir(projectDir), "systems.ts");
49763
50310
  try {
49764
50311
  await withSnapshotRollback([systemsFilePath], async () => {
50312
+ if (importLine !== void 0) {
50313
+ await appendBeforeAnchor(systemsFilePath, importLine + "\n", importAnchor);
50314
+ }
49765
50315
  await appendBeforeAnchor(systemsFilePath, code, anchor, startAnchor);
49766
50316
  const validationError = runValidation(projectDir);
49767
50317
  if (validationError !== null) {
@@ -50208,6 +50758,14 @@ var init_scaffold_knowledge = __esm({
50208
50758
  function toConstName(systemPath) {
50209
50759
  return systemPath.split(/[.-]/).map((segment, index) => index === 0 ? segment : segment.charAt(0).toUpperCase() + segment.slice(1)).join("") + "ApiInterface";
50210
50760
  }
50761
+ function buildContentPlaceholderReadinessContract(systemPath) {
50762
+ return {
50763
+ requiredObjects: [`${systemPath}:object/item`],
50764
+ requiredCatalogs: [
50765
+ "TODO -- replace with this System real pipeline, step, and status catalog ids (see defineContentPipeline and defineContentSystem in the organization-model subpath)"
50766
+ ]
50767
+ };
50768
+ }
50211
50769
  function emitApiInterfaceBlock(gap) {
50212
50770
  const constName = toConstName(gap.systemPath);
50213
50771
  const cataloged = SYSTEM_INTERFACE_PROFILES.find(
@@ -50220,17 +50778,44 @@ function emitApiInterfaceBlock(gap) {
50220
50778
  );
50221
50779
  }
50222
50780
  const readinessProfile = cataloged.readinessProfile;
50223
- const resourceIdsField = gap.resourceIds.length === 0 ? "" : `,
50224
- resourceIds: [
50225
- ${gap.resourceIds.map((id) => `'${id}'`).join(",\n ")}
50226
- ]`;
50781
+ if (gap.resourceIds.length === 0) {
50782
+ throw new Error(
50783
+ `Cannot emit an apiInterface for system path "${gap.systemPath}": the gap carries no resourceIds. defineSystemApiInterface requires at least one scoped resource id \u2014 an interface with none computes as ready and answers every route with a 503. Re-run this scaffolder once the system has at least one API-backed resource declared.`
50784
+ );
50785
+ }
50786
+ const resourceIds = gap.resourceIds;
50787
+ const isContractValidated = cataloged.validation === "contract";
50788
+ const readinessContract = isContractValidated ? buildContentPlaceholderReadinessContract(gap.systemPath) : void 0;
50789
+ defineSystemApiInterface({
50790
+ systemPath: gap.systemPath,
50791
+ readinessProfile,
50792
+ resourceIds,
50793
+ ...readinessContract !== void 0 ? { readinessContract } : {}
50794
+ });
50795
+ const resourceIdsLines = resourceIds.map((id) => ` '${id}'`).join(",\n");
50796
+ const readinessContractField = readinessContract === void 0 ? "" : `,
50797
+ // TODO: requiredCatalogs below is a placeholder. Replace it with this System's actual pipeline,
50798
+ // step, and status catalog ids before deploying \u2014 see extend-content.md in the SDK scaffold docs.
50799
+ readinessContract: {
50800
+ requiredObjects: [
50801
+ ${readinessContract.requiredObjects.map((id) => `'${id}'`).join(",\n ")}
50802
+ ],
50803
+ requiredCatalogs: [
50804
+ ${readinessContract.requiredCatalogs.map((id) => `'${id}'`).join(",\n ")}
50805
+ ]
50806
+ }`;
50227
50807
  const constFileCode = `// Auto-generated by om:scaffold:fill \u2014 do not edit manually.
50228
50808
  // Regenerate by running: elevasis-sdk om:scaffold:fill --gaps <path>
50229
50809
 
50230
- export const ${constName} = {
50231
- lifecycle: 'active' as const,
50232
- readinessProfile: '${readinessProfile}'${resourceIdsField}
50233
- }
50810
+ import { defineSystemApiInterface } from '@elevasis/core/organization-model'
50811
+
50812
+ export const ${constName} = defineSystemApiInterface({
50813
+ systemPath: '${gap.systemPath}',
50814
+ readinessProfile: '${readinessProfile}',
50815
+ resourceIds: [
50816
+ ${resourceIdsLines}
50817
+ ]${readinessContractField}
50818
+ })
50234
50819
  `;
50235
50820
  const importLine = `import { ${constName} } from './api-interfaces/${gap.systemPath}'`;
50236
50821
  const fieldLine = ` apiInterface: ${constName},`;
@@ -50331,11 +50916,21 @@ async function scaffoldFill(opts) {
50331
50916
  gap.resourceIds
50332
50917
  ) : gap.resourceId ? [gap.resourceId] : []
50333
50918
  );
50334
- const emitResult = emitApiInterfaceBlock({
50335
- systemPath,
50336
- resourceIds,
50337
- message: gap.reason
50338
- });
50919
+ let emitResult;
50920
+ try {
50921
+ emitResult = emitApiInterfaceBlock({
50922
+ systemPath,
50923
+ resourceIds,
50924
+ message: gap.reason
50925
+ });
50926
+ } catch (err) {
50927
+ skippedGaps.push({
50928
+ field: gap.field,
50929
+ resourceId: gap.resourceId,
50930
+ reason: err instanceof Error ? err.message : String(err)
50931
+ });
50932
+ continue;
50933
+ }
50339
50934
  const constFilePath = (0, import_node_path17.join)(getOrganizationModelDir(projectDir), "api-interfaces", `${systemPath}.ts`);
50340
50935
  touchedFiles.push(constFilePath);
50341
50936
  emitResults.push(emitResult);
@@ -55314,7 +55909,129 @@ function registerUiCommands(program3) {
55314
55909
  var import_node_fs9 = require("node:fs");
55315
55910
  var import_node_path8 = __toESM(require("node:path"), 1);
55316
55911
  init_source();
55912
+ init_organization_model();
55317
55913
  init_config2();
55914
+ init_load_org_model();
55915
+
55916
+ // src/cli/commands/om/deployed-readiness.ts
55917
+ init_organization_model();
55918
+ init_api_client();
55919
+ function listApiInterfaceSystemPaths(model) {
55920
+ return listAllSystems(model).filter(({ system }) => system.apiInterface !== void 0).map(({ path: path3 }) => path3);
55921
+ }
55922
+ function listDeployedReadinessTargets(model) {
55923
+ const declared = new Set(listApiInterfaceSystemPaths(model));
55924
+ const targets = SYSTEM_INTERFACE_PROFILES.map((profile) => ({
55925
+ systemPath: profile.systemPath,
55926
+ interfaceKey: profile.interfaceKey,
55927
+ declaredLocally: declared.has(profile.systemPath)
55928
+ }));
55929
+ const covered = new Set(targets.map((target) => `${target.systemPath}::${target.interfaceKey}`));
55930
+ for (const systemPath of declared) {
55931
+ const key = `${systemPath}::api`;
55932
+ if (covered.has(key)) continue;
55933
+ covered.add(key);
55934
+ targets.push({ systemPath, interfaceKey: "api", declaredLocally: true });
55935
+ }
55936
+ return targets;
55937
+ }
55938
+ async function fetchDeployedReadiness(model, options = {}) {
55939
+ const targets = listDeployedReadinessTargets(model);
55940
+ const report = {
55941
+ activeDeploymentId: null,
55942
+ snapshotHash: null,
55943
+ kind: null,
55944
+ entries: []
55945
+ };
55946
+ if (targets.length === 0) {
55947
+ report.unavailableReason = "no System-interface profile to check \u2014 neither the platform catalog nor the project model declares one";
55948
+ return report;
55949
+ }
55950
+ for (const target of targets) {
55951
+ let response;
55952
+ try {
55953
+ const endpoint = `/api/external/organization-model/readiness?systemPath=${encodeURIComponent(target.systemPath)}&interfaceKey=${encodeURIComponent(target.interfaceKey)}`;
55954
+ response = await apiGet(endpoint, options.apiUrl);
55955
+ } catch (error46) {
55956
+ report.unavailableReason = error46 instanceof Error ? error46.message : String(error46);
55957
+ return report;
55958
+ }
55959
+ report.activeDeploymentId = response.activeDeploymentId;
55960
+ report.snapshotHash = response.snapshotHash;
55961
+ report.kind = response.kind;
55962
+ report.entries.push({
55963
+ systemPath: response.readiness.systemPath,
55964
+ interfaceKey: response.readiness.interfaceKey,
55965
+ ready: response.readiness.ready,
55966
+ issues: response.readiness.issues,
55967
+ declaredLocally: target.declaredLocally
55968
+ });
55969
+ }
55970
+ return report;
55971
+ }
55972
+ function isUnadoptedNotDeclared(entry) {
55973
+ return !entry.declaredLocally && entry.issues.every((issue2) => issue2.family === "SYSTEM_INTERFACE_MISSING");
55974
+ }
55975
+ function readinessDiagnostics(report) {
55976
+ const diagnostics = [];
55977
+ for (const entry of report.entries) {
55978
+ if (entry.ready) {
55979
+ diagnostics.push({
55980
+ severity: "info",
55981
+ code: "deployed-interface-ready",
55982
+ systemPath: entry.systemPath,
55983
+ message: `${entry.systemPath}/${entry.interfaceKey} is ready in the deployed snapshot.`
55984
+ });
55985
+ continue;
55986
+ }
55987
+ const unadopted = isUnadoptedNotDeclared(entry);
55988
+ for (const issue2 of entry.issues) {
55989
+ diagnostics.push({
55990
+ severity: unadopted ? "info" : "error",
55991
+ code: `deployed-${issue2.code}`,
55992
+ systemPath: entry.systemPath,
55993
+ ...issue2.ref !== void 0 && { targetId: issue2.ref },
55994
+ message: `${entry.systemPath}/${entry.interfaceKey} ${unadopted ? "not adopted" : "not ready"} [${issue2.family}]: ${issue2.message}`,
55995
+ source: "deployed-snapshot"
55996
+ });
55997
+ }
55998
+ }
55999
+ return diagnostics;
56000
+ }
56001
+ function readinessRoster(report) {
56002
+ return report.entries.map((entry) => {
56003
+ if (entry.ready) {
56004
+ return {
56005
+ systemPath: entry.systemPath,
56006
+ interfaceKey: entry.interfaceKey,
56007
+ status: "ready",
56008
+ detail: "ready",
56009
+ issues: []
56010
+ };
56011
+ }
56012
+ if (isUnadoptedNotDeclared(entry)) {
56013
+ return {
56014
+ systemPath: entry.systemPath,
56015
+ interfaceKey: entry.interfaceKey,
56016
+ status: "not-adopted",
56017
+ detail: "not adopted",
56018
+ issues: entry.issues
56019
+ };
56020
+ }
56021
+ return {
56022
+ systemPath: entry.systemPath,
56023
+ interfaceKey: entry.interfaceKey,
56024
+ status: "not-ready",
56025
+ detail: entry.issues[0]?.message ?? "not ready",
56026
+ issues: entry.issues
56027
+ };
56028
+ });
56029
+ }
56030
+ function countReadinessRosterFailures(rows) {
56031
+ return rows.filter((row) => row.status === "not-ready").length;
56032
+ }
56033
+
56034
+ // src/cli/commands/doctor.ts
55318
56035
  function ok(label, detail) {
55319
56036
  console.log(`${source_default.green("[OK]")} ${source_default.bold(label)}: ${detail}`);
55320
56037
  }
@@ -55422,6 +56139,38 @@ function registerDoctorCommand(program3) {
55422
56139
  if (isVerbose) verbose(`Error: ${networkError}`);
55423
56140
  failCount++;
55424
56141
  }
56142
+ let model = DEFAULT_ORGANIZATION_MODEL;
56143
+ try {
56144
+ model = await loadOrgModel(projectRoot);
56145
+ } catch (err) {
56146
+ if (isVerbose) {
56147
+ const msg = err instanceof Error ? err.message : String(err);
56148
+ verbose(`Organization model load failed, roster limited to the platform catalog: ${msg}`);
56149
+ }
56150
+ }
56151
+ const readiness = await fetchDeployedReadiness(model, { apiUrl });
56152
+ if (readiness.unavailableReason !== void 0) {
56153
+ warn("Systems", `Readiness unavailable \u2014 ${readiness.unavailableReason}`);
56154
+ if (isVerbose) verbose(`GET ${apiUrl}/api/external/organization-model/readiness`);
56155
+ } else {
56156
+ const rows = readinessRoster(readiness);
56157
+ for (const row of rows) {
56158
+ const label = `Systems: ${row.systemPath}/${row.interfaceKey}`;
56159
+ if (row.status === "ready") {
56160
+ ok(label, row.detail);
56161
+ } else if (row.status === "not-adopted") {
56162
+ warn(label, row.detail);
56163
+ } else {
56164
+ fail(label, row.detail);
56165
+ }
56166
+ if (isVerbose) {
56167
+ for (const issue2 of row.issues) {
56168
+ verbose(`${issue2.code}: ${issue2.message}`);
56169
+ }
56170
+ }
56171
+ }
56172
+ failCount += countReadinessRosterFailures(rows);
56173
+ }
55425
56174
  console.log();
55426
56175
  printSummary(failCount);
55427
56176
  if (failCount > 0) {
@@ -55841,7 +56590,7 @@ function appendQuery4(params, key, value) {
55841
56590
  }
55842
56591
  function registerContentList(program3) {
55843
56592
  program3.command("content:list").description(
55844
- "List content pipeline items\n Example: elevasis-sdk content:list --status queued --pipeline-id short-form-repurpose"
56593
+ 'List content pipeline items\n Example: elevasis-sdk content:list --status <status> --pipeline-id <pipelineId>\n Note: both values come from the org model this project declares, not a platform enum --\n read them from the content:catalog/status catalog and content:pipeline.\n Note: "awaiting review" is not a status -- that read is content:queue.'
55845
56594
  ).option("--status <status>", "Filter by content item status").option("--pillar <pillar>", "Filter by content pillar").option("--pipeline-id <id>", "Filter by pipeline template id").option("--client-id <id>", "Filter by client id").option("--reviewed-by <id>", "Filter by reviewer user id").option("--search <query>", "Search by title").option("--limit <n>", "Maximum number of results").option("--offset <n>", "Pagination offset").option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
55846
56595
  wrapAction("content:list", async (options) => {
55847
56596
  const apiUrl = resolveApiUrl(options.apiUrl, options.prod);
@@ -55918,6 +56667,12 @@ Content item: ${item.title}`));
55918
56667
  // src/cli/commands/content/board.ts
55919
56668
  init_source();
55920
56669
 
56670
+ // ../core/src/content/review-gates.ts
56671
+ function isAwaitingReview(item, step) {
56672
+ if (!step) return false;
56673
+ return step.reviewMode !== "none" && item.reviewedAt === null;
56674
+ }
56675
+
55921
56676
  // ../core/src/content/derive-board.ts
55922
56677
  function sortPipelineSteps(steps) {
55923
56678
  return [...steps].sort((a, b) => {
@@ -55941,17 +56696,13 @@ function deriveItemPlacement(item, sortedSteps) {
55941
56696
  });
55942
56697
  if (!currentStep) {
55943
56698
  const lastStep = sortedSteps[sortedSteps.length - 1];
55944
- if (lastStep !== void 0 && lastStep.reviewMode !== "none" && item.reviewedAt === null) {
56699
+ if (lastStep !== void 0 && isAwaitingReview(item, lastStep)) {
55945
56700
  return { bucket: "column", stepKey: lastStep.key };
55946
56701
  }
55947
56702
  return { bucket: "done", stepKey: null };
55948
56703
  }
55949
56704
  return { bucket: "column", stepKey: currentStep.key };
55950
56705
  }
55951
- function deriveAwaitingReview(step, item) {
55952
- if (!step) return false;
55953
- return step.reviewMode !== "none" && item.reviewedAt === null;
55954
- }
55955
56706
  function deriveContentBoard(items, pipeline, now) {
55956
56707
  const sortedSteps = sortPipelineSteps(pipeline.steps);
55957
56708
  const stepsByKey = new Map(sortedSteps.map((step) => [step.key, step]));
@@ -55965,7 +56716,7 @@ function deriveContentBoard(items, pipeline, now) {
55965
56716
  item,
55966
56717
  stepKey: placement.stepKey,
55967
56718
  ageMs: now - Date.parse(item.updatedAt),
55968
- awaitingReview: deriveAwaitingReview(step, item)
56719
+ awaitingReview: isAwaitingReview(item, step)
55969
56720
  };
55970
56721
  if (placement.bucket === "done") {
55971
56722
  done.push(card);
@@ -55989,9 +56740,9 @@ function deriveContentBoard(items, pipeline, now) {
55989
56740
  const columns = sortedSteps.map((step) => {
55990
56741
  const cards = cardsByStepKey.get(step.key) ?? [];
55991
56742
  const column = { step, cards };
55992
- if (step.reviewMode === "live" || step.reviewMode === "queued") {
56743
+ if (step.reviewVenue !== "none") {
55993
56744
  column.gate = {
55994
- reviewMode: step.reviewMode,
56745
+ venue: step.reviewVenue,
55995
56746
  waitingCount: cards.filter((card) => card.awaitingReview).length
55996
56747
  };
55997
56748
  }
@@ -56077,7 +56828,7 @@ function printCards(cards, stepsByKey) {
56077
56828
  }
56078
56829
  function registerContentBoard(program3) {
56079
56830
  program3.command("content:board <pipelineId>").description(
56080
- "Render one pipeline as a board -- columns, review gates, and waiting counts\n Example: elevasis-sdk content:board short-form-repurpose --pretty"
56831
+ "Render one pipeline as a board -- columns, review gates, and waiting counts\n Example: elevasis-sdk content:board <pipelineId> --pretty\n Note: pipeline ids come from the org model this project declares -- list them with content:pipeline."
56081
56832
  ).option("--limit <n>", `Items to pull before deriving (default and API maximum ${DEFAULT_ITEM_LIMIT})`).option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
56082
56833
  wrapAction("content:board", async (pipelineId, options) => {
56083
56834
  const apiUrl = resolveApiUrl(options.apiUrl, options.prod);
@@ -56108,7 +56859,9 @@ Board: ${pipelineId} ${source_default.gray(`${items.data.length} of ${items.tot
56108
56859
  }
56109
56860
  console.log();
56110
56861
  for (const column of board.columns) {
56111
- const gate = column.gate ? source_default.yellow(` [${column.gate.reviewMode} gate -- ${column.gate.waitingCount} waiting]`) : "";
56862
+ const gate = column.gate ? source_default.yellow(
56863
+ ` [${column.gate.venue === "workspace" ? "workspace" : "queue"} gate -- ${column.gate.waitingCount} waiting]`
56864
+ ) : "";
56112
56865
  console.log(` ${source_default.bold(column.step.label)} ${source_default.gray(column.step.key)}${gate}`);
56113
56866
  printCards(column.cards, stepsByKey);
56114
56867
  }
@@ -56170,13 +56923,13 @@ Pipeline: ${pipeline.id}`));
56170
56923
  const steps = Array.isArray(pipeline.steps) ? pipeline.steps : [];
56171
56924
  console.log(source_default.gray(` Steps (${steps.length}):`));
56172
56925
  for (const step of steps) {
56173
- console.log(source_default.gray(` - ${step.key} (reviewMode: ${step.reviewMode})`));
56926
+ console.log(source_default.gray(` - ${step.key} (review: ${step.reviewMode}, venue: ${step.reviewVenue})`));
56174
56927
  }
56175
56928
  console.log();
56176
56929
  }
56177
56930
  function registerContentPipeline(program3) {
56178
56931
  program3.command("content:pipeline [id]").description(
56179
- "List content pipeline templates, or show one pipeline's step contract\n Example: elevasis-sdk content:pipeline short-form-repurpose"
56932
+ "List content pipeline templates, or show one pipeline's step contract\n Example: elevasis-sdk content:pipeline <pipelineId>\n Note: run without an id to list the pipeline ids this project declares in its org model."
56180
56933
  ).option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
56181
56934
  wrapAction("content:pipeline", async (id, options) => {
56182
56935
  const apiUrl = resolveApiUrl(options.apiUrl, options.prod);
@@ -56221,7 +56974,7 @@ function appendQuery5(params, key, value) {
56221
56974
  }
56222
56975
  function registerContentDistributions(program3) {
56223
56976
  program3.command("content:distributions").description(
56224
- "List content distributions\n Example: elevasis-sdk content:distributions --pipeline-id short-form-repurpose"
56977
+ "List content distributions\n Example: elevasis-sdk content:distributions --pipeline-id <pipelineId>\n Note: pipeline ids come from the org model this project declares -- list them with content:pipeline."
56225
56978
  ).option("--content-item-id <id>", "Filter by content item id").option("--pipeline-id <id>", "Filter by pipeline template id").option("--platform <platform>", "Filter by distribution platform").option("--status <status>", "Filter by distribution status").option("--limit <n>", "Maximum number of results").option("--offset <n>", "Pagination offset").option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
56226
56979
  wrapAction("content:distributions", async (options) => {
56227
56980
  const apiUrl = resolveApiUrl(options.apiUrl, options.prod);
@@ -56404,13 +57157,47 @@ function resolveTextArgument(value) {
56404
57157
  throw new Error(`Could not read --text file "${path3}": ${error46 instanceof Error ? error46.message : String(error46)}`);
56405
57158
  }
56406
57159
  }
57160
+ function resolveMetadataOption(options) {
57161
+ if (options.metadata !== void 0 && options.metadataFile !== void 0) {
57162
+ throw new Error("Pass exactly one of --metadata or --metadata-file, not both");
57163
+ }
57164
+ let raw;
57165
+ if (options.metadataFile !== void 0) {
57166
+ const path3 = resolveProjectRelative(options.metadataFile);
57167
+ try {
57168
+ raw = (0, import_node_fs10.readFileSync)(path3, "utf8");
57169
+ } catch (error46) {
57170
+ throw new Error(
57171
+ `Could not read --metadata-file "${options.metadataFile}": ${error46 instanceof Error ? error46.message : String(error46)}`
57172
+ );
57173
+ }
57174
+ } else {
57175
+ raw = options.metadata;
57176
+ }
57177
+ if (raw === void 0) return void 0;
57178
+ let parsed;
57179
+ try {
57180
+ parsed = JSON.parse(raw);
57181
+ } catch (error46) {
57182
+ const source = options.metadataFile !== void 0 ? "--metadata-file" : "--metadata";
57183
+ throw new Error(`${source} must be valid JSON: ${error46 instanceof Error ? error46.message : String(error46)}`);
57184
+ }
57185
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
57186
+ const source = options.metadataFile !== void 0 ? "--metadata-file" : "--metadata";
57187
+ throw new Error(`${source} must be a JSON object, e.g. {"key":"value"}`);
57188
+ }
57189
+ return parsed;
57190
+ }
56407
57191
  function registerContentSourceAssetCreate(program3) {
56408
57192
  program3.command("content:source-asset:create").description(
56409
57193
  'Create a content source asset from inline text or a URL, optionally linking it to an item\n Example: elevasis-sdk content:source-asset:create --kind transcript --title "Episode 12" --text @transcript.txt --item <uuid>'
56410
57194
  ).requiredOption("--kind <kind>", "Source asset kind (e.g. transcript) -- validated against the org model catalog").requiredOption("--title <title>", "Human-readable title (1..500 chars)").option("--text <value>", "Inline text, or @path to read a local file. Mutually exclusive with --url").option(
56411
57195
  "--field <key>",
56412
57196
  "Payload field the --text content is written to. Defaults to the --kind value, matching the catalog declaration"
56413
- ).option("--url <url>", "External URL the asset references. Mutually exclusive with --text").option("--duration <seconds>", "Duration in seconds, for time-based referenced media").option("--item <itemId>", "Link the new asset to this content item after creating it").option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
57197
+ ).option("--url <url>", "External URL the asset references. Mutually exclusive with --text").option("--duration <seconds>", "Duration in seconds, for time-based referenced media").option("--storage-path <path>", "Storage path the asset references (1..2000 chars)").option("--metadata <json>", "Arbitrary metadata as a JSON object string. Mutually exclusive with --metadata-file").option(
57198
+ "--metadata-file <path>",
57199
+ "Path to a JSON file containing metadata (project-relative unless absolute). Mutually exclusive with --metadata"
57200
+ ).option("--item <itemId>", "Link the new asset to this content item after creating it").option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
56414
57201
  wrapAction("content:source-asset:create", async (options) => {
56415
57202
  if (options.text !== void 0 && options.url !== void 0) {
56416
57203
  throw new Error("Pass exactly one of --text or --url, not both");
@@ -56441,6 +57228,9 @@ function registerContentSourceAssetCreate(program3) {
56441
57228
  }
56442
57229
  body.durationSeconds = duration3;
56443
57230
  }
57231
+ if (options.storagePath !== void 0) body.storagePath = options.storagePath;
57232
+ const metadata = resolveMetadataOption(options);
57233
+ if (metadata !== void 0) body.metadata = metadata;
56444
57234
  const apiUrl = resolveApiUrl(options.apiUrl, options.prod);
56445
57235
  const asset = await apiPost("/api/external/content/source-assets", body, apiUrl);
56446
57236
  let linkedItem;
@@ -56460,6 +57250,7 @@ Created source asset ${asset.id}`));
56460
57250
  console.log(source_default.gray(` Title: ${asset.title}`));
56461
57251
  console.log(source_default.gray(` Kind: ${asset.kind}`));
56462
57252
  if (asset.externalUrl) console.log(source_default.gray(` URL: ${asset.externalUrl}`));
57253
+ if (asset.storagePath) console.log(source_default.gray(` Storage path: ${asset.storagePath}`));
56463
57254
  if (linkedItem) console.log(source_default.cyan(` Linked to item ${linkedItem.id} (${linkedItem.title})`));
56464
57255
  console.log();
56465
57256
  })
@@ -57836,71 +58627,6 @@ function formatOmDoctorReport(report) {
57836
58627
  return lines.join("\n");
57837
58628
  }
57838
58629
 
57839
- // src/cli/commands/om/deployed-readiness.ts
57840
- init_organization_model();
57841
- init_api_client();
57842
- function listApiInterfaceSystemPaths(model) {
57843
- return listAllSystems(model).filter(({ system }) => system.apiInterface !== void 0).map(({ path: path3 }) => path3);
57844
- }
57845
- async function fetchDeployedReadiness(model, options = {}) {
57846
- const systemPaths = listApiInterfaceSystemPaths(model);
57847
- const report = {
57848
- activeDeploymentId: null,
57849
- snapshotHash: null,
57850
- kind: null,
57851
- entries: []
57852
- };
57853
- if (systemPaths.length === 0) {
57854
- report.unavailableReason = "no System in the project model declares an apiInterface";
57855
- return report;
57856
- }
57857
- for (const systemPath of systemPaths) {
57858
- let response;
57859
- try {
57860
- const endpoint = `/api/external/organization-model/readiness?systemPath=${encodeURIComponent(systemPath)}&interfaceKey=api`;
57861
- response = await apiGet(endpoint, options.apiUrl);
57862
- } catch (error46) {
57863
- report.unavailableReason = error46 instanceof Error ? error46.message : String(error46);
57864
- return report;
57865
- }
57866
- report.activeDeploymentId = response.activeDeploymentId;
57867
- report.snapshotHash = response.snapshotHash;
57868
- report.kind = response.kind;
57869
- report.entries.push({
57870
- systemPath: response.readiness.systemPath,
57871
- interfaceKey: response.readiness.interfaceKey,
57872
- ready: response.readiness.ready,
57873
- issues: response.readiness.issues
57874
- });
57875
- }
57876
- return report;
57877
- }
57878
- function readinessDiagnostics(report) {
57879
- const diagnostics = [];
57880
- for (const entry of report.entries) {
57881
- if (entry.ready) {
57882
- diagnostics.push({
57883
- severity: "info",
57884
- code: "deployed-interface-ready",
57885
- systemPath: entry.systemPath,
57886
- message: `${entry.systemPath}/${entry.interfaceKey} is ready in the deployed snapshot.`
57887
- });
57888
- continue;
57889
- }
57890
- for (const issue2 of entry.issues) {
57891
- diagnostics.push({
57892
- severity: "error",
57893
- code: `deployed-${issue2.code}`,
57894
- systemPath: entry.systemPath,
57895
- ...issue2.ref !== void 0 && { targetId: issue2.ref },
57896
- message: `${entry.systemPath}/${entry.interfaceKey} not ready [${issue2.family}]: ${issue2.message}`,
57897
- source: "deployed-snapshot"
57898
- });
57899
- }
57900
- }
57901
- return diagnostics;
57902
- }
57903
-
57904
58630
  // src/cli/commands/om/doctor.ts
57905
58631
  function registerOmDoctorCommand(program3) {
57906
58632
  program3.command("om:doctor").description(
@@ -58714,65 +59440,7 @@ if (envPath) {
58714
59440
  }
58715
59441
  var program2 = new Command();
58716
59442
  program2.name("elevasis-sdk").description(
58717
- source_default.cyan("Elevasis SDK CLI") + `
58718
-
58719
- Commands:
58720
- elevasis-sdk check Validate project resources
58721
- elevasis-sdk deploy Bundle and deploy to platform
58722
- elevasis-sdk resources List deployed resources
58723
- elevasis-sdk describe <resourceId> Describe a resource
58724
- elevasis-sdk exec <resourceId> -i '{}' Execute a resource
58725
- elevasis-sdk executions <resourceId> List execution history
58726
- elevasis-sdk execution <resourceId> <id> Get execution details
58727
- elevasis-sdk execution:cancel <resourceId> <id> Cancel a running execution
58728
- elevasis-sdk executions:delete <resourceId> Delete execution history (destructive)
58729
- elevasis-sdk deployments List deployments
58730
- elevasis-sdk project:list [--search <query>] List projects with optional search
58731
- elevasis-sdk project:resolve <query> Resolve a project ID from a name or UUID
58732
- elevasis-sdk project:work <query> Open a lifecycle-aware project work brief
58733
- elevasis-sdk client:list [--search <query>] List clients with optional search
58734
- elevasis-sdk client:get <id> Get client detail and lineage
58735
- elevasis-sdk client:status Show client portfolio status
58736
- elevasis-sdk content:list [--status queued] List content pipeline items
58737
- elevasis-sdk content:get <itemId> Get an item, its attempts, and distributions
58738
- elevasis-sdk content:queue List items awaiting a queued-gate review
58739
- elevasis-sdk content:pipeline [id] List pipeline templates, or one step contract
58740
- elevasis-sdk content:distributions List content distributions
58741
- elevasis-sdk content:review <itemId> --step <key> --approve|--reject --user <email>
58742
- Clear a queued review gate on a content item
58743
- elevasis-sdk queue:list [--status pending] List HITL command queue tasks
58744
- elevasis-sdk queue:select <id> --action-id <id> Select and execute a HITL queue action
58745
- elevasis-sdk schedule:list [--status active] List task schedules
58746
- elevasis-sdk schedule:create --name <name> ... Create a task schedule
58747
- elevasis-sdk agent:list List deployed agents
58748
- elevasis-sdk agent:get <id> Get agent metadata and OM linkage
58749
- elevasis-sdk session:create <resourceId> Create an agent session
58750
- elevasis-sdk session:turn <id> -f tmp/turn.json Execute a session turn
58751
- elevasis-sdk session:messages <id> Export session transcript messages
58752
- elevasis-sdk session:list List agent sessions
58753
- elevasis-sdk session:get <id> Get session details
58754
- elevasis-sdk session:end <id> End an active agent session
58755
- elevasis-sdk grant:list List public/code-gated agent access grants
58756
- elevasis-sdk grant:create --resource <id> Create an agent access grant
58757
- elevasis-sdk grant:disable <slug> Disable an agent access grant
58758
- elevasis-sdk acquisition:list:list List acquisition lists
58759
- elevasis-sdk acquisition:deal:list List acquisition deals
58760
- elevasis-sdk knowledge:generate Generate knowledge nodes from MDX files
58761
- elevasis-sdk knowledge:ls <path> List knowledge nodes for a path
58762
- elevasis-sdk knowledge:cat <id> Print raw MDX body of a knowledge node
58763
- elevasis-sdk knowledge:graph <id> Show outgoing and incoming edges for a node
58764
- elevasis-sdk request:submit -f <path> Submit a structured request report
58765
- elevasis-sdk request:list [--status open] List reported requests
58766
- elevasis-sdk request:get <id> Get a reported request by id
58767
- elevasis-sdk request:update <id> -i <json> Amend a request you filed
58768
- elevasis-sdk request:delete <id> Withdraw a request you filed
58769
- elevasis-sdk ui:use-local Use a local @elevasis/ui tarball
58770
- elevasis-sdk ui:use-published Restore published @elevasis/ui
58771
- elevasis-sdk cli [domain] Generate a registered command catalog
58772
- elevasis-sdk rename <id> --to <newId> [--prod] Rename resource across platform tables
58773
- elevasis-sdk doctor [--verbose] Check project environment and API connectivity
58774
-
58775
- Use "elevasis-sdk <command> --help" for more information about a command.`
59443
+ source_default.cyan("Elevasis SDK CLI") + '\n\nRun `elevasis-sdk cli` for the full command catalog. It is built by scanning the\ncommands actually registered below, so it can never drift out of sync the way a\nhand-written list here would.\n\n elevasis-sdk cli Full catalog, grouped by domain\n elevasis-sdk cli --domain <domain> Filter to one domain, e.g. project, content, agent\n elevasis-sdk cli --format json Machine-readable catalog\n\nUse "elevasis-sdk <command> --help" for a specific command\'s options.'
58776
59444
  ).version(SDK_VERSION);
58777
59445
  program2.hook("preAction", () => {
58778
59446
  runPreflight();