@elevasis/sdk 1.48.0 → 1.49.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 (46) hide show
  1. package/dist/cli.cjs +742 -231
  2. package/dist/index.d.ts +685 -47
  3. package/dist/index.js +274 -40
  4. package/dist/node/index.d.ts +108 -24
  5. package/dist/test-utils/index.d.ts +647 -34
  6. package/dist/test-utils/index.js +240 -38
  7. package/dist/worker/index.d.ts +663 -39
  8. package/dist/worker/index.js +115 -6
  9. package/package.json +4 -4
  10. package/reference/_navigation.md +4 -4
  11. package/reference/_reference-manifest.json +1 -1
  12. package/reference/core/index.mdx +6 -4
  13. package/reference/index.mdx +11 -5
  14. package/reference/packages/core/src/README.md +46 -44
  15. package/reference/packages/core/src/content/README.md +13 -12
  16. package/reference/rules/ui.md +1 -1
  17. package/reference/rules/vibe-intents.md +2 -2
  18. package/reference/rules/vibe.md +30 -10
  19. package/reference/scaffold/recipes/extend-content.md +82 -3
  20. package/reference/sdk/cli-management.mdx +184 -41
  21. package/reference/sdk/cli.mdx +103 -64
  22. package/reference/sdk/define-builders.mdx +1 -1
  23. package/reference/sdk/deployment/command-center.mdx +2 -2
  24. package/reference/sdk/deployment/index.mdx +1 -1
  25. package/reference/sdk/exports.mdx +4 -4
  26. package/reference/sdk/framework/agent.mdx +4 -3
  27. package/reference/sdk/framework/index.mdx +1 -1
  28. package/reference/sdk/framework/project-structure.mdx +34 -23
  29. package/reference/sdk/framework/tutorial-system.mdx +1 -1
  30. package/reference/sdk/getting-started.mdx +25 -52
  31. package/reference/sdk/index.mdx +3 -3
  32. package/reference/sdk/platform-tools/adapters-integration.mdx +1 -1
  33. package/reference/sdk/platform-tools/adapters-platform.mdx +1 -1
  34. package/reference/sdk/platform-tools/type-safety.mdx +1 -1
  35. package/reference/sdk/resources/patterns.mdx +10 -11
  36. package/reference/sdk/resources/types.mdx +15 -9
  37. package/reference/sdk/templates/data-enrichment.mdx +1 -1
  38. package/reference/sdk/templates/email-sender.mdx +1 -1
  39. package/reference/sdk/templates/index.mdx +47 -47
  40. package/reference/sdk/templates/lead-scorer.mdx +1 -1
  41. package/reference/sdk/templates/pdf-generator.mdx +42 -24
  42. package/reference/sdk/templates/recurring-job.mdx +20 -15
  43. package/reference/sdk/templates/text-classifier.mdx +1 -1
  44. package/reference/sdk/templates/web-scraper.mdx +9 -5
  45. package/reference/ui/exports.mdx +1 -1
  46. 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(),
@@ -25035,7 +25055,7 @@ var init_content = __esm({
25035
25055
  "use strict";
25036
25056
  init_zod();
25037
25057
  ContentPipelineStepActorSchema = external_exports.enum(["workflow", "agent", "vendor"]);
25038
- ContentPipelineStepReviewModeSchema = external_exports.enum(["live", "queued", "none"]);
25058
+ ContentPipelineStepReviewModeSchema = external_exports.enum(["none", "required"]);
25039
25059
  ContentPayloadFieldTypeSchema = external_exports.enum(["string", "text", "number", "boolean", "url", "string-array"]);
25040
25060
  ContentPayloadFieldDeclarationSchema = external_exports.object({
25041
25061
  key: external_exports.string().trim().min(1).max(200),
@@ -26271,6 +26291,13 @@ var init_lead_gen = __esm({
26271
26291
  }
26272
26292
  });
26273
26293
 
26294
+ // ../core/src/organization-model/catalogs/define-content-pipeline.ts
26295
+ var init_define_content_pipeline = __esm({
26296
+ "../core/src/organization-model/catalogs/define-content-pipeline.ts"() {
26297
+ "use strict";
26298
+ }
26299
+ });
26300
+
26274
26301
  // ../core/src/organization-model/readiness/engine.ts
26275
26302
  function addReadinessIssue(issues, family, code, message, details = {}) {
26276
26303
  issues.push({
@@ -26611,6 +26638,7 @@ var init_organization_model = __esm({
26611
26638
  init_graph();
26612
26639
  init_lead_gen();
26613
26640
  init_content();
26641
+ init_define_content_pipeline();
26614
26642
  init_branding();
26615
26643
  init_systems();
26616
26644
  init_resources();
@@ -44095,7 +44123,7 @@ function getModelInfo(model) {
44095
44123
  return MODEL_INFO[model];
44096
44124
  }
44097
44125
  for (const knownModel of MODEL_KEYS_BY_SPECIFICITY) {
44098
- if (model.startsWith(knownModel)) {
44126
+ if (model.startsWith(`${knownModel}-`)) {
44099
44127
  return MODEL_INFO[knownModel];
44100
44128
  }
44101
44129
  }
@@ -44121,7 +44149,7 @@ function validateModelConfig(config3) {
44121
44149
  throw new ModelConfigError(`Invalid config for ${model}: ${firstError.message}`, fieldName, model);
44122
44150
  }
44123
44151
  }
44124
- var GPT5OptionsSchema, GPT5ConfigSchema, MockConfigSchema, OpenRouterOptionsSchema, OpenRouterConfigSchema, AnthropicOptionsSchema, AnthropicStandardConfigSchema, AnthropicClaude5ConfigSchema, AnthropicConfigSchema, MODEL_INFO, MODEL_KEYS_BY_SPECIFICITY;
44152
+ 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
44153
  var init_model_info = __esm({
44126
44154
  "../core/src/execution/engine/llm/model-info.ts"() {
44127
44155
  "use strict";
@@ -44141,6 +44169,19 @@ var init_model_info = __esm({
44141
44169
  topP: external_exports.number().min(0).max(1).optional(),
44142
44170
  modelOptions: GPT5OptionsSchema.optional()
44143
44171
  });
44172
+ GPT56OptionsSchema = external_exports.object({
44173
+ reasoning_effort: external_exports.enum(["none", "low", "medium", "high", "xhigh", "max"]).optional(),
44174
+ verbosity: external_exports.enum(["low", "medium", "high"]).optional()
44175
+ });
44176
+ GPT56ConfigSchema = external_exports.object({
44177
+ model: external_exports.enum(["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"]),
44178
+ provider: external_exports.enum(["openai"]),
44179
+ apiKey: external_exports.string(),
44180
+ temperature: external_exports.literal(1).optional(),
44181
+ maxOutputTokens: external_exports.number().min(4e3).optional(),
44182
+ topP: external_exports.number().min(0).max(1).optional(),
44183
+ modelOptions: GPT56OptionsSchema.optional()
44184
+ });
44144
44185
  MockConfigSchema = external_exports.object({
44145
44186
  model: external_exports.enum(["mock"]),
44146
44187
  provider: external_exports.enum(["mock"]),
@@ -44193,9 +44234,12 @@ var init_model_info = __esm({
44193
44234
  AnthropicClaude5ConfigSchema,
44194
44235
  AnthropicStandardConfigSchema
44195
44236
  ]);
44237
+ GPT56_CACHE_READ_RATE_MULTIPLIER = 0.1;
44238
+ CACHE_CREATION_RATE_MULTIPLIER = 1.25;
44196
44239
  MODEL_INFO = {
44197
44240
  // OpenAI GPT-5 (Reasoning Models)
44198
44241
  "gpt-5": {
44242
+ provider: "openai",
44199
44243
  inputCostPer1M: 125,
44200
44244
  // $1.25 per 1M tokens
44201
44245
  outputCostPer1M: 1e3,
@@ -44209,6 +44253,7 @@ var init_model_info = __esm({
44209
44253
  configSchema: GPT5ConfigSchema
44210
44254
  },
44211
44255
  "gpt-5.4-mini": {
44256
+ provider: "openai",
44212
44257
  inputCostPer1M: 75,
44213
44258
  // $0.75 per 1M tokens
44214
44259
  outputCostPer1M: 450,
@@ -44222,6 +44267,7 @@ var init_model_info = __esm({
44222
44267
  configSchema: GPT5ConfigSchema
44223
44268
  },
44224
44269
  "gpt-5.4-nano": {
44270
+ provider: "openai",
44225
44271
  inputCostPer1M: 20,
44226
44272
  // $0.20 per 1M tokens
44227
44273
  outputCostPer1M: 125,
@@ -44233,8 +44279,60 @@ var init_model_info = __esm({
44233
44279
  category: "standard",
44234
44280
  configSchema: GPT5ConfigSchema
44235
44281
  },
44282
+ // OpenAI GPT-5.6 family (GA 2026-07-09). All three tiers share 1.05M context, 128K max output,
44283
+ // image input, tool use, structured outputs, and prompt caching -- they differ in reasoning depth
44284
+ // and price, not capability. The bare `gpt-5.6` alias is deliberately unregistered; see OpenAIModel.
44285
+ "gpt-5.6-sol": {
44286
+ provider: "openai",
44287
+ inputCostPer1M: 500,
44288
+ // $5.00 per 1M tokens
44289
+ outputCostPer1M: 3e3,
44290
+ // $30.00 per 1M tokens
44291
+ minTokens: 4e3,
44292
+ recommendedTokens: 8e3,
44293
+ maxTokens: 105e4,
44294
+ // 1.05M context window
44295
+ maxOutputTokens: 128e3,
44296
+ category: "reasoning",
44297
+ configSchema: GPT56ConfigSchema,
44298
+ cacheReadRateMultiplier: GPT56_CACHE_READ_RATE_MULTIPLIER,
44299
+ cacheCreationRateMultiplier: CACHE_CREATION_RATE_MULTIPLIER
44300
+ },
44301
+ "gpt-5.6-terra": {
44302
+ provider: "openai",
44303
+ inputCostPer1M: 250,
44304
+ // $2.50 per 1M tokens
44305
+ outputCostPer1M: 1500,
44306
+ // $15.00 per 1M tokens
44307
+ minTokens: 4e3,
44308
+ recommendedTokens: 8e3,
44309
+ maxTokens: 105e4,
44310
+ // 1.05M context window
44311
+ maxOutputTokens: 128e3,
44312
+ category: "standard",
44313
+ configSchema: GPT56ConfigSchema,
44314
+ cacheReadRateMultiplier: GPT56_CACHE_READ_RATE_MULTIPLIER,
44315
+ cacheCreationRateMultiplier: CACHE_CREATION_RATE_MULTIPLIER
44316
+ },
44317
+ "gpt-5.6-luna": {
44318
+ provider: "openai",
44319
+ inputCostPer1M: 100,
44320
+ // $1.00 per 1M tokens
44321
+ outputCostPer1M: 600,
44322
+ // $6.00 per 1M tokens
44323
+ minTokens: 4e3,
44324
+ recommendedTokens: 8e3,
44325
+ maxTokens: 105e4,
44326
+ // 1.05M context window
44327
+ maxOutputTokens: 128e3,
44328
+ category: "standard",
44329
+ configSchema: GPT56ConfigSchema,
44330
+ cacheReadRateMultiplier: GPT56_CACHE_READ_RATE_MULTIPLIER,
44331
+ cacheCreationRateMultiplier: CACHE_CREATION_RATE_MULTIPLIER
44332
+ },
44236
44333
  // Mock model for testing
44237
44334
  mock: {
44335
+ provider: "mock",
44238
44336
  inputCostPer1M: 0,
44239
44337
  // Free for tests
44240
44338
  outputCostPer1M: 0,
@@ -44248,6 +44346,7 @@ var init_model_info = __esm({
44248
44346
  },
44249
44347
  // OpenRouter Models (via openrouter.ai)
44250
44348
  "openrouter/z-ai/glm-5": {
44349
+ provider: "openrouter",
44251
44350
  inputCostPer1M: 72,
44252
44351
  // $0.72 per 1M tokens
44253
44352
  outputCostPer1M: 230,
@@ -44261,6 +44360,7 @@ var init_model_info = __esm({
44261
44360
  },
44262
44361
  // Anthropic Claude Models (direct SDK access via @anthropic-ai/sdk)
44263
44362
  "claude-opus-5": {
44363
+ provider: "anthropic",
44264
44364
  inputCostPer1M: 500,
44265
44365
  // $5.00 per 1M tokens
44266
44366
  outputCostPer1M: 2500,
@@ -44274,6 +44374,7 @@ var init_model_info = __esm({
44274
44374
  configSchema: AnthropicConfigSchema
44275
44375
  },
44276
44376
  "claude-sonnet-5": {
44377
+ provider: "anthropic",
44277
44378
  // List pricing. An introductory rate of $2.00/$10.00 runs through 2026-08-31; encoding the
44278
44379
  // temporary rate would make historical cost analytics wrong once it lapses.
44279
44380
  inputCostPer1M: 300,
@@ -44289,6 +44390,7 @@ var init_model_info = __esm({
44289
44390
  configSchema: AnthropicConfigSchema
44290
44391
  },
44291
44392
  "claude-haiku-4-5-20251001": {
44393
+ provider: "anthropic",
44292
44394
  inputCostPer1M: 100,
44293
44395
  // $1.00 per 1M tokens
44294
44396
  outputCostPer1M: 500,
@@ -44302,6 +44404,7 @@ var init_model_info = __esm({
44302
44404
  configSchema: AnthropicConfigSchema
44303
44405
  },
44304
44406
  "claude-haiku-4-5": {
44407
+ provider: "anthropic",
44305
44408
  inputCostPer1M: 100,
44306
44409
  // $1.00 per 1M tokens
44307
44410
  outputCostPer1M: 500,
@@ -44690,6 +44793,138 @@ var init_response_schema = __esm({
44690
44793
  }
44691
44794
  });
44692
44795
 
44796
+ // ../core/src/execution/engine/workflow/types.ts
44797
+ var StepType;
44798
+ var init_types5 = __esm({
44799
+ "../core/src/execution/engine/workflow/types.ts"() {
44800
+ "use strict";
44801
+ StepType = {
44802
+ LINEAR: "linear",
44803
+ CONDITIONAL: "conditional"
44804
+ };
44805
+ }
44806
+ });
44807
+
44808
+ // ../core/src/execution/engine/workflow/errors.ts
44809
+ var WorkflowStepError, WorkflowValidationError;
44810
+ var init_errors5 = __esm({
44811
+ "../core/src/execution/engine/workflow/errors.ts"() {
44812
+ "use strict";
44813
+ init_errors3();
44814
+ WorkflowStepError = class extends ExecutionError {
44815
+ type = "workflow_step_error";
44816
+ severity = "critical";
44817
+ category = "workflow";
44818
+ /**
44819
+ * @param cause - The error the step actually threw. Kept so the original stack and any
44820
+ * non-`ExecutionError` throw survive the wrap; its classification is additionally copied into
44821
+ * `context` by the caller, because `type`/`severity`/`category` are fixed on this class.
44822
+ */
44823
+ constructor(message, context, cause) {
44824
+ super(message, context);
44825
+ if (cause !== void 0) this.cause = cause;
44826
+ }
44827
+ };
44828
+ WorkflowValidationError = class extends ExecutionError {
44829
+ type = "workflow_validation_error";
44830
+ severity = "info";
44831
+ category = "validation";
44832
+ constructor(message, context) {
44833
+ super(message, context);
44834
+ }
44835
+ };
44836
+ }
44837
+ });
44838
+
44839
+ // ../core/src/execution/engine/workflow/utils.ts
44840
+ function validateEntryPoint(steps, entryPoint) {
44841
+ if (!(entryPoint in steps)) {
44842
+ throw new WorkflowValidationError(`Entry point step '${entryPoint}' not found in workflow`, {
44843
+ entryPoint
44844
+ });
44845
+ }
44846
+ }
44847
+ function findTerminalSteps(steps) {
44848
+ return Object.values(steps).filter((step) => step.next === null);
44849
+ }
44850
+ function validateTerminalSteps(steps, workflowId) {
44851
+ const terminalSteps = findTerminalSteps(steps);
44852
+ if (terminalSteps.length === 0) {
44853
+ throw new WorkflowValidationError(`Workflow '${workflowId}' must have at least one terminal step (next: null)`, {
44854
+ workflowId
44855
+ });
44856
+ }
44857
+ }
44858
+ function validateStepReferences(steps) {
44859
+ for (const [id, step] of Object.entries(steps)) {
44860
+ if (step.next === null) {
44861
+ continue;
44862
+ }
44863
+ if (step.next.type === StepType.LINEAR) {
44864
+ if (!(step.next.target in steps)) {
44865
+ throw new WorkflowValidationError(`Step '${id}' references non-existent target '${step.next.target}'`, {
44866
+ stepId: id,
44867
+ target: step.next.target
44868
+ });
44869
+ }
44870
+ } else if (step.next.type === StepType.CONDITIONAL) {
44871
+ const targets = [...step.next.routes.map((r) => r.target), step.next.default];
44872
+ for (const target of targets) {
44873
+ if (!(target in steps)) {
44874
+ throw new WorkflowValidationError(`Step '${id}' references non-existent target '${target}'`, {
44875
+ stepId: id,
44876
+ target
44877
+ });
44878
+ }
44879
+ }
44880
+ }
44881
+ }
44882
+ }
44883
+ function detectCycle(visited, executionPath, currentStepId) {
44884
+ if (visited.has(currentStepId)) {
44885
+ const cycle = executionPath.slice(executionPath.indexOf(currentStepId));
44886
+ throw new WorkflowStepError(`Cycle detected in workflow: ${cycle.join(" -> ")} -> ${currentStepId}`, {
44887
+ stepId: currentStepId,
44888
+ cycle: [...cycle, currentStepId]
44889
+ });
44890
+ }
44891
+ }
44892
+ function validateWorkflowGraph(steps, entryPoint, workflowId) {
44893
+ const onPath = /* @__PURE__ */ new Set();
44894
+ const executionPath = [];
44895
+ const reached = /* @__PURE__ */ new Set();
44896
+ const walk = (stepId) => {
44897
+ detectCycle(onPath, executionPath, stepId);
44898
+ onPath.add(stepId);
44899
+ executionPath.push(stepId);
44900
+ reached.add(stepId);
44901
+ const step = steps[stepId];
44902
+ if (step && step.next !== null) {
44903
+ const targets = step.next.type === StepType.LINEAR ? [step.next.target] : [...step.next.routes.map((route) => route.target), step.next.default];
44904
+ for (const target of targets) {
44905
+ if (target in steps) walk(target);
44906
+ }
44907
+ }
44908
+ executionPath.pop();
44909
+ onPath.delete(stepId);
44910
+ };
44911
+ if (entryPoint in steps) walk(entryPoint);
44912
+ const orphanIds = Object.keys(steps).filter((id) => !reached.has(id));
44913
+ if (orphanIds.length > 0) {
44914
+ throw new WorkflowValidationError(
44915
+ `Workflow '${workflowId}' has step(s) unreachable from entry point '${entryPoint}': ${orphanIds.join(", ")}`,
44916
+ { workflowId, entryPoint, orphanIds }
44917
+ );
44918
+ }
44919
+ }
44920
+ var init_utils3 = __esm({
44921
+ "../core/src/execution/engine/workflow/utils.ts"() {
44922
+ "use strict";
44923
+ init_types5();
44924
+ init_errors5();
44925
+ }
44926
+ });
44927
+
44693
44928
  // ../core/src/platform/registry/validation.ts
44694
44929
  function getResourceValidatorMode(explicitMode) {
44695
44930
  if (explicitMode) return explicitMode;
@@ -44708,7 +44943,14 @@ function emitGovernanceIssues(issues, mode, onWarning) {
44708
44943
  if (issues.length === 0) return;
44709
44944
  if (mode === "strict") {
44710
44945
  const first = issues[0];
44711
- throw new RegistryValidationError(first.orgName, first.resourceId, "organizationModel.resources", first.message);
44946
+ const messages = issues.map((issue2) => issue2.message);
44947
+ throw new RegistryValidationError(
44948
+ first.orgName,
44949
+ first.resourceId,
44950
+ "organizationModel.resources",
44951
+ messages.join("\n"),
44952
+ messages
44953
+ );
44712
44954
  }
44713
44955
  const warn2 = onWarning ?? ((issue2) => console.warn(issue2.message));
44714
44956
  for (const issue2 of issues) {
@@ -44869,7 +45111,7 @@ function addTopologyIssues(issues, orgName, deployment, organizationModel, syste
44869
45111
  if (ref.kind === "humanCheckpoint") return humanCheckpointIds.has(ref.id);
44870
45112
  if (ref.kind === "externalResource") return externalResourceIds.has(ref.id);
44871
45113
  if (ref.kind === "ontology") {
44872
- if (ontologyIndex === void 0) return true;
45114
+ if (ontologyIndex === void 0) return false;
44873
45115
  return Object.values(ontologyIndex).some((records) => records[ref.id] !== void 0);
44874
45116
  }
44875
45117
  return false;
@@ -45059,7 +45301,8 @@ function detectMissingApiInterfaceDeclarations(orgName, organizationModel) {
45059
45301
  }
45060
45302
  return gaps;
45061
45303
  }
45062
- function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel) {
45304
+ function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel, options = {}) {
45305
+ const mode = getResourceValidatorMode(options.mode);
45063
45306
  const issues = [];
45064
45307
  if (organizationModel === void 0) return { valid: true, issues };
45065
45308
  const model = organizationModel;
@@ -45085,17 +45328,27 @@ function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel) {
45085
45328
  }
45086
45329
  }
45087
45330
  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
- );
45331
+ if (mode === "strict") {
45332
+ const first = issues[0];
45333
+ const messages = issues.map((issue2) => issue2.message);
45334
+ throw new RegistryValidationError(
45335
+ first.orgName,
45336
+ `${first.systemPath}/${first.interfaceKey}`,
45337
+ first.path ?? "organizationModel.systems.apiInterface",
45338
+ messages.join("\n"),
45339
+ messages
45340
+ );
45341
+ }
45342
+ const warn2 = options.onWarning ?? ((issue2) => console.warn(issue2.message));
45343
+ for (const issue2 of issues) {
45344
+ warn2(issue2);
45345
+ }
45346
+ return { valid: false, issues };
45095
45347
  }
45096
45348
  return { valid: true, issues };
45097
45349
  }
45098
- function validateDeploymentSpec(orgName, resources) {
45350
+ function validateDeploymentSpec(orgName, resources, options = {}) {
45351
+ const warn2 = options.onWarning ?? ((message) => console.warn(message));
45099
45352
  const seenIds = /* @__PURE__ */ new Set();
45100
45353
  resources.workflows?.forEach((workflow) => {
45101
45354
  const id = workflow.config.resourceId;
@@ -45114,6 +45367,14 @@ function validateDeploymentSpec(orgName, resources) {
45114
45367
  if (workflow.interface) {
45115
45368
  validateExecutionInterface(orgName, id, workflow.interface, workflow.contract.inputSchema);
45116
45369
  }
45370
+ try {
45371
+ validateEntryPoint(workflow.steps, workflow.entryPoint);
45372
+ validateTerminalSteps(workflow.steps, id);
45373
+ validateStepReferences(workflow.steps);
45374
+ validateWorkflowGraph(workflow.steps, workflow.entryPoint, id);
45375
+ } catch (error46) {
45376
+ warn2(`[${orgName}] Workflow '${id}' graph validation: ${error46 instanceof Error ? error46.message : String(error46)}`);
45377
+ }
45117
45378
  });
45118
45379
  resources.agents?.forEach((agent) => {
45119
45380
  const id = agent.config.resourceId;
@@ -45127,14 +45388,20 @@ function validateDeploymentSpec(orgName, resources) {
45127
45388
  }
45128
45389
  seenIds.add(id);
45129
45390
  validateResourceModelConfig(orgName, id, agent.modelConfig);
45130
- validateAgentGrammar(orgName, id, agent);
45131
- validateAgentCheapAssertions(orgName, id, agent);
45391
+ validateAgentGrammar(orgName, id, agent, options.mode);
45392
+ validateAgentCheapAssertions(orgName, id, agent, options.mode);
45132
45393
  if (agent.interface) {
45133
45394
  validateExecutionInterface(orgName, id, agent.interface, agent.contract.inputSchema);
45134
45395
  }
45135
45396
  });
45136
- validateResourceGovernance(orgName, resources);
45137
- validateDeclaredSystemInterfaceReadiness(orgName, resources.organizationModel);
45397
+ validateResourceGovernance(orgName, resources, void 0, {
45398
+ mode: options.mode,
45399
+ onWarning: (issue2) => warn2(issue2.message)
45400
+ });
45401
+ validateDeclaredSystemInterfaceReadiness(orgName, resources.organizationModel, {
45402
+ mode: options.mode,
45403
+ onWarning: (issue2) => warn2(issue2.message)
45404
+ });
45138
45405
  }
45139
45406
  function validateResourceModelConfig(orgName, resourceId, modelConfig) {
45140
45407
  try {
@@ -45209,7 +45476,7 @@ function describeGrammarRefusal(reasons, toolInputSchema) {
45209
45476
  }
45210
45477
  return `refused strict mode: ${reasons.join(", ")}`;
45211
45478
  }
45212
- function validateAgentGrammar(orgName, agentId, agent) {
45479
+ function validateAgentGrammar(orgName, agentId, agent, mode) {
45213
45480
  const dialect = dialectForProvider(agent.modelConfig.provider);
45214
45481
  if (!dialect) return;
45215
45482
  const capabilities = agentCapabilitiesForGrammarCheck(agent.config);
@@ -45230,12 +45497,12 @@ function validateAgentGrammar(orgName, agentId, agent) {
45230
45497
  compileSchema(offending.inputSchema, dialect).refusalReasons,
45231
45498
  offending.inputSchema
45232
45499
  )}. 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") {
45500
+ if (getResourceValidatorMode(mode) === "strict") {
45234
45501
  throw new RegistryValidationError(orgName, agentId, "tools", message);
45235
45502
  }
45236
45503
  console.warn(message);
45237
45504
  }
45238
- function validateAgentCheapAssertions(orgName, agentId, agent) {
45505
+ function validateAgentCheapAssertions(orgName, agentId, agent, mode) {
45239
45506
  const issues = [];
45240
45507
  const config3 = agent.config;
45241
45508
  if (config3.sessionCapable && config3.securityLevel === "none") {
@@ -45265,7 +45532,7 @@ function validateAgentCheapAssertions(orgName, agentId, agent) {
45265
45532
  }
45266
45533
  if (issues.length === 0) return;
45267
45534
  const message = `[${orgName}] Agent '${agentId}': ${issues.join(" ")}`;
45268
- if (getResourceValidatorMode() === "strict") {
45535
+ if (getResourceValidatorMode(mode) === "strict") {
45269
45536
  throw new RegistryValidationError(orgName, agentId, "config", message);
45270
45537
  }
45271
45538
  console.warn(message);
@@ -45532,34 +45799,24 @@ var init_validation2 = __esm({
45532
45799
  init_compile();
45533
45800
  init_dialect();
45534
45801
  init_response_schema();
45802
+ init_utils3();
45535
45803
  init_helpers();
45536
45804
  init_ontology();
45537
45805
  init_readiness();
45538
45806
  init_systems();
45539
45807
  RegistryValidationError = class extends Error {
45540
- constructor(orgName, resourceId, field2, message) {
45808
+ constructor(orgName, resourceId, field2, message, issues) {
45541
45809
  super(message);
45542
45810
  this.orgName = orgName;
45543
45811
  this.resourceId = resourceId;
45544
45812
  this.field = field2;
45813
+ this.issues = issues;
45545
45814
  this.name = "RegistryValidationError";
45546
45815
  }
45547
45816
  };
45548
45817
  }
45549
45818
  });
45550
45819
 
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
45820
  // ../core/src/execution/engine/base/serialization.ts
45564
45821
  function serializeDefinition(definition, options) {
45565
45822
  const opts = {
@@ -47295,7 +47552,7 @@ var init_croner = __esm({
47295
47552
  });
47296
47553
 
47297
47554
  // ../core/src/execution/scheduler/utils.ts
47298
- var init_utils3 = __esm({
47555
+ var init_utils4 = __esm({
47299
47556
  "../core/src/execution/scheduler/utils.ts"() {
47300
47557
  "use strict";
47301
47558
  init_esm2();
@@ -47309,7 +47566,7 @@ var init_scheduler = __esm({
47309
47566
  "use strict";
47310
47567
  init_types8();
47311
47568
  init_schemas3();
47312
- init_utils3();
47569
+ init_utils4();
47313
47570
  }
47314
47571
  });
47315
47572
 
@@ -47702,7 +47959,7 @@ var init_schemas6 = __esm({
47702
47959
  });
47703
47960
 
47704
47961
  // ../core/src/operations/observability/utils.ts
47705
- var init_utils4 = __esm({
47962
+ var init_utils5 = __esm({
47706
47963
  "../core/src/operations/observability/utils.ts"() {
47707
47964
  "use strict";
47708
47965
  }
@@ -47714,7 +47971,7 @@ var init_observability = __esm({
47714
47971
  "use strict";
47715
47972
  init_types13();
47716
47973
  init_schemas6();
47717
- init_utils4();
47974
+ init_utils5();
47718
47975
  }
47719
47976
  });
47720
47977
 
@@ -48582,6 +48839,21 @@ var init_credentials2 = __esm({
48582
48839
  }
48583
48840
  });
48584
48841
 
48842
+ // ../core/src/integrations/cloud-storage/types.ts
48843
+ var init_types20 = __esm({
48844
+ "../core/src/integrations/cloud-storage/types.ts"() {
48845
+ "use strict";
48846
+ }
48847
+ });
48848
+
48849
+ // ../core/src/integrations/cloud-storage/index.ts
48850
+ var init_cloud_storage = __esm({
48851
+ "../core/src/integrations/cloud-storage/index.ts"() {
48852
+ "use strict";
48853
+ init_types20();
48854
+ }
48855
+ });
48856
+
48585
48857
  // ../core/src/index.ts
48586
48858
  var init_src = __esm({
48587
48859
  "../core/src/index.ts"() {
@@ -48598,6 +48870,7 @@ var init_src = __esm({
48598
48870
  init_forms();
48599
48871
  init_oauth();
48600
48872
  init_credentials2();
48873
+ init_cloud_storage();
48601
48874
  }
48602
48875
  });
48603
48876
 
@@ -48654,6 +48927,12 @@ function resolveApiKey(prod) {
48654
48927
  }
48655
48928
  return process.env.ELEVASIS_PLATFORM_KEY ?? "";
48656
48929
  }
48930
+ function isProdApiUrl(apiUrl) {
48931
+ return !apiUrl.includes("localhost");
48932
+ }
48933
+ function resolveApiKeyForUrl(apiUrl) {
48934
+ return resolveApiKey(isProdApiUrl(apiUrl));
48935
+ }
48657
48936
  function tryFindProjectRoot(startDir) {
48658
48937
  const raw = (0, import_path.resolve)(startDir);
48659
48938
  let dir;
@@ -48738,12 +49017,89 @@ var init_config2 = __esm({
48738
49017
  }
48739
49018
  });
48740
49019
 
49020
+ // src/cli/readiness-failure.ts
49021
+ function isReadinessFailureDetails(details) {
49022
+ if (!details || typeof details !== "object") return false;
49023
+ const candidate = details;
49024
+ return typeof candidate.systemPath === "string" && typeof candidate.interfaceKey === "string" && // Deliberately `string`, not a check against the known families. Narrowing
49025
+ // it here would reject a readiness refusal carrying a family this build has
49026
+ // not learned yet, and `request()` would fall through to the gateway
49027
+ // message -- which tells the operator the API did not reject the request and
49028
+ // it may still be running server-side. That is false for every readiness
49029
+ // refusal, familiar family or not. An unrecognized code is handled where it
49030
+ // can be handled honestly, in `guidanceForFamily`.
49031
+ typeof candidate.readinessCode === "string" && Array.isArray(candidate.issues);
49032
+ }
49033
+ function parseReadinessFailureDetails(errorText) {
49034
+ let parsed;
49035
+ try {
49036
+ parsed = JSON.parse(errorText);
49037
+ } catch {
49038
+ return void 0;
49039
+ }
49040
+ if (parsed.code !== "SERVICE_UNAVAILABLE") return void 0;
49041
+ return isReadinessFailureDetails(parsed.details) ? parsed.details : void 0;
49042
+ }
49043
+ function formatIssue(issue2) {
49044
+ let line = ` - [${issue2.code}] ${issue2.message}`;
49045
+ if (issue2.path) line += ` (path: ${issue2.path})`;
49046
+ if (issue2.ref) line += ` (ref: ${issue2.ref})`;
49047
+ return line;
49048
+ }
49049
+ function describeUnknownFamily(readinessCode) {
49050
+ 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.
49051
+ 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.`;
49052
+ }
49053
+ function guidanceForFamily(details) {
49054
+ const lookup = FAMILY_GUIDANCE;
49055
+ return lookup[details.readinessCode]?.(details) ?? describeUnknownFamily(details.readinessCode);
49056
+ }
49057
+ function describeReadinessFailure(details, endpoint) {
49058
+ const profileSuffix = details.readinessProfile ? ` (readiness profile: ${details.readinessProfile})` : "";
49059
+ const lines = [
49060
+ `API request refused (503): ${details.systemPath}/${details.interfaceKey} is not ready for this API surface${profileSuffix}.`,
49061
+ `This IS the API rejecting the request -- it is not a gateway hiccup, and re-running it will not help.`,
49062
+ ` Endpoint: ${endpoint}`,
49063
+ ""
49064
+ ];
49065
+ lines.push(
49066
+ 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)
49067
+ );
49068
+ if (details.issues.length > 0) {
49069
+ lines.push("", " Issues:", ...details.issues.map(formatIssue));
49070
+ }
49071
+ lines.push("", ` Run 'elevasis-sdk doctor' to see what else is not ready.`);
49072
+ return lines.join("\n");
49073
+ }
49074
+ var FAMILY_GUIDANCE;
49075
+ var init_readiness_failure = __esm({
49076
+ "src/cli/readiness-failure.ts"() {
49077
+ "use strict";
49078
+ FAMILY_GUIDANCE = {
49079
+ 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).
49080
+ Known trap: an empty apiInterface.resourceIds throws -- omit the apiInterface block entirely for the supported opt-out.`,
49081
+ SYSTEM_INTERFACE_DISABLED: ({ systemPath }) => `The "${systemPath}" System declares an apiInterface but it is not active. Re-enable it (apiInterface.lifecycle: 'active') and redeploy.`,
49082
+ // Two failures share this family and they need opposite advice.
49083
+ //
49084
+ // A validator that rejected a declaration emits a `path`, and pointing at it
49085
+ // is the whole fix. A stored snapshot that would not parse emits no `path` --
49086
+ // the API sets `ref` (a deployment or organization id) and never `path` --
49087
+ // and the broken thing is the deployed copy, not the source the operator
49088
+ // would go and edit. Sending them after a "path" that is not in the payload,
49089
+ // to fix a declaration that may be perfectly fine, was the failure this
49090
+ // wording had before.
49091
+ 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.`,
49092
+ SYSTEM_INTERFACE_NOT_READY: ({ systemPath }) => `The "${systemPath}" System's readinessContract is unsatisfied. See the issues below for the missing requiredObjects / requiredCatalogs refs.`,
49093
+ 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.`
49094
+ };
49095
+ }
49096
+ });
49097
+
48741
49098
  // src/cli/api-client.ts
48742
49099
  function getApiKey(apiUrl) {
48743
- const isProd = !apiUrl.includes("localhost");
48744
- const key = resolveApiKey(isProd);
49100
+ const key = resolveApiKeyForUrl(apiUrl);
48745
49101
  if (!key) {
48746
- const varName = isProd ? "ELEVASIS_PLATFORM_KEY" : "ELEVASIS_PLATFORM_KEY_DEV";
49102
+ const varName = isProdApiUrl(apiUrl) ? "ELEVASIS_PLATFORM_KEY" : "ELEVASIS_PLATFORM_KEY_DEV";
48747
49103
  throw new Error(`${varName} environment variable is required.
48748
49104
  Set it in your .env file: ${varName}=sk_...`);
48749
49105
  }
@@ -48805,6 +49161,10 @@ async function request(method, endpoint, apiUrl, body) {
48805
49161
  if (response.status === 401) {
48806
49162
  throw new Error(`401 Unauthorized: Invalid or missing ELEVASIS_PLATFORM_KEY. Check your .env file.`);
48807
49163
  }
49164
+ const readinessDetails = parseReadinessFailureDetails(errorText);
49165
+ if (readinessDetails) {
49166
+ throw new Error(describeReadinessFailure(readinessDetails, endpoint));
49167
+ }
48808
49168
  if (GATEWAY_STATUSES.has(response.status)) {
48809
49169
  throw new Error(describeGatewayFailure(response.status, endpoint, elapsedMs));
48810
49170
  }
@@ -48832,6 +49192,7 @@ var init_api_client = __esm({
48832
49192
  "src/cli/api-client.ts"() {
48833
49193
  "use strict";
48834
49194
  init_config2();
49195
+ init_readiness_failure();
48835
49196
  DEFAULT_TIMEOUT_MS = 2 * 60 * 60 * 1e3;
48836
49197
  GATEWAY_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
48837
49198
  }
@@ -48864,7 +49225,7 @@ var init_package = __esm({
48864
49225
  "package.json"() {
48865
49226
  package_default = {
48866
49227
  name: "@elevasis/sdk",
48867
- version: "1.48.0",
49228
+ version: "1.49.0",
48868
49229
  description: "SDK for building Elevasis organization resources",
48869
49230
  type: "module",
48870
49231
  bin: {
@@ -49069,7 +49430,15 @@ function extractResourceMetadata(resource, schemaWarnings) {
49069
49430
  return meta;
49070
49431
  }
49071
49432
  function bumpVersion(current, type) {
49072
- const [major, minor, patch] = current.split(".").map(Number);
49433
+ const match = PLAIN_SEMVER_RE.exec(current);
49434
+ if (!match) {
49435
+ throw new Error(
49436
+ `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.`
49437
+ );
49438
+ }
49439
+ const major = Number(match[1]);
49440
+ const minor = Number(match[2]);
49441
+ const patch = Number(match[3]);
49073
49442
  switch (type) {
49074
49443
  case "major":
49075
49444
  return `${major + 1}.0.0`;
@@ -49080,36 +49449,55 @@ function bumpVersion(current, type) {
49080
49449
  }
49081
49450
  }
49082
49451
  function updateDeploymentVersionSource(source, newVersion) {
49083
- let offset = 0;
49452
+ const exportIndex = source.indexOf("export default");
49453
+ if (exportIndex === -1) {
49454
+ throw new Error('Unable to find "export default" in the deployment entry file');
49455
+ }
49456
+ const rootBraceIndex = source.indexOf("{", exportIndex);
49457
+ if (rootBraceIndex === -1) {
49458
+ throw new Error("Unable to find the default-exported object in the deployment entry file");
49459
+ }
49460
+ let depth = 0;
49461
+ let offset = rootBraceIndex;
49084
49462
  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;
49463
+ const char = source[offset];
49464
+ if (char === "{" || char === "[" || char === "(") {
49465
+ depth += 1;
49466
+ offset += 1;
49092
49467
  continue;
49093
49468
  }
49094
- let cursor = keyIndex + "version".length;
49095
- while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49096
- if (source[cursor] !== ":") {
49097
- offset = cursor;
49469
+ if (char === "}" || char === "]" || char === ")") {
49470
+ depth -= 1;
49471
+ offset += 1;
49472
+ if (depth === 0) break;
49098
49473
  continue;
49099
49474
  }
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;
49475
+ if (depth === 1 && char === "v" && source.startsWith("version", offset)) {
49476
+ const before = source[offset - 1];
49477
+ const after = source[offset + "version".length];
49478
+ const isIdentifierBoundary = (before === void 0 || !/[A-Za-z0-9_$]/.test(before)) && (after === void 0 || !/[A-Za-z0-9_$]/.test(after));
49479
+ if (isIdentifierBoundary) {
49480
+ let cursor = offset + "version".length;
49481
+ while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49482
+ if (source[cursor] === ":") {
49483
+ cursor += 1;
49484
+ while (/\s/.test(source[cursor] ?? "")) cursor += 1;
49485
+ const quote = source[cursor];
49486
+ if (quote === "'" || quote === '"') {
49487
+ const valueStart = cursor + 1;
49488
+ const valueEnd = source.indexOf(quote, valueStart);
49489
+ if (valueEnd !== -1) {
49490
+ return `${source.slice(0, valueStart)}${newVersion}${source.slice(valueEnd)}`;
49491
+ }
49492
+ }
49493
+ }
49494
+ }
49106
49495
  }
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)}`;
49496
+ offset += 1;
49111
49497
  }
49112
- throw new Error("Unable to find a quoted version property in the deployment entry file");
49498
+ throw new Error(
49499
+ "Unable to find a quoted version property on the default-exported deployment spec (not nested inside a resource config) in the entry file"
49500
+ );
49113
49501
  }
49114
49502
  function listOrganizationModelContractRefs(org) {
49115
49503
  return Object.values(org.organizationModel?.resources ?? {}).flatMap((resource) => {
@@ -49121,7 +49509,7 @@ function listOrganizationModelContractRefs(org) {
49121
49509
  ].filter((entry) => entry[1] !== void 0).map(([side, ref]) => ({ resourceId: resource.id, side, ref }));
49122
49510
  });
49123
49511
  }
49124
- function validateResourceGovernancePreflight(orgName, org, contractRegistry) {
49512
+ function validateResourceGovernancePreflight(orgName, org, contractRegistry, onWarning = (message) => console.warn(message)) {
49125
49513
  if (org.organizationModel !== void 0) {
49126
49514
  OrganizationModelSchema.parse(org.organizationModel);
49127
49515
  }
@@ -49141,24 +49529,43 @@ Run \`pnpm exec elevasis-sdk om:scaffold:fill --gaps <path>\` to scaffold the mi
49141
49529
  );
49142
49530
  }
49143
49531
  validateDeclaredSystemInterfaceReadiness(orgName, org.organizationModel);
49144
- if (process.env.ELEVASIS_RESOURCE_VALIDATOR === "warn-only") return;
49145
- validateResourceGovernance(orgName, org, org.organizationModel, { mode: "strict" });
49532
+ const mode = process.env.ELEVASIS_RESOURCE_VALIDATOR === "warn-only" ? "warn-only" : "strict";
49533
+ validateResourceGovernance(orgName, org, org.organizationModel, {
49534
+ mode,
49535
+ onWarning: (issue2) => onWarning(issue2.message)
49536
+ });
49146
49537
  const contractRefs = listOrganizationModelContractRefs(org);
49147
- if (contractRefs.length === 0 || contractRegistry === void 0) return;
49538
+ if (contractRefs.length === 0) return;
49539
+ if (contractRegistry === void 0) {
49540
+ onWarning(
49541
+ `[${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.`
49542
+ );
49543
+ return;
49544
+ }
49148
49545
  for (const { resourceId, side, ref } of contractRefs) {
49149
49546
  try {
49150
49547
  resolveContractRef(ref, contractRegistry);
49151
49548
  } catch (error46) {
49152
49549
  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
- );
49550
+ const field2 = `organizationModel.resources.${resourceId}.ontology.contract.${side}`;
49551
+ if (mode === "warn-only") {
49552
+ onWarning(`[${orgName}] ${field2}: ${message}`);
49553
+ continue;
49554
+ }
49555
+ throw new RegistryValidationError(orgName, resourceId, field2, message);
49159
49556
  }
49160
49557
  }
49161
49558
  }
49559
+ function formatZodValidationError(error46) {
49560
+ return error46.issues.map((issue2) => {
49561
+ const path3 = issue2.path.length > 0 ? issue2.path.join(".") : "(root)";
49562
+ return `${path3}: ${issue2.message}`;
49563
+ });
49564
+ }
49565
+ function formatRegistryValidationError(error46) {
49566
+ if (error46.issues && error46.issues.length > 1) return error46.issues;
49567
+ return [error46.message];
49568
+ }
49162
49569
  function registerDeployCommand(program3) {
49163
49570
  program3.command("deploy").description(
49164
49571
  "Validate, bundle, upload, and deploy project resources\n Example: elevasis-sdk deploy --api-url http://localhost:5170"
@@ -49182,7 +49589,7 @@ function registerDeployCommand(program3) {
49182
49589
  authSpinner.fail(source_default.red("Authentication failed"));
49183
49590
  const errMsg = error46 instanceof Error ? error46.message : String(error46);
49184
49591
  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";
49592
+ const keyVar = !isProdApiUrl(apiUrl) && process.env.NODE_ENV === "development" && process.env.ELEVASIS_PLATFORM_KEY_DEV ? "ELEVASIS_PLATFORM_KEY_DEV" : "ELEVASIS_PLATFORM_KEY";
49186
49593
  console.error(source_default.red(" Invalid API key."));
49187
49594
  console.error(source_default.gray(` Your ${keyVar} was rejected by the server.`));
49188
49595
  console.error(source_default.gray(" Check your .env file and verify the key in the Elevasis dashboard."));
@@ -49206,7 +49613,13 @@ function registerDeployCommand(program3) {
49206
49613
  throw new Error("Invalid entry: no default export found");
49207
49614
  }
49208
49615
  const contractRegistry = deploymentModule.contractRegistry ?? deploymentModule.ELEVASIS_CONTRACT_REGISTRY;
49209
- validateResourceGovernancePreflight(orgName, org, contractRegistry);
49616
+ const governanceWarnings = [];
49617
+ validateResourceGovernancePreflight(
49618
+ orgName,
49619
+ org,
49620
+ contractRegistry,
49621
+ (message) => governanceWarnings.push(message)
49622
+ );
49210
49623
  new ResourceRegistry({ [orgName]: org });
49211
49624
  activeWorkflows = (org.workflows ?? []).filter((w) => !w.config.archived);
49212
49625
  activeAgents = (org.agents ?? []).filter((a) => !a.config.archived);
@@ -49215,6 +49628,12 @@ function registerDeployCommand(program3) {
49215
49628
  validateSpinner.succeed(
49216
49629
  source_default.green("Validating...") + source_default.white(" done") + source_default.gray(` (${totalCount} resource${totalCount !== 1 ? "s" : ""}, 0 errors)`)
49217
49630
  );
49631
+ if (governanceWarnings.length > 0) {
49632
+ for (const warning of governanceWarnings) {
49633
+ console.log(source_default.yellow(` warn ${warning}`));
49634
+ }
49635
+ console.log("");
49636
+ }
49218
49637
  if (archivedCount > 0) {
49219
49638
  console.log(source_default.gray(` Skipping ${archivedCount} archived resource${archivedCount !== 1 ? "s" : ""}`));
49220
49639
  }
@@ -49248,12 +49667,30 @@ function registerDeployCommand(program3) {
49248
49667
  if (error46 instanceof RegistryValidationError) {
49249
49668
  validateSpinner.fail(source_default.red("Validation failed"));
49250
49669
  console.error("");
49251
- console.error(source_default.red(` ERROR ${error46.message}`));
49670
+ const issues = formatRegistryValidationError(error46);
49671
+ if (issues.length > 1) {
49672
+ console.error(source_default.red(` ${issues.length} issues:`));
49673
+ for (const issue2 of issues) {
49674
+ console.error(source_default.red(` - ${issue2}`));
49675
+ }
49676
+ } else {
49677
+ console.error(source_default.red(` ERROR ${issues[0]}`));
49678
+ }
49252
49679
  if (error46.resourceId) {
49253
49680
  console.error(source_default.gray(` Resource: ${error46.resourceId}`));
49254
49681
  }
49255
49682
  console.error("");
49256
49683
  console.error(source_default.gray(" Deploy aborted."));
49684
+ } else if (error46 instanceof external_exports.ZodError) {
49685
+ validateSpinner.fail(source_default.red("Validation failed: organization model does not match the expected shape"));
49686
+ console.error("");
49687
+ for (const line of formatZodValidationError(error46)) {
49688
+ console.error(source_default.red(` ERROR ${line}`));
49689
+ }
49690
+ console.error("");
49691
+ console.error(source_default.gray(" Deploy aborted."));
49692
+ } else if (validateSpinner.isSpinning) {
49693
+ validateSpinner.fail(source_default.red("Validation failed"));
49257
49694
  }
49258
49695
  throw error46;
49259
49696
  }
@@ -49318,11 +49755,11 @@ import { startWorker } from '@elevasis/sdk/worker'
49318
49755
  const uploadSpinner = ora("Uploading...").start();
49319
49756
  try {
49320
49757
  const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
49321
- const apiKey = resolveApiKey(options.prod);
49758
+ const apiKey = resolveApiKeyForUrl(apiUrl);
49322
49759
  if (!apiKey) {
49323
49760
  uploadSpinner.fail(source_default.red("Missing API key environment variable"));
49324
49761
  console.error(source_default.gray(" Set it in your .env file or shell environment:"));
49325
- if (!options.prod && process.env.NODE_ENV === "development") {
49762
+ if (!isProdApiUrl(apiUrl) && process.env.NODE_ENV === "development") {
49326
49763
  console.error(
49327
49764
  source_default.gray(" ELEVASIS_PLATFORM_KEY_DEV=sk_... (or ELEVASIS_PLATFORM_KEY as fallback)")
49328
49765
  );
@@ -49390,7 +49827,7 @@ import { startWorker } from '@elevasis/sdk/worker'
49390
49827
  )
49391
49828
  );
49392
49829
  }
49393
- var import_path2, import_promises, import_fs2, import_crypto, import_url, import_module;
49830
+ var import_path2, import_promises, import_fs2, import_crypto, import_url, import_module, PLAIN_SEMVER_RE;
49394
49831
  var init_deploy = __esm({
49395
49832
  "src/cli/commands/deploy.ts"() {
49396
49833
  "use strict";
@@ -49411,6 +49848,7 @@ var init_deploy = __esm({
49411
49848
  init_api_client();
49412
49849
  init_wrap_action();
49413
49850
  init_version();
49851
+ PLAIN_SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;
49414
49852
  }
49415
49853
  });
49416
49854
 
@@ -55314,7 +55752,129 @@ function registerUiCommands(program3) {
55314
55752
  var import_node_fs9 = require("node:fs");
55315
55753
  var import_node_path8 = __toESM(require("node:path"), 1);
55316
55754
  init_source();
55755
+ init_organization_model();
55317
55756
  init_config2();
55757
+ init_load_org_model();
55758
+
55759
+ // src/cli/commands/om/deployed-readiness.ts
55760
+ init_organization_model();
55761
+ init_api_client();
55762
+ function listApiInterfaceSystemPaths(model) {
55763
+ return listAllSystems(model).filter(({ system }) => system.apiInterface !== void 0).map(({ path: path3 }) => path3);
55764
+ }
55765
+ function listDeployedReadinessTargets(model) {
55766
+ const declared = new Set(listApiInterfaceSystemPaths(model));
55767
+ const targets = SYSTEM_INTERFACE_PROFILES.map((profile) => ({
55768
+ systemPath: profile.systemPath,
55769
+ interfaceKey: profile.interfaceKey,
55770
+ declaredLocally: declared.has(profile.systemPath)
55771
+ }));
55772
+ const covered = new Set(targets.map((target) => `${target.systemPath}::${target.interfaceKey}`));
55773
+ for (const systemPath of declared) {
55774
+ const key = `${systemPath}::api`;
55775
+ if (covered.has(key)) continue;
55776
+ covered.add(key);
55777
+ targets.push({ systemPath, interfaceKey: "api", declaredLocally: true });
55778
+ }
55779
+ return targets;
55780
+ }
55781
+ async function fetchDeployedReadiness(model, options = {}) {
55782
+ const targets = listDeployedReadinessTargets(model);
55783
+ const report = {
55784
+ activeDeploymentId: null,
55785
+ snapshotHash: null,
55786
+ kind: null,
55787
+ entries: []
55788
+ };
55789
+ if (targets.length === 0) {
55790
+ report.unavailableReason = "no System-interface profile to check \u2014 neither the platform catalog nor the project model declares one";
55791
+ return report;
55792
+ }
55793
+ for (const target of targets) {
55794
+ let response;
55795
+ try {
55796
+ const endpoint = `/api/external/organization-model/readiness?systemPath=${encodeURIComponent(target.systemPath)}&interfaceKey=${encodeURIComponent(target.interfaceKey)}`;
55797
+ response = await apiGet(endpoint, options.apiUrl);
55798
+ } catch (error46) {
55799
+ report.unavailableReason = error46 instanceof Error ? error46.message : String(error46);
55800
+ return report;
55801
+ }
55802
+ report.activeDeploymentId = response.activeDeploymentId;
55803
+ report.snapshotHash = response.snapshotHash;
55804
+ report.kind = response.kind;
55805
+ report.entries.push({
55806
+ systemPath: response.readiness.systemPath,
55807
+ interfaceKey: response.readiness.interfaceKey,
55808
+ ready: response.readiness.ready,
55809
+ issues: response.readiness.issues,
55810
+ declaredLocally: target.declaredLocally
55811
+ });
55812
+ }
55813
+ return report;
55814
+ }
55815
+ function isUnadoptedNotDeclared(entry) {
55816
+ return !entry.declaredLocally && entry.issues.every((issue2) => issue2.family === "SYSTEM_INTERFACE_MISSING");
55817
+ }
55818
+ function readinessDiagnostics(report) {
55819
+ const diagnostics = [];
55820
+ for (const entry of report.entries) {
55821
+ if (entry.ready) {
55822
+ diagnostics.push({
55823
+ severity: "info",
55824
+ code: "deployed-interface-ready",
55825
+ systemPath: entry.systemPath,
55826
+ message: `${entry.systemPath}/${entry.interfaceKey} is ready in the deployed snapshot.`
55827
+ });
55828
+ continue;
55829
+ }
55830
+ const unadopted = isUnadoptedNotDeclared(entry);
55831
+ for (const issue2 of entry.issues) {
55832
+ diagnostics.push({
55833
+ severity: unadopted ? "info" : "error",
55834
+ code: `deployed-${issue2.code}`,
55835
+ systemPath: entry.systemPath,
55836
+ ...issue2.ref !== void 0 && { targetId: issue2.ref },
55837
+ message: `${entry.systemPath}/${entry.interfaceKey} ${unadopted ? "not adopted" : "not ready"} [${issue2.family}]: ${issue2.message}`,
55838
+ source: "deployed-snapshot"
55839
+ });
55840
+ }
55841
+ }
55842
+ return diagnostics;
55843
+ }
55844
+ function readinessRoster(report) {
55845
+ return report.entries.map((entry) => {
55846
+ if (entry.ready) {
55847
+ return {
55848
+ systemPath: entry.systemPath,
55849
+ interfaceKey: entry.interfaceKey,
55850
+ status: "ready",
55851
+ detail: "ready",
55852
+ issues: []
55853
+ };
55854
+ }
55855
+ if (isUnadoptedNotDeclared(entry)) {
55856
+ return {
55857
+ systemPath: entry.systemPath,
55858
+ interfaceKey: entry.interfaceKey,
55859
+ status: "not-adopted",
55860
+ detail: "not adopted",
55861
+ issues: entry.issues
55862
+ };
55863
+ }
55864
+ return {
55865
+ systemPath: entry.systemPath,
55866
+ interfaceKey: entry.interfaceKey,
55867
+ status: "not-ready",
55868
+ detail: entry.issues[0]?.message ?? "not ready",
55869
+ issues: entry.issues
55870
+ };
55871
+ });
55872
+ }
55873
+ function countReadinessRosterFailures(rows) {
55874
+ return rows.filter((row) => row.status === "not-ready").length;
55875
+ }
55876
+
55877
+ // src/cli/commands/doctor.ts
55318
55878
  function ok(label, detail) {
55319
55879
  console.log(`${source_default.green("[OK]")} ${source_default.bold(label)}: ${detail}`);
55320
55880
  }
@@ -55422,6 +55982,38 @@ function registerDoctorCommand(program3) {
55422
55982
  if (isVerbose) verbose(`Error: ${networkError}`);
55423
55983
  failCount++;
55424
55984
  }
55985
+ let model = DEFAULT_ORGANIZATION_MODEL;
55986
+ try {
55987
+ model = await loadOrgModel(projectRoot);
55988
+ } catch (err) {
55989
+ if (isVerbose) {
55990
+ const msg = err instanceof Error ? err.message : String(err);
55991
+ verbose(`Organization model load failed, roster limited to the platform catalog: ${msg}`);
55992
+ }
55993
+ }
55994
+ const readiness = await fetchDeployedReadiness(model, { apiUrl });
55995
+ if (readiness.unavailableReason !== void 0) {
55996
+ warn("Systems", `Readiness unavailable \u2014 ${readiness.unavailableReason}`);
55997
+ if (isVerbose) verbose(`GET ${apiUrl}/api/external/organization-model/readiness`);
55998
+ } else {
55999
+ const rows = readinessRoster(readiness);
56000
+ for (const row of rows) {
56001
+ const label = `Systems: ${row.systemPath}/${row.interfaceKey}`;
56002
+ if (row.status === "ready") {
56003
+ ok(label, row.detail);
56004
+ } else if (row.status === "not-adopted") {
56005
+ warn(label, row.detail);
56006
+ } else {
56007
+ fail(label, row.detail);
56008
+ }
56009
+ if (isVerbose) {
56010
+ for (const issue2 of row.issues) {
56011
+ verbose(`${issue2.code}: ${issue2.message}`);
56012
+ }
56013
+ }
56014
+ }
56015
+ failCount += countReadinessRosterFailures(rows);
56016
+ }
55425
56017
  console.log();
55426
56018
  printSummary(failCount);
55427
56019
  if (failCount > 0) {
@@ -55918,6 +56510,12 @@ Content item: ${item.title}`));
55918
56510
  // src/cli/commands/content/board.ts
55919
56511
  init_source();
55920
56512
 
56513
+ // ../core/src/content/review-gates.ts
56514
+ function isAwaitingReview(item, step) {
56515
+ if (!step) return false;
56516
+ return step.reviewMode !== "none" && item.reviewedAt === null;
56517
+ }
56518
+
55921
56519
  // ../core/src/content/derive-board.ts
55922
56520
  function sortPipelineSteps(steps) {
55923
56521
  return [...steps].sort((a, b) => {
@@ -55941,17 +56539,13 @@ function deriveItemPlacement(item, sortedSteps) {
55941
56539
  });
55942
56540
  if (!currentStep) {
55943
56541
  const lastStep = sortedSteps[sortedSteps.length - 1];
55944
- if (lastStep !== void 0 && lastStep.reviewMode !== "none" && item.reviewedAt === null) {
56542
+ if (lastStep !== void 0 && isAwaitingReview(item, lastStep)) {
55945
56543
  return { bucket: "column", stepKey: lastStep.key };
55946
56544
  }
55947
56545
  return { bucket: "done", stepKey: null };
55948
56546
  }
55949
56547
  return { bucket: "column", stepKey: currentStep.key };
55950
56548
  }
55951
- function deriveAwaitingReview(step, item) {
55952
- if (!step) return false;
55953
- return step.reviewMode !== "none" && item.reviewedAt === null;
55954
- }
55955
56549
  function deriveContentBoard(items, pipeline, now) {
55956
56550
  const sortedSteps = sortPipelineSteps(pipeline.steps);
55957
56551
  const stepsByKey = new Map(sortedSteps.map((step) => [step.key, step]));
@@ -55965,7 +56559,7 @@ function deriveContentBoard(items, pipeline, now) {
55965
56559
  item,
55966
56560
  stepKey: placement.stepKey,
55967
56561
  ageMs: now - Date.parse(item.updatedAt),
55968
- awaitingReview: deriveAwaitingReview(step, item)
56562
+ awaitingReview: isAwaitingReview(item, step)
55969
56563
  };
55970
56564
  if (placement.bucket === "done") {
55971
56565
  done.push(card);
@@ -55989,9 +56583,9 @@ function deriveContentBoard(items, pipeline, now) {
55989
56583
  const columns = sortedSteps.map((step) => {
55990
56584
  const cards = cardsByStepKey.get(step.key) ?? [];
55991
56585
  const column = { step, cards };
55992
- if (step.reviewMode === "live" || step.reviewMode === "queued") {
56586
+ if (step.reviewVenue !== "none") {
55993
56587
  column.gate = {
55994
- reviewMode: step.reviewMode,
56588
+ venue: step.reviewVenue,
55995
56589
  waitingCount: cards.filter((card) => card.awaitingReview).length
55996
56590
  };
55997
56591
  }
@@ -56108,7 +56702,9 @@ Board: ${pipelineId} ${source_default.gray(`${items.data.length} of ${items.tot
56108
56702
  }
56109
56703
  console.log();
56110
56704
  for (const column of board.columns) {
56111
- const gate = column.gate ? source_default.yellow(` [${column.gate.reviewMode} gate -- ${column.gate.waitingCount} waiting]`) : "";
56705
+ const gate = column.gate ? source_default.yellow(
56706
+ ` [${column.gate.venue === "workspace" ? "workspace" : "queue"} gate -- ${column.gate.waitingCount} waiting]`
56707
+ ) : "";
56112
56708
  console.log(` ${source_default.bold(column.step.label)} ${source_default.gray(column.step.key)}${gate}`);
56113
56709
  printCards(column.cards, stepsByKey);
56114
56710
  }
@@ -56170,7 +56766,7 @@ Pipeline: ${pipeline.id}`));
56170
56766
  const steps = Array.isArray(pipeline.steps) ? pipeline.steps : [];
56171
56767
  console.log(source_default.gray(` Steps (${steps.length}):`));
56172
56768
  for (const step of steps) {
56173
- console.log(source_default.gray(` - ${step.key} (reviewMode: ${step.reviewMode})`));
56769
+ console.log(source_default.gray(` - ${step.key} (review: ${step.reviewMode}, venue: ${step.reviewVenue})`));
56174
56770
  }
56175
56771
  console.log();
56176
56772
  }
@@ -56404,13 +57000,47 @@ function resolveTextArgument(value) {
56404
57000
  throw new Error(`Could not read --text file "${path3}": ${error46 instanceof Error ? error46.message : String(error46)}`);
56405
57001
  }
56406
57002
  }
57003
+ function resolveMetadataOption(options) {
57004
+ if (options.metadata !== void 0 && options.metadataFile !== void 0) {
57005
+ throw new Error("Pass exactly one of --metadata or --metadata-file, not both");
57006
+ }
57007
+ let raw;
57008
+ if (options.metadataFile !== void 0) {
57009
+ const path3 = resolveProjectRelative(options.metadataFile);
57010
+ try {
57011
+ raw = (0, import_node_fs10.readFileSync)(path3, "utf8");
57012
+ } catch (error46) {
57013
+ throw new Error(
57014
+ `Could not read --metadata-file "${options.metadataFile}": ${error46 instanceof Error ? error46.message : String(error46)}`
57015
+ );
57016
+ }
57017
+ } else {
57018
+ raw = options.metadata;
57019
+ }
57020
+ if (raw === void 0) return void 0;
57021
+ let parsed;
57022
+ try {
57023
+ parsed = JSON.parse(raw);
57024
+ } catch (error46) {
57025
+ const source = options.metadataFile !== void 0 ? "--metadata-file" : "--metadata";
57026
+ throw new Error(`${source} must be valid JSON: ${error46 instanceof Error ? error46.message : String(error46)}`);
57027
+ }
57028
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
57029
+ const source = options.metadataFile !== void 0 ? "--metadata-file" : "--metadata";
57030
+ throw new Error(`${source} must be a JSON object, e.g. {"key":"value"}`);
57031
+ }
57032
+ return parsed;
57033
+ }
56407
57034
  function registerContentSourceAssetCreate(program3) {
56408
57035
  program3.command("content:source-asset:create").description(
56409
57036
  '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
57037
  ).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
57038
  "--field <key>",
56412
57039
  "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(
57040
+ ).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(
57041
+ "--metadata-file <path>",
57042
+ "Path to a JSON file containing metadata (project-relative unless absolute). Mutually exclusive with --metadata"
57043
+ ).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
57044
  wrapAction("content:source-asset:create", async (options) => {
56415
57045
  if (options.text !== void 0 && options.url !== void 0) {
56416
57046
  throw new Error("Pass exactly one of --text or --url, not both");
@@ -56441,6 +57071,9 @@ function registerContentSourceAssetCreate(program3) {
56441
57071
  }
56442
57072
  body.durationSeconds = duration3;
56443
57073
  }
57074
+ if (options.storagePath !== void 0) body.storagePath = options.storagePath;
57075
+ const metadata = resolveMetadataOption(options);
57076
+ if (metadata !== void 0) body.metadata = metadata;
56444
57077
  const apiUrl = resolveApiUrl(options.apiUrl, options.prod);
56445
57078
  const asset = await apiPost("/api/external/content/source-assets", body, apiUrl);
56446
57079
  let linkedItem;
@@ -56460,6 +57093,7 @@ Created source asset ${asset.id}`));
56460
57093
  console.log(source_default.gray(` Title: ${asset.title}`));
56461
57094
  console.log(source_default.gray(` Kind: ${asset.kind}`));
56462
57095
  if (asset.externalUrl) console.log(source_default.gray(` URL: ${asset.externalUrl}`));
57096
+ if (asset.storagePath) console.log(source_default.gray(` Storage path: ${asset.storagePath}`));
56463
57097
  if (linkedItem) console.log(source_default.cyan(` Linked to item ${linkedItem.id} (${linkedItem.title})`));
56464
57098
  console.log();
56465
57099
  })
@@ -57836,71 +58470,6 @@ function formatOmDoctorReport(report) {
57836
58470
  return lines.join("\n");
57837
58471
  }
57838
58472
 
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
58473
  // src/cli/commands/om/doctor.ts
57905
58474
  function registerOmDoctorCommand(program3) {
57906
58475
  program3.command("om:doctor").description(
@@ -58714,65 +59283,7 @@ if (envPath) {
58714
59283
  }
58715
59284
  var program2 = new Command();
58716
59285
  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.`
59286
+ 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
59287
  ).version(SDK_VERSION);
58777
59288
  program2.hook("preAction", () => {
58778
59289
  runPreflight();