@epilot/cli 0.1.47 → 0.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ npm install -g @epilot/cli
29
29
 
30
30
  <!-- usage-help -->
31
31
  ```
32
- epilot v0.1.47 — CLI for epilot APIs
32
+ epilot v0.1.49 — CLI for epilot APIs
33
33
 
34
34
  USAGE
35
35
  epilot <api> <operationId> [params...] [flags]
@@ -41,6 +41,10 @@
41
41
  {
42
42
  "name": "Patches",
43
43
  "description": "Manage blueprint patches for mass rollouts"
44
+ },
45
+ {
46
+ "name": "Uniqueness Criteria",
47
+ "description": "Configure per-org field sets used to match existing resources during install"
44
48
  }
45
49
  ],
46
50
  "security": [
@@ -2964,6 +2968,118 @@
2964
2968
  }
2965
2969
  }
2966
2970
  },
2971
+ "/v3/blueprint-manifest/blueprints/{blueprint_id}/deployments/{job_id}:restore": {
2972
+ "post": {
2973
+ "operationId": "restoreBlueprintDeploymentV3",
2974
+ "summary": "Restore a specific deployment by job_id",
2975
+ "description": "Roll a deployment back to its pre-install state. Two phases:\n\n 1. Upsert — re-applies the captured payloads via snapshot-api's\n `:restore` (server-side; runs config-engine.apply with captured\n target ids pre-seeded). Skipped for pure-create deployments\n whose snapshot was empty.\n 2. Delete sweep — for lineage rows of this blueprint instance not\n present in the snapshot's captured set, deletes the live\n resource via the type's adapter. Co-ownership / drift /\n no-delete-capability skip the entry with the corresponding\n reason.\n\nResolves `(blueprint_id, job_id)` to the entry in\n`Blueprint.deployments[]` and reads its `snapshot_id` and\n`destination_blueprint_id` — the caller never needs to handle\nsnapshot ids directly.\n\nAsync — returns 202 with a job id. Poll the job to track progress.\nThe per-instance lock (`installation_status === 'IN_PROGRESS'`)\nrejects concurrent installs or restores with 409.\n",
2976
+ "tags": [
2977
+ "Blueprints"
2978
+ ],
2979
+ "parameters": [
2980
+ {
2981
+ "in": "path",
2982
+ "name": "blueprint_id",
2983
+ "required": true,
2984
+ "schema": {
2985
+ "$ref": "#/components/schemas/BlueprintID"
2986
+ }
2987
+ },
2988
+ {
2989
+ "in": "path",
2990
+ "name": "job_id",
2991
+ "required": true,
2992
+ "schema": {
2993
+ "$ref": "#/components/schemas/BlueprintJobID"
2994
+ }
2995
+ }
2996
+ ],
2997
+ "responses": {
2998
+ "202": {
2999
+ "description": "Restore job started",
3000
+ "headers": {
3001
+ "Location": {
3002
+ "description": "URL to poll the job",
3003
+ "schema": {
3004
+ "type": "string"
3005
+ }
3006
+ }
3007
+ },
3008
+ "content": {
3009
+ "application/json": {
3010
+ "schema": {
3011
+ "type": "object",
3012
+ "properties": {
3013
+ "job_id": {
3014
+ "$ref": "#/components/schemas/BlueprintJobID"
3015
+ },
3016
+ "blueprint_instance_id": {
3017
+ "$ref": "#/components/schemas/BlueprintID"
3018
+ },
3019
+ "snapshot_id": {
3020
+ "type": "string"
3021
+ }
3022
+ }
3023
+ }
3024
+ }
3025
+ }
3026
+ },
3027
+ "400": {
3028
+ "description": "Deployment has no snapshot, or the snapshot is not in a `completed` state."
3029
+ },
3030
+ "404": {
3031
+ "description": "Blueprint not found, or no deployment with the given job_id on this blueprint."
3032
+ },
3033
+ "409": {
3034
+ "description": "Another install or restore is in flight for this blueprint instance."
3035
+ }
3036
+ }
3037
+ }
3038
+ },
3039
+ "/v3/blueprint-manifest/blueprints/{blueprint_id}/deployments/{job_id}/restore-preview": {
3040
+ "get": {
3041
+ "operationId": "getRestorePreview",
3042
+ "summary": "Predicted outcome of reverting a deployment",
3043
+ "description": "Computes what would happen if the user triggered a restore on this\ndeployment, without performing any writes. The forecast uses the\nsnapshot's captured resources (when present) plus the current lineage\nstate plus per-adapter gates (co-ownership, no-delete-capability,\nheuristic-match, drift when wired).\n\nIdempotent and side-effect free. Safe to call repeatedly. The result\nmay shift between calls if operators edit destination resources or\nanother blueprint adopts a shared resource in the meantime.\n",
3044
+ "tags": [
3045
+ "Blueprints"
3046
+ ],
3047
+ "parameters": [
3048
+ {
3049
+ "in": "path",
3050
+ "name": "blueprint_id",
3051
+ "required": true,
3052
+ "schema": {
3053
+ "$ref": "#/components/schemas/BlueprintID"
3054
+ }
3055
+ },
3056
+ {
3057
+ "in": "path",
3058
+ "name": "job_id",
3059
+ "required": true,
3060
+ "description": "The install job whose deployment is being previewed.",
3061
+ "schema": {
3062
+ "$ref": "#/components/schemas/BlueprintJobID"
3063
+ }
3064
+ }
3065
+ ],
3066
+ "responses": {
3067
+ "200": {
3068
+ "description": "Predicted outcome. `failed`-action items are absent here — the\npreview can't forecast errors.\n",
3069
+ "content": {
3070
+ "application/json": {
3071
+ "schema": {
3072
+ "$ref": "#/components/schemas/RestoreOutcome"
3073
+ }
3074
+ }
3075
+ }
3076
+ },
3077
+ "404": {
3078
+ "description": "Blueprint or deployment not found."
3079
+ }
3080
+ }
3081
+ }
3082
+ },
2967
3083
  "/v3/blueprint-manifest/blueprints/{blueprint_id}/lineage": {
2968
3084
  "get": {
2969
3085
  "operationId": "getBlueprintLineageV3",
@@ -3006,10 +3122,184 @@
3006
3122
  }
3007
3123
  }
3008
3124
  }
3125
+ },
3126
+ "/v1/blueprint-manifest/uniqueness-criteria": {
3127
+ "get": {
3128
+ "operationId": "listUniquenessCriteria",
3129
+ "summary": "listUniquenessCriteria",
3130
+ "description": "List all custom uniqueness criteria configured for the caller's organization.\nThese overrides are applied during install (V2 and V3) when matching incoming\nresources against existing ones in the destination org, replacing the default\nper-resource-type field set with the caller's chosen fields (AND-combined).\n",
3131
+ "tags": [
3132
+ "Uniqueness Criteria"
3133
+ ],
3134
+ "responses": {
3135
+ "200": {
3136
+ "description": "All configured criteria for the org",
3137
+ "content": {
3138
+ "application/json": {
3139
+ "schema": {
3140
+ "type": "object",
3141
+ "properties": {
3142
+ "results": {
3143
+ "type": "array",
3144
+ "items": {
3145
+ "$ref": "#/components/schemas/UniquenessCriteria"
3146
+ }
3147
+ }
3148
+ }
3149
+ }
3150
+ }
3151
+ }
3152
+ }
3153
+ }
3154
+ }
3155
+ },
3156
+ "/v1/blueprint-manifest/uniqueness-criteria/{resource_type}": {
3157
+ "parameters": [
3158
+ {
3159
+ "in": "path",
3160
+ "required": true,
3161
+ "name": "resource_type",
3162
+ "schema": {
3163
+ "$ref": "#/components/schemas/UniquenessCriteriaResourceType"
3164
+ }
3165
+ }
3166
+ ],
3167
+ "get": {
3168
+ "operationId": "getUniquenessCriteria",
3169
+ "summary": "getUniquenessCriteria",
3170
+ "description": "Get the configured uniqueness criteria for a specific resource type, if any.",
3171
+ "tags": [
3172
+ "Uniqueness Criteria"
3173
+ ],
3174
+ "responses": {
3175
+ "200": {
3176
+ "description": "Configured criteria for the resource type",
3177
+ "content": {
3178
+ "application/json": {
3179
+ "schema": {
3180
+ "$ref": "#/components/schemas/UniquenessCriteria"
3181
+ }
3182
+ }
3183
+ }
3184
+ },
3185
+ "404": {
3186
+ "description": "No custom criteria configured (defaults will be used)"
3187
+ }
3188
+ }
3189
+ },
3190
+ "put": {
3191
+ "operationId": "putUniquenessCriteria",
3192
+ "summary": "putUniquenessCriteria",
3193
+ "description": "Set or replace the uniqueness criteria for a resource type. The provided fields\nmust be valid attributes on the resource's schema (the UI typically loads the\nschema to populate options). All listed fields are AND-combined during matching.\n",
3194
+ "tags": [
3195
+ "Uniqueness Criteria"
3196
+ ],
3197
+ "requestBody": {
3198
+ "required": true,
3199
+ "content": {
3200
+ "application/json": {
3201
+ "schema": {
3202
+ "type": "object",
3203
+ "required": [
3204
+ "fields"
3205
+ ],
3206
+ "properties": {
3207
+ "fields": {
3208
+ "type": "array",
3209
+ "minItems": 1,
3210
+ "items": {
3211
+ "type": "string"
3212
+ }
3213
+ }
3214
+ }
3215
+ }
3216
+ }
3217
+ }
3218
+ },
3219
+ "responses": {
3220
+ "200": {
3221
+ "description": "Stored criteria",
3222
+ "content": {
3223
+ "application/json": {
3224
+ "schema": {
3225
+ "$ref": "#/components/schemas/UniquenessCriteria"
3226
+ }
3227
+ }
3228
+ }
3229
+ },
3230
+ "400": {
3231
+ "description": "Invalid resource type or field list"
3232
+ }
3233
+ }
3234
+ },
3235
+ "delete": {
3236
+ "operationId": "deleteUniquenessCriteria",
3237
+ "summary": "deleteUniquenessCriteria",
3238
+ "description": "Remove the custom criteria for a resource type, reverting to the default fields.",
3239
+ "tags": [
3240
+ "Uniqueness Criteria"
3241
+ ],
3242
+ "responses": {
3243
+ "204": {
3244
+ "description": "Criteria deleted (defaults will be used)"
3245
+ }
3246
+ }
3247
+ }
3009
3248
  }
3010
3249
  },
3011
3250
  "components": {
3012
3251
  "schemas": {
3252
+ "UniquenessCriteriaResourceType": {
3253
+ "type": "string",
3254
+ "description": "Resource type for which custom uniqueness criteria can be configured.",
3255
+ "enum": [
3256
+ "emailtemplate",
3257
+ "product",
3258
+ "price",
3259
+ "tax",
3260
+ "coupon",
3261
+ "product_recommendation",
3262
+ "file",
3263
+ "document_template",
3264
+ "schema",
3265
+ "taxonomy",
3266
+ "notification_template",
3267
+ "family",
3268
+ "permission",
3269
+ "journey"
3270
+ ]
3271
+ },
3272
+ "UniquenessCriteria": {
3273
+ "type": "object",
3274
+ "required": [
3275
+ "org_id",
3276
+ "resource_type",
3277
+ "fields",
3278
+ "updated_at"
3279
+ ],
3280
+ "properties": {
3281
+ "org_id": {
3282
+ "type": "string"
3283
+ },
3284
+ "resource_type": {
3285
+ "$ref": "#/components/schemas/UniquenessCriteriaResourceType"
3286
+ },
3287
+ "fields": {
3288
+ "type": "array",
3289
+ "minItems": 1,
3290
+ "items": {
3291
+ "type": "string"
3292
+ }
3293
+ },
3294
+ "updated_at": {
3295
+ "type": "string",
3296
+ "format": "date-time"
3297
+ },
3298
+ "updated_by": {
3299
+ "type": "string"
3300
+ }
3301
+ }
3302
+ },
3013
3303
  "LineageEntry": {
3014
3304
  "type": "object",
3015
3305
  "properties": {
@@ -3292,6 +3582,104 @@
3292
3582
  "PARTIAL_SUCCESS",
3293
3583
  "FAILED"
3294
3584
  ]
3585
+ },
3586
+ "restore_details": {
3587
+ "type": "object",
3588
+ "description": "Restore lifecycle metadata for this deployment.",
3589
+ "properties": {
3590
+ "has_revertible_changes": {
3591
+ "type": "boolean",
3592
+ "description": "Whether this sync changed destination resources in a way that can\nbe reverted. `false` means the sync completed without create,\nupdate, internal-update, or delete impacts, so there is no revert\naction to offer.\n"
3593
+ },
3594
+ "resource_impact_summary": {
3595
+ "type": "object",
3596
+ "description": "Counts of resource impact values from the V3 apply result.",
3597
+ "properties": {
3598
+ "create": {
3599
+ "type": "integer",
3600
+ "minimum": 0
3601
+ },
3602
+ "update": {
3603
+ "type": "integer",
3604
+ "minimum": 0
3605
+ },
3606
+ "internal_update": {
3607
+ "type": "integer",
3608
+ "minimum": 0
3609
+ },
3610
+ "delete": {
3611
+ "type": "integer",
3612
+ "minimum": 0
3613
+ },
3614
+ "no_op": {
3615
+ "type": "integer",
3616
+ "minimum": 0
3617
+ },
3618
+ "ignored": {
3619
+ "type": "integer",
3620
+ "minimum": 0
3621
+ }
3622
+ }
3623
+ },
3624
+ "last_restore_job_id": {
3625
+ "type": "string",
3626
+ "description": "BlueprintInstallationJob id of the most recent restore that ran\nagainst this deployment. Used by the FE to keep the restore-status\nbadge visible across page reloads. Frontends poll this job to\nrender the latest restore outcome.\n"
3627
+ },
3628
+ "last_restore_at": {
3629
+ "type": "string",
3630
+ "format": "date-time",
3631
+ "description": "Timestamp of the most recent restore that ran against this\ndeployment. Stamped when the restore sweep finishes. Used by the\nFE to show when a sync was reverted.\n"
3632
+ },
3633
+ "last_restored_by": {
3634
+ "type": "object",
3635
+ "description": "Identity of the caller who triggered the most recent restore.\nStamped when the restore sweep finishes. Used by the FE to show\nwho reverted a sync.\n",
3636
+ "properties": {
3637
+ "name": {
3638
+ "type": "string",
3639
+ "description": "Display name (email or token name) of the restorer."
3640
+ },
3641
+ "user_id": {
3642
+ "type": "string",
3643
+ "description": "User id of the restorer, when triggered by a user."
3644
+ }
3645
+ }
3646
+ },
3647
+ "status": {
3648
+ "type": "string",
3649
+ "description": "Computed server-side from `(job_id, restore_details.last_restore_job_id, installation_status)`.\n`available` when the deployment is restorable but has no prior\nrestore (including pure-create deployments without `snapshot_id`,\nreverted via sweep-only);\n`in_progress` while an install or restore is running on this\nblueprint instance;\n`restored` / `partially_restored` / `restore_failed` reflect the\nterminal status of the job referenced by `last_restore_job_id`;\n`unavailable` means there is no revert action, for example\nmalformed deployment rows missing `job_id` or no-change syncs.\n",
3650
+ "enum": [
3651
+ "available",
3652
+ "in_progress",
3653
+ "restored",
3654
+ "partially_restored",
3655
+ "restore_failed",
3656
+ "unavailable"
3657
+ ]
3658
+ }
3659
+ }
3660
+ },
3661
+ "has_revertible_changes": {
3662
+ "type": "boolean",
3663
+ "deprecated": true,
3664
+ "description": "Deprecated. Use `restore_details.has_revertible_changes`.\n"
3665
+ },
3666
+ "last_restore_job_id": {
3667
+ "type": "string",
3668
+ "deprecated": true,
3669
+ "description": "Deprecated. Use `restore_details.last_restore_job_id`.\n"
3670
+ },
3671
+ "restore_status": {
3672
+ "type": "string",
3673
+ "deprecated": true,
3674
+ "description": "Deprecated. Use `restore_details.status`.\n",
3675
+ "enum": [
3676
+ "available",
3677
+ "in_progress",
3678
+ "restored",
3679
+ "partially_restored",
3680
+ "restore_failed",
3681
+ "unavailable"
3682
+ ]
3295
3683
  }
3296
3684
  }
3297
3685
  }
@@ -3884,6 +4272,12 @@
3884
4272
  {
3885
4273
  "type": "object",
3886
4274
  "properties": {
4275
+ "job_type": {
4276
+ "type": "string",
4277
+ "enum": [
4278
+ "export"
4279
+ ]
4280
+ },
3887
4281
  "blueprint_id": {
3888
4282
  "$ref": "#/components/schemas/BlueprintID"
3889
4283
  },
@@ -3911,6 +4305,12 @@
3911
4305
  {
3912
4306
  "type": "object",
3913
4307
  "properties": {
4308
+ "job_type": {
4309
+ "type": "string",
4310
+ "enum": [
4311
+ "install"
4312
+ ]
4313
+ },
3914
4314
  "source_blueprint_id": {
3915
4315
  "$ref": "#/components/schemas/BlueprintID"
3916
4316
  },
@@ -3970,6 +4370,64 @@
3970
4370
  }
3971
4371
  ]
3972
4372
  },
4373
+ "BlueprintRestoreJob": {
4374
+ "allOf": [
4375
+ {
4376
+ "$ref": "#/components/schemas/CommonBlueprintJobFields"
4377
+ },
4378
+ {
4379
+ "type": "object",
4380
+ "properties": {
4381
+ "job_type": {
4382
+ "type": "string",
4383
+ "enum": [
4384
+ "restore"
4385
+ ]
4386
+ },
4387
+ "destination_blueprint_id": {
4388
+ "$ref": "#/components/schemas/BlueprintID"
4389
+ },
4390
+ "destination_org_id": {
4391
+ "type": "string"
4392
+ },
4393
+ "install_job_id": {
4394
+ "type": "string",
4395
+ "nullable": true,
4396
+ "description": "The install job whose deployment is being reverted. Maps back\nto the entry in `Blueprint.deployments[]`.\n"
4397
+ },
4398
+ "snapshot_id": {
4399
+ "type": "string",
4400
+ "nullable": true,
4401
+ "description": "The snapshot driving Phase 1 of the restore. Null for sweep-only\nrestores (pure-create deployments with no captured manifest).\n"
4402
+ },
4403
+ "sync_engine": {
4404
+ "type": "string",
4405
+ "enum": [
4406
+ "v3"
4407
+ ]
4408
+ },
4409
+ "status": {
4410
+ "type": "string",
4411
+ "enum": [
4412
+ "IN_PROGRESS",
4413
+ "SUCCESS",
4414
+ "PARTIAL_SUCCESS",
4415
+ "FAILED"
4416
+ ]
4417
+ },
4418
+ "restore_result": {
4419
+ "nullable": true,
4420
+ "description": "Absent while the job is still IN_PROGRESS.",
4421
+ "allOf": [
4422
+ {
4423
+ "$ref": "#/components/schemas/RestoreOutcome"
4424
+ }
4425
+ ]
4426
+ }
4427
+ }
4428
+ }
4429
+ ]
4430
+ },
3973
4431
  "V3ResourceProgressEntry": {
3974
4432
  "type": "object",
3975
4433
  "required": [
@@ -4009,6 +4467,84 @@
4009
4467
  }
4010
4468
  }
4011
4469
  },
4470
+ "RestoreOutcomeItem": {
4471
+ "type": "object",
4472
+ "required": [
4473
+ "lineage_id",
4474
+ "type",
4475
+ "action"
4476
+ ],
4477
+ "properties": {
4478
+ "lineage_id": {
4479
+ "type": "string"
4480
+ },
4481
+ "type": {
4482
+ "type": "string"
4483
+ },
4484
+ "name": {
4485
+ "type": "string",
4486
+ "nullable": true
4487
+ },
4488
+ "target_id": {
4489
+ "type": "string",
4490
+ "nullable": true
4491
+ },
4492
+ "action": {
4493
+ "type": "string",
4494
+ "description": "On `restore-preview`: the action the restore would take.\nOn `restore_result`: the action that was applied.\n`failed` only appears on `restore_result`.\n",
4495
+ "enum": [
4496
+ "restore",
4497
+ "delete",
4498
+ "skip",
4499
+ "failed"
4500
+ ]
4501
+ },
4502
+ "reason": {
4503
+ "type": "string",
4504
+ "nullable": true,
4505
+ "description": "Only set when `action == skip`.",
4506
+ "enum": [
4507
+ "modified",
4508
+ "co_owned",
4509
+ "delete_unsupported",
4510
+ "heuristic_match"
4511
+ ]
4512
+ },
4513
+ "last_synced_at": {
4514
+ "type": "string",
4515
+ "format": "date-time",
4516
+ "nullable": true,
4517
+ "description": "Only set when `reason == modified`. From the lineage row's last install write."
4518
+ },
4519
+ "current_updated_at": {
4520
+ "type": "string",
4521
+ "format": "date-time",
4522
+ "nullable": true,
4523
+ "description": "Only set when `reason == modified`. From the destination resource's current state."
4524
+ },
4525
+ "error_message": {
4526
+ "type": "string",
4527
+ "nullable": true,
4528
+ "description": "Only set when `action == failed`."
4529
+ }
4530
+ }
4531
+ },
4532
+ "RestoreOutcome": {
4533
+ "type": "object",
4534
+ "properties": {
4535
+ "snapshot_id": {
4536
+ "type": "string",
4537
+ "nullable": true,
4538
+ "description": "The snapshot driving Phase 1 of the restore. Null/absent for\nsweep-only restores (pure-create deployments with no captured\nmanifest).\n"
4539
+ },
4540
+ "resources": {
4541
+ "type": "array",
4542
+ "items": {
4543
+ "$ref": "#/components/schemas/RestoreOutcomeItem"
4544
+ }
4545
+ }
4546
+ }
4547
+ },
4012
4548
  "BlueprintJob": {
4013
4549
  "oneOf": [
4014
4550
  {
@@ -4017,6 +4553,9 @@
4017
4553
  {
4018
4554
  "$ref": "#/components/schemas/BlueprintInstallationJob"
4019
4555
  },
4556
+ {
4557
+ "$ref": "#/components/schemas/BlueprintRestoreJob"
4558
+ },
4020
4559
  {
4021
4560
  "$ref": "#/components/schemas/BlueprintDependenciesSyncJob"
4022
4561
  },
@@ -4026,7 +4565,18 @@
4026
4565
  {
4027
4566
  "$ref": "#/components/schemas/BlueprintVerificationJob"
4028
4567
  }
4029
- ]
4568
+ ],
4569
+ "discriminator": {
4570
+ "propertyName": "job_type",
4571
+ "mapping": {
4572
+ "export": "#/components/schemas/BlueprintExportJob",
4573
+ "install": "#/components/schemas/BlueprintInstallationJob",
4574
+ "restore": "#/components/schemas/BlueprintRestoreJob",
4575
+ "dependencies_sync": "#/components/schemas/BlueprintDependenciesSyncJob",
4576
+ "validate": "#/components/schemas/BlueprintValidateJob",
4577
+ "verification": "#/components/schemas/BlueprintVerificationJob"
4578
+ }
4579
+ }
4030
4580
  },
4031
4581
  "BlueprintDependenciesSyncJob": {
4032
4582
  "allOf": [
@@ -4036,6 +4586,12 @@
4036
4586
  {
4037
4587
  "type": "object",
4038
4588
  "properties": {
4589
+ "job_type": {
4590
+ "type": "string",
4591
+ "enum": [
4592
+ "dependencies_sync"
4593
+ ]
4594
+ },
4039
4595
  "blueprint_id": {
4040
4596
  "$ref": "#/components/schemas/BlueprintID"
4041
4597
  },
@@ -4060,6 +4616,12 @@
4060
4616
  {
4061
4617
  "type": "object",
4062
4618
  "properties": {
4619
+ "job_type": {
4620
+ "type": "string",
4621
+ "enum": [
4622
+ "validate"
4623
+ ]
4624
+ },
4063
4625
  "blueprint_id": {
4064
4626
  "$ref": "#/components/schemas/BlueprintID"
4065
4627
  },
@@ -4094,6 +4656,12 @@
4094
4656
  {
4095
4657
  "type": "object",
4096
4658
  "properties": {
4659
+ "job_type": {
4660
+ "type": "string",
4661
+ "enum": [
4662
+ "verification"
4663
+ ]
4664
+ },
4097
4665
  "source_org_id": {
4098
4666
  "type": "string"
4099
4667
  },
@@ -4111,6 +4679,7 @@
4111
4679
  "enum": [
4112
4680
  "IN_PROGRESS",
4113
4681
  "SUCCESS",
4682
+ "PARTIAL_SUCCESS",
4114
4683
  "FAILED"
4115
4684
  ]
4116
4685
  },
@@ -4142,6 +4711,7 @@
4142
4711
  "enum": [
4143
4712
  "IN_PROGRESS",
4144
4713
  "SUCCESS",
4714
+ "PARTIAL_SUCCESS",
4145
4715
  "FAILED"
4146
4716
  ]
4147
4717
  },
@@ -98,7 +98,6 @@
98
98
  "description": "Filter to snapshots containing one or more resources. Format\n`<type>:<id>`. Split on the first colon — the `<id>` half may\ncontain colons (e.g., role acl ids like `role:acl:internal:foo`).\nRepeat the param for multiple resources — results are OR-unioned.\nMaximum 50 pairs per request.\n",
99
99
  "schema": {
100
100
  "type": "array",
101
- "maxItems": 50,
102
101
  "items": {
103
102
  "type": "string",
104
103
  "pattern": "^[^:]+:.+$"
@@ -143,6 +142,44 @@
143
142
  }
144
143
  }
145
144
  },
145
+ "/v1/snapshots:capture-org": {
146
+ "post": {
147
+ "operationId": "captureOrgSnapshot",
148
+ "summary": "captureOrgSnapshot",
149
+ "description": "Snapshot the caller's whole organization now. Fetches a fresh inventory\nof the org's configuration resources from configuration-hub-api, persists\nit as an inventory artifact, and starts a `scope: \"org\"` chunked capture.\nAsync — returns immediately with a snapshot ID; client polls `getSnapshot`\nand watches `capture_summary` fill in until `create.status` moves from\n`in_progress` to `completed` or `failed`.\n\nSensitive types (`access_token`, `environment_variable`), types with no\nengine adapter, and any `excluded_types` are dropped from the capture and\nrecorded in the snapshot's coverage report.\n",
150
+ "tags": [
151
+ "Snapshots"
152
+ ],
153
+ "requestBody": {
154
+ "required": false,
155
+ "content": {
156
+ "application/json": {
157
+ "schema": {
158
+ "$ref": "#/components/schemas/CreateOrgSnapshotRequest"
159
+ }
160
+ }
161
+ }
162
+ },
163
+ "responses": {
164
+ "202": {
165
+ "description": "Org snapshot creation started",
166
+ "content": {
167
+ "application/json": {
168
+ "schema": {
169
+ "$ref": "#/components/schemas/CreateSnapshotResponse"
170
+ }
171
+ }
172
+ }
173
+ },
174
+ "401": {
175
+ "$ref": "#/components/responses/Unauthorized"
176
+ },
177
+ "422": {
178
+ "$ref": "#/components/responses/UnprocessableEntity"
179
+ }
180
+ }
181
+ }
182
+ },
146
183
  "/v1/snapshots/{id}": {
147
184
  "parameters": [
148
185
  {
@@ -214,10 +251,20 @@
214
251
  "post": {
215
252
  "operationId": "restoreSnapshot",
216
253
  "summary": "restoreSnapshot",
217
- "description": "Restore a snapshot to the org. Async — returns immediately; client polls\n`getSnapshot` until the latest entry in `restores` moves from\n`in_progress` to `completed` or `failed`.\n\nv1: full restore only. Cherry-pick (`resources?` body filter) is an open\nquestion — see RFC OQ #1.\n",
254
+ "description": "Restore a snapshot to the org. Async — returns immediately; client polls\n`getSnapshot` until the latest entry in `restores` moves from\n`in_progress` to one of `completed | partial | failed`.\n\nv1: full restore only. Cherry-pick (`resources?` body filter) is an open\nquestion — see RFC OQ #1.\n",
218
255
  "tags": [
219
256
  "Snapshots"
220
257
  ],
258
+ "requestBody": {
259
+ "required": false,
260
+ "content": {
261
+ "application/json": {
262
+ "schema": {
263
+ "$ref": "#/components/schemas/RestoreSnapshotRequest"
264
+ }
265
+ }
266
+ }
267
+ },
221
268
  "responses": {
222
269
  "202": {
223
270
  "description": "Restore started",
@@ -428,6 +475,16 @@
428
475
  }
429
476
  }
430
477
  }
478
+ },
479
+ "UnprocessableEntity": {
480
+ "description": "Unprocessable entity",
481
+ "content": {
482
+ "application/json": {
483
+ "schema": {
484
+ "$ref": "#/components/schemas/EmptyInventoryError"
485
+ }
486
+ }
487
+ }
431
488
  }
432
489
  },
433
490
  "schemas": {
@@ -446,6 +503,38 @@
446
503
  }
447
504
  }
448
505
  },
506
+ "EmptyInventoryError": {
507
+ "type": "object",
508
+ "required": [
509
+ "message",
510
+ "skipped_types"
511
+ ],
512
+ "description": "Returned (422) when the org inventory contains no capturable resources\nafter filtering out sensitive, unsupported, and excluded types. The\n`skipped_types` array explains why every type was dropped.\n",
513
+ "properties": {
514
+ "message": {
515
+ "type": "string",
516
+ "example": "No capturable resources in the org inventory"
517
+ },
518
+ "skipped_types": {
519
+ "type": "array",
520
+ "items": {
521
+ "type": "object",
522
+ "required": [
523
+ "type",
524
+ "reason"
525
+ ],
526
+ "properties": {
527
+ "type": {
528
+ "type": "string"
529
+ },
530
+ "reason": {
531
+ "type": "string"
532
+ }
533
+ }
534
+ }
535
+ }
536
+ }
537
+ },
449
538
  "ResourceRef": {
450
539
  "type": "object",
451
540
  "required": [
@@ -551,10 +640,11 @@
551
640
  "enum": [
552
641
  "manual",
553
642
  "sync",
554
- "blueprint_install"
643
+ "blueprint_install",
644
+ "scheduled"
555
645
  ],
556
646
  "default": "manual",
557
- "description": "What initiated this snapshot. `scheduled` may be added in a later\nphase for nightly backups (RFC OQ #3).\n"
647
+ "description": "What initiated this snapshot. `scheduled` is used for automatic\nnightly backups triggered by an org's EventBridge schedule\n(RFC Scheduled org snapshots).\n"
558
648
  },
559
649
  "blueprint_instance_id": {
560
650
  "type": "string",
@@ -569,6 +659,45 @@
569
659
  }
570
660
  }
571
661
  },
662
+ "CreateOrgSnapshotRequest": {
663
+ "type": "object",
664
+ "description": "Request body for `captureOrgSnapshot`. All fields optional — an empty body\nsnapshots the whole org with a default name and the 90-day default TTL.\n",
665
+ "properties": {
666
+ "name": {
667
+ "type": "string",
668
+ "description": "Snapshot name. Defaults to \"Org snapshot — <ISO timestamp>\"."
669
+ },
670
+ "retention": {
671
+ "type": "object",
672
+ "description": "Retention window. Converted to an absolute `expires_at` at creation\ntime. Omit for the default 90-day TTL.\n",
673
+ "required": [
674
+ "value",
675
+ "unit"
676
+ ],
677
+ "properties": {
678
+ "value": {
679
+ "type": "integer",
680
+ "minimum": 1
681
+ },
682
+ "unit": {
683
+ "type": "string",
684
+ "enum": [
685
+ "days",
686
+ "weeks",
687
+ "months"
688
+ ]
689
+ }
690
+ }
691
+ },
692
+ "excluded_types": {
693
+ "type": "array",
694
+ "description": "Resource types to exclude from the capture, in addition to the\nalways-excluded sensitive types (`access_token`,\n`environment_variable`).\n",
695
+ "items": {
696
+ "type": "string"
697
+ }
698
+ }
699
+ }
700
+ },
572
701
  "CreateSnapshotResponse": {
573
702
  "type": "object",
574
703
  "required": [
@@ -596,6 +725,22 @@
596
725
  }
597
726
  }
598
727
  },
728
+ "RestoreSnapshotRequest": {
729
+ "type": "object",
730
+ "description": "Both flags default to `false`, which restores every captured resource —\nConfig Hub's manual-restore semantics. blueprint-manifest-api sets\nboth `true` when reverting a blueprint install so user edits and\ncross-blueprint contributions survive. Each flag is independent so a\ncaller can preserve edits without preserving co-ownership (or vice\nversa). Skipped resources surface under `Operation.skipped`.\n",
731
+ "properties": {
732
+ "preserve_modified": {
733
+ "type": "boolean",
734
+ "default": false,
735
+ "description": "When `true`, skip captured resources whose live destination payload\nhas diverged from the install-time fingerprint stored on lineage.\nSurfaces under `Operation.skipped` with `reason: 'modified'`.\n"
736
+ },
737
+ "preserve_co_owned": {
738
+ "type": "boolean",
739
+ "default": false,
740
+ "description": "When `true`, skip captured resources whose lineage row carries\nanother blueprint instance's id (co-ownership ≥2). Surfaces under\n`Operation.skipped` with `reason: 'co_owned'`.\n"
741
+ }
742
+ }
743
+ },
599
744
  "RestoreSnapshotResponse": {
600
745
  "type": "object",
601
746
  "required": [
@@ -643,7 +788,8 @@
643
788
  "enum": [
644
789
  "manual",
645
790
  "sync",
646
- "blueprint_install"
791
+ "blueprint_install",
792
+ "scheduled"
647
793
  ]
648
794
  },
649
795
  "blueprint_instance_id": {
@@ -669,6 +815,47 @@
669
815
  "matched_count": {
670
816
  "type": "integer",
671
817
  "description": "Number of `resource` filter pairs from the request that are\ncontained in this snapshot. Present only on `listSnapshots`\nresponses where the caller passed at least one `resource`\nfilter — absent on `getSnapshot` and on unfiltered list calls.\nDrives the coverage badge in Config Hub's snapshot picker.\n"
818
+ },
819
+ "scope": {
820
+ "type": "string",
821
+ "enum": [
822
+ "selection",
823
+ "org"
824
+ ],
825
+ "description": "Capture scope. `selection` (default for manual/sync/blueprint_install)\nmeans only the explicitly listed resources were snapshotted.\n`org` means a full org inventory was discovered and captured\n(scheduled snapshots set this automatically).\n"
826
+ },
827
+ "expires_at": {
828
+ "type": "string",
829
+ "format": "date-time",
830
+ "description": "ISO-8601 timestamp after which this snapshot will be deleted.\nDerived from the org's retention setting at capture time for\nscheduled snapshots; not set for manual snapshots (which use\na hardcoded 90-day TTL written directly as a DynamoDB `ttl` epoch).\n"
831
+ },
832
+ "capture_summary": {
833
+ "type": "object",
834
+ "description": "Per-snapshot coverage report set by the capture worker on completion.\nRecords how many resources were attempted, captured, skipped\n(unsupported type or explicitly excluded), and failed.\n",
835
+ "required": [
836
+ "total",
837
+ "captured",
838
+ "skipped",
839
+ "failed"
840
+ ],
841
+ "properties": {
842
+ "total": {
843
+ "type": "integer",
844
+ "description": "Total resources in the inventory that were attempted."
845
+ },
846
+ "captured": {
847
+ "type": "integer",
848
+ "description": "Resources successfully fetched and written to the manifest."
849
+ },
850
+ "skipped": {
851
+ "type": "integer",
852
+ "description": "Resources skipped — type not supported by config-engine or\nexcluded from capture (e.g. access_token, environment_variable).\n"
853
+ },
854
+ "failed": {
855
+ "type": "integer",
856
+ "description": "Resources where the fetch call returned an error."
857
+ }
858
+ }
672
859
  }
673
860
  }
674
861
  },
@@ -701,14 +888,43 @@
701
888
  "enum": [
702
889
  "in_progress",
703
890
  "completed",
891
+ "partial",
704
892
  "failed"
705
- ]
893
+ ],
894
+ "description": "`partial` indicates the operation completed but skipped at least\none resource — see `skipped`. Only populated by restores triggered\nwith `mode: 'preserve_edits'`.\n"
706
895
  },
707
896
  "error": {
708
897
  "type": "string"
709
898
  },
710
899
  "triggered_by": {
711
900
  "$ref": "#/components/schemas/CallerIdentity"
901
+ },
902
+ "skipped": {
903
+ "type": "array",
904
+ "description": "Per-resource skips, populated only for restores triggered with\n`mode: 'preserve_edits'`. Empty / absent for Config Hub's\ndefault overwrite-mode restores.\n",
905
+ "items": {
906
+ "$ref": "#/components/schemas/SkippedResource"
907
+ }
908
+ }
909
+ }
910
+ },
911
+ "SkippedResource": {
912
+ "type": "object",
913
+ "required": [
914
+ "lineage_id",
915
+ "reason"
916
+ ],
917
+ "properties": {
918
+ "lineage_id": {
919
+ "type": "string"
920
+ },
921
+ "reason": {
922
+ "type": "string",
923
+ "enum": [
924
+ "modified",
925
+ "co_owned"
926
+ ],
927
+ "description": "- `modified` — current destination payload's fingerprint differs\n from the install-time fingerprint on the lineage row.\n- `co_owned` — lineage row has ≥2 distinct\n `blueprint_instance_ids`; restoring would unilaterally affect\n another blueprint instance's contribution.\n"
712
928
  }
713
929
  }
714
930
  },
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  API_LIST
4
- } from "../chunk-VOOQ4GMS.js";
4
+ } from "../chunk-44NTPQBR.js";
5
5
 
6
6
  // bin/epilot.ts
7
7
  import { runMain } from "citty";
@@ -11,7 +11,7 @@ import { defineCommand } from "citty";
11
11
  var main = defineCommand({
12
12
  meta: {
13
13
  name: "epilot",
14
- version: "0.1.47",
14
+ version: "0.1.49",
15
15
  description: "CLI for epilot APIs"
16
16
  },
17
17
  args: {
@@ -30,8 +30,8 @@ var main = defineCommand({
30
30
  auth: () => import("../auth-CN5EFFDE.js").then((m) => m.default),
31
31
  profile: () => import("../profile-OZJL5ZPT.js").then((m) => m.default),
32
32
  config: () => import("../config-DGZIMLZK.js").then((m) => m.default),
33
- completion: () => import("../completion-EKYW2Z3F.js").then((m) => m.default),
34
- upgrade: () => import("../upgrade-FCRZPJWQ.js").then((m) => m.default),
33
+ completion: () => import("../completion-4HOIJNFX.js").then((m) => m.default),
34
+ upgrade: () => import("../upgrade-EXMK4UHK.js").then((m) => m.default),
35
35
  "access-token": () => import("../access-token-WWE6BDJH.js").then((m) => m.default),
36
36
  address: () => import("../address-EH3C4CVB.js").then((m) => m.default),
37
37
  "address-suggestions": () => import("../address-suggestions-RRSLOBFW.js").then((m) => m.default),
@@ -134,13 +134,13 @@ process.stderr.on("error", (err) => {
134
134
  if (err.code === "EPIPE") process.exit(0);
135
135
  throw err;
136
136
  });
137
- var VERSION = true ? "0.1.47" : (await null).default.version;
137
+ var VERSION = true ? "0.1.49" : (await null).default.version;
138
138
  var reorderedArgv = hoistFlagsAfterSubcommand(process.argv.slice(2));
139
139
  process.argv = [process.argv[0], process.argv[1], ...reorderedArgv];
140
140
  var args = process.argv.slice(2);
141
141
  var completionsIdx = args.indexOf("--_completions");
142
142
  if (completionsIdx >= 0) {
143
- const { handleCompletions } = await import("../completion-EKYW2Z3F.js");
143
+ const { handleCompletions } = await import("../completion-4HOIJNFX.js");
144
144
  handleCompletions(args[completionsIdx + 1], args[completionsIdx + 2]);
145
145
  process.exit(0);
146
146
  }
@@ -155,7 +155,7 @@ var API_LIST = [
155
155
  kebabName: "blueprint-manifest",
156
156
  title: "Blueprint Manifest API",
157
157
  serverUrl: "https://blueprint-manifest.sls.epilot.io",
158
- operationCount: 55,
158
+ operationCount: 61,
159
159
  operationIds: [
160
160
  "getJob",
161
161
  "createExport",
@@ -211,7 +211,13 @@ var API_LIST = [
211
211
  "updateMarketplaceListingVersion",
212
212
  "publishMarketplaceListingVersion",
213
213
  "installBlueprintV3",
214
- "getBlueprintLineageV3"
214
+ "restoreBlueprintDeploymentV3",
215
+ "getRestorePreview",
216
+ "getBlueprintLineageV3",
217
+ "listUniquenessCriteria",
218
+ "getUniquenessCriteria",
219
+ "putUniquenessCriteria",
220
+ "deleteUniquenessCriteria"
215
221
  ]
216
222
  },
217
223
  {
@@ -1173,10 +1179,11 @@ var API_LIST = [
1173
1179
  kebabName: "snapshot",
1174
1180
  title: "Snapshot API",
1175
1181
  serverUrl: "https://snapshot.sls.epilot.io",
1176
- operationCount: 8,
1182
+ operationCount: 9,
1177
1183
  operationIds: [
1178
1184
  "listSnapshots",
1179
1185
  "createSnapshot",
1186
+ "captureOrgSnapshot",
1180
1187
  "getSnapshot",
1181
1188
  "deleteSnapshot",
1182
1189
  "restoreSnapshot",
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  API_LIST
4
- } from "./chunk-VOOQ4GMS.js";
4
+ } from "./chunk-44NTPQBR.js";
5
5
  import {
6
6
  DIM,
7
7
  GREEN,
@@ -72,7 +72,7 @@ ${GREEN}${BOLD}Upgraded to @epilot/cli@${latest}${RESET}
72
72
  }
73
73
  });
74
74
  var getCurrentVersion = () => {
75
- if (true) return "0.1.47";
75
+ if (true) return "0.1.49";
76
76
  try {
77
77
  const output = execSync("npm ls -g @epilot/cli --depth=0 --json 2>/dev/null", {
78
78
  encoding: "utf-8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epilot/cli",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "CLI for epilot APIs",
5
5
  "type": "module",
6
6
  "bin": {