@elevasis/core 0.11.2 → 0.12.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 (36) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +8 -1
  3. package/dist/organization-model/index.d.ts +2 -1
  4. package/dist/organization-model/index.js +8 -1
  5. package/dist/test-utils/index.d.ts +10 -3
  6. package/dist/test-utils/index.js +6 -0
  7. package/package.json +1 -1
  8. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +27 -270
  9. package/src/auth/multi-tenancy/credentials/server/encryption.ts +83 -39
  10. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +47 -0
  11. package/src/auth/multi-tenancy/index.ts +3 -0
  12. package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -107
  13. package/src/auth/multi-tenancy/memberships/api-schemas.ts +6 -5
  14. package/src/auth/multi-tenancy/memberships/membership.ts +130 -138
  15. package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -0
  16. package/src/auth/multi-tenancy/role-management/index.ts +16 -0
  17. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +299 -293
  18. package/src/execution/engine/tools/integration/service.test.ts +214 -0
  19. package/src/execution/engine/tools/integration/service.ts +169 -161
  20. package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -496
  21. package/src/integrations/credentials/api-schemas.ts +127 -143
  22. package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -318
  23. package/src/integrations/webhook-endpoints/api-schemas.ts +103 -102
  24. package/src/integrations/webhook-endpoints/types.ts +58 -51
  25. package/src/operations/activities/api-schemas.ts +80 -79
  26. package/src/operations/activities/types.ts +64 -63
  27. package/src/organization-model/contracts.ts +1 -0
  28. package/src/organization-model/defaults.ts +6 -0
  29. package/src/organization-model/domains/navigation.ts +37 -23
  30. package/src/organization-model/published.ts +2 -1
  31. package/src/platform/constants/versions.ts +1 -1
  32. package/src/reference/_generated/contracts.md +27 -270
  33. package/src/scaffold-registry/__tests__/index.test.ts +72 -7
  34. package/src/scaffold-registry/index.ts +159 -26
  35. package/src/server.ts +281 -272
  36. package/src/supabase/database.types.ts +7 -3
@@ -3,7 +3,8 @@ import {
3
3
  OPERATIONS_COMMAND_VIEW_SURFACE_ID,
4
4
  PROJECTS_VIEW_CAPABILITY_ID,
5
5
  PROJECTS_FEATURE_ID,
6
- PROJECTS_INDEX_SURFACE_ID
6
+ PROJECTS_INDEX_SURFACE_ID,
7
+ SETTINGS_ROLES_SURFACE_ID
7
8
  } from '../contracts'
8
9
  import { DescriptionSchema, IconNameSchema, LabelSchema, ModelIdSchema, PathSchema, ReferenceIdsSchema } from './shared'
9
10
 
@@ -260,33 +261,45 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
260
261
  resourceIds: [],
261
262
  capabilityIds: []
262
263
  },
263
- {
264
- id: 'settings.appearance',
265
- label: 'Appearance',
266
- path: '/settings/appearance',
264
+ {
265
+ id: 'settings.appearance',
266
+ label: 'Appearance',
267
+ path: '/settings/appearance',
267
268
  surfaceType: 'settings',
268
269
  enabled: true,
269
270
  featureId: 'settings',
270
271
  featureIds: ['settings'],
271
272
  entityIds: [],
272
- resourceIds: [],
273
- capabilityIds: []
274
- },
275
- {
276
- id: 'settings.organization',
277
- label: 'Organization',
278
- path: '/settings/organization',
273
+ resourceIds: [],
274
+ capabilityIds: []
275
+ },
276
+ {
277
+ id: SETTINGS_ROLES_SURFACE_ID,
278
+ label: 'My Roles',
279
+ path: '/settings/roles',
280
+ surfaceType: 'settings',
281
+ enabled: true,
282
+ featureId: 'settings',
283
+ featureIds: ['settings'],
284
+ entityIds: [],
285
+ resourceIds: [],
286
+ capabilityIds: []
287
+ },
288
+ {
289
+ id: 'settings.organization',
290
+ label: 'Organization',
291
+ path: '/settings/organization',
279
292
  surfaceType: 'settings',
280
293
  enabled: true,
281
294
  featureId: 'settings',
282
295
  featureIds: ['settings'],
283
296
  entityIds: [],
284
- resourceIds: [],
285
- capabilityIds: []
286
- },
287
- {
288
- id: 'settings.credentials',
289
- label: 'Credentials',
297
+ resourceIds: [],
298
+ capabilityIds: []
299
+ },
300
+ {
301
+ id: 'settings.credentials',
302
+ label: 'Credentials',
290
303
  path: '/settings/credentials',
291
304
  surfaceType: 'settings',
292
305
  enabled: true,
@@ -372,11 +385,12 @@ export const DEFAULT_ORGANIZATION_MODEL_NAVIGATION: z.infer<typeof OrganizationM
372
385
  label: 'Settings',
373
386
  placement: 'bottom',
374
387
  surfaceIds: [
375
- 'settings.account',
376
- 'settings.appearance',
377
- 'settings.organization',
378
- 'settings.credentials',
379
- 'settings.api-keys',
388
+ 'settings.account',
389
+ 'settings.appearance',
390
+ SETTINGS_ROLES_SURFACE_ID,
391
+ 'settings.organization',
392
+ 'settings.credentials',
393
+ 'settings.api-keys',
380
394
  'settings.webhooks',
381
395
  'settings.deployments'
382
396
  ]
@@ -14,7 +14,8 @@ export {
14
14
  SEO_FEATURE_ID,
15
15
  SALES_PIPELINE_SURFACE_ID,
16
16
  PROSPECTING_LISTS_SURFACE_ID,
17
- OPERATIONS_COMMAND_VIEW_SURFACE_ID
17
+ OPERATIONS_COMMAND_VIEW_SURFACE_ID,
18
+ SETTINGS_ROLES_SURFACE_ID
18
19
  } from './contracts'
19
20
  export { DEFAULT_ORGANIZATION_MODEL } from './defaults'
20
21
  export {
@@ -1,3 +1,3 @@
1
1
  export const VERSION = {
2
- CURRENT: '1.6.11'
2
+ CURRENT: '1.6.14'
3
3
  }
@@ -180,7 +180,8 @@ export type OrganizationModelKeyResult = z.infer<typeof KeyResultSchema>
180
180
  ### `DeepPartial`
181
181
 
182
182
  ```typescript
183
- export type DeepPartial<T> = T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T
183
+ export type DeepPartial<T> =
184
+ T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T
184
185
  ```
185
186
 
186
187
  ## Feature System
@@ -189,13 +190,12 @@ export type DeepPartial<T> = T extends Array<infer U> ? Array<DeepPartial<U>> :
189
190
 
190
191
  ```typescript
191
192
  export type FeatureSidebarComponent = ComponentType
192
- export type FeatureIconComponent = ComponentType<{ size?: number;
193
193
  ```
194
194
 
195
195
  ### `FeatureIconComponent`
196
196
 
197
197
  ```typescript
198
- export type FeatureIconComponent = ComponentType<{ size?: number;
198
+ export type FeatureIconComponent = ComponentType<{ size?: number; stroke?: number }>
199
199
  ```
200
200
 
201
201
  ### `FeatureSidebarWidthResolver`
@@ -361,26 +361,10 @@ export interface ElevasisFeaturesContextValue {
361
361
  ### `ResourceStatus`
362
362
 
363
363
  ```typescript
364
- /**
365
- * Resource Registry type definitions
366
- */
367
-
368
- import type { IntegrationType } from '../../execution/engine/tools/integration'
369
- import type { ResourceCategory, ResourceLink } from './resource-link'
370
-
371
- // ============================================================================
372
- // Core Resource Type Definitions
373
- // ============================================================================
374
-
375
364
  /**
376
365
  * Environment/deployment status for resources
377
- */
378
- export type ResourceStatus = 'dev' | 'prod'
379
-
380
- /**
381
- * All resource types in the platform
382
- * Used as the discriminator field in ResourceDefinition
383
- */
366
+ */
367
+ export type ResourceStatus = 'dev' | 'prod'
384
368
  ```
385
369
 
386
370
  ### `ResourceType`
@@ -389,13 +373,8 @@ export type ResourceStatus = 'dev' | 'prod'
389
373
  /**
390
374
  * All resource types in the platform
391
375
  * Used as the discriminator field in ResourceDefinition
392
- */
393
- export type ResourceType = 'agent' | 'workflow' | 'trigger' | 'integration' | 'external' | 'human'
394
-
395
- /**
396
- * Executable resource types (subset of ResourceType)
397
- * These resources can be directly executed by the execution engine
398
- */
376
+ */
377
+ export type ResourceType = 'agent' | 'workflow' | 'trigger' | 'integration' | 'external' | 'human'
399
378
  ```
400
379
 
401
380
  ### `ExecutableResourceType`
@@ -404,17 +383,8 @@ export type ResourceType = 'agent' | 'workflow' | 'trigger' | 'integration' | 'e
404
383
  /**
405
384
  * Executable resource types (subset of ResourceType)
406
385
  * These resources can be directly executed by the execution engine
407
- */
408
- export type ExecutableResourceType = 'workflow' | 'agent'
409
-
410
- // ============================================================================
411
- // Base Resource Interface
412
- // ============================================================================
413
-
414
- /**
415
- * Base interface for ALL platform resources
416
- * Shared by both executable (agents, workflows) and non-executable (triggers, integrations, etc.) resources
417
- */
386
+ */
387
+ export type ExecutableResourceType = 'workflow' | 'agent'
418
388
  ```
419
389
 
420
390
  ### `ResourceDefinition`
@@ -423,7 +393,7 @@ export type ExecutableResourceType = 'workflow' | 'agent'
423
393
  /**
424
394
  * Base interface for ALL platform resources
425
395
  * Shared by both executable (agents, workflows) and non-executable (triggers, integrations, etc.) resources
426
- */
396
+ */
427
397
  export interface ResourceDefinition {
428
398
  /** Unique resource identifier */
429
399
  resourceId: string
@@ -463,44 +433,10 @@ export interface ResourceDefinition {
463
433
  ### `ResourceList`
464
434
 
465
435
  ```typescript
466
- /** Unique resource identifier */
467
- resourceId: string
468
-
469
- /** Display name */
470
- name: string
471
-
472
- /** Purpose and functionality description */
473
- description: string
474
-
475
- /** Version for change tracking and evolution */
476
- version: string
477
-
478
- /** Resource type discriminator */
479
- type: ResourceType
480
-
481
- /** Environment/deployment status */
482
- status: ResourceStatus
483
-
484
- /** Graph links to Organization Model nodes */
485
- links?: ResourceLink[]
486
-
487
- /** Infrastructure category for filtering */
488
- category?: ResourceCategory
489
-
490
- /** Whether the agent supports multi-turn sessions (agents only) */
491
- sessionCapable?: boolean
492
-
493
- /** Whether the resource is local (monorepo) or remote (externally deployed) */
494
- origin?: 'local' | 'remote'
495
-
496
- /** Whether this resource is archived and should be excluded from registration and deployment */
497
- archived?: boolean
498
- }
499
-
500
436
  /**
501
437
  * Resource list for organization
502
438
  * Returns ResourceDefinition metadata (not full definitions)
503
- */
439
+ */
504
440
  export interface ResourceList {
505
441
  workflows: ResourceDefinition[]
506
442
  agents: ResourceDefinition[]
@@ -513,16 +449,14 @@ export interface ResourceList {
513
449
  ### `WebhookProviderType`
514
450
 
515
451
  ```typescript
516
- /** Webhook provider identifiers */
517
- export type WebhookProviderType = 'cal-com' | 'stripe' | 'signature-api' | 'instantly' | 'apify' | 'test'
518
-
519
- /** Webhook trigger configuration */
452
+ /** Webhook provider identifiers */
453
+ export type WebhookProviderType = 'cal-com' | 'stripe' | 'signature-api' | 'instantly' | 'apify' | 'test'
520
454
  ```
521
455
 
522
456
  ### `WebhookTriggerConfig`
523
457
 
524
458
  ```typescript
525
- /** Webhook trigger configuration */
459
+ /** Webhook trigger configuration */
526
460
  export interface WebhookTriggerConfig {
527
461
  /** Provider identifier */
528
462
  provider: WebhookProviderType
@@ -538,17 +472,7 @@ export interface WebhookTriggerConfig {
538
472
  ### `ScheduleTriggerConfig`
539
473
 
540
474
  ```typescript
541
- /** Provider identifier */
542
- provider: WebhookProviderType
543
- /** Event type for documentation (not used for matching - workflow handles routing) */
544
- event?: string
545
- /** Optional filtering (e.g., specific form ID for Fillout) */
546
- filter?: Record<string, string>
547
- /** References credential in credentials table for per-org webhook secrets */
548
- credentialName?: string
549
- }
550
-
551
- /** Schedule trigger configuration */
475
+ /** Schedule trigger configuration */
552
476
  export interface ScheduleTriggerConfig {
553
477
  /** Cron expression (e.g., '0 6 * * *') */
554
478
  cron: string
@@ -560,13 +484,7 @@ export interface ScheduleTriggerConfig {
560
484
  ### `EventTriggerConfig`
561
485
 
562
486
  ```typescript
563
- /** Cron expression (e.g., '0 6 * * *') */
564
- cron: string
565
- /** Optional timezone (default: UTC) */
566
- timezone?: string
567
- }
568
-
569
- /** Event trigger configuration */
487
+ /** Event trigger configuration */
570
488
  export interface EventTriggerConfig {
571
489
  /** Internal event type */
572
490
  eventType: string
@@ -578,50 +496,8 @@ export interface EventTriggerConfig {
578
496
  ### `TriggerConfig`
579
497
 
580
498
  ```typescript
581
- /** Internal event type */
582
- eventType: string
583
- /** Event source */
584
- source?: string
585
- }
586
-
587
- /** Union of all trigger configs */
588
- export type TriggerConfig = WebhookTriggerConfig | ScheduleTriggerConfig | EventTriggerConfig
589
-
590
- // ============================================================================
591
- // Trigger Definition
592
- // ============================================================================
593
-
594
- /**
595
- * Trigger metadata - entry points that initiate resource execution
596
- *
597
- * Triggers represent how executions start: webhooks from external services,
598
- * scheduled cron jobs, platform events, or manual user actions.
599
- *
600
- * BREAKING CHANGES (2025-11-30):
601
- * - Now extends ResourceDefinition (inherits: resourceId, name, description, version, type, status, links, category)
602
- * - Field renames: `id` -> `resourceId` (inherited), `type` -> `triggerType`
603
- * - Relationship rename: `invokes` -> `triggers` (unified vocabulary)
604
- * - New required fields: `version` (inherited), `type: 'trigger'` (inherited)
605
- * - triggers object now includes `externalResources` option
606
- *
607
- * @example
608
- * // TriggerDefinition - metadata only
609
- * {
610
- * resourceId: 'trigger-new-order',
611
- * type: 'trigger',
612
- * triggerType: 'webhook',
613
- * name: 'New Order',
614
- * description: 'Webhook from Shopify on new orders',
615
- * version: '1.0.0',
616
- * status: 'prod',
617
- * webhookPath: '/webhooks/shopify/orders'
618
- * }
619
- *
620
- * // Relationships declared in ResourceRelationships (not on TriggerDefinition):
621
- * // relationships: {
622
- * // 'trigger-new-order': { triggers: { workflows: ['order-fulfillment-workflow'] } }
623
- * // }
624
- */
499
+ /** Union of all trigger configs */
500
+ export type TriggerConfig = WebhookTriggerConfig | ScheduleTriggerConfig | EventTriggerConfig
625
501
  ```
626
502
 
627
503
  ### `TriggerDefinition`
@@ -657,7 +533,7 @@ export type TriggerConfig = WebhookTriggerConfig | ScheduleTriggerConfig | Event
657
533
  * // relationships: {
658
534
  * // 'trigger-new-order': { triggers: { workflows: ['order-fulfillment-workflow'] } }
659
535
  * // }
660
- */
536
+ */
661
537
  export interface TriggerDefinition extends ResourceDefinition {
662
538
  /** Resource type discriminator (narrowed from base union) */
663
539
  type: 'trigger'
@@ -684,27 +560,6 @@ export interface TriggerDefinition extends ResourceDefinition {
684
560
  ### `IntegrationDefinition`
685
561
 
686
562
  ```typescript
687
- /** Resource type discriminator (narrowed from base union) */
688
- type: 'trigger'
689
-
690
- /** Trigger mechanism type (renamed from 'type' to avoid collision with base type discriminator) */
691
- triggerType: 'webhook' | 'schedule' | 'manual' | 'event'
692
-
693
- /** Type-specific configuration */
694
- config?: TriggerConfig
695
-
696
- // Legacy fields (deprecated, use config instead)
697
- /** For webhook triggers: path like '/webhooks/shopify/orders' */
698
- webhookPath?: string
699
- /** For schedule triggers: cron expression like '0 6 * * *' */
700
- schedule?: string
701
- /** For event triggers: event type like 'low-stock-alert' */
702
- eventType?: string
703
-
704
- // NOTE: What this trigger starts is declared in ResourceRelationships, not here
705
- // This prevents duplication - triggers are forward-declared in relationships
706
- }
707
-
708
563
  /**
709
564
  * Integration metadata - external service connections
710
565
  *
@@ -729,7 +584,7 @@ export interface TriggerDefinition extends ResourceDefinition {
729
584
  * version: '1.0.0',
730
585
  * status: 'prod'
731
586
  * }
732
- */
587
+ */
733
588
  export interface IntegrationDefinition extends ResourceDefinition {
734
589
  /** Resource type discriminator (narrowed from base union) */
735
590
  type: 'integration'
@@ -744,15 +599,6 @@ export interface IntegrationDefinition extends ResourceDefinition {
744
599
  ### `RelationshipDeclaration`
745
600
 
746
601
  ```typescript
747
- /** Resource type discriminator (narrowed from base union) */
748
- type: 'integration'
749
-
750
- /** Integration provider type */
751
- provider: IntegrationType
752
- /** References credentials table (e.g., 'shopify-prod', 'zendesk-api') */
753
- credentialName: string
754
- }
755
-
756
602
  /**
757
603
  * Explicit resource relationship declaration
758
604
  *
@@ -764,7 +610,7 @@ export interface IntegrationDefinition extends ResourceDefinition {
764
610
  * triggers: { workflows: ['order-fulfillment-workflow'] },
765
611
  * uses: { integrations: ['integration-shopify-prod', 'integration-postgres'] }
766
612
  * }
767
- */
613
+ */
768
614
  export interface RelationshipDeclaration {
769
615
  /** Resources this resource triggers */
770
616
  triggers?: {
@@ -784,20 +630,6 @@ export interface RelationshipDeclaration {
784
630
  ### `ResourceRelationships`
785
631
 
786
632
  ```typescript
787
- /** Resources this resource triggers */
788
- triggers?: {
789
- /** Agent resourceIds this resource triggers */
790
- agents?: string[]
791
- /** Workflow resourceIds this resource triggers */
792
- workflows?: string[]
793
- }
794
- /** Integrations this resource uses */
795
- uses?: {
796
- /** Integration IDs this resource uses */
797
- integrations?: string[]
798
- }
799
- }
800
-
801
633
  /**
802
634
  * Resource relationships map
803
635
  * Maps resourceId to its relationship declarations
@@ -809,17 +641,8 @@ export interface RelationshipDeclaration {
809
641
  * uses: { integrations: ['integration-shopify-prod'] }
810
642
  * }
811
643
  * }
812
- */
813
- export type ResourceRelationships = Record<string, RelationshipDeclaration>
814
-
815
- // ============================================================================
816
- // External Resource Types
817
- // ============================================================================
818
-
819
- /**
820
- * External platform type
821
- * Supported third-party automation platforms
822
- */
644
+ */
645
+ export type ResourceRelationships = Record<string, RelationshipDeclaration>
823
646
  ```
824
647
 
825
648
  ### `ExternalPlatform`
@@ -828,39 +651,8 @@ export type ResourceRelationships = Record<string, RelationshipDeclaration>
828
651
  /**
829
652
  * External platform type
830
653
  * Supported third-party automation platforms
831
- */
832
- export type ExternalPlatform = 'n8n' | 'make' | 'zapier' | 'other'
833
-
834
- /**
835
- * External automation resource metadata
836
- *
837
- * Represents workflows/automations running on third-party platforms
838
- * (n8n, Make, Zapier, etc.) for visualization in Command View.
839
- *
840
- * NOTE: This is metadata ONLY for visualization. No execution logic,
841
- * no API integration with external platforms, no status syncing.
842
- *
843
- * BREAKING CHANGES (2025-11-30):
844
- * - Now extends ResourceDefinition (inherits: resourceId, name, description, version, type, status, links, category)
845
- * - Field renames: `id` -> `resourceId` (inherited)
846
- * - New required field: `version` (inherited) - organizations must add version to all external resources
847
- * - New required field: `type: 'external'` (inherited) - resource type discriminator
848
- * - REMOVED FIELD: `triggeredBy` - per relationship-consolidation design, all relationships are forward-only declarations
849
- *
850
- * @example
851
- * {
852
- * resourceId: 'external-n8n-order-sync',
853
- * type: 'external',
854
- * version: '1.0.0',
855
- * platform: 'n8n',
856
- * name: 'Shopify Order Sync',
857
- * description: 'Legacy n8n workflow for syncing Shopify orders',
858
- * status: 'prod',
859
- * platformUrl: 'https://n8n.client.com/workflow/123',
860
- * triggers: { workflows: ['order-fulfillment-workflow'] },
861
- * uses: { integrations: ['integration-shopify-prod'] }
862
- * }
863
- */
654
+ */
655
+ export type ExternalPlatform = 'n8n' | 'make' | 'zapier' | 'other'
864
656
  ```
865
657
 
866
658
  ### `ExternalResourceDefinition`
@@ -895,7 +687,7 @@ export type ExternalPlatform = 'n8n' | 'make' | 'zapier' | 'other'
895
687
  * triggers: { workflows: ['order-fulfillment-workflow'] },
896
688
  * uses: { integrations: ['integration-shopify-prod'] }
897
689
  * }
898
- */
690
+ */
899
691
  export interface ExternalResourceDefinition extends ResourceDefinition {
900
692
  /** Resource type discriminator (narrowed from base union) */
901
693
  type: 'external'
@@ -932,37 +724,6 @@ export interface ExternalResourceDefinition extends ResourceDefinition {
932
724
  ### `HumanCheckpointDefinition`
933
725
 
934
726
  ```typescript
935
- /** Resource type discriminator (narrowed from base union) */
936
- type: 'external'
937
-
938
- /** Platform type */
939
- platform: ExternalPlatform
940
-
941
- // Optional platform-specific metadata
942
- /** Link to external platform (e.g., n8n workflow editor URL) */
943
- platformUrl?: string
944
- /** Platform's internal ID/reference */
945
- externalId?: string
946
-
947
- /** What this external resource triggers (external -> internal) */
948
- triggers?: {
949
- /** Elevasis workflow resourceIds this external automation triggers */
950
- workflows?: string[]
951
- /** Elevasis agent resourceIds this external automation triggers */
952
- agents?: string[]
953
- }
954
-
955
- /** Integrations this external resource uses (shared credentials) */
956
- uses?: {
957
- /** Integration IDs this external automation uses */
958
- integrations?: string[]
959
- }
960
-
961
- // NOTE: triggeredBy field removed - per relationship-consolidation design,
962
- // all relationships are forward-only declarations. Graph edges are built
963
- // from forward declarations only.
964
- }
965
-
966
727
  /**
967
728
  * Human Checkpoint definition - human decision points in automation
968
729
  *
@@ -987,7 +748,7 @@ export interface ExternalResourceDefinition extends ResourceDefinition {
987
748
  * requestedBy: { agents: ['order-processor-agent'] },
988
749
  * routesTo: { agents: ['order-fulfillment-agent'] }
989
750
  * }
990
- */
751
+ */
991
752
  export interface HumanCheckpointDefinition extends ResourceDefinition {
992
753
  /** Resource type discriminator (narrowed from base union) */
993
754
  type: 'human'
@@ -1015,10 +776,6 @@ export interface HumanCheckpointDefinition extends ResourceDefinition {
1015
776
  ### `DeploymentSpec`
1016
777
 
1017
778
  ```typescript
1018
- /** Always undefined for system resources; present for API compatibility with RemoteOrgConfig consumers */
1019
- sdkVersion?: never
1020
- }
1021
-
1022
779
  /**
1023
780
  * Organization-specific resource collection
1024
781
  *
@@ -1,5 +1,15 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { findMatchingEntries, findMissingDependentPaths, loadScaffoldRegistryFast } from '../index'
1
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
2
+ import { tmpdir } from 'node:os'
3
+ import path from 'node:path'
4
+ import { afterEach, describe, expect, it } from 'vitest'
5
+ import {
6
+ findEmptySourcePatterns,
7
+ findMatchingEntries,
8
+ findMissingDependentPaths,
9
+ loadScaffoldRegistryFast,
10
+ normalizeScaffoldPath,
11
+ scaffoldPathMatchesPattern
12
+ } from '../index'
3
13
  import type { ScaffoldRegistry, ScaffoldRegistryEntry } from '../schema'
4
14
 
5
15
  function makeEntry(id: string, sources: string[]): ScaffoldRegistryEntry {
@@ -20,6 +30,21 @@ function matchedIds(registry: ScaffoldRegistry, filePath: string): string[] {
20
30
  return findMatchingEntries(registry, filePath).map((e) => e.id)
21
31
  }
22
32
 
33
+ let tempRoots: string[] = []
34
+
35
+ function makeTempRoot(): string {
36
+ const root = mkdtempSync(path.join(tmpdir(), 'scaffold-registry-'))
37
+ tempRoots.push(root)
38
+ return root
39
+ }
40
+
41
+ afterEach(() => {
42
+ for (const root of tempRoots) {
43
+ rmSync(root, { recursive: true, force: true })
44
+ }
45
+ tempRoots = []
46
+ })
47
+
23
48
  describe('loadScaffoldRegistryFast', () => {
24
49
  it('preserves external sync metadata from the compiled registry', () => {
25
50
  const registry = loadScaffoldRegistryFast()
@@ -89,6 +114,10 @@ describe('findMissingDependentPaths', () => {
89
114
  })
90
115
 
91
116
  describe('findMatchingEntries (pattern matching)', () => {
117
+ it('normalizes Windows and relative paths', () => {
118
+ expect(normalizeScaffoldPath('.\\packages\\core\\src\\')).toBe('packages/core/src')
119
+ })
120
+
92
121
  it('matches exact paths', () => {
93
122
  const reg = registryFromEntries([makeEntry('exact', ['packages/core/src/index.ts'])])
94
123
  expect(matchedIds(reg, 'packages/core/src/index.ts')).toEqual(['exact'])
@@ -110,12 +139,11 @@ describe('findMatchingEntries (pattern matching)', () => {
110
139
  expect(matchedIds(reg, 'packages/core/nested/package.json')).toEqual([])
111
140
  })
112
141
 
113
- it('current matcher does NOT support mixed **/*.ext patterns (Step 3 upgrade)', () => {
114
- // The simple matcher's `/*` suffix branch only handles a single trailing
115
- // wildcard. Patterns like `**/*.ts` fall through and effectively miss real
116
- // files. Locked in to flag any change when full micromatch lands.
142
+ it('matches mixed **/*.ext patterns at direct-child and nested depths', () => {
117
143
  const reg = registryFromEntries([makeEntry('ext', ['apps/api/src/**/*.ts'])])
118
- expect(matchedIds(reg, 'apps/api/src/foo.ts')).toEqual([])
144
+ expect(matchedIds(reg, 'apps/api/src/foo.ts')).toEqual(['ext'])
145
+ expect(matchedIds(reg, 'apps/api/src/nested/deeply/foo.ts')).toEqual(['ext'])
146
+ expect(matchedIds(reg, 'apps/api/src/foo.tsx')).toEqual([])
119
147
  })
120
148
 
121
149
  it('normalizes Windows backslashes to forward slashes', () => {
@@ -138,4 +166,41 @@ describe('findMatchingEntries (pattern matching)', () => {
138
166
  const reg = registryFromEntries([makeEntry('a', ['packages/core/src/**'])])
139
167
  expect(matchedIds(reg, 'apps/api/src/foo.ts')).toEqual([])
140
168
  })
169
+
170
+ it('exposes the same matcher for direct consumers', () => {
171
+ expect(scaffoldPathMatchesPattern('packages/core/src/foo.test.ts', 'packages/core/src/**/*.ts')).toBe(true)
172
+ expect(scaffoldPathMatchesPattern('packages/core/src/foo.test.ts', 'packages/ui/src/**/*.ts')).toBe(false)
173
+ })
174
+ })
175
+
176
+ describe('findEmptySourcePatterns', () => {
177
+ it('flags source patterns that do not match any file or directory', () => {
178
+ const root = makeTempRoot()
179
+ mkdirSync(path.join(root, 'packages', 'core', 'src'), { recursive: true })
180
+ writeFileSync(path.join(root, 'packages', 'core', 'src', 'index.ts'), 'export {}\n', 'utf8')
181
+
182
+ const registry = registryFromEntries([
183
+ makeEntry('ok-exact', ['packages/core/src/index.ts']),
184
+ makeEntry('ok-glob', ['packages/core/src/**/*.ts']),
185
+ makeEntry('empty', ['packages/core/src/**/*.tsx'])
186
+ ])
187
+
188
+ expect(findEmptySourcePatterns(registry, root)).toEqual([
189
+ { entryId: 'empty', pattern: 'packages/core/src/**/*.tsx' }
190
+ ])
191
+ })
192
+
193
+ it('treats exact directories as non-empty source coverage', () => {
194
+ const root = makeTempRoot()
195
+ mkdirSync(path.join(root, 'external', '_template', '.claude', 'skills'), { recursive: true })
196
+
197
+ const registry = registryFromEntries([
198
+ makeEntry('dir', ['external/_template/.claude/skills']),
199
+ makeEntry('missing-dir', ['external/_template/.claude/commands'])
200
+ ])
201
+
202
+ expect(findEmptySourcePatterns(registry, root)).toEqual([
203
+ { entryId: 'missing-dir', pattern: 'external/_template/.claude/commands' }
204
+ ])
205
+ })
141
206
  })