@elevasis/sdk 1.18.0 → 1.20.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 (58) hide show
  1. package/dist/cli.cjs +1915 -70
  2. package/dist/index.d.ts +825 -16
  3. package/dist/index.js +714 -63
  4. package/dist/node/index.d.ts +1 -0
  5. package/dist/node/index.js +213 -2
  6. package/dist/test-utils/index.d.ts +479 -14
  7. package/dist/test-utils/index.js +660 -54
  8. package/dist/worker/index.js +516 -54
  9. package/package.json +4 -4
  10. package/reference/_navigation.md +2 -1
  11. package/reference/_reference-manifest.json +14 -0
  12. package/reference/claude-config/registries/graph-skills.json +4 -0
  13. package/reference/claude-config/rules/agent-start-here.md +5 -5
  14. package/reference/claude-config/rules/deployment.md +4 -3
  15. package/reference/claude-config/rules/frontend.md +2 -2
  16. package/reference/claude-config/rules/operations.md +17 -13
  17. package/reference/claude-config/rules/organization-model.md +7 -5
  18. package/reference/claude-config/rules/organization-os.md +13 -11
  19. package/reference/claude-config/rules/ui.md +3 -3
  20. package/reference/claude-config/rules/vibe.md +4 -4
  21. package/reference/claude-config/skills/explore/SKILL.md +4 -4
  22. package/reference/claude-config/skills/knowledge/SKILL.md +17 -16
  23. package/reference/claude-config/skills/knowledge/operations/codify-level-a.md +7 -7
  24. package/reference/claude-config/skills/knowledge/operations/codify-level-b.md +13 -13
  25. package/reference/claude-config/skills/knowledge/operations/customers.md +1 -1
  26. package/reference/claude-config/skills/knowledge/operations/goals.md +1 -1
  27. package/reference/claude-config/skills/knowledge/operations/identity.md +1 -1
  28. package/reference/claude-config/skills/knowledge/operations/offerings.md +1 -1
  29. package/reference/claude-config/skills/knowledge/operations/roles.md +1 -1
  30. package/reference/claude-config/skills/knowledge/operations/techStack.md +19 -91
  31. package/reference/claude-config/skills/project/SKILL.md +73 -13
  32. package/reference/claude-config/skills/save/SKILL.md +5 -5
  33. package/reference/claude-config/skills/tutorial/technical.md +11 -14
  34. package/reference/claude-config/sync-notes/2026-05-06-crm-spine.md +60 -0
  35. package/reference/claude-config/sync-notes/2026-05-07-sdk-changes-release-train.md +34 -0
  36. package/reference/claude-config/sync-notes/2026-05-08-resource-governance-scaffold-guidance.md +38 -0
  37. package/reference/claude-config/sync-notes/2026-05-09-clients-domain.md +32 -0
  38. package/reference/claude-config/sync-notes/2026-05-09-command-system.md +33 -0
  39. package/reference/claude-config/sync-notes/2026-05-09-resource-governance-and-misc.md +69 -0
  40. package/reference/examples/organization-model.ts +17 -5
  41. package/reference/framework/index.mdx +1 -1
  42. package/reference/framework/project-structure.mdx +10 -8
  43. package/reference/packages/core/src/business/README.md +2 -2
  44. package/reference/packages/core/src/organization-model/README.md +10 -3
  45. package/reference/resources/index.mdx +27 -17
  46. package/reference/scaffold/core/organization-model.mdx +33 -14
  47. package/reference/scaffold/operations/workflow-recipes.md +35 -29
  48. package/reference/scaffold/recipes/add-a-feature.md +18 -3
  49. package/reference/scaffold/recipes/add-a-resource.md +50 -10
  50. package/reference/scaffold/recipes/customize-crm-actions.md +12 -6
  51. package/reference/scaffold/recipes/customize-organization-model.md +18 -3
  52. package/reference/scaffold/recipes/extend-crm.md +17 -19
  53. package/reference/scaffold/recipes/extend-lead-gen.md +31 -31
  54. package/reference/scaffold/recipes/index.md +1 -1
  55. package/reference/scaffold/reference/contracts.md +512 -307
  56. package/reference/scaffold/reference/feature-registry.md +1 -1
  57. package/reference/scaffold/reference/glossary.md +8 -3
  58. package/reference/scaffold/ui/recipes.md +21 -6
package/dist/cli.cjs CHANGED
@@ -36630,6 +36630,7 @@ var ORGANIZATION_MODEL_ICON_TOKENS = [
36630
36630
  "knowledge.reference",
36631
36631
  "feature.dashboard",
36632
36632
  "feature.calendar",
36633
+ "feature.business",
36633
36634
  "feature.sales",
36634
36635
  "feature.crm",
36635
36636
  "feature.finance",
@@ -36869,6 +36870,13 @@ var LEAD_GEN_STAGE_CATALOG = {
36869
36870
  order: 2,
36870
36871
  entity: "company"
36871
36872
  },
36873
+ crawled: {
36874
+ key: "crawled",
36875
+ label: "Websites crawled",
36876
+ description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
36877
+ order: 2.5,
36878
+ entity: "company"
36879
+ },
36872
36880
  extracted: {
36873
36881
  key: "extracted",
36874
36882
  label: "Websites analyzed",
@@ -36888,7 +36896,9 @@ var LEAD_GEN_STAGE_CATALOG = {
36888
36896
  label: "Decision-makers found",
36889
36897
  description: "Decision-maker contacts discovered and attached to a qualified company.",
36890
36898
  order: 6,
36891
- entity: "company"
36899
+ entity: "company",
36900
+ recordEntity: "contact",
36901
+ recordStageKey: "discovered"
36892
36902
  },
36893
36903
  // Prospecting — contact discovery
36894
36904
  discovered: {
@@ -36926,7 +36936,8 @@ var LEAD_GEN_STAGE_CATALOG = {
36926
36936
  label: "Reviewed and exported",
36927
36937
  description: "Approved records have been reviewed and exported for handoff.",
36928
36938
  order: 10,
36929
- entity: "contact"
36939
+ entity: "company",
36940
+ additionalEntities: ["contact"]
36930
36941
  },
36931
36942
  interested: {
36932
36943
  key: "interested",
@@ -36985,18 +36996,47 @@ var DEFAULT_ORGANIZATION_MODEL_PROJECTS = {
36985
36996
  // ../core/src/organization-model/domains/prospecting.ts
36986
36997
  var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
36987
36998
  id: ModelIdSchema,
36988
- order: external_exports.number().int().min(0)
36999
+ order: external_exports.number().min(0)
37000
+ });
37001
+ var RecordColumnConfigSchema = external_exports.object({
37002
+ key: ModelIdSchema,
37003
+ label: external_exports.string().trim().min(1).max(120),
37004
+ path: external_exports.string().trim().min(1).max(500),
37005
+ width: external_exports.union([external_exports.number().positive(), external_exports.string().trim().min(1).max(100)]).optional(),
37006
+ renderType: external_exports.enum(["text", "badge", "datetime", "count", "json"]).optional(),
37007
+ badgeColor: external_exports.string().trim().min(1).max(40).optional()
37008
+ });
37009
+ var RecordColumnsConfigSchema = external_exports.object({
37010
+ company: external_exports.array(RecordColumnConfigSchema).optional(),
37011
+ contact: external_exports.array(RecordColumnConfigSchema).optional()
37012
+ }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
37013
+ message: "recordColumns must include at least one entity column set"
37014
+ });
37015
+ var CredentialRequirementSchema = external_exports.object({
37016
+ key: ModelIdSchema,
37017
+ provider: ModelIdSchema,
37018
+ credentialType: external_exports.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
37019
+ label: external_exports.string().trim().min(1).max(120),
37020
+ required: external_exports.boolean(),
37021
+ selectionMode: external_exports.enum(["single", "multiple"]).optional(),
37022
+ inputPath: external_exports.string().trim().min(1).max(500),
37023
+ verifyOnRun: external_exports.boolean().optional()
36989
37024
  });
36990
37025
  var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
36991
37026
  id: ModelIdSchema,
36992
37027
  primaryEntity: external_exports.enum(["company", "contact"]),
36993
37028
  outputs: external_exports.array(external_exports.enum(["company", "contact", "export"])).min(1),
36994
37029
  stageKey: ModelIdSchema,
37030
+ recordEntity: external_exports.enum(["company", "contact"]).optional(),
37031
+ recordsStageKey: ModelIdSchema.optional(),
37032
+ recordSourceStageKey: ModelIdSchema.optional(),
36995
37033
  dependsOn: external_exports.array(ModelIdSchema).optional(),
36996
37034
  dependencyMode: external_exports.literal("per-record-eligibility"),
36997
37035
  capabilityKey: ModelIdSchema,
36998
37036
  defaultBatchSize: external_exports.number().int().positive(),
36999
- maxBatchSize: external_exports.number().int().positive()
37037
+ maxBatchSize: external_exports.number().int().positive(),
37038
+ recordColumns: RecordColumnsConfigSchema.optional(),
37039
+ credentialRequirements: external_exports.array(CredentialRequirementSchema).optional()
37000
37040
  }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
37001
37041
  message: "defaultBatchSize must be less than or equal to maxBatchSize",
37002
37042
  path: ["defaultBatchSize"]
@@ -37005,6 +37045,148 @@ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
37005
37045
  id: ModelIdSchema,
37006
37046
  steps: external_exports.array(ProspectingBuildTemplateStepSchema).min(1)
37007
37047
  });
37048
+ var DTC_RECORD_COLUMNS = {
37049
+ populated: {
37050
+ company: [
37051
+ { key: "name", label: "Company", path: "company.name" },
37052
+ { key: "domain", label: "Domain", path: "company.domain" },
37053
+ { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
37054
+ { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
37055
+ { key: "location", label: "Location", path: "company.locationState" }
37056
+ ]
37057
+ },
37058
+ crawled: {
37059
+ company: [
37060
+ { key: "name", label: "Company", path: "company.name" },
37061
+ { key: "domain", label: "Domain", path: "company.domain" },
37062
+ { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
37063
+ { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
37064
+ ]
37065
+ },
37066
+ extracted: {
37067
+ company: [
37068
+ { key: "name", label: "Company", path: "company.name" },
37069
+ { key: "domain", label: "Domain", path: "company.domain" },
37070
+ { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
37071
+ { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
37072
+ { key: "automation-gaps", label: "Automation gaps", path: "company.enrichmentData.websiteCrawl.automationGaps", renderType: "json" },
37073
+ { key: "contact-count", label: "Contacts", path: "company.enrichmentData.websiteCrawl.emailCount", renderType: "count" }
37074
+ ]
37075
+ },
37076
+ qualified: {
37077
+ company: [
37078
+ { key: "name", label: "Company", path: "company.name" },
37079
+ { key: "domain", label: "Domain", path: "company.domain" },
37080
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
37081
+ { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
37082
+ { key: "disqualified-reason", label: "Disqualified reason", path: "processingState.qualified.data.disqualifiedReason" }
37083
+ ]
37084
+ },
37085
+ decisionMakers: {
37086
+ contact: [
37087
+ { key: "name", label: "Name", path: "contact.name" },
37088
+ { key: "title", label: "Title", path: "contact.title" },
37089
+ { key: "email", label: "Email", path: "contact.email" },
37090
+ { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
37091
+ { key: "priority-score", label: "Priority", path: "contact.enrichmentData.apollo.priorityScore", renderType: "badge" }
37092
+ ]
37093
+ },
37094
+ uploaded: {
37095
+ company: [
37096
+ { key: "name", label: "Company", path: "company.name" },
37097
+ { key: "domain", label: "Domain", path: "company.domain" },
37098
+ { key: "contacts", label: "Contacts", path: "company.enrichmentData.approvedLeadListExport.contacts", renderType: "json" },
37099
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
37100
+ { key: "approval", label: "Approval", path: "company.enrichmentData.approvedLeadListExport.approvalStatus", renderType: "badge" }
37101
+ ]
37102
+ }
37103
+ };
37104
+ var CapabilitySchema = external_exports.object({
37105
+ id: ModelIdSchema,
37106
+ label: external_exports.string(),
37107
+ description: external_exports.string(),
37108
+ resourceId: ModelIdSchema
37109
+ });
37110
+ var CAPABILITY_REGISTRY = [
37111
+ {
37112
+ id: "lead-gen.company.source",
37113
+ label: "Source companies",
37114
+ description: "Import source companies from a list provider.",
37115
+ resourceId: "lgn-import-workflow"
37116
+ },
37117
+ {
37118
+ id: "lead-gen.company.apollo-import",
37119
+ label: "Import from Apollo",
37120
+ description: "Pull companies and seed contact data from an Apollo search or list.",
37121
+ resourceId: "lgn-01c-apollo-import-workflow"
37122
+ },
37123
+ {
37124
+ id: "lead-gen.contact.discover",
37125
+ label: "Discover contact emails",
37126
+ description: "Find email addresses for contacts at qualified companies.",
37127
+ resourceId: "lgn-04-email-discovery-workflow"
37128
+ },
37129
+ {
37130
+ id: "lead-gen.contact.verify-email",
37131
+ label: "Verify emails",
37132
+ description: "Check email deliverability before outreach.",
37133
+ resourceId: "lgn-05-email-verification-workflow"
37134
+ },
37135
+ {
37136
+ id: "lead-gen.company.apify-crawl",
37137
+ label: "Crawl websites",
37138
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis.",
37139
+ resourceId: "lgn-02a-apify-website-crawl-workflow"
37140
+ },
37141
+ {
37142
+ id: "lead-gen.company.website-extract",
37143
+ label: "Extract website signals",
37144
+ description: "Scrape and analyze company websites for qualification signals.",
37145
+ resourceId: "lgn-02-website-extract-workflow"
37146
+ },
37147
+ {
37148
+ id: "lead-gen.company.qualify",
37149
+ label: "Qualify companies",
37150
+ description: "Score and filter companies against the ICP rubric.",
37151
+ resourceId: "lgn-03-company-qualification-workflow"
37152
+ },
37153
+ {
37154
+ id: "lead-gen.company.dtc-subscription-qualify",
37155
+ label: "Qualify DTC subscription fit",
37156
+ description: "Classify subscription potential and consumable-product fit for DTC brands.",
37157
+ resourceId: "lgn-03b-dtc-subscription-score-workflow"
37158
+ },
37159
+ {
37160
+ id: "lead-gen.contact.apollo-decision-maker-enrich",
37161
+ label: "Enrich decision-makers",
37162
+ description: "Find and enrich qualified contacts at qualified companies via Apollo.",
37163
+ resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow"
37164
+ },
37165
+ {
37166
+ id: "lead-gen.contact.personalize",
37167
+ label: "Personalize outreach",
37168
+ description: "Generate personalized opening lines for each contact.",
37169
+ resourceId: "ist-personalization-workflow"
37170
+ },
37171
+ {
37172
+ id: "lead-gen.review.outreach-ready",
37173
+ label: "Upload to outreach",
37174
+ description: "Upload approved contacts to the outreach sequence after QC review.",
37175
+ resourceId: "ist-upload-contacts-workflow"
37176
+ },
37177
+ {
37178
+ id: "lead-gen.export.list",
37179
+ label: "Export lead list",
37180
+ description: "Export approved leads as a downloadable lead list.",
37181
+ resourceId: "lgn-06-export-list-workflow"
37182
+ },
37183
+ {
37184
+ id: "lead-gen.company.cleanup",
37185
+ label: "Clean up companies",
37186
+ description: "Remove disqualified or duplicate companies from the list.",
37187
+ resourceId: "lgn-company-cleanup-workflow"
37188
+ }
37189
+ ];
37008
37190
  var PROSPECTING_STEPS = {
37009
37191
  localServices: {
37010
37192
  sourceCompanies: {
@@ -37102,7 +37284,45 @@ var PROSPECTING_STEPS = {
37102
37284
  dependencyMode: "per-record-eligibility",
37103
37285
  capabilityKey: "lead-gen.company.apollo-import",
37104
37286
  defaultBatchSize: 250,
37105
- maxBatchSize: 1e3
37287
+ maxBatchSize: 1e3,
37288
+ recordColumns: DTC_RECORD_COLUMNS.populated,
37289
+ credentialRequirements: [
37290
+ {
37291
+ key: "apollo",
37292
+ provider: "apollo",
37293
+ credentialType: "api-key-secret",
37294
+ label: "Apollo API key",
37295
+ required: true,
37296
+ selectionMode: "single",
37297
+ inputPath: "credential"
37298
+ }
37299
+ ]
37300
+ },
37301
+ apifyCrawl: {
37302
+ id: "apify-crawl",
37303
+ label: "Websites crawled",
37304
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis. Overwrites the synthetic seed Apollo Import wrote with real page content.",
37305
+ primaryEntity: "company",
37306
+ outputs: ["company"],
37307
+ stageKey: "crawled",
37308
+ dependsOn: ["import-apollo-search"],
37309
+ dependencyMode: "per-record-eligibility",
37310
+ capabilityKey: "lead-gen.company.apify-crawl",
37311
+ defaultBatchSize: 50,
37312
+ maxBatchSize: 100,
37313
+ recordColumns: DTC_RECORD_COLUMNS.crawled,
37314
+ credentialRequirements: [
37315
+ {
37316
+ key: "apify",
37317
+ provider: "apify",
37318
+ credentialType: "api-key-secret",
37319
+ label: "Apify API token",
37320
+ required: true,
37321
+ selectionMode: "single",
37322
+ inputPath: "credential",
37323
+ verifyOnRun: true
37324
+ }
37325
+ ]
37106
37326
  },
37107
37327
  analyzeWebsites: {
37108
37328
  id: "analyze-websites",
@@ -37111,11 +37331,12 @@ var PROSPECTING_STEPS = {
37111
37331
  primaryEntity: "company",
37112
37332
  outputs: ["company"],
37113
37333
  stageKey: "extracted",
37114
- dependsOn: ["import-apollo-search"],
37334
+ dependsOn: ["apify-crawl"],
37115
37335
  dependencyMode: "per-record-eligibility",
37116
37336
  capabilityKey: "lead-gen.company.website-extract",
37117
37337
  defaultBatchSize: 50,
37118
- maxBatchSize: 100
37338
+ maxBatchSize: 100,
37339
+ recordColumns: DTC_RECORD_COLUMNS.extracted
37119
37340
  },
37120
37341
  scoreDtcFit: {
37121
37342
  id: "score-dtc-fit",
@@ -37128,7 +37349,8 @@ var PROSPECTING_STEPS = {
37128
37349
  dependencyMode: "per-record-eligibility",
37129
37350
  capabilityKey: "lead-gen.company.dtc-subscription-qualify",
37130
37351
  defaultBatchSize: 100,
37131
- maxBatchSize: 250
37352
+ maxBatchSize: 250,
37353
+ recordColumns: DTC_RECORD_COLUMNS.qualified
37132
37354
  },
37133
37355
  enrichDecisionMakers: {
37134
37356
  id: "enrich-decision-makers",
@@ -37137,37 +37359,52 @@ var PROSPECTING_STEPS = {
37137
37359
  primaryEntity: "company",
37138
37360
  outputs: ["contact"],
37139
37361
  stageKey: "decision-makers-enriched",
37362
+ recordEntity: "contact",
37140
37363
  dependsOn: ["score-dtc-fit"],
37141
37364
  dependencyMode: "per-record-eligibility",
37142
37365
  capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
37143
37366
  defaultBatchSize: 100,
37144
- maxBatchSize: 250
37145
- },
37146
- verifyEmails: {
37147
- id: "verify-emails",
37148
- label: "Emails verified",
37149
- description: "Verify deliverability before the QC and handoff step.",
37150
- primaryEntity: "contact",
37151
- outputs: ["contact"],
37152
- stageKey: "verified",
37153
- dependsOn: ["enrich-decision-makers"],
37154
- dependencyMode: "per-record-eligibility",
37155
- capabilityKey: "lead-gen.contact.verify-email",
37156
- defaultBatchSize: 250,
37157
- maxBatchSize: 500
37367
+ maxBatchSize: 250,
37368
+ recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
37369
+ credentialRequirements: [
37370
+ {
37371
+ key: "apollo",
37372
+ provider: "apollo",
37373
+ credentialType: "api-key-secret",
37374
+ label: "Apollo API key",
37375
+ required: true,
37376
+ selectionMode: "single",
37377
+ inputPath: "credential"
37378
+ }
37379
+ ]
37158
37380
  },
37159
37381
  reviewAndExport: {
37160
37382
  id: "review-and-export",
37161
37383
  label: "Reviewed and exported",
37162
- description: "Operator QC approves or rejects leads, then approved records are exported as a lead list.",
37384
+ description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
37163
37385
  primaryEntity: "company",
37164
37386
  outputs: ["export"],
37165
37387
  stageKey: "uploaded",
37166
- dependsOn: ["verify-emails"],
37388
+ recordsStageKey: "uploaded",
37389
+ recordSourceStageKey: "qualified",
37390
+ dependsOn: ["enrich-decision-makers"],
37167
37391
  dependencyMode: "per-record-eligibility",
37168
37392
  capabilityKey: "lead-gen.export.list",
37169
37393
  defaultBatchSize: 100,
37170
- maxBatchSize: 250
37394
+ maxBatchSize: 250,
37395
+ recordColumns: DTC_RECORD_COLUMNS.uploaded,
37396
+ credentialRequirements: [
37397
+ {
37398
+ key: "clickup",
37399
+ provider: "clickup",
37400
+ credentialType: "api-key-secret",
37401
+ label: "ClickUp API token",
37402
+ required: true,
37403
+ selectionMode: "single",
37404
+ inputPath: "clickupCredential",
37405
+ verifyOnRun: true
37406
+ }
37407
+ ]
37171
37408
  }
37172
37409
  }
37173
37410
  };
@@ -37189,7 +37426,7 @@ function toProspectingLifecycleStage(stage) {
37189
37426
  };
37190
37427
  }
37191
37428
  function leadGenStagesForEntity(entity) {
37192
- return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity).sort((a, b) => a.order - b.order).map(toProspectingLifecycleStage);
37429
+ return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity || stage.additionalEntities?.includes(entity)).sort((a, b) => a.order - b.order).map(toProspectingLifecycleStage);
37193
37430
  }
37194
37431
  var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
37195
37432
  listEntityId: "leadgen.list",
@@ -37219,10 +37456,10 @@ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
37219
37456
  description: "Prospecting pipeline for DTC subscription or subscription-ready brands where Apollo is the source and contact-enrichment layer, Elevasis handles company research and fit scoring, and approved leads export as an approved lead list.",
37220
37457
  steps: [
37221
37458
  PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
37459
+ PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
37222
37460
  PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
37223
37461
  PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
37224
37462
  PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
37225
- PROSPECTING_STEPS.dtcApolloClickup.verifyEmails,
37226
37463
  PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
37227
37464
  ]
37228
37465
  }
@@ -37423,14 +37660,105 @@ var DEFAULT_ORGANIZATION_MODEL_OFFERINGS = {
37423
37660
  products: []
37424
37661
  };
37425
37662
 
37663
+ // ../core/src/organization-model/domains/systems.ts
37664
+ var SystemKindSchema = external_exports.enum(["product", "operational", "platform", "diagnostic"]);
37665
+ var SystemStatusSchema = external_exports.enum(["active", "deprecated", "archived"]);
37666
+ var SystemIdSchema = ModelIdSchema;
37667
+ var SystemEntrySchema = external_exports.object({
37668
+ /** Stable tenant-defined system id (e.g. "sys.lead-gen"). */
37669
+ id: SystemIdSchema,
37670
+ /** Human-readable system title shown in governance and operations UI. */
37671
+ title: LabelSchema,
37672
+ /** One-paragraph purpose statement for the bounded context. */
37673
+ description: DescriptionSchema,
37674
+ /** Closed system shape enum; catalog values remain tenant-defined. */
37675
+ kind: SystemKindSchema,
37676
+ /** Optional role responsible for this system. */
37677
+ responsibleRoleId: ModelIdSchema.optional(),
37678
+ /** Optional knowledge nodes that govern this system. */
37679
+ governedByKnowledge: ReferenceIdsSchema,
37680
+ /** Optional goals this system contributes to. */
37681
+ drivesGoals: ReferenceIdsSchema,
37682
+ status: SystemStatusSchema
37683
+ });
37684
+ var SystemsDomainSchema = external_exports.object({
37685
+ systems: external_exports.array(SystemEntrySchema).default([])
37686
+ });
37687
+ var DEFAULT_ORGANIZATION_MODEL_SYSTEMS = {
37688
+ systems: []
37689
+ };
37690
+
37691
+ // ../core/src/organization-model/domains/resources.ts
37692
+ var ResourceKindSchema = external_exports.enum(["workflow", "agent", "integration"]);
37693
+ var ResourceGovernanceStatusSchema = external_exports.enum(["active", "deprecated", "archived"]);
37694
+ var AgentKindSchema = external_exports.enum(["orchestrator", "specialist", "utility", "system"]);
37695
+ var ResourceIdSchema = external_exports.string().trim().min(1).max(255).regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, "Resource IDs must use letters, numbers, -, _, or . separators");
37696
+ var ResourceEntryBaseSchema = external_exports.object({
37697
+ /** Canonical resource id; runtime resourceId derives from this value. */
37698
+ id: ResourceIdSchema,
37699
+ /** Required single System membership. */
37700
+ systemId: SystemIdSchema,
37701
+ /** Optional role responsible for maintaining this resource. */
37702
+ ownerRoleId: ModelIdSchema.optional(),
37703
+ status: ResourceGovernanceStatusSchema
37704
+ });
37705
+ var WorkflowResourceEntrySchema = ResourceEntryBaseSchema.extend({
37706
+ kind: external_exports.literal("workflow"),
37707
+ /** Mirrors WorkflowConfig.capabilityKey when the runtime workflow has one. */
37708
+ capabilityKey: external_exports.string().trim().min(1).max(255).optional()
37709
+ });
37710
+ var AgentResourceEntrySchema = ResourceEntryBaseSchema.extend({
37711
+ kind: external_exports.literal("agent"),
37712
+ /** Mirrors code-side AgentConfig.kind. */
37713
+ agentKind: AgentKindSchema,
37714
+ /** Role this agent embodies, if any. */
37715
+ actsAsRoleId: ModelIdSchema.optional(),
37716
+ /** Mirrors AgentConfig.sessionCapable. */
37717
+ sessionCapable: external_exports.boolean()
37718
+ });
37719
+ var IntegrationResourceEntrySchema = ResourceEntryBaseSchema.extend({
37720
+ kind: external_exports.literal("integration"),
37721
+ provider: external_exports.string().trim().min(1).max(100)
37722
+ });
37723
+ var ResourceEntrySchema = external_exports.discriminatedUnion("kind", [
37724
+ WorkflowResourceEntrySchema,
37725
+ AgentResourceEntrySchema,
37726
+ IntegrationResourceEntrySchema
37727
+ ]);
37728
+ var ResourcesDomainSchema = external_exports.object({
37729
+ entries: external_exports.array(ResourceEntrySchema).default([])
37730
+ });
37731
+ var DEFAULT_ORGANIZATION_MODEL_RESOURCES = {
37732
+ entries: []
37733
+ };
37734
+
37426
37735
  // ../core/src/organization-model/domains/roles.ts
37736
+ var RoleIdSchema = ModelIdSchema;
37737
+ var HumanRoleHolderSchema = external_exports.object({
37738
+ kind: external_exports.literal("human"),
37739
+ userId: external_exports.string().trim().min(1).max(200)
37740
+ });
37741
+ var AgentRoleHolderSchema = external_exports.object({
37742
+ kind: external_exports.literal("agent"),
37743
+ agentId: ResourceIdSchema
37744
+ });
37745
+ var TeamRoleHolderSchema = external_exports.object({
37746
+ kind: external_exports.literal("team"),
37747
+ memberIds: external_exports.array(external_exports.string().trim().min(1).max(200)).min(1)
37748
+ });
37749
+ var RoleHolderSchema = external_exports.discriminatedUnion("kind", [
37750
+ HumanRoleHolderSchema,
37751
+ AgentRoleHolderSchema,
37752
+ TeamRoleHolderSchema
37753
+ ]);
37754
+ var RoleHoldersSchema = external_exports.union([RoleHolderSchema, external_exports.array(RoleHolderSchema).min(1)]);
37427
37755
  var RoleSchema = external_exports.object({
37428
37756
  /** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
37429
- id: external_exports.string().trim().min(1).max(100),
37757
+ id: RoleIdSchema,
37430
37758
  /** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
37431
37759
  title: external_exports.string().trim().min(1).max(200),
37432
37760
  /**
37433
- * List of responsibilities this role owns plain-language descriptions of
37761
+ * List of responsibilities this role owns - plain-language descriptions of
37434
37762
  * what the person in this role is accountable for delivering.
37435
37763
  * Defaults to empty array so minimal role definitions stay concise.
37436
37764
  */
@@ -37438,16 +37766,18 @@ var RoleSchema = external_exports.object({
37438
37766
  /**
37439
37767
  * Optional: ID of another role this role reports to.
37440
37768
  * When present, must reference another `roles[].id` in the same organization.
37441
- * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
37442
- * Absence indicates a top-level role (no reporting line).
37443
37769
  */
37444
- reportsToId: external_exports.string().trim().min(1).max(100).optional(),
37770
+ reportsToId: RoleIdSchema.optional(),
37771
+ /**
37772
+ * Optional: human, agent, or team holder currently filling this role.
37773
+ * Agent holders reference OM Resource IDs and are validated at the model level.
37774
+ */
37775
+ heldBy: RoleHoldersSchema.optional(),
37445
37776
  /**
37446
- * Optional: name or email of the person currently holding this role.
37447
- * Free-form string supports "Alice Johnson", "alice@example.com", or
37448
- * any human-readable identifier. Not validated against any user registry.
37777
+ * Optional Systems this role is accountable for.
37778
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
37449
37779
  */
37450
- heldBy: external_exports.string().trim().max(200).optional()
37780
+ responsibleFor: external_exports.array(SystemIdSchema).optional()
37451
37781
  });
37452
37782
  var RolesDomainSchema = external_exports.object({
37453
37783
  roles: external_exports.array(RoleSchema).default([])
@@ -37690,8 +38020,8 @@ var OrgKnowledgeNodeSchema = external_exports.object({
37690
38020
  skills: external_exports.array(KnowledgeSkillBindingSchema).optional(),
37691
38021
  /** Domain key used to derive fast graph->skill registries. */
37692
38022
  domain: KnowledgeDomainBindingSchema.optional(),
37693
- /** Identifiers of the roles or members who own this knowledge node. */
37694
- ownerIds: external_exports.array(ModelIdSchema).default([]),
38023
+ /** Role identifiers that own this knowledge node. */
38024
+ ownerIds: external_exports.array(RoleIdSchema).default([]),
37695
38025
  /** ISO date string (YYYY-MM-DD or full ISO 8601) of last meaningful update. */
37696
38026
  updatedAt: external_exports.string().trim().min(1).max(50)
37697
38027
  });
@@ -37713,6 +38043,8 @@ var OrganizationModelSchemaBase = external_exports.object({
37713
38043
  offerings: OfferingsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_OFFERINGS),
37714
38044
  roles: RolesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ROLES),
37715
38045
  goals: GoalsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_GOALS),
38046
+ systems: SystemsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_SYSTEMS),
38047
+ resources: ResourcesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_RESOURCES),
37716
38048
  statuses: StatusesDomainSchema.default({ entries: [] }),
37717
38049
  operations: OperationsDomainSchema.default({ entries: [] }),
37718
38050
  knowledge: KnowledgeDomainSchema.default({ nodes: [] })
@@ -37743,8 +38075,15 @@ var LEGACY_FEATURE_ALIASES = /* @__PURE__ */ new Map([
37743
38075
  function hasFeature(featuresById, featureId) {
37744
38076
  return featuresById.has(featureId) || featuresById.has(LEGACY_FEATURE_ALIASES.get(featureId) ?? "");
37745
38077
  }
38078
+ function defaultFeaturePathFor(id) {
38079
+ return `/${id.replaceAll(".", "/")}`;
38080
+ }
38081
+ function asRoleHolderArray(heldBy) {
38082
+ return Array.isArray(heldBy) ? heldBy : [heldBy];
38083
+ }
37746
38084
  var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
37747
38085
  const featuresById = collectIds(model.features, ctx, ["features"], "Feature");
38086
+ const featureIdsByEffectivePath = /* @__PURE__ */ new Map();
37748
38087
  model.features.forEach((feature, featureIndex) => {
37749
38088
  const segments = feature.id.split(".");
37750
38089
  if (segments.length > 1) {
@@ -37760,6 +38099,20 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
37760
38099
  const hasChildren = model.features.some(
37761
38100
  (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.id !== feature.id
37762
38101
  );
38102
+ const contributesRoutePath = feature.path !== void 0 || !hasChildren;
38103
+ if (contributesRoutePath) {
38104
+ const effectivePath = feature.path ?? defaultFeaturePathFor(feature.id);
38105
+ const existingFeatureId = featureIdsByEffectivePath.get(effectivePath);
38106
+ if (existingFeatureId !== void 0) {
38107
+ addIssue(
38108
+ ctx,
38109
+ ["features", featureIndex, feature.path === void 0 ? "id" : "path"],
38110
+ `Feature "${feature.id}" effective path "${effectivePath}" duplicates feature "${existingFeatureId}"`
38111
+ );
38112
+ } else {
38113
+ featureIdsByEffectivePath.set(effectivePath, feature.id);
38114
+ }
38115
+ }
37763
38116
  if (hasChildren && feature.enabled) {
37764
38117
  const hasEnabledDescendant = model.features.some(
37765
38118
  (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.enabled
@@ -37773,6 +38126,43 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
37773
38126
  }
37774
38127
  }
37775
38128
  });
38129
+ const surfacesById = collectIds(model.navigation.surfaces, ctx, ["navigation", "surfaces"], "Navigation surface");
38130
+ if (model.navigation.defaultSurfaceId !== void 0 && !surfacesById.has(model.navigation.defaultSurfaceId)) {
38131
+ addIssue(
38132
+ ctx,
38133
+ ["navigation", "defaultSurfaceId"],
38134
+ `Navigation defaultSurfaceId references unknown surface "${model.navigation.defaultSurfaceId}"`
38135
+ );
38136
+ }
38137
+ model.navigation.groups.forEach((group, groupIndex) => {
38138
+ group.surfaceIds.forEach((surfaceId, surfaceIndex) => {
38139
+ if (!surfacesById.has(surfaceId)) {
38140
+ addIssue(
38141
+ ctx,
38142
+ ["navigation", "groups", groupIndex, "surfaceIds", surfaceIndex],
38143
+ `Navigation group "${group.id}" references unknown surface "${surfaceId}"`
38144
+ );
38145
+ }
38146
+ });
38147
+ });
38148
+ model.navigation.surfaces.forEach((surface, surfaceIndex) => {
38149
+ if (surface.featureId !== void 0 && !hasFeature(featuresById, surface.featureId)) {
38150
+ addIssue(
38151
+ ctx,
38152
+ ["navigation", "surfaces", surfaceIndex, "featureId"],
38153
+ `Navigation surface "${surface.id}" references unknown feature "${surface.featureId}"`
38154
+ );
38155
+ }
38156
+ surface.featureIds.forEach((featureId, featureIndex) => {
38157
+ if (!hasFeature(featuresById, featureId)) {
38158
+ addIssue(
38159
+ ctx,
38160
+ ["navigation", "surfaces", surfaceIndex, "featureIds", featureIndex],
38161
+ `Navigation surface "${surface.id}" references unknown feature "${featureId}"`
38162
+ );
38163
+ }
38164
+ });
38165
+ });
37776
38166
  const segmentsById = new Map(model.customers.segments.map((seg) => [seg.id, seg]));
37777
38167
  model.offerings.products.forEach((product, productIndex) => {
37778
38168
  product.targetSegmentIds.forEach((segmentId, segmentIndex) => {
@@ -37801,6 +38191,8 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
37801
38191
  );
37802
38192
  }
37803
38193
  });
38194
+ const goalsById = new Map(model.goals.objectives.map((objective) => [objective.id, objective]));
38195
+ const knowledgeById = new Map(model.knowledge.nodes.map((node) => [node.id, node]));
37804
38196
  const rolesById = new Map(model.roles.roles.map((role) => [role.id, role]));
37805
38197
  model.roles.roles.forEach((role, roleIndex) => {
37806
38198
  if (role.reportsToId !== void 0 && !rolesById.has(role.reportsToId)) {
@@ -37811,6 +38203,102 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
37811
38203
  );
37812
38204
  }
37813
38205
  });
38206
+ const systemsById = collectIds(model.systems.systems, ctx, ["systems", "systems"], "System");
38207
+ model.roles.roles.forEach((role, roleIndex) => {
38208
+ role.responsibleFor?.forEach((systemId, systemIndex) => {
38209
+ if (!systemsById.has(systemId)) {
38210
+ addIssue(
38211
+ ctx,
38212
+ ["roles", "roles", roleIndex, "responsibleFor", systemIndex],
38213
+ `Role "${role.id}" references unknown responsibleFor system "${systemId}"`
38214
+ );
38215
+ }
38216
+ });
38217
+ });
38218
+ model.systems.systems.forEach((system, systemIndex) => {
38219
+ if (system.responsibleRoleId !== void 0 && !rolesById.has(system.responsibleRoleId)) {
38220
+ addIssue(
38221
+ ctx,
38222
+ ["systems", "systems", systemIndex, "responsibleRoleId"],
38223
+ `System "${system.id}" references unknown responsibleRoleId "${system.responsibleRoleId}"`
38224
+ );
38225
+ }
38226
+ system.governedByKnowledge.forEach((nodeId2, nodeIndex) => {
38227
+ if (!knowledgeById.has(nodeId2)) {
38228
+ addIssue(
38229
+ ctx,
38230
+ ["systems", "systems", systemIndex, "governedByKnowledge", nodeIndex],
38231
+ `System "${system.id}" references unknown knowledge node "${nodeId2}"`
38232
+ );
38233
+ }
38234
+ });
38235
+ system.drivesGoals.forEach((goalId, goalIndex) => {
38236
+ if (!goalsById.has(goalId)) {
38237
+ addIssue(
38238
+ ctx,
38239
+ ["systems", "systems", systemIndex, "drivesGoals", goalIndex],
38240
+ `System "${system.id}" references unknown goal "${goalId}"`
38241
+ );
38242
+ }
38243
+ });
38244
+ });
38245
+ const resourcesById = collectIds(model.resources.entries, ctx, ["resources", "entries"], "Resource");
38246
+ model.resources.entries.forEach((resource, resourceIndex) => {
38247
+ if (!systemsById.has(resource.systemId)) {
38248
+ addIssue(
38249
+ ctx,
38250
+ ["resources", "entries", resourceIndex, "systemId"],
38251
+ `Resource "${resource.id}" references unknown systemId "${resource.systemId}"`
38252
+ );
38253
+ }
38254
+ if (resource.ownerRoleId !== void 0 && !rolesById.has(resource.ownerRoleId)) {
38255
+ addIssue(
38256
+ ctx,
38257
+ ["resources", "entries", resourceIndex, "ownerRoleId"],
38258
+ `Resource "${resource.id}" references unknown ownerRoleId "${resource.ownerRoleId}"`
38259
+ );
38260
+ }
38261
+ if (resource.kind === "agent" && resource.actsAsRoleId !== void 0 && !rolesById.has(resource.actsAsRoleId)) {
38262
+ addIssue(
38263
+ ctx,
38264
+ ["resources", "entries", resourceIndex, "actsAsRoleId"],
38265
+ `Agent resource "${resource.id}" references unknown actsAsRoleId "${resource.actsAsRoleId}"`
38266
+ );
38267
+ }
38268
+ });
38269
+ model.roles.roles.forEach((role, roleIndex) => {
38270
+ if (role.heldBy === void 0) return;
38271
+ asRoleHolderArray(role.heldBy).forEach((holder, holderIndex) => {
38272
+ if (holder.kind !== "agent") return;
38273
+ const resource = resourcesById.get(holder.agentId);
38274
+ if (resource === void 0) {
38275
+ addIssue(
38276
+ ctx,
38277
+ ["roles", "roles", roleIndex, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
38278
+ `Role "${role.id}" references unknown agent holder resource "${holder.agentId}"`
38279
+ );
38280
+ return;
38281
+ }
38282
+ if (resource.kind !== "agent") {
38283
+ addIssue(
38284
+ ctx,
38285
+ ["roles", "roles", roleIndex, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
38286
+ `Role "${role.id}" agent holder "${holder.agentId}" must reference an agent resource`
38287
+ );
38288
+ }
38289
+ });
38290
+ });
38291
+ model.knowledge.nodes.forEach((node, nodeIndex) => {
38292
+ node.ownerIds.forEach((roleId, ownerIndex) => {
38293
+ if (!rolesById.has(roleId)) {
38294
+ addIssue(
38295
+ ctx,
38296
+ ["knowledge", "nodes", nodeIndex, "ownerIds", ownerIndex],
38297
+ `Knowledge node "${node.id}" references unknown owner role "${roleId}"`
38298
+ );
38299
+ }
38300
+ });
38301
+ });
37814
38302
  });
37815
38303
 
37816
38304
  // ../core/src/organization-model/graph/schema.ts
@@ -37820,6 +38308,7 @@ var OrganizationGraphNodeKindSchema = external_exports.enum([
37820
38308
  "surface",
37821
38309
  "entity",
37822
38310
  "capability",
38311
+ "stage",
37823
38312
  "resource",
37824
38313
  "knowledge"
37825
38314
  ]);
@@ -38132,6 +38621,149 @@ var RegistryValidationError = class extends Error {
38132
38621
  this.name = "RegistryValidationError";
38133
38622
  }
38134
38623
  };
38624
+ function getResourceValidatorMode(explicitMode) {
38625
+ if (explicitMode) return explicitMode;
38626
+ const env2 = globalThis.process?.env;
38627
+ return env2?.ELEVASIS_RESOURCE_VALIDATOR === "warn-only" ? "warn-only" : "strict";
38628
+ }
38629
+ function addGovernanceIssue(issues, type, orgName, resourceId, message) {
38630
+ issues.push({
38631
+ type,
38632
+ orgName,
38633
+ resourceId,
38634
+ message
38635
+ });
38636
+ }
38637
+ function emitGovernanceIssues(issues, mode, onWarning) {
38638
+ if (issues.length === 0) return;
38639
+ if (mode === "strict") {
38640
+ const first = issues[0];
38641
+ throw new RegistryValidationError(first.orgName, first.resourceId, "organizationModel.resources", first.message);
38642
+ }
38643
+ const warn2 = onWarning ?? ((issue2) => console.warn(issue2.message));
38644
+ for (const issue2 of issues) {
38645
+ warn2(issue2);
38646
+ }
38647
+ }
38648
+ function getRuntimeResources(resources) {
38649
+ return [
38650
+ ...(resources.workflows ?? []).map((workflow) => ({
38651
+ resourceId: workflow.config.resourceId,
38652
+ type: workflow.config.type,
38653
+ descriptor: workflow.config.resource
38654
+ })),
38655
+ ...(resources.agents ?? []).map((agent) => ({
38656
+ resourceId: agent.config.resourceId,
38657
+ type: agent.config.type,
38658
+ descriptor: agent.config.resource
38659
+ })),
38660
+ ...(resources.integrations ?? []).map((integration) => ({
38661
+ resourceId: integration.resourceId,
38662
+ type: integration.type,
38663
+ descriptor: integration.resource
38664
+ }))
38665
+ ];
38666
+ }
38667
+ function validateResourceGovernance(orgName, deployment, organizationModel = deployment.organizationModel, options = {}) {
38668
+ const mode = getResourceValidatorMode(options.mode);
38669
+ const omResources = organizationModel?.resources?.entries;
38670
+ const omSystems = organizationModel?.systems?.systems;
38671
+ const issues = [];
38672
+ if (!omResources || !omSystems) {
38673
+ return { valid: true, mode, issues };
38674
+ }
38675
+ const systemsById = new Map(omSystems.map((system) => [system.id, system]));
38676
+ const activeOmResources = omResources.filter((resource) => resource.status === "active");
38677
+ const omResourcesById = new Map(activeOmResources.map((resource) => [resource.id, resource]));
38678
+ const runtimeResources = getRuntimeResources(deployment);
38679
+ const runtimeResourcesById = new Map(runtimeResources.map((resource) => [resource.resourceId, resource]));
38680
+ for (const resource of activeOmResources) {
38681
+ if (!systemsById.has(resource.systemId)) {
38682
+ addGovernanceIssue(
38683
+ issues,
38684
+ "missing-om-system",
38685
+ orgName,
38686
+ resource.id,
38687
+ `[${orgName}] OM resource '${resource.id}' references missing System '${resource.systemId}'.`
38688
+ );
38689
+ }
38690
+ const runtimeResource = runtimeResourcesById.get(resource.id);
38691
+ if (!runtimeResource) {
38692
+ addGovernanceIssue(
38693
+ issues,
38694
+ "missing-code-resource",
38695
+ orgName,
38696
+ resource.id,
38697
+ `[${orgName}] OM resource '${resource.id}' has no matching code-side resource.`
38698
+ );
38699
+ continue;
38700
+ }
38701
+ if (runtimeResource.type !== resource.kind) {
38702
+ addGovernanceIssue(
38703
+ issues,
38704
+ "type-mismatch",
38705
+ orgName,
38706
+ resource.id,
38707
+ `[${orgName}] Resource '${resource.id}' type mismatch: code has '${runtimeResource.type}', OM has '${resource.kind}'.`
38708
+ );
38709
+ }
38710
+ if (runtimeResource.descriptor && runtimeResource.descriptor.systemId !== resource.systemId) {
38711
+ addGovernanceIssue(
38712
+ issues,
38713
+ "system-mismatch",
38714
+ orgName,
38715
+ resource.id,
38716
+ `[${orgName}] Resource '${resource.id}' system mismatch: code descriptor has '${runtimeResource.descriptor.systemId}', OM has '${resource.systemId}'.`
38717
+ );
38718
+ }
38719
+ }
38720
+ for (const runtimeResource of runtimeResources) {
38721
+ const omResource = omResourcesById.get(runtimeResource.resourceId);
38722
+ if (!omResource) {
38723
+ addGovernanceIssue(
38724
+ issues,
38725
+ "missing-om-resource",
38726
+ orgName,
38727
+ runtimeResource.resourceId,
38728
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' has no active OM Resource descriptor.`
38729
+ );
38730
+ }
38731
+ if (!runtimeResource.descriptor) {
38732
+ addGovernanceIssue(
38733
+ issues,
38734
+ "raw-resource-id",
38735
+ orgName,
38736
+ runtimeResource.resourceId,
38737
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' authors raw resourceId/type values. Use an OM Resource descriptor and bindResourceDescriptor().`
38738
+ );
38739
+ continue;
38740
+ }
38741
+ if (runtimeResource.descriptor.id !== runtimeResource.resourceId) {
38742
+ addGovernanceIssue(
38743
+ issues,
38744
+ "raw-resource-id",
38745
+ orgName,
38746
+ runtimeResource.resourceId,
38747
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' does not derive identity from its OM descriptor '${runtimeResource.descriptor.id}'.`
38748
+ );
38749
+ }
38750
+ if (runtimeResource.descriptor.kind !== runtimeResource.type) {
38751
+ addGovernanceIssue(
38752
+ issues,
38753
+ "type-mismatch",
38754
+ orgName,
38755
+ runtimeResource.resourceId,
38756
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' descriptor kind '${runtimeResource.descriptor.kind}' does not match runtime type '${runtimeResource.type}'.`
38757
+ );
38758
+ }
38759
+ }
38760
+ emitGovernanceIssues(issues, mode, options.onWarning);
38761
+ return {
38762
+ valid: issues.length === 0,
38763
+ mode,
38764
+ issues
38765
+ };
38766
+ }
38135
38767
  function validateDeploymentSpec(orgName, resources) {
38136
38768
  const seenIds = /* @__PURE__ */ new Set();
38137
38769
  resources.workflows?.forEach((workflow) => {
@@ -38168,6 +38800,7 @@ function validateDeploymentSpec(orgName, resources) {
38168
38800
  validateExecutionInterface(orgName, id, agent.interface, agent.contract.inputSchema);
38169
38801
  }
38170
38802
  });
38803
+ validateResourceGovernance(orgName, resources);
38171
38804
  }
38172
38805
  function validateResourceModelConfig(orgName, resourceId, modelConfig) {
38173
38806
  try {
@@ -40695,6 +41328,29 @@ function redactSecret(value) {
40695
41328
  }
40696
41329
 
40697
41330
  // ../core/src/platform/registry/serialization.ts
41331
+ function summarizeSystem(system) {
41332
+ if (!system) return void 0;
41333
+ return {
41334
+ id: system.id,
41335
+ title: system.title,
41336
+ description: system.description,
41337
+ kind: system.kind,
41338
+ status: system.status
41339
+ };
41340
+ }
41341
+ function createGovernanceMetadataResolver(resources) {
41342
+ const resourcesById = new Map((resources.organizationModel?.resources?.entries ?? []).map((r) => [r.id, r]));
41343
+ const systemsById = new Map((resources.organizationModel?.systems?.systems ?? []).map((s) => [s.id, s]));
41344
+ return (resourceId, descriptor) => {
41345
+ const resource = descriptor ?? resourcesById.get(resourceId);
41346
+ if (!resource) return {};
41347
+ return {
41348
+ systemId: resource.systemId,
41349
+ system: summarizeSystem(systemsById.get(resource.systemId)),
41350
+ governanceStatus: resource.status
41351
+ };
41352
+ };
41353
+ }
40698
41354
  function serializeAllOrganizations(registry2) {
40699
41355
  const cache = /* @__PURE__ */ new Map();
40700
41356
  for (const [orgName, resources] of Object.entries(registry2)) {
@@ -40703,6 +41359,7 @@ function serializeAllOrganizations(registry2) {
40703
41359
  return cache;
40704
41360
  }
40705
41361
  function serializeOrganization(resources) {
41362
+ const getGovernanceMetadata = createGovernanceMetadataResolver(resources);
40706
41363
  const workflowDefinitions = /* @__PURE__ */ new Map();
40707
41364
  const workflowResources = [];
40708
41365
  const commandViewWorkflows = [];
@@ -40718,7 +41375,8 @@ function serializeOrganization(resources) {
40718
41375
  type: "workflow",
40719
41376
  status: workflow.config.status,
40720
41377
  links: workflow.config.links,
40721
- category: workflow.config.category
41378
+ category: workflow.config.category,
41379
+ ...getGovernanceMetadata(resourceId, workflow.config.resource)
40722
41380
  });
40723
41381
  commandViewWorkflows.push({
40724
41382
  resourceId,
@@ -40729,6 +41387,7 @@ function serializeOrganization(resources) {
40729
41387
  status: workflow.config.status,
40730
41388
  links: workflow.config.links,
40731
41389
  category: workflow.config.category,
41390
+ ...getGovernanceMetadata(resourceId, workflow.config.resource),
40732
41391
  stepCount: Object.keys(workflow.steps).length,
40733
41392
  entryPoint: workflow.entryPoint
40734
41393
  });
@@ -40748,7 +41407,8 @@ function serializeOrganization(resources) {
40748
41407
  type: "agent",
40749
41408
  status: agent.config.status,
40750
41409
  links: agent.config.links,
40751
- category: agent.config.category
41410
+ category: agent.config.category,
41411
+ ...getGovernanceMetadata(resourceId, agent.config.resource)
40752
41412
  });
40753
41413
  commandViewAgents.push({
40754
41414
  resourceId,
@@ -40759,6 +41419,7 @@ function serializeOrganization(resources) {
40759
41419
  status: agent.config.status,
40760
41420
  links: agent.config.links,
40761
41421
  category: agent.config.category,
41422
+ ...getGovernanceMetadata(resourceId, agent.config.resource),
40762
41423
  modelProvider: agent.modelConfig.provider,
40763
41424
  modelId: agent.modelConfig.model,
40764
41425
  toolCount: agent.tools.length,
@@ -40903,6 +41564,16 @@ function filterArchived(org) {
40903
41564
  humanCheckpoints: org.humanCheckpoints?.filter((h) => !h.archived)
40904
41565
  };
40905
41566
  }
41567
+ function summarizeSystem2(system) {
41568
+ if (!system) return void 0;
41569
+ return {
41570
+ id: system.id,
41571
+ title: system.title,
41572
+ description: system.description,
41573
+ kind: system.kind,
41574
+ status: system.status
41575
+ };
41576
+ }
40906
41577
  var ResourceRegistry = class {
40907
41578
  constructor(registry2) {
40908
41579
  this.registry = registry2;
@@ -41049,6 +41720,17 @@ var ResourceRegistry = class {
41049
41720
  environment
41050
41721
  };
41051
41722
  }
41723
+ const resourcesById = new Map((orgResources.organizationModel?.resources?.entries ?? []).map((r) => [r.id, r]));
41724
+ const systemsById = new Map((orgResources.organizationModel?.systems?.systems ?? []).map((s) => [s.id, s]));
41725
+ const getGovernanceMetadata = (resourceId, descriptor) => {
41726
+ const resource = descriptor ?? resourcesById.get(resourceId);
41727
+ if (!resource) return {};
41728
+ return {
41729
+ systemId: resource.systemId,
41730
+ system: summarizeSystem2(systemsById.get(resource.systemId)),
41731
+ governanceStatus: resource.status
41732
+ };
41733
+ };
41052
41734
  const workflows = (orgResources.workflows || []).map((def) => ({
41053
41735
  resourceId: def.config.resourceId,
41054
41736
  name: def.config.name,
@@ -41058,7 +41740,8 @@ var ResourceRegistry = class {
41058
41740
  status: def.config.status,
41059
41741
  links: def.config.links,
41060
41742
  category: def.config.category,
41061
- origin: this.remoteResources.has(`${organizationName}/${def.config.resourceId}`) ? "remote" : "local"
41743
+ origin: this.remoteResources.has(`${organizationName}/${def.config.resourceId}`) ? "remote" : "local",
41744
+ ...getGovernanceMetadata(def.config.resourceId, def.config.resource)
41062
41745
  })).filter((resource) => !environment || resource.status === environment);
41063
41746
  const agents = (orgResources.agents || []).map((def) => ({
41064
41747
  resourceId: def.config.resourceId,
@@ -41070,7 +41753,8 @@ var ResourceRegistry = class {
41070
41753
  links: def.config.links,
41071
41754
  category: def.config.category,
41072
41755
  sessionCapable: def.config.sessionCapable ?? false,
41073
- origin: this.remoteResources.has(`${organizationName}/${def.config.resourceId}`) ? "remote" : "local"
41756
+ origin: this.remoteResources.has(`${organizationName}/${def.config.resourceId}`) ? "remote" : "local",
41757
+ ...getGovernanceMetadata(def.config.resourceId, def.config.resource)
41074
41758
  })).filter((resource) => !environment || resource.status === environment);
41075
41759
  return {
41076
41760
  workflows,
@@ -41533,6 +42217,15 @@ var DEFAULT_ORGANIZATION_MODEL = {
41533
42217
  color: "green",
41534
42218
  icon: "feature.finance"
41535
42219
  },
42220
+ {
42221
+ id: "business",
42222
+ label: "Business",
42223
+ description: "Revenue, client relationships, and project delivery",
42224
+ enabled: true,
42225
+ color: "blue",
42226
+ icon: "feature.business",
42227
+ uiPosition: "sidebar-primary"
42228
+ },
41536
42229
  {
41537
42230
  id: "sales",
41538
42231
  label: "Sales",
@@ -41540,7 +42233,7 @@ var DEFAULT_ORGANIZATION_MODEL = {
41540
42233
  enabled: true,
41541
42234
  color: "blue",
41542
42235
  icon: "feature.sales",
41543
- uiPosition: "sidebar-primary"
42236
+ path: "/sales"
41544
42237
  },
41545
42238
  {
41546
42239
  id: "sales.crm",
@@ -41567,8 +42260,16 @@ var DEFAULT_ORGANIZATION_MODEL = {
41567
42260
  enabled: true,
41568
42261
  color: "orange",
41569
42262
  icon: "feature.projects",
41570
- path: "/projects",
41571
- uiPosition: "sidebar-primary"
42263
+ path: "/projects"
42264
+ },
42265
+ {
42266
+ id: "clients",
42267
+ label: "Clients",
42268
+ description: "Client relationships, accounts, and business context",
42269
+ enabled: true,
42270
+ color: "orange",
42271
+ icon: "feature.projects",
42272
+ path: "/business/clients"
41572
42273
  },
41573
42274
  {
41574
42275
  id: "operations",
@@ -41813,6 +42514,8 @@ var DEFAULT_ORGANIZATION_MODEL = {
41813
42514
  offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
41814
42515
  roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
41815
42516
  goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
42517
+ systems: DEFAULT_ORGANIZATION_MODEL_SYSTEMS,
42518
+ resources: DEFAULT_ORGANIZATION_MODEL_RESOURCES,
41816
42519
  statuses: DEFAULT_ORGANIZATION_MODEL_STATUSES,
41817
42520
  operations: DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
41818
42521
  knowledge: DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE
@@ -41957,24 +42660,93 @@ function buildOrganizationGraph(input) {
41957
42660
  });
41958
42661
  }
41959
42662
  }
41960
- if (commandViewData) {
41961
- const commandViewResources = collectCommandViewResources(commandViewData).sort(
41962
- (a, b) => a.resourceId.localeCompare(b.resourceId)
41963
- );
41964
- for (const resource of commandViewResources) {
41965
- const id = nodeId("resource", resource.resourceId);
41966
- const resourceNode = upsertResourceNode(nodes, nodeIds, resourceNodesById, {
41967
- id,
41968
- kind: "resource",
41969
- label: resource.name,
41970
- sourceId: resource.resourceId,
41971
- description: resource.description,
41972
- resourceType: normalizeCommandViewResourceType(resource.type)
41973
- });
41974
- pushUniqueEdge(edges, edgeIds, {
41975
- id: edgeId("contains", organizationNode.id, resourceNode.id),
41976
- kind: "contains",
41977
- sourceId: organizationNode.id,
42663
+ const allStages = [
42664
+ ...organizationModel.prospecting.companyStages,
42665
+ ...organizationModel.prospecting.contactStages
42666
+ ].sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
42667
+ for (const stage of allStages) {
42668
+ const id = nodeId("stage", stage.id);
42669
+ pushUniqueNode(nodes, nodeIds, {
42670
+ id,
42671
+ kind: "stage",
42672
+ label: stage.label,
42673
+ sourceId: stage.id,
42674
+ ...stage.description ? { description: stage.description } : {},
42675
+ ...stage.icon ? { icon: stage.icon } : {}
42676
+ });
42677
+ pushUniqueEdge(edges, edgeIds, {
42678
+ id: edgeId("contains", organizationNode.id, id),
42679
+ kind: "contains",
42680
+ sourceId: organizationNode.id,
42681
+ targetId: id
42682
+ });
42683
+ }
42684
+ for (const cap of [...CAPABILITY_REGISTRY].sort((a, b) => a.id.localeCompare(b.id))) {
42685
+ const id = nodeId("capability", cap.id);
42686
+ pushUniqueNode(nodes, nodeIds, {
42687
+ id,
42688
+ kind: "capability",
42689
+ label: cap.label,
42690
+ sourceId: cap.id,
42691
+ description: cap.description
42692
+ });
42693
+ pushUniqueEdge(edges, edgeIds, {
42694
+ id: edgeId("contains", organizationNode.id, id),
42695
+ kind: "contains",
42696
+ sourceId: organizationNode.id,
42697
+ targetId: id
42698
+ });
42699
+ const resourceNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, cap.resourceId);
42700
+ pushUniqueEdge(edges, edgeIds, {
42701
+ id: edgeId("maps_to", id, resourceNode.id),
42702
+ kind: "maps_to",
42703
+ sourceId: id,
42704
+ targetId: resourceNode.id
42705
+ });
42706
+ }
42707
+ for (const template of [...organizationModel.prospecting.buildTemplates].sort((a, b) => a.id.localeCompare(b.id))) {
42708
+ const stepById = new Map(template.steps.map((s) => [s.id, s]));
42709
+ for (const step of [...template.steps].sort((a, b) => a.id.localeCompare(b.id))) {
42710
+ const stageNodeId = nodeId("stage", step.stageKey);
42711
+ const capNodeId = nodeId("capability", step.capabilityKey);
42712
+ pushUniqueEdge(edges, edgeIds, {
42713
+ id: edgeId("uses", stageNodeId, capNodeId, step.id),
42714
+ kind: "uses",
42715
+ sourceId: stageNodeId,
42716
+ targetId: capNodeId
42717
+ });
42718
+ for (const depId of step.dependsOn ?? []) {
42719
+ const depStep = stepById.get(depId);
42720
+ if (depStep) {
42721
+ const depStageNodeId = nodeId("stage", depStep.stageKey);
42722
+ pushUniqueEdge(edges, edgeIds, {
42723
+ id: edgeId("references", stageNodeId, depStageNodeId, step.id),
42724
+ kind: "references",
42725
+ sourceId: stageNodeId,
42726
+ targetId: depStageNodeId
42727
+ });
42728
+ }
42729
+ }
42730
+ }
42731
+ }
42732
+ if (commandViewData) {
42733
+ const commandViewResources = collectCommandViewResources(commandViewData).sort(
42734
+ (a, b) => a.resourceId.localeCompare(b.resourceId)
42735
+ );
42736
+ for (const resource of commandViewResources) {
42737
+ const id = nodeId("resource", resource.resourceId);
42738
+ const resourceNode = upsertResourceNode(nodes, nodeIds, resourceNodesById, {
42739
+ id,
42740
+ kind: "resource",
42741
+ label: resource.name,
42742
+ sourceId: resource.resourceId,
42743
+ description: resource.description,
42744
+ resourceType: normalizeCommandViewResourceType(resource.type)
42745
+ });
42746
+ pushUniqueEdge(edges, edgeIds, {
42747
+ id: edgeId("contains", organizationNode.id, resourceNode.id),
42748
+ kind: "contains",
42749
+ sourceId: organizationNode.id,
41978
42750
  targetId: resourceNode.id
41979
42751
  });
41980
42752
  pushResourceLinks(edges, edgeIds, resourceNode.id, resource.links);
@@ -42213,7 +42985,7 @@ function wrapAction(commandName, fn) {
42213
42985
  // package.json
42214
42986
  var package_default = {
42215
42987
  name: "@elevasis/sdk",
42216
- version: "1.18.0",
42988
+ version: "1.20.0",
42217
42989
  description: "SDK for building Elevasis organization resources",
42218
42990
  type: "module",
42219
42991
  bin: {
@@ -42419,6 +43191,10 @@ function bumpVersion(current, type) {
42419
43191
  return `${major}.${minor}.${patch + 1}`;
42420
43192
  }
42421
43193
  }
43194
+ function validateResourceGovernancePreflight(orgName, org) {
43195
+ if (process.env.ELEVASIS_RESOURCE_VALIDATOR === "warn-only") return;
43196
+ validateResourceGovernance(orgName, org, org.organizationModel, { mode: "strict" });
43197
+ }
42422
43198
  function registerDeployCommand(program3) {
42423
43199
  program3.command("deploy").description(
42424
43200
  "Validate, bundle, upload, and deploy project resources\n Example: elevasis-sdk deploy --api-url http://localhost:5170"
@@ -42463,6 +43239,7 @@ function registerDeployCommand(program3) {
42463
43239
  console.error(source_default.gray(` Entry file: ${resolvePackageRelative(entryPath)}`));
42464
43240
  throw new Error("Invalid entry: no default export found");
42465
43241
  }
43242
+ validateResourceGovernancePreflight(orgName, org);
42466
43243
  new ResourceRegistry({ [orgName]: org });
42467
43244
  activeWorkflows = (org.workflows ?? []).filter((w) => !w.config.archived);
42468
43245
  activeAgents = (org.agents ?? []).filter((a) => !a.config.archived);
@@ -42661,6 +43438,7 @@ function registerCheckCommand(program3) {
42661
43438
  console.error(source_default.gray(" Expected: export default { workflows: [...], agents: [...] }"));
42662
43439
  throw new Error("Invalid entry");
42663
43440
  }
43441
+ validateResourceGovernancePreflight("_check", org);
42664
43442
  new ResourceRegistry({ _check: org });
42665
43443
  const workflowCount = org.workflows?.length ?? 0;
42666
43444
  const agentCount = org.agents?.length ?? 0;
@@ -43728,17 +44506,179 @@ function renderProjectWorkBrief(brief) {
43728
44506
  return lines.join("\n");
43729
44507
  }
43730
44508
 
44509
+ // src/cli/commands/client/client.ts
44510
+ function isUuid2(value) {
44511
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
44512
+ }
44513
+ function normalizeStr(value) {
44514
+ return value.trim().toLowerCase();
44515
+ }
44516
+ function formatClientCandidates(clients) {
44517
+ return clients.slice(0, 5).map((c) => `${c.name} (${c.id})`).join(", ");
44518
+ }
44519
+ async function resolveClient(query, apiUrlOverride) {
44520
+ const trimmedQuery = query.trim();
44521
+ if (!trimmedQuery) {
44522
+ throw new Error("Client query is required");
44523
+ }
44524
+ const apiUrl = resolveApiUrl(apiUrlOverride);
44525
+ if (isUuid2(trimmedQuery)) {
44526
+ try {
44527
+ const result2 = await apiGet(`/api/external/clients/${trimmedQuery}`, apiUrl);
44528
+ return result2;
44529
+ } catch (error46) {
44530
+ if (!(error46 instanceof Error) || !error46.message.includes("(404)")) {
44531
+ throw error46;
44532
+ }
44533
+ }
44534
+ }
44535
+ const params = new URLSearchParams({ search: trimmedQuery });
44536
+ const result = await apiGet(`/api/external/clients?${params.toString()}`, apiUrl);
44537
+ const clients = result.data;
44538
+ if (clients.length === 0) {
44539
+ throw new Error(`No client matched "${trimmedQuery}"`);
44540
+ }
44541
+ const normalizedQuery = normalizeStr(trimmedQuery);
44542
+ const exactNameMatches = clients.filter((c) => normalizeStr(c.name) === normalizedQuery);
44543
+ if (exactNameMatches.length === 1) {
44544
+ return exactNameMatches[0];
44545
+ }
44546
+ if (exactNameMatches.length > 1) {
44547
+ throw new Error(`Multiple clients matched "${trimmedQuery}": ${formatClientCandidates(exactNameMatches)}`);
44548
+ }
44549
+ if (clients.length === 1) {
44550
+ return clients[0];
44551
+ }
44552
+ const prefixMatches = clients.filter((c) => normalizeStr(c.name).startsWith(normalizedQuery));
44553
+ if (prefixMatches.length === 1) {
44554
+ return prefixMatches[0];
44555
+ }
44556
+ throw new Error(`Multiple clients matched "${trimmedQuery}": ${formatClientCandidates(clients)}`);
44557
+ }
44558
+ function printJson(value) {
44559
+ console.log(JSON.stringify(value, null, 2));
44560
+ }
44561
+ function appendQuery(params, key, value) {
44562
+ if (value === void 0 || value === null || value === "") return;
44563
+ params.set(key, String(value));
44564
+ }
44565
+ function endpointWithQuery(endpoint, params) {
44566
+ const query = params.toString();
44567
+ return query ? `${endpoint}?${query}` : endpoint;
44568
+ }
44569
+ function registerClientList(program3) {
44570
+ program3.command("client:list").description("List clients\n Example: elevasis-sdk client:list --status active").option("--status <status>", "Filter by status: active | onboarding | paused | completed | churned").option("--search <query>", "Search by client name").option("--limit <limit>", "Maximum number of clients to return").option("--offset <offset>", "Number of clients to skip").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
44571
+ wrapAction(
44572
+ "client:list",
44573
+ async (options) => {
44574
+ const apiUrl = resolveApiUrl(options.apiUrl);
44575
+ const params = new URLSearchParams();
44576
+ appendQuery(params, "status", options.status);
44577
+ appendQuery(params, "search", options.search);
44578
+ appendQuery(params, "limit", options.limit);
44579
+ appendQuery(params, "offset", options.offset);
44580
+ const result = await apiGet(endpointWithQuery("/api/external/clients", params), apiUrl);
44581
+ if (!options.pretty) {
44582
+ printJson(result);
44583
+ return;
44584
+ }
44585
+ if (result.data.length === 0) {
44586
+ console.log(source_default.yellow("No clients found."));
44587
+ return;
44588
+ }
44589
+ console.log(source_default.cyan(`
44590
+ Clients (${result.data.length} of ${result.total}):
44591
+ `));
44592
+ for (const client of result.data) {
44593
+ console.log(` ${source_default.bold(client.name)} ${source_default.gray(client.status)}`);
44594
+ console.log(source_default.gray(` ID: ${client.id}`));
44595
+ if (client.sourceDealId) console.log(source_default.gray(` Source deal: ${client.sourceDealId}`));
44596
+ }
44597
+ console.log();
44598
+ }
44599
+ )
44600
+ );
44601
+ }
44602
+ function registerClientGet(program3) {
44603
+ program3.command("client:get <id>").description("Get a client by ID\n Example: elevasis-sdk client:get <uuid>").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
44604
+ wrapAction("client:get", async (id, options) => {
44605
+ const apiUrl = resolveApiUrl(options.apiUrl);
44606
+ const result = await apiGet(`/api/external/clients/${id}`, apiUrl);
44607
+ if (!options.pretty) {
44608
+ printJson(result);
44609
+ return;
44610
+ }
44611
+ console.log(source_default.cyan(`
44612
+ Client: ${result.name}`));
44613
+ console.log(source_default.gray(` ID: ${result.id}`));
44614
+ console.log(source_default.gray(` Status: ${result.status}`));
44615
+ if (result.sourceDealId) console.log(source_default.gray(` Deal: ${result.sourceDealId}`));
44616
+ if (result.lineage) console.log(source_default.gray(" Lineage: included"));
44617
+ console.log();
44618
+ })
44619
+ );
44620
+ }
44621
+ function registerClientStatus(program3) {
44622
+ program3.command("client:status").description("Show client portfolio status").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
44623
+ wrapAction("client:status", async (options) => {
44624
+ const apiUrl = resolveApiUrl(options.apiUrl);
44625
+ const result = await apiGet("/api/external/clients/status", apiUrl);
44626
+ if (!options.pretty) {
44627
+ printJson(result);
44628
+ return;
44629
+ }
44630
+ console.log(source_default.cyan("\nClient status"));
44631
+ console.log(source_default.gray(` Total: ${result.totalClients}`));
44632
+ console.log(
44633
+ source_default.gray(
44634
+ ` Statuses: ${Object.entries(result.byStatus).map(([k, v]) => `${k}=${v}`).join(", ")}`
44635
+ )
44636
+ );
44637
+ console.log(
44638
+ source_default.gray(
44639
+ ` Links: deals=${result.linkedDeals}, projects=${result.linkedProjects}, companies=${result.linkedCompanies}, contacts=${result.linkedContacts}`
44640
+ )
44641
+ );
44642
+ console.log();
44643
+ })
44644
+ );
44645
+ }
44646
+ function registerClientResolve(program3) {
44647
+ program3.command("client:resolve <query>").description(
44648
+ 'Resolve a client ID from a name, UUID, or search query\n Example: elevasis-sdk client:resolve "Acme"'
44649
+ ).option("--api-url <url>", "API base URL").option("--pretty", "Render client details instead of only the resolved ID").action(
44650
+ wrapAction("client:resolve", async (query, options) => {
44651
+ const client = await resolveClient(query, options.apiUrl);
44652
+ if (options.pretty) {
44653
+ console.log(source_default.cyan(`
44654
+ Resolved client: ${client.name}`));
44655
+ console.log(source_default.gray(` ID: ${client.id}`));
44656
+ console.log(source_default.gray(` Status: ${client.status}`));
44657
+ console.log();
44658
+ } else {
44659
+ console.log(client.id);
44660
+ }
44661
+ })
44662
+ );
44663
+ }
44664
+
43731
44665
  // src/cli/commands/project/projects.ts
43732
44666
  function registerProjectList(program3) {
43733
- program3.command("project:list").description("List projects\n Example: elevasis-sdk project:list --search alpha").option("--kind <kind>", "Filter by kind: client_engagement | internal | research | other").option("--status <status>", "Filter by status: active | on_track | at_risk | blocked | completed | paused").option("--search <query>", "Search by project name or description").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
44667
+ program3.command("project:list").description("List projects\n Example: elevasis-sdk project:list --search alpha").option("--kind <kind>", "Filter by kind: client_engagement | internal | research | other").option("--status <status>", "Filter by status: active | on_track | at_risk | blocked | completed | paused").option("--search <query>", "Search by project name or description").option("--client <id-or-name>", "Filter by client hub record (UUID or fuzzy name)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
43734
44668
  wrapAction(
43735
44669
  "project:list",
43736
44670
  async (options) => {
43737
44671
  const apiUrl = resolveApiUrl(options.apiUrl);
44672
+ let clientId;
44673
+ if (options.client) {
44674
+ const resolved = await resolveClient(options.client, options.apiUrl);
44675
+ clientId = resolved.id;
44676
+ }
43738
44677
  const params = new URLSearchParams();
43739
44678
  if (options.kind) params.set("kind", options.kind);
43740
44679
  if (options.status) params.set("status", options.status);
43741
44680
  if (options.search) params.set("search", options.search);
44681
+ if (clientId) params.set("client_id", clientId);
43742
44682
  const qs = params.toString();
43743
44683
  const endpoint = `/api/external/projects${qs ? `?${qs}` : ""}`;
43744
44684
  const result = await apiGet(endpoint, apiUrl);
@@ -43827,11 +44767,16 @@ Project: ${p.name}`));
43827
44767
  );
43828
44768
  }
43829
44769
  function registerProjectCreate(program3) {
43830
- program3.command("project:create").description('Create a new project\n Example: elevasis-sdk project:create --name "My Project" --kind internal').requiredOption("--name <name>", "Project name").requiredOption("--kind <kind>", "Project kind: client_engagement | internal | research | other").option("--status <status>", "Project status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "Project description").option("--deal-id <uuid>", "Link to a deal (UUID)").option("--client-company-id <uuid>", "Link to a client company (UUID)").option("--start-date <date>", "Start date (ISO 8601, e.g. 2026-06-01)").option("--target-end-date <date>", "Target end date (ISO 8601, e.g. 2026-12-31)").option("--contract-value <amount>", "Contract value (number)", parseFloat).option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
44770
+ program3.command("project:create").description('Create a new project\n Example: elevasis-sdk project:create --name "My Project" --kind internal').requiredOption("--name <name>", "Project name").requiredOption("--kind <kind>", "Project kind: client_engagement | internal | research | other").option("--status <status>", "Project status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "Project description").option("--deal-id <uuid>", "Link to a deal (UUID)").option("--client <id-or-name>", "Link to a client hub record (UUID or fuzzy name)").option("--client-company-id <uuid>", "Link to a client company (UUID)").option("--start-date <date>", "Start date (ISO 8601, e.g. 2026-06-01)").option("--target-end-date <date>", "Target end date (ISO 8601, e.g. 2026-12-31)").option("--contract-value <amount>", "Contract value (number)", parseFloat).option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
43831
44771
  wrapAction(
43832
44772
  "project:create",
43833
44773
  async (options) => {
43834
44774
  const apiUrl = resolveApiUrl(options.apiUrl);
44775
+ let clientId;
44776
+ if (options.client) {
44777
+ const resolved = await resolveClient(options.client, options.apiUrl);
44778
+ clientId = resolved.id;
44779
+ }
43835
44780
  const body = {
43836
44781
  name: options.name,
43837
44782
  kind: options.kind
@@ -43839,6 +44784,7 @@ function registerProjectCreate(program3) {
43839
44784
  if (options.status) body.status = options.status;
43840
44785
  if (options.description) body.description = options.description;
43841
44786
  if (options.dealId) body.deal_id = options.dealId;
44787
+ if (clientId) body.client_id = clientId;
43842
44788
  if (options.clientCompanyId) body.client_company_id = options.clientCompanyId;
43843
44789
  if (options.startDate) body.start_date = options.startDate;
43844
44790
  if (options.targetEndDate) body.target_end_date = options.targetEndDate;
@@ -43861,15 +44807,32 @@ Project created: ${p.name}`));
43861
44807
  );
43862
44808
  }
43863
44809
  function registerProjectUpdate(program3) {
43864
- program3.command("project:update <id>").description("Update a project\n Example: elevasis-sdk project:update <uuid> --status completed").option("--name <name>", "New project name").option("--status <status>", "New status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "New description").option("--deal-id <uuid>", "Link to a deal (UUID)").option("--client-company-id <uuid>", "Link to a client company (UUID)").option("--start-date <date>", "Start date (ISO 8601, e.g. 2026-06-01)").option("--target-end-date <date>", "Target end date (ISO 8601, e.g. 2026-12-31)").option("--actual-end-date <date>", "Actual end date (ISO 8601)").option("--contract-value <amount>", "Contract value (number)", parseFloat).option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
44810
+ program3.command("project:update <id>").description("Update a project\n Example: elevasis-sdk project:update <uuid> --status completed").option("--name <name>", "New project name").option("--status <status>", "New status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "New description").option("--deal-id <uuid>", "Link to a deal (UUID)").option("--client <id-or-name>", "Link to a client hub record (UUID or fuzzy name)").option("--clear-client", "Remove the client hub link (sets client_id to null)").option("--client-company-id <uuid>", "Link to a client company (UUID)").option("--start-date <date>", "Start date (ISO 8601, e.g. 2026-06-01)").option("--target-end-date <date>", "Target end date (ISO 8601, e.g. 2026-12-31)").option("--actual-end-date <date>", "Actual end date (ISO 8601)").option("--contract-value <amount>", "Contract value (number)", parseFloat).option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
43865
44811
  wrapAction(
43866
44812
  "project:update",
43867
44813
  async (id, options) => {
44814
+ if (options.client && options.clearClient) {
44815
+ process.stderr.write(
44816
+ JSON.stringify({
44817
+ error: "--client and --clear-client are mutually exclusive",
44818
+ code: "CONFLICTING_FLAGS"
44819
+ }) + "\n"
44820
+ );
44821
+ process.exit(1);
44822
+ }
44823
+ let clientId;
44824
+ if (options.clearClient) {
44825
+ clientId = null;
44826
+ } else if (options.client) {
44827
+ const resolved = await resolveClient(options.client, options.apiUrl);
44828
+ clientId = resolved.id;
44829
+ }
43868
44830
  const body = {};
43869
44831
  if (options.name !== void 0) body.name = options.name;
43870
44832
  if (options.status !== void 0) body.status = options.status;
43871
44833
  if (options.description !== void 0) body.description = options.description;
43872
44834
  if (options.dealId !== void 0) body.deal_id = options.dealId;
44835
+ if (clientId !== void 0) body.client_id = clientId;
43873
44836
  if (options.clientCompanyId !== void 0) body.client_company_id = options.clientCompanyId;
43874
44837
  if (options.startDate !== void 0) body.start_date = options.startDate;
43875
44838
  if (options.targetEndDate !== void 0) body.target_end_date = options.targetEndDate;
@@ -43879,7 +44842,7 @@ function registerProjectUpdate(program3) {
43879
44842
  if (Object.keys(body).length === 0) {
43880
44843
  process.stderr.write(
43881
44844
  JSON.stringify({
43882
- error: "At least one field must be provided (--name, --status, --description, --deal-id, --client-company-id, --start-date, --target-end-date, --actual-end-date, --contract-value, --metadata)",
44845
+ error: "At least one field must be provided (--name, --status, --description, --deal-id, --client, --clear-client, --client-company-id, --start-date, --target-end-date, --actual-end-date, --contract-value, --metadata)",
43883
44846
  code: "MISSING_FIELDS"
43884
44847
  }) + "\n"
43885
44848
  );
@@ -44354,6 +45317,7 @@ var CreateProjectRequestSchema = external_exports.object({
44354
45317
  status: ProjectStatusSchema.optional(),
44355
45318
  description: external_exports.string().nullable().optional(),
44356
45319
  deal_id: UuidSchema.nullable().optional(),
45320
+ client_id: UuidSchema.nullable().optional(),
44357
45321
  client_company_id: UuidSchema.nullable().optional(),
44358
45322
  start_date: external_exports.string().nullable().optional(),
44359
45323
  target_end_date: external_exports.string().nullable().optional(),
@@ -44366,6 +45330,7 @@ var UpdateProjectRequestSchema = external_exports.object({
44366
45330
  status: ProjectStatusSchema.optional(),
44367
45331
  description: external_exports.string().nullable().optional(),
44368
45332
  deal_id: UuidSchema.nullable().optional(),
45333
+ client_id: UuidSchema.nullable().optional(),
44369
45334
  client_company_id: UuidSchema.nullable().optional(),
44370
45335
  start_date: external_exports.string().nullable().optional(),
44371
45336
  target_end_date: external_exports.string().nullable().optional(),
@@ -44376,9 +45341,24 @@ var UpdateProjectRequestSchema = external_exports.object({
44376
45341
  var GetProjectsQuerySchema = external_exports.object({
44377
45342
  kind: ProjectKindSchema.optional(),
44378
45343
  status: ProjectStatusSchema.optional(),
44379
- search: external_exports.string().trim().min(1).max(255).optional()
45344
+ search: external_exports.string().trim().min(1).max(255).optional(),
45345
+ client_id: UuidSchema.optional()
44380
45346
  }).strict();
44381
45347
  var ProjectIdParamsSchema = external_exports.object({ id: UuidSchema });
45348
+ var ProjectSourceDealRefSchema = external_exports.object({
45349
+ id: external_exports.string(),
45350
+ clientId: external_exports.string().nullable().optional(),
45351
+ contactEmail: external_exports.string(),
45352
+ stageKey: external_exports.string().nullable(),
45353
+ stateKey: external_exports.string().nullable(),
45354
+ sourceListId: external_exports.string().nullable(),
45355
+ updatedAt: external_exports.string()
45356
+ });
45357
+ var ProjectClientRefSchema = external_exports.object({
45358
+ id: external_exports.string(),
45359
+ name: external_exports.string(),
45360
+ status: external_exports.string()
45361
+ });
44382
45362
  var CreateMilestoneRequestSchema = external_exports.object({
44383
45363
  name: external_exports.string().trim().min(1).max(255),
44384
45364
  status: MilestoneStatusSchema.optional(),
@@ -45040,6 +46020,132 @@ function optionalStringArray(frontmatter, key, filePath) {
45040
46020
  }
45041
46021
  return value.map((entry) => entry.trim()).filter(Boolean);
45042
46022
  }
46023
+ var ROUTING_STOPWORDS = /* @__PURE__ */ new Set([
46024
+ "about",
46025
+ "after",
46026
+ "again",
46027
+ "against",
46028
+ "all",
46029
+ "also",
46030
+ "and",
46031
+ "any",
46032
+ "are",
46033
+ "before",
46034
+ "but",
46035
+ "can",
46036
+ "cannot",
46037
+ "could",
46038
+ "for",
46039
+ "from",
46040
+ "has",
46041
+ "have",
46042
+ "how",
46043
+ "into",
46044
+ "its",
46045
+ "may",
46046
+ "more",
46047
+ "must",
46048
+ "not",
46049
+ "now",
46050
+ "off",
46051
+ "one",
46052
+ "only",
46053
+ "our",
46054
+ "out",
46055
+ "over",
46056
+ "per",
46057
+ "run",
46058
+ "same",
46059
+ "should",
46060
+ "than",
46061
+ "that",
46062
+ "the",
46063
+ "their",
46064
+ "then",
46065
+ "there",
46066
+ "this",
46067
+ "through",
46068
+ "use",
46069
+ "uses",
46070
+ "using",
46071
+ "when",
46072
+ "where",
46073
+ "with",
46074
+ "workflow",
46075
+ "workflows",
46076
+ "would",
46077
+ "you",
46078
+ "your"
46079
+ ]);
46080
+ function toRegistryPath(path3) {
46081
+ return path3.replace(/\\/g, "/");
46082
+ }
46083
+ function slugify(value) {
46084
+ return value.trim().toLowerCase().replace(/['"]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
46085
+ }
46086
+ function toTitle(value) {
46087
+ return value.split(/[-:\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
46088
+ }
46089
+ function tokenizeRoutingText(...values) {
46090
+ return values.join(" ").toLowerCase().replace(/```[\s\S]*?```/g, " ").replace(/[\\/]/g, " ").match(/[a-z0-9]+(?:[.-][a-z0-9]+)*/g)?.flatMap((token) => {
46091
+ const expanded = token.includes(".") ? [token, ...token.split(".")] : [token];
46092
+ return expanded.flatMap((entry) => entry.includes("-") ? [entry, ...entry.split("-")] : [entry]);
46093
+ }) ?? [];
46094
+ }
46095
+ function rankedTerms(values, limit) {
46096
+ const counts = /* @__PURE__ */ new Map();
46097
+ for (const value of values) {
46098
+ const token = slugify(value);
46099
+ if (!token || ROUTING_STOPWORDS.has(token)) continue;
46100
+ if (token.length < 3 && token !== "ai") continue;
46101
+ counts.set(token, (counts.get(token) ?? 0) + 1);
46102
+ }
46103
+ return [...counts.entries()].sort(([termA, countA], [termB, countB]) => countB - countA || termA.localeCompare(termB)).slice(0, limit).map(([term]) => term);
46104
+ }
46105
+ function uniqueSorted(values) {
46106
+ return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b));
46107
+ }
46108
+ function nodeRoutingTerms(node, sourcePath, limit) {
46109
+ return rankedTerms(
46110
+ tokenizeRoutingText(
46111
+ node.id,
46112
+ node.kind,
46113
+ node.title,
46114
+ node.summary,
46115
+ node.body,
46116
+ node.domain ?? "",
46117
+ sourcePath,
46118
+ ...node.links.map((link) => link.nodeId),
46119
+ ...node.skills
46120
+ ),
46121
+ limit
46122
+ );
46123
+ }
46124
+ function nodeTags(node, sourcePath) {
46125
+ return uniqueSorted([
46126
+ ...node.domain ? [node.domain] : [],
46127
+ node.kind,
46128
+ ...tokenizeRoutingText(
46129
+ node.title,
46130
+ node.summary,
46131
+ sourcePath,
46132
+ ...node.links.map((link) => link.nodeId),
46133
+ ...node.skills
46134
+ ).map(slugify).filter((term) => term && !ROUTING_STOPWORDS.has(term) && (term.length >= 3 || term === "ai")).slice(0, 20)
46135
+ ]);
46136
+ }
46137
+ function readCommandForNode(node) {
46138
+ return [
46139
+ {
46140
+ command: `pnpm exec elevasis knowledge:cat ${node.id}`,
46141
+ description: `Read ${node.title}`
46142
+ },
46143
+ {
46144
+ command: `pnpm exec elevasis knowledge:ls /by-kind/${node.kind}`,
46145
+ description: `List ${node.kind} knowledge nodes`
46146
+ }
46147
+ ];
46148
+ }
45043
46149
  function readKnowledgeNodeMdx(filePath) {
45044
46150
  const raw = (0, import_node_fs2.readFileSync)(filePath, "utf8");
45045
46151
  const { frontmatter, body } = parseFrontmatter(raw, filePath);
@@ -45080,6 +46186,79 @@ function generateGraphSkillsRegistry(nodes) {
45080
46186
  domains: Object.fromEntries(Object.entries(domains).sort(([a], [b]) => a.localeCompare(b)))
45081
46187
  };
45082
46188
  }
46189
+ function generateKnowledgeFlagRegistry(nodes, sourcePaths = {}) {
46190
+ const routes = /* @__PURE__ */ new Map();
46191
+ for (const node of nodes) {
46192
+ const routeKey = node.domain ?? `kind-${node.kind}`;
46193
+ const flag = `--${slugify(routeKey)}`;
46194
+ const sourcePath = toRegistryPath(sourcePaths[node.id] ?? "");
46195
+ const routingTerms = nodeRoutingTerms(node, sourcePath, 24);
46196
+ const tags = nodeTags(node, sourcePath);
46197
+ const skills = uniqueSorted(node.skills);
46198
+ const cliBindings = readCommandForNode(node);
46199
+ const route = routes.get(flag) ?? {
46200
+ flag,
46201
+ label: toTitle(routeKey),
46202
+ ...node.domain ? { domain: node.domain } : { kind: node.kind },
46203
+ tags: [],
46204
+ queryTerms: [],
46205
+ skills: [],
46206
+ cliBindings: [],
46207
+ nodes: []
46208
+ };
46209
+ route.tags = uniqueSorted([...route.tags, ...tags]);
46210
+ route.queryTerms = rankedTerms([...route.queryTerms, ...routingTerms], 40);
46211
+ route.skills = uniqueSorted([...route.skills, ...skills]);
46212
+ route.cliBindings = [...route.cliBindings, ...cliBindings].filter(
46213
+ (binding, index, bindings) => bindings.findIndex((candidate) => candidate.command === binding.command) === index
46214
+ );
46215
+ route.nodes.push({
46216
+ id: node.id,
46217
+ title: node.title,
46218
+ kind: node.kind,
46219
+ ...node.domain ? { domain: node.domain } : {},
46220
+ sourcePath,
46221
+ tags,
46222
+ routingTerms,
46223
+ links: node.links.map((link) => link.nodeId),
46224
+ skills,
46225
+ cliBindings
46226
+ });
46227
+ routes.set(flag, route);
46228
+ }
46229
+ const sortedRoutes = [...routes.values()].sort((a, b) => a.flag.localeCompare(b.flag));
46230
+ const aliasCandidates = sortedRoutes.flatMap((route) => {
46231
+ const aliasTerms = uniqueSorted([
46232
+ route.flag.replace(/^--/, ""),
46233
+ route.label.toLowerCase(),
46234
+ ...route.tags.slice(0, 12),
46235
+ ...route.queryTerms.slice(0, 12)
46236
+ ]);
46237
+ return aliasTerms.map((alias) => [alias, route.flag]);
46238
+ });
46239
+ const aliasCounts = aliasCandidates.reduce((counts, [alias]) => {
46240
+ counts.set(alias, (counts.get(alias) ?? 0) + 1);
46241
+ return counts;
46242
+ }, /* @__PURE__ */ new Map());
46243
+ const aliases = Object.fromEntries(
46244
+ aliasCandidates.filter(([alias]) => aliasCounts.get(alias) === 1).sort(([aliasA], [aliasB]) => aliasA.localeCompare(aliasB))
46245
+ );
46246
+ return {
46247
+ generatedBy: "generate-knowledge-nodes",
46248
+ routingMode: "deterministic-keyword",
46249
+ flags: Object.fromEntries(
46250
+ sortedRoutes.map((route) => [
46251
+ route.flag,
46252
+ {
46253
+ ...route,
46254
+ cliBindings: route.cliBindings.sort((a, b) => a.command.localeCompare(b.command)),
46255
+ nodes: route.nodes.sort((a, b) => a.id.localeCompare(b.id))
46256
+ }
46257
+ ])
46258
+ ),
46259
+ aliases
46260
+ };
46261
+ }
45083
46262
  function generateKnowledgeNodesTs(options) {
45084
46263
  const exportedName = options.exportedName ?? "mdxKnowledgeNodes";
45085
46264
  const typeImport = options.typeImportPath ? [`import type { OrgKnowledgeNode } from '${options.typeImportPath}'`, ""] : [];
@@ -45099,6 +46278,9 @@ function generateKnowledgeNodes(options) {
45099
46278
  (a, b) => (0, import_node_path2.relative)(options.sourceDir, a).localeCompare((0, import_node_path2.relative)(options.sourceDir, b))
45100
46279
  );
45101
46280
  const nodes = files.map(readKnowledgeNodeMdx);
46281
+ const sourcePaths = Object.fromEntries(
46282
+ files.map((file2, index) => [nodes[index].id, toRegistryPath((0, import_node_path2.relative)(options.sourceDir, file2))])
46283
+ );
45102
46284
  const ids = /* @__PURE__ */ new Set();
45103
46285
  for (const node of nodes) {
45104
46286
  if (ids.has(node.id)) throw new Error(`[knowledge-node-codegen] Duplicate knowledge node id: ${node.id}`);
@@ -45120,6 +46302,15 @@ function generateKnowledgeNodes(options) {
45120
46302
  (0, import_node_fs2.writeFileSync)(
45121
46303
  options.graphSkillsOutputPath,
45122
46304
  `${JSON.stringify(generateGraphSkillsRegistry(nodes), null, 2)}
46305
+ `,
46306
+ "utf8"
46307
+ );
46308
+ }
46309
+ if (options.knowledgeFlagsOutputPath) {
46310
+ (0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(options.knowledgeFlagsOutputPath), { recursive: true });
46311
+ (0, import_node_fs2.writeFileSync)(
46312
+ options.knowledgeFlagsOutputPath,
46313
+ `${JSON.stringify(generateKnowledgeFlagRegistry(nodes, sourcePaths), null, 2)}
45123
46314
  `,
45124
46315
  "utf8"
45125
46316
  );
@@ -45131,7 +46322,19 @@ function generateKnowledgeNodes(options) {
45131
46322
  function registerKnowledgeGenerate(program3) {
45132
46323
  program3.command("knowledge:generate").description(
45133
46324
  "Generate OrganizationModel knowledge nodes from MDX source files\n Example: elevasis-sdk knowledge:generate"
45134
- ).option("--source <path>", "MDX source directory relative to project root", "core/config/knowledge/nodes").option("--output <path>", "Generated TS file relative to project root", "core/config/knowledge/_generated/nodes.ts").option("--skills-output <path>", "Generated graph skill registry relative to project root", ".claude/registries/graph-skills.json").action(
46325
+ ).option("--source <path>", "MDX source directory relative to project root", "core/config/knowledge/nodes").option(
46326
+ "--output <path>",
46327
+ "Generated TS file relative to project root",
46328
+ "core/config/knowledge/_generated/nodes.ts"
46329
+ ).option(
46330
+ "--skills-output <path>",
46331
+ "Generated graph skill registry relative to project root",
46332
+ ".claude/registries/graph-skills.json"
46333
+ ).option(
46334
+ "--flags-output <path>",
46335
+ "Generated knowledge flag registry relative to project root",
46336
+ ".claude/registries/knowledge-flags.json"
46337
+ ).action(
45135
46338
  wrapAction("knowledge:generate", async (options) => {
45136
46339
  const projectRoot = getProjectRoot();
45137
46340
  const sourceDir = (0, import_node_path3.resolve)(projectRoot, options.source ?? "core/config/knowledge/nodes");
@@ -45140,6 +46343,10 @@ function registerKnowledgeGenerate(program3) {
45140
46343
  projectRoot,
45141
46344
  options.skillsOutput ?? ".claude/registries/graph-skills.json"
45142
46345
  );
46346
+ const knowledgeFlagsOutputPath = (0, import_node_path3.resolve)(
46347
+ projectRoot,
46348
+ options.flagsOutput ?? ".claude/registries/knowledge-flags.json"
46349
+ );
45143
46350
  if (!(0, import_node_fs3.existsSync)(sourceDir)) {
45144
46351
  process.stderr.write(`knowledge:generate: source directory not found: ${sourceDir}
45145
46352
  `);
@@ -45150,11 +46357,14 @@ function registerKnowledgeGenerate(program3) {
45150
46357
  sourceDir,
45151
46358
  outputPath,
45152
46359
  graphSkillsOutputPath,
46360
+ knowledgeFlagsOutputPath,
45153
46361
  sourceLabel: options.source ?? "core/config/knowledge/nodes"
45154
46362
  });
45155
46363
  process.stdout.write(`Generated ${result.nodes.length} knowledge node(s): ${result.outputPath}
45156
46364
  `);
45157
46365
  process.stdout.write(`Generated graph skill registry: ${graphSkillsOutputPath}
46366
+ `);
46367
+ process.stdout.write(`Generated knowledge flag registry: ${knowledgeFlagsOutputPath}
45158
46368
  `);
45159
46369
  })
45160
46370
  );
@@ -45538,12 +46748,631 @@ function printSummary(failCount) {
45538
46748
  }
45539
46749
  }
45540
46750
 
46751
+ // src/cli/commands/cli/catalog.ts
46752
+ function buildCliCatalogFromProgram(program3, options = {}) {
46753
+ const commands = program3.commands.flatMap((command) => collectRuntimeCommands(command));
46754
+ return groupCommands(commands, "registered Commander commands", options.domain);
46755
+ }
46756
+ function groupCommands(commands, sourceRoot, domain2) {
46757
+ const filtered = domain2 ? commands.filter((command) => command.domain === domain2) : commands;
46758
+ const sorted = filtered.sort((a, b) => a.domain.localeCompare(b.domain) || a.syntax.localeCompare(b.syntax));
46759
+ const domainNames = [...new Set(sorted.map((command) => command.domain))];
46760
+ return {
46761
+ sourceRoot,
46762
+ domains: domainNames.map((name) => ({
46763
+ name,
46764
+ commands: sorted.filter((command) => command.domain === name)
46765
+ }))
46766
+ };
46767
+ }
46768
+ function collectRuntimeCommands(command, parent) {
46769
+ const commandName = command.name();
46770
+ const argSuffix = formatRuntimeArguments(command.registeredArguments);
46771
+ const syntaxSegment = argSuffix ? `${commandName} ${argSuffix}` : commandName;
46772
+ const syntax = parent ? `${parent.syntax} ${syntaxSegment}` : syntaxSegment;
46773
+ const domain2 = parent?.domain ?? domainFromCommand(commandName);
46774
+ const current = {
46775
+ command: commandName,
46776
+ syntax,
46777
+ domain: domain2
46778
+ };
46779
+ const aliases = command.aliases().map((alias) => parent ? `${parent.syntax} ${alias}` : alias);
46780
+ return [
46781
+ {
46782
+ syntax,
46783
+ command: commandName,
46784
+ domain: domain2,
46785
+ description: firstLine(command.description()),
46786
+ aliases,
46787
+ options: command.options.map((option) => ({
46788
+ flags: option.flags,
46789
+ description: option.description,
46790
+ required: option.mandatory
46791
+ })),
46792
+ source: "runtime"
46793
+ },
46794
+ ...command.commands.flatMap((child) => collectRuntimeCommands(child, current))
46795
+ ];
46796
+ }
46797
+ function formatRuntimeArguments(args) {
46798
+ return args.map((arg) => {
46799
+ const name = `${arg.name()}${arg.variadic ? "..." : ""}`;
46800
+ return arg.required ? `<${name}>` : `[${name}]`;
46801
+ }).join(" ");
46802
+ }
46803
+ function renderCliCatalogMarkdown(catalog) {
46804
+ const lines = [
46805
+ "# elevasis-sdk CLI Catalog",
46806
+ "",
46807
+ `Source: \`${catalog.sourceRoot}\``,
46808
+ ""
46809
+ ];
46810
+ if (catalog.domains.length === 0) {
46811
+ lines.push("No commands found.");
46812
+ return lines.join("\n");
46813
+ }
46814
+ for (const domain2 of catalog.domains) {
46815
+ lines.push(`## ${domain2.name}`, "");
46816
+ lines.push("| Command | Description | Aliases | Options | Source |");
46817
+ lines.push("| --- | --- | --- | --- | --- |");
46818
+ for (const command of domain2.commands) {
46819
+ const aliases = command.aliases.length > 0 ? command.aliases.map((alias) => `\`${alias}\``).join(", ") : "-";
46820
+ const options = command.options.length > 0 ? command.options.map((option) => `${option.required ? "required " : ""}\`${option.flags}\``).join("<br>") : "-";
46821
+ lines.push(
46822
+ `| \`elevasis-sdk ${command.syntax}\` | ${escapeMarkdownTable(command.description || "-")} | ${aliases} | ${options} | \`${command.source}\` |`
46823
+ );
46824
+ }
46825
+ lines.push("");
46826
+ }
46827
+ return lines.join("\n").trimEnd();
46828
+ }
46829
+ function renderCliCatalogJson(catalog) {
46830
+ return JSON.stringify(catalog, null, 2);
46831
+ }
46832
+ function domainFromCommand(command) {
46833
+ if (command.includes(":")) return command.split(":")[0];
46834
+ return "platform";
46835
+ }
46836
+ function firstLine(value) {
46837
+ return value.split("\n")[0]?.trim() ?? "";
46838
+ }
46839
+ function escapeMarkdownTable(value) {
46840
+ return value.replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
46841
+ }
46842
+ function knownDomains(catalog) {
46843
+ return catalog.domains.map((domain2) => domain2.name);
46844
+ }
46845
+
46846
+ // src/cli/commands/cli/cli.ts
46847
+ var FORMATS = /* @__PURE__ */ new Set(["markdown", "json"]);
46848
+ function registerCliCatalogCommand(program3) {
46849
+ program3.command("cli [domain]").description("Generate a catalog of registered elevasis-sdk commands").option("--domain <domain>", "Filter to one domain, e.g. project, knowledge, platform").option("--format <format>", "Output format: markdown | json", "markdown").action(
46850
+ wrapAction("cli", async (domainArg, options) => {
46851
+ const format = options.format ?? "markdown";
46852
+ if (!FORMATS.has(format)) {
46853
+ throw new Error(`Unsupported format "${format}". Expected markdown or json.`);
46854
+ }
46855
+ const domain2 = options.domain ?? domainArg;
46856
+ const catalog = buildCliCatalogFromProgram(program3, { domain: domain2 });
46857
+ if (domain2 && catalog.domains.length === 0) {
46858
+ const fullCatalog = buildCliCatalogFromProgram(program3);
46859
+ throw new Error(`No CLI domain "${domain2}" found. Known domains: ${knownDomains(fullCatalog).join(", ")}`);
46860
+ }
46861
+ console.log(format === "json" ? renderCliCatalogJson(catalog) : renderCliCatalogMarkdown(catalog));
46862
+ })
46863
+ );
46864
+ }
46865
+
46866
+ // src/cli/commands/acquisition/deals.ts
46867
+ function appendQuery2(params, key, value) {
46868
+ if (value === void 0 || value === null || value === "") return;
46869
+ params.set(key, String(value));
46870
+ }
46871
+ function endpointWithQuery2(endpoint, params) {
46872
+ const query = params.toString();
46873
+ return query ? `${endpoint}?${query}` : endpoint;
46874
+ }
46875
+ function printJson2(value) {
46876
+ console.log(JSON.stringify(value, null, 2));
46877
+ }
46878
+ function dealEmail(deal) {
46879
+ return deal.contactEmail ?? deal.contact_email ?? "unknown contact";
46880
+ }
46881
+ function dealStage(deal) {
46882
+ return deal.stageKey ?? deal.stage_key ?? "unknown";
46883
+ }
46884
+ function dealState(deal) {
46885
+ return deal.stateKey ?? deal.state_key ?? null;
46886
+ }
46887
+ function dealListId(deal) {
46888
+ return deal.sourceListId ?? deal.source_list_id ?? null;
46889
+ }
46890
+ function registerAcquisitionDealList(program3) {
46891
+ program3.command("acquisition:deal:list").description("List acquisition deals\n Example: elevasis-sdk acquisition:deal:list --stage discovery").option("--stage <stage>", "Filter by CRM stage").option("--list <id>", "Filter by source acquisition list ID").option("--batch <batch>", "Filter by source batch ID").option("--stale-since <datetime>", "Filter to deals stale since an ISO datetime").option("--search <query>", "Search by contact, company, or deal label").option("--limit <limit>", "Maximum number of deals to return").option("--offset <offset>", "Number of deals to skip").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
46892
+ wrapAction(
46893
+ "acquisition:deal:list",
46894
+ async (options) => {
46895
+ const apiUrl = resolveApiUrl(options.apiUrl);
46896
+ const params = new URLSearchParams();
46897
+ appendQuery2(params, "stage", options.stage);
46898
+ appendQuery2(params, "list", options.list);
46899
+ appendQuery2(params, "batch", options.batch);
46900
+ appendQuery2(params, "staleSince", options.staleSince);
46901
+ appendQuery2(params, "search", options.search);
46902
+ appendQuery2(params, "limit", options.limit);
46903
+ appendQuery2(params, "offset", options.offset);
46904
+ const result = await apiGet(endpointWithQuery2("/api/external/deals", params), apiUrl);
46905
+ if (!options.pretty) {
46906
+ printJson2(result);
46907
+ return;
46908
+ }
46909
+ if (result.data.length === 0) {
46910
+ console.log(source_default.yellow("No acquisition deals found."));
46911
+ return;
46912
+ }
46913
+ console.log(source_default.cyan(`
46914
+ Acquisition deals (${result.data.length} of ${result.total}):
46915
+ `));
46916
+ for (const deal of result.data) {
46917
+ const state = dealState(deal);
46918
+ console.log(` ${source_default.bold(dealEmail(deal))} ${source_default.gray(dealStage(deal))}${state ? `/${state}` : ""}`);
46919
+ console.log(source_default.gray(` ID: ${deal.id}`));
46920
+ const listId = dealListId(deal);
46921
+ if (listId) console.log(source_default.gray(` List: ${listId}`));
46922
+ }
46923
+ console.log();
46924
+ }
46925
+ )
46926
+ );
46927
+ }
46928
+ function registerAcquisitionDealGet(program3) {
46929
+ program3.command("acquisition:deal:get <id>").description("Get an acquisition deal by ID\n Example: elevasis-sdk acquisition:deal:get <uuid>").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
46930
+ wrapAction("acquisition:deal:get", async (id, options) => {
46931
+ const apiUrl = resolveApiUrl(options.apiUrl);
46932
+ const result = await apiGet("/api/external/deals/" + id, apiUrl);
46933
+ if (!options.pretty) {
46934
+ printJson2(result);
46935
+ return;
46936
+ }
46937
+ console.log(source_default.cyan(`
46938
+ Acquisition deal: ${dealEmail(result)}`));
46939
+ console.log(source_default.gray(` ID: ${result.id}`));
46940
+ console.log(source_default.gray(` Stage: ${dealStage(result)}`));
46941
+ const state = dealState(result);
46942
+ if (state) console.log(source_default.gray(` State: ${state}`));
46943
+ const listId = dealListId(result);
46944
+ if (listId) console.log(source_default.gray(` List: ${listId}`));
46945
+ if (result.lineage) console.log(source_default.gray(" Lineage: included"));
46946
+ console.log();
46947
+ })
46948
+ );
46949
+ }
46950
+ function registerAcquisitionDealStatus(program3) {
46951
+ program3.command("acquisition:deal:status").description("Show CRM funnel status for acquisition deals").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
46952
+ wrapAction("acquisition:deal:status", async (options) => {
46953
+ const apiUrl = resolveApiUrl(options.apiUrl);
46954
+ const result = await apiGet("/api/external/deals/summary", apiUrl);
46955
+ if (!options.pretty) {
46956
+ printJson2(result);
46957
+ return;
46958
+ }
46959
+ console.log(source_default.cyan("\nAcquisition deal status"));
46960
+ console.log(source_default.gray(` Total: ${result.totalDeals}`));
46961
+ console.log(source_default.gray(` Open: ${result.openDeals}`));
46962
+ console.log(source_default.gray(` Won: ${result.wonDeals}`));
46963
+ console.log(source_default.gray(` Lost: ${result.lostDeals}`));
46964
+ console.log(source_default.gray(` Win rate: ${result.winRate}`));
46965
+ if (result.stageSummary.length > 0) {
46966
+ console.log(
46967
+ source_default.gray(` Stages: ${result.stageSummary.map((stage) => `${stage.stage}=${stage.count}`).join(", ")}`)
46968
+ );
46969
+ }
46970
+ console.log();
46971
+ })
46972
+ );
46973
+ }
46974
+
46975
+ // src/cli/commands/acquisition/lists.ts
46976
+ function appendQuery3(params, key, value) {
46977
+ if (value === void 0 || value === null || value === "") return;
46978
+ params.set(key, String(value));
46979
+ }
46980
+ function endpointWithQuery3(endpoint, params) {
46981
+ const query = params.toString();
46982
+ return query ? `${endpoint}?${query}` : endpoint;
46983
+ }
46984
+ function printJson3(value) {
46985
+ console.log(JSON.stringify(value, null, 2));
46986
+ }
46987
+ function renderListSummary(list) {
46988
+ const batches = list.batchIds?.length ? `${list.batchIds.length} batch(es)` : "no batches";
46989
+ const vertical = typeof list.scrapingConfig?.vertical === "string" ? ` ${list.scrapingConfig.vertical}` : "";
46990
+ console.log(` ${source_default.bold(list.name)} ${source_default.gray(list.status ?? "unknown")}${vertical}`);
46991
+ console.log(source_default.gray(` ID: ${list.id}`));
46992
+ console.log(source_default.gray(` ${batches}`));
46993
+ if (list.description) console.log(source_default.gray(` ${list.description}`));
46994
+ }
46995
+ function registerAcquisitionListList(program3) {
46996
+ program3.command("acquisition:list:list").description("List acquisition lists\n Example: elevasis-sdk acquisition:list:list --status launched").option("--status <status>", "Filter by status: draft | enriching | launched | closing | archived").option("--batch <batch>", "Filter by batch ID").option("--vertical <vertical>", "Filter by scraping vertical").option("--limit <limit>", "Maximum number of lists to return").option("--offset <offset>", "Number of lists to skip").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
46997
+ wrapAction(
46998
+ "acquisition:list:list",
46999
+ async (options) => {
47000
+ const apiUrl = resolveApiUrl(options.apiUrl);
47001
+ const params = new URLSearchParams();
47002
+ appendQuery3(params, "status", options.status);
47003
+ appendQuery3(params, "batch", options.batch);
47004
+ appendQuery3(params, "vertical", options.vertical);
47005
+ appendQuery3(params, "limit", options.limit);
47006
+ appendQuery3(params, "offset", options.offset);
47007
+ const result = await apiGet(
47008
+ endpointWithQuery3("/api/external/acquisition/lists", params),
47009
+ apiUrl
47010
+ );
47011
+ if (!options.pretty) {
47012
+ printJson3(result);
47013
+ return;
47014
+ }
47015
+ if (result.length === 0) {
47016
+ console.log(source_default.yellow("No acquisition lists found."));
47017
+ return;
47018
+ }
47019
+ console.log(source_default.cyan(`
47020
+ Acquisition lists (${result.length}):
47021
+ `));
47022
+ for (const list of result) renderListSummary(list);
47023
+ console.log();
47024
+ }
47025
+ )
47026
+ );
47027
+ }
47028
+ function registerAcquisitionListGet(program3) {
47029
+ program3.command("acquisition:list:get <id>").description("Get an acquisition list by ID\n Example: elevasis-sdk acquisition:list:get <uuid>").option("--no-include-deals", "Exclude thin deal lineage refs").option("--deal-limit <limit>", "Maximum number of thin deal refs to include").option("--include-progress", "Include processing progress aggregates").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
47030
+ wrapAction(
47031
+ "acquisition:list:get",
47032
+ async (id, options) => {
47033
+ const apiUrl = resolveApiUrl(options.apiUrl);
47034
+ const params = new URLSearchParams();
47035
+ if (options.includeDeals === false) appendQuery3(params, "includeDeals", false);
47036
+ appendQuery3(params, "dealLimit", options.dealLimit);
47037
+ if (options.includeProgress) appendQuery3(params, "includeProgress", true);
47038
+ const result = await apiGet(
47039
+ endpointWithQuery3(`/api/external/acquisition/lists/${id}`, params),
47040
+ apiUrl
47041
+ );
47042
+ if (!options.pretty) {
47043
+ printJson3(result);
47044
+ return;
47045
+ }
47046
+ console.log(source_default.cyan(`
47047
+ Acquisition list: ${result.name}`));
47048
+ console.log(source_default.gray(` ID: ${result.id}`));
47049
+ console.log(source_default.gray(` Status: ${result.status ?? "unknown"}`));
47050
+ if (result.description) console.log(source_default.gray(` Summary: ${result.description}`));
47051
+ if (result.batchIds?.length) console.log(source_default.gray(` Batches: ${result.batchIds.join(", ")}`));
47052
+ if (result.lineage) console.log(source_default.gray(" Lineage: included"));
47053
+ if (result.progress) console.log(source_default.gray(" Progress: included"));
47054
+ console.log();
47055
+ }
47056
+ )
47057
+ );
47058
+ }
47059
+ function registerAcquisitionListStatus(program3) {
47060
+ program3.command("acquisition:list:status").description("Show portfolio status across acquisition lists").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
47061
+ wrapAction("acquisition:list:status", async (options) => {
47062
+ const apiUrl = resolveApiUrl(options.apiUrl);
47063
+ const result = await apiGet("/api/external/acquisition/lists/status", apiUrl);
47064
+ if (!options.pretty) {
47065
+ printJson3(result);
47066
+ return;
47067
+ }
47068
+ console.log(source_default.cyan("\nAcquisition list status"));
47069
+ console.log(source_default.gray(` Lists: ${result.totalLists}`));
47070
+ console.log(source_default.gray(` Companies: ${result.totalCompanies}`));
47071
+ console.log(source_default.gray(` Contacts: ${result.totalContacts}`));
47072
+ console.log(source_default.gray(` Deals: ${result.totalDeals}`));
47073
+ const statusEntries = Object.entries(result.byStatus);
47074
+ if (statusEntries.length > 0) {
47075
+ console.log(source_default.gray(` By status: ${statusEntries.map(([key, count]) => `${key}=${count}`).join(", ")}`));
47076
+ }
47077
+ console.log();
47078
+ })
47079
+ );
47080
+ }
47081
+
47082
+ // src/cli/commands/acquisition/index.ts
47083
+ function registerAcquisitionCommands(program3) {
47084
+ registerAcquisitionListList(program3);
47085
+ registerAcquisitionListGet(program3);
47086
+ registerAcquisitionListStatus(program3);
47087
+ registerAcquisitionDealList(program3);
47088
+ registerAcquisitionDealGet(program3);
47089
+ registerAcquisitionDealStatus(program3);
47090
+ }
47091
+
47092
+ // src/cli/commands/client/client-write.ts
47093
+ function registerClientCreate(program3) {
47094
+ program3.command("client:create").description('Create a new client\n Example: elevasis-sdk client:create --name "Acme Corp"').requiredOption("--name <name>", "Client name").option("--status <status>", "Client status: active | onboarding | paused | completed | churned").option("--source-deal-id <uuid>", "UUID of the source deal").option("--primary-company-id <uuid>", "UUID of the primary company").option("--primary-contact-id <uuid>", "UUID of the primary contact").option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
47095
+ wrapAction(
47096
+ "client:create",
47097
+ async (options) => {
47098
+ const apiUrl = resolveApiUrl(options.apiUrl);
47099
+ const body = { name: options.name };
47100
+ if (options.status !== void 0) body.status = options.status;
47101
+ if (options.sourceDealId !== void 0) body.sourceDealId = options.sourceDealId;
47102
+ if (options.primaryCompanyId !== void 0) body.primaryCompanyId = options.primaryCompanyId;
47103
+ if (options.primaryContactId !== void 0) body.primaryContactId = options.primaryContactId;
47104
+ if (options.metadata !== void 0) body.metadata = JSON.parse(options.metadata);
47105
+ const result = await apiPost("/api/external/clients", body, apiUrl);
47106
+ if (options.pretty) {
47107
+ console.log(source_default.green(`
47108
+ Client created: ${result.name}`));
47109
+ console.log(source_default.gray(` ID: ${result.id}`));
47110
+ console.log(source_default.gray(` Status: ${result.status}`));
47111
+ console.log();
47112
+ } else {
47113
+ console.log(JSON.stringify(result, null, 2));
47114
+ }
47115
+ }
47116
+ )
47117
+ );
47118
+ }
47119
+ function registerClientUpdate(program3) {
47120
+ program3.command("client:update <id>").description("Update a client\n Example: elevasis-sdk client:update <uuid> --status active").option("--name <name>", "New client name").option("--status <status>", "New status: active | onboarding | paused | completed | churned").option("--source-deal-id <uuid>", "Set source deal (UUID)").option("--clear-source-deal", "Remove the source deal link (sets sourceDealId to null)").option("--primary-company-id <uuid>", "Set primary company (UUID)").option("--clear-primary-company", "Remove the primary company link (sets primaryCompanyId to null)").option("--primary-contact-id <uuid>", "Set primary contact (UUID)").option("--clear-primary-contact", "Remove the primary contact link (sets primaryContactId to null)").option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
47121
+ wrapAction(
47122
+ "client:update",
47123
+ async (id, options) => {
47124
+ if (options.sourceDealId && options.clearSourceDeal) {
47125
+ process.stderr.write(
47126
+ JSON.stringify({
47127
+ error: "--source-deal-id and --clear-source-deal are mutually exclusive",
47128
+ code: "CONFLICTING_FLAGS"
47129
+ }) + "\n"
47130
+ );
47131
+ process.exit(1);
47132
+ }
47133
+ if (options.primaryCompanyId && options.clearPrimaryCompany) {
47134
+ process.stderr.write(
47135
+ JSON.stringify({
47136
+ error: "--primary-company-id and --clear-primary-company are mutually exclusive",
47137
+ code: "CONFLICTING_FLAGS"
47138
+ }) + "\n"
47139
+ );
47140
+ process.exit(1);
47141
+ }
47142
+ if (options.primaryContactId && options.clearPrimaryContact) {
47143
+ process.stderr.write(
47144
+ JSON.stringify({
47145
+ error: "--primary-contact-id and --clear-primary-contact are mutually exclusive",
47146
+ code: "CONFLICTING_FLAGS"
47147
+ }) + "\n"
47148
+ );
47149
+ process.exit(1);
47150
+ }
47151
+ const client = await resolveClient(id, options.apiUrl);
47152
+ const body = {};
47153
+ if (options.name !== void 0) body.name = options.name;
47154
+ if (options.status !== void 0) body.status = options.status;
47155
+ if (options.clearSourceDeal) {
47156
+ body.sourceDealId = null;
47157
+ } else if (options.sourceDealId !== void 0) {
47158
+ body.sourceDealId = options.sourceDealId;
47159
+ }
47160
+ if (options.clearPrimaryCompany) {
47161
+ body.primaryCompanyId = null;
47162
+ } else if (options.primaryCompanyId !== void 0) {
47163
+ body.primaryCompanyId = options.primaryCompanyId;
47164
+ }
47165
+ if (options.clearPrimaryContact) {
47166
+ body.primaryContactId = null;
47167
+ } else if (options.primaryContactId !== void 0) {
47168
+ body.primaryContactId = options.primaryContactId;
47169
+ }
47170
+ if (options.metadata !== void 0) body.metadata = JSON.parse(options.metadata);
47171
+ if (Object.keys(body).length === 0) {
47172
+ process.stderr.write(
47173
+ JSON.stringify({
47174
+ error: "At least one field must be provided (--name, --status, --source-deal-id, --clear-source-deal, --primary-company-id, --clear-primary-company, --primary-contact-id, --clear-primary-contact, --metadata)",
47175
+ code: "MISSING_FIELDS"
47176
+ }) + "\n"
47177
+ );
47178
+ process.exit(1);
47179
+ }
47180
+ const apiUrl = resolveApiUrl(options.apiUrl);
47181
+ const result = await apiPatch(`/api/external/clients/${client.id}`, body, apiUrl);
47182
+ if (options.pretty) {
47183
+ console.log(source_default.green(`
47184
+ Client updated: ${result.name}`));
47185
+ console.log(source_default.gray(` ID: ${result.id}`));
47186
+ console.log(source_default.gray(` Status: ${result.status}`));
47187
+ console.log();
47188
+ } else {
47189
+ console.log(JSON.stringify(result, null, 2));
47190
+ }
47191
+ }
47192
+ )
47193
+ );
47194
+ }
47195
+ function registerClientDelete(program3) {
47196
+ program3.command("client:delete <id>").description("Delete a client\n Example: elevasis-sdk client:delete <uuid>").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
47197
+ wrapAction("client:delete", async (id, options) => {
47198
+ const client = await resolveClient(id, options.apiUrl);
47199
+ const apiUrl = resolveApiUrl(options.apiUrl);
47200
+ await apiDelete(`/api/external/clients/${client.id}`, apiUrl);
47201
+ if (options.pretty) {
47202
+ console.log(source_default.green(`
47203
+ Client ${client.id} deleted.`));
47204
+ console.log();
47205
+ } else {
47206
+ console.log(JSON.stringify({ success: true, id: client.id }, null, 2));
47207
+ }
47208
+ })
47209
+ );
47210
+ }
47211
+
47212
+ // src/cli/commands/client/index.ts
47213
+ function registerClientCommands(program3) {
47214
+ registerClientList(program3);
47215
+ registerClientGet(program3);
47216
+ registerClientStatus(program3);
47217
+ registerClientResolve(program3);
47218
+ registerClientCreate(program3);
47219
+ registerClientUpdate(program3);
47220
+ registerClientDelete(program3);
47221
+ }
47222
+
47223
+ // src/cli/commands/agent/agent.ts
47224
+ function printJson4(value) {
47225
+ console.log(JSON.stringify(value, null, 2));
47226
+ }
47227
+ function registerAgentList(program3) {
47228
+ program3.command("agent:list").description("List deployed agents for your organization").option("--api-url <url>", "API base URL").option("--json", "Output as JSON").action(
47229
+ wrapAction("agent:list", async (options) => {
47230
+ const apiUrl = resolveApiUrl(options.apiUrl);
47231
+ const result = await apiGet("/api/external/resources", apiUrl);
47232
+ const agents = result.resources.filter((resource) => resource.resourceType === "agent");
47233
+ if (options.json) {
47234
+ printJson4({ agents, total: agents.length });
47235
+ return;
47236
+ }
47237
+ if (agents.length === 0) {
47238
+ console.log(source_default.yellow("No deployed agents found."));
47239
+ return;
47240
+ }
47241
+ console.log(source_default.magenta(`Agents (${agents.length}):`));
47242
+ for (const agent of agents) {
47243
+ console.log(source_default.white(` ${source_default.bold(agent.resourceId)}`));
47244
+ if (agent.name) console.log(source_default.gray(` Name: ${agent.name}`));
47245
+ if (agent.description) console.log(source_default.gray(` Description: ${agent.description}`));
47246
+ if (agent.agentKind) console.log(source_default.gray(` Kind: ${agent.agentKind}`));
47247
+ if (agent.systemId) console.log(source_default.gray(` System: ${agent.systemId}`));
47248
+ if (agent.actsAsRoleId) console.log(source_default.gray(` Acts as role: ${agent.actsAsRoleId}`));
47249
+ console.log(source_default.gray(` Session capable: ${agent.sessionCapable ? "yes" : "no"}`));
47250
+ if (agent.status) console.log(source_default.gray(` Status: ${agent.status}`));
47251
+ console.log();
47252
+ }
47253
+ })
47254
+ );
47255
+ }
47256
+ function registerAgentGet(program3) {
47257
+ program3.command("agent:get <id>").description("Get full agent metadata and organization model linkage").option("--api-url <url>", "API base URL").option("--json", "Output as JSON").action(
47258
+ wrapAction("agent:get", async (id, options) => {
47259
+ const apiUrl = resolveApiUrl(options.apiUrl);
47260
+ const definition = await apiGet(`/api/external/resources/${id}/definition`, apiUrl);
47261
+ if (options.json) {
47262
+ printJson4(definition);
47263
+ return;
47264
+ }
47265
+ console.log(source_default.magenta(`Agent: ${definition.name ?? definition.resourceId ?? id}`));
47266
+ console.log(source_default.gray(` ID: ${definition.resourceId ?? id}`));
47267
+ console.log(source_default.gray(` Type: ${definition.type ?? "agent"}`));
47268
+ if (definition.description) console.log(source_default.gray(` Description: ${definition.description}`));
47269
+ if (definition.agentKind) console.log(source_default.gray(` Kind: ${definition.agentKind}`));
47270
+ if (definition.systemId) console.log(source_default.gray(` System: ${definition.systemId}`));
47271
+ if (definition.actsAsRoleId) console.log(source_default.gray(` Acts as role: ${definition.actsAsRoleId}`));
47272
+ console.log(source_default.gray(` Session capable: ${definition.sessionCapable ? "yes" : "no"}`));
47273
+ if (definition.status) console.log(source_default.gray(` Status: ${definition.status}`));
47274
+ })
47275
+ );
47276
+ }
47277
+
47278
+ // src/cli/commands/agent/index.ts
47279
+ function registerAgentCommands(program3) {
47280
+ registerAgentList(program3);
47281
+ registerAgentGet(program3);
47282
+ }
47283
+
47284
+ // src/cli/commands/session/session.ts
47285
+ function printJson5(value) {
47286
+ console.log(JSON.stringify(value, null, 2));
47287
+ }
47288
+ function appendQuery4(params, key, value) {
47289
+ if (value === void 0 || value === null || value === "") return;
47290
+ params.set(key, String(value));
47291
+ }
47292
+ function endpointWithQuery4(endpoint, params) {
47293
+ const query = params.toString();
47294
+ return query ? `${endpoint}?${query}` : endpoint;
47295
+ }
47296
+ function registerSessionList(program3) {
47297
+ program3.command("session:list").description("List active multi-turn agent sessions").option("--resource-id <id>", "Filter by agent resource ID").option("--user-id <id>", "Filter by user ID").option("--limit <limit>", "Maximum number of sessions to return").option("--api-url <url>", "API base URL").option("--json", "Output as JSON").action(
47298
+ wrapAction("session:list", async (options) => {
47299
+ const apiUrl = resolveApiUrl(options.apiUrl);
47300
+ const params = new URLSearchParams();
47301
+ appendQuery4(params, "resourceId", options.resourceId);
47302
+ appendQuery4(params, "userId", options.userId);
47303
+ appendQuery4(params, "limit", options.limit);
47304
+ const result = await apiGet(endpointWithQuery4("/api/external/sessions", params), apiUrl);
47305
+ if (options.json) {
47306
+ printJson5(result);
47307
+ return;
47308
+ }
47309
+ const activeSessions = result.sessions.filter((session) => !session.isEnded);
47310
+ if (activeSessions.length === 0) {
47311
+ console.log(source_default.yellow("No active sessions found."));
47312
+ return;
47313
+ }
47314
+ console.log(source_default.cyan(`Sessions (${activeSessions.length} active of ${result.total}):`));
47315
+ for (const session of activeSessions) {
47316
+ console.log(source_default.white(` ${source_default.bold(session.sessionId)}`));
47317
+ if (session.title) console.log(source_default.gray(` Title: ${session.title}`));
47318
+ console.log(source_default.gray(` Agent: ${session.resourceId}`));
47319
+ console.log(source_default.gray(` Turns: ${session.turnCount}`));
47320
+ console.log(source_default.gray(` Updated: ${new Date(session.updatedAt).toLocaleString()}`));
47321
+ console.log();
47322
+ }
47323
+ })
47324
+ );
47325
+ }
47326
+ function registerSessionGet(program3) {
47327
+ program3.command("session:get <id>").description("Get session details and transcript").option("--api-url <url>", "API base URL").option("--json", "Output as JSON").action(
47328
+ wrapAction("session:get", async (id, options) => {
47329
+ const apiUrl = resolveApiUrl(options.apiUrl);
47330
+ const session = await apiGet(`/api/external/sessions/${id}`, apiUrl);
47331
+ if (options.json) {
47332
+ printJson5(session);
47333
+ return;
47334
+ }
47335
+ console.log(source_default.cyan(`Session: ${session.title ?? session.sessionId}`));
47336
+ console.log(source_default.gray(` ID: ${session.sessionId}`));
47337
+ console.log(source_default.gray(` Agent: ${session.resourceId}`));
47338
+ console.log(source_default.gray(` Status: ${session.isEnded ? "ended" : "active"}`));
47339
+ console.log(source_default.gray(` Turns: ${session.turnCount}`));
47340
+ console.log(source_default.gray(` Created: ${new Date(session.createdAt).toLocaleString()}`));
47341
+ console.log(source_default.gray(` Updated: ${new Date(session.updatedAt).toLocaleString()}`));
47342
+ if (session.endedAt) console.log(source_default.gray(` Ended: ${new Date(session.endedAt).toLocaleString()}`));
47343
+ if (session.messages) console.log(source_default.gray(` Transcript messages: ${session.messages.length}`));
47344
+ })
47345
+ );
47346
+ }
47347
+ function registerSessionEnd(program3) {
47348
+ program3.command("session:end <id>").description("Terminate an active agent session").option("--api-url <url>", "API base URL").option("--json", "Output as JSON").action(
47349
+ wrapAction("session:end", async (id, options) => {
47350
+ const apiUrl = resolveApiUrl(options.apiUrl);
47351
+ const result = await apiDelete(`/api/external/sessions/${id}`, apiUrl);
47352
+ if (options.json) {
47353
+ printJson5(result);
47354
+ return;
47355
+ }
47356
+ console.log(source_default.green(`Ended session ${result.sessionId ?? id}.`));
47357
+ })
47358
+ );
47359
+ }
47360
+
47361
+ // src/cli/commands/session/index.ts
47362
+ function registerSessionCommands(program3) {
47363
+ registerSessionList(program3);
47364
+ registerSessionGet(program3);
47365
+ registerSessionEnd(program3);
47366
+ }
47367
+
45541
47368
  // src/cli/index.ts
45542
47369
  var PREFLIGHT_SKIP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h", "--version", "-V"]);
47370
+ var PREFLIGHT_SKIP_COMMANDS = /* @__PURE__ */ new Set(["cli"]);
45543
47371
  var LOCAL_PROJECT_COMMANDS = /* @__PURE__ */ new Set(["ui:use-local", "ui:use-published", "knowledge:generate"]);
45544
47372
  function shouldSkipPreflight() {
45545
47373
  const args = process.argv.slice(2);
45546
47374
  if (args.length === 0) return true;
47375
+ if (PREFLIGHT_SKIP_COMMANDS.has(args[0] ?? "")) return true;
45547
47376
  return args.every((a) => PREFLIGHT_SKIP_FLAGS.has(a));
45548
47377
  }
45549
47378
  function isLocalProjectCommand() {
@@ -45602,6 +47431,16 @@ Commands:
45602
47431
  elevasis-sdk project:list [--search <query>] List projects with optional search
45603
47432
  elevasis-sdk project:resolve <query> Resolve a project ID from a name or UUID
45604
47433
  elevasis-sdk project:work <query> Open a lifecycle-aware project work brief
47434
+ elevasis-sdk client:list [--search <query>] List clients with optional search
47435
+ elevasis-sdk client:get <id> Get client detail and lineage
47436
+ elevasis-sdk client:status Show client portfolio status
47437
+ elevasis-sdk agent:list List deployed agents
47438
+ elevasis-sdk agent:get <id> Get agent metadata and OM linkage
47439
+ elevasis-sdk session:list List active agent sessions
47440
+ elevasis-sdk session:get <id> Get session details and transcript
47441
+ elevasis-sdk session:end <id> Terminate an active agent session
47442
+ elevasis-sdk acquisition:list:list List acquisition lists
47443
+ elevasis-sdk acquisition:deal:list List acquisition deals
45605
47444
  elevasis-sdk knowledge:generate Generate knowledge nodes from MDX files
45606
47445
  elevasis-sdk knowledge:ls <path> List knowledge nodes for a path
45607
47446
  elevasis-sdk knowledge:cat <id> Print raw MDX body of a knowledge node
@@ -45609,6 +47448,7 @@ Commands:
45609
47448
  elevasis-sdk request:submit -f <path> Submit a structured request report
45610
47449
  elevasis-sdk ui:use-local Use a local @elevasis/ui tarball
45611
47450
  elevasis-sdk ui:use-published Restore published @elevasis/ui
47451
+ elevasis-sdk cli [domain] Generate a registered command catalog
45612
47452
  elevasis-sdk rename <id> --to <newId> [--prod] Rename resource across platform tables
45613
47453
  elevasis-sdk doctor [--verbose] Check project environment and API connectivity
45614
47454
 
@@ -45629,10 +47469,15 @@ registerCredsCommand(program2);
45629
47469
  registerErrorCommand(program2);
45630
47470
  registerRenameCommand(program2);
45631
47471
  registerProjectCommands(program2);
47472
+ registerClientCommands(program2);
47473
+ registerAgentCommands(program2);
47474
+ registerSessionCommands(program2);
47475
+ registerAcquisitionCommands(program2);
45632
47476
  registerKnowledgeCommands(program2);
45633
47477
  registerRequestCommands(program2);
45634
47478
  registerUiCommands(program2);
45635
47479
  registerDoctorCommand(program2);
47480
+ registerCliCatalogCommand(program2);
45636
47481
  program2.parse();
45637
47482
  // Annotate the CommonJS export names for ESM import in node:
45638
47483
  0 && (module.exports = {