@epilot/cli 0.1.81 → 0.1.83

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.81 — CLI for epilot APIs
32
+ epilot v0.1.83 — CLI for epilot APIs
33
33
 
34
34
  USAGE
35
35
  epilot <api> <operationId> [params...] [flags]
@@ -1105,6 +1105,136 @@
1105
1105
  }
1106
1106
  }
1107
1107
  },
1108
+ "/v2/blueprint-manifest/blueprints/{blueprint_id}/notes": {
1109
+ "post": {
1110
+ "operationId": "addBlueprintNote",
1111
+ "summary": "addBlueprintNote",
1112
+ "description": "Append an internal note to a blueprint. `id`, `created_at` and `created_by`\nare stamped server-side from the caller, so notes cannot be backdated or\nattributed to someone else. Existing notes are never modified.\n",
1113
+ "tags": [
1114
+ "Blueprints"
1115
+ ],
1116
+ "parameters": [
1117
+ {
1118
+ "in": "path",
1119
+ "required": true,
1120
+ "name": "blueprint_id",
1121
+ "schema": {
1122
+ "$ref": "#/components/schemas/BlueprintID"
1123
+ }
1124
+ }
1125
+ ],
1126
+ "requestBody": {
1127
+ "required": true,
1128
+ "content": {
1129
+ "application/json": {
1130
+ "schema": {
1131
+ "type": "object",
1132
+ "required": [
1133
+ "text"
1134
+ ],
1135
+ "properties": {
1136
+ "text": {
1137
+ "type": "string",
1138
+ "description": "Plain-text note body. Must not be blank.",
1139
+ "minLength": 1
1140
+ }
1141
+ }
1142
+ }
1143
+ }
1144
+ }
1145
+ },
1146
+ "responses": {
1147
+ "201": {
1148
+ "description": "The created note",
1149
+ "content": {
1150
+ "application/json": {
1151
+ "schema": {
1152
+ "$ref": "#/components/schemas/BlueprintNote"
1153
+ }
1154
+ }
1155
+ }
1156
+ },
1157
+ "400": {
1158
+ "description": "Blank note text",
1159
+ "content": {
1160
+ "application/json": {
1161
+ "schema": {
1162
+ "type": "object",
1163
+ "properties": {
1164
+ "message": {
1165
+ "type": "string"
1166
+ }
1167
+ }
1168
+ }
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+ }
1174
+ },
1175
+ "/v2/blueprint-manifest/blueprints/{blueprint_id}/notes/{note_id}": {
1176
+ "delete": {
1177
+ "operationId": "deleteBlueprintNote",
1178
+ "summary": "deleteBlueprintNote",
1179
+ "description": "Remove a single internal note from a blueprint.",
1180
+ "tags": [
1181
+ "Blueprints"
1182
+ ],
1183
+ "parameters": [
1184
+ {
1185
+ "in": "path",
1186
+ "required": true,
1187
+ "name": "blueprint_id",
1188
+ "schema": {
1189
+ "$ref": "#/components/schemas/BlueprintID"
1190
+ }
1191
+ },
1192
+ {
1193
+ "in": "path",
1194
+ "required": true,
1195
+ "name": "note_id",
1196
+ "schema": {
1197
+ "type": "string"
1198
+ }
1199
+ }
1200
+ ],
1201
+ "responses": {
1202
+ "200": {
1203
+ "description": "The blueprint's remaining notes",
1204
+ "content": {
1205
+ "application/json": {
1206
+ "schema": {
1207
+ "type": "object",
1208
+ "properties": {
1209
+ "notes": {
1210
+ "type": "array",
1211
+ "items": {
1212
+ "$ref": "#/components/schemas/BlueprintNote"
1213
+ }
1214
+ }
1215
+ }
1216
+ }
1217
+ }
1218
+ }
1219
+ },
1220
+ "404": {
1221
+ "description": "Blueprint or note not found",
1222
+ "content": {
1223
+ "application/json": {
1224
+ "schema": {
1225
+ "type": "object",
1226
+ "properties": {
1227
+ "message": {
1228
+ "type": "string"
1229
+ }
1230
+ }
1231
+ }
1232
+ }
1233
+ }
1234
+ }
1235
+ }
1236
+ }
1237
+ },
1108
1238
  "/v2/blueprint-manifest/blueprints/{blueprint_id}/validate": {
1109
1239
  "post": {
1110
1240
  "operationId": "validateBlueprint",
@@ -1208,7 +1338,11 @@
1208
1338
  "description": "Auth token with access to the destination org. Required for cross-org verification when the caller token only has access to the source org. If not provided, the caller's bearer token is used for both orgs."
1209
1339
  },
1210
1340
  "installation_job_id": {
1211
- "$ref": "#/components/schemas/BlueprintJobID",
1341
+ "allOf": [
1342
+ {
1343
+ "$ref": "#/components/schemas/BlueprintJobID"
1344
+ }
1345
+ ],
1212
1346
  "description": "Optional install job this verification is checking. If omitted, the latest destination blueprint installation job is used when available."
1213
1347
  },
1214
1348
  "sync_engine": {
@@ -2944,6 +3078,63 @@
2944
3078
  }
2945
3079
  }
2946
3080
  },
3081
+ "/v3/blueprint-manifest/blueprints:pre-install": {
3082
+ "post": {
3083
+ "operationId": "preInstallBlueprintV3",
3084
+ "summary": "Preview a V3 blueprint package before installation",
3085
+ "description": "Validates a signed V3 package and returns the destination-specific resource plan used by the install UI.",
3086
+ "tags": [
3087
+ "Blueprints"
3088
+ ],
3089
+ "requestBody": {
3090
+ "required": true,
3091
+ "content": {
3092
+ "application/json": {
3093
+ "schema": {
3094
+ "type": "object",
3095
+ "required": [
3096
+ "blueprint_file"
3097
+ ],
3098
+ "properties": {
3099
+ "blueprint_file": {
3100
+ "type": "string",
3101
+ "description": "S3 key of a V3 blueprint package previously uploaded through uploadManifest"
3102
+ },
3103
+ "source_blueprint_type": {
3104
+ "type": "string",
3105
+ "enum": [
3106
+ "marketplace"
3107
+ ]
3108
+ },
3109
+ "slug": {
3110
+ "type": "string",
3111
+ "description": "Marketplace slug to preserve across updates"
3112
+ }
3113
+ }
3114
+ }
3115
+ }
3116
+ }
3117
+ },
3118
+ "responses": {
3119
+ "200": {
3120
+ "description": "Destination-specific V3 blueprint preview",
3121
+ "content": {
3122
+ "application/json": {
3123
+ "schema": {
3124
+ "$ref": "#/components/schemas/BlueprintPreview"
3125
+ }
3126
+ }
3127
+ }
3128
+ },
3129
+ "400": {
3130
+ "description": "Invalid request or unsupported V3 package"
3131
+ },
3132
+ "404": {
3133
+ "description": "Blueprint package not found"
3134
+ }
3135
+ }
3136
+ }
3137
+ },
2947
3138
  "/v3/blueprint-manifest/blueprint:install": {
2948
3139
  "post": {
2949
3140
  "operationId": "installBlueprintV3",
@@ -2994,6 +3185,12 @@
2994
3185
  "type": "string",
2995
3186
  "description": "Auth token for the destination org. Required for cross-org installs where the caller's token belongs to the source org. Defaults to the caller's bearer token."
2996
3187
  },
3188
+ "source_blueprint_type": {
3189
+ "type": "string",
3190
+ "enum": [
3191
+ "marketplace"
3192
+ ]
3193
+ },
2997
3194
  "options": {
2998
3195
  "$ref": "#/components/schemas/BlueprintInstallationJobOptions"
2999
3196
  },
@@ -3012,7 +3209,9 @@
3012
3209
  "sameOrgPlanThenContinue": {
3013
3210
  "summary": "Same-org install, manual approval (default)",
3014
3211
  "value": {
3015
- "source_blueprint_id": "11111111-1111-1111-1111-111111111111"
3212
+ "source_org_id": "source-org-id",
3213
+ "source_blueprint_id": "11111111-1111-1111-1111-111111111111",
3214
+ "destination_org_id": "source-org-id"
3016
3215
  }
3017
3216
  },
3018
3217
  "crossOrgAutoApply": {
@@ -3186,6 +3385,121 @@
3186
3385
  }
3187
3386
  }
3188
3387
  },
3388
+ "/v3/blueprint-manifest/blueprints/{blueprint_id}/deployments/{job_id}:health-check": {
3389
+ "post": {
3390
+ "operationId": "triggerDeploymentHealthCheckV3",
3391
+ "summary": "Run a health check on a deployment",
3392
+ "description": "Starts a read-only health scan of the resources this deployment's\nblueprint instance tracks in the destination org (see\ndocs/rfcs/RFC-org-health-check.md, Phase 0). Checks:\n\n - live readability — every lineage-tracked resource is read back\n via its adapter; tracked-but-unreadable resources are flagged.\n - referential integrity — destination payloads containing\n unreplaced source-org ids, or references to tracked resources\n that are not readable.\n - install completeness — install operations whose final attempt\n ended `failed` or `skipped`, with their rejection reasons.\n\nAsync — returns 202 immediately with a `running` report stub. Poll\nthe health-report endpoint until `status` is `completed` or\n`failed`. Never mutates any resource.\n",
3393
+ "tags": [
3394
+ "Blueprints"
3395
+ ],
3396
+ "parameters": [
3397
+ {
3398
+ "in": "path",
3399
+ "name": "blueprint_id",
3400
+ "required": true,
3401
+ "schema": {
3402
+ "$ref": "#/components/schemas/BlueprintID"
3403
+ }
3404
+ },
3405
+ {
3406
+ "in": "path",
3407
+ "name": "job_id",
3408
+ "required": true,
3409
+ "description": "The install job whose deployment is being checked.",
3410
+ "schema": {
3411
+ "$ref": "#/components/schemas/BlueprintJobID"
3412
+ }
3413
+ }
3414
+ ],
3415
+ "requestBody": {
3416
+ "required": false,
3417
+ "content": {
3418
+ "application/json": {
3419
+ "schema": {
3420
+ "type": "object",
3421
+ "properties": {
3422
+ "source_org_id": {
3423
+ "type": "string",
3424
+ "description": "Source/sandbox org to deep-compare entity mappings against."
3425
+ },
3426
+ "source_auth_token": {
3427
+ "type": "string",
3428
+ "description": "Read token for the source org. Never persisted; used only for this scan."
3429
+ }
3430
+ }
3431
+ }
3432
+ }
3433
+ }
3434
+ },
3435
+ "responses": {
3436
+ "202": {
3437
+ "description": "Health check started",
3438
+ "headers": {
3439
+ "Location": {
3440
+ "description": "URL to poll the health report",
3441
+ "schema": {
3442
+ "type": "string"
3443
+ }
3444
+ }
3445
+ },
3446
+ "content": {
3447
+ "application/json": {
3448
+ "schema": {
3449
+ "$ref": "#/components/schemas/DeploymentHealthReport"
3450
+ }
3451
+ }
3452
+ }
3453
+ },
3454
+ "404": {
3455
+ "description": "Blueprint not found, or no deployment with the given job_id on this blueprint."
3456
+ }
3457
+ }
3458
+ }
3459
+ },
3460
+ "/v3/blueprint-manifest/blueprints/{blueprint_id}/deployments/{job_id}/health-report": {
3461
+ "get": {
3462
+ "operationId": "getDeploymentHealthReportV3",
3463
+ "summary": "Get the latest health report of a deployment",
3464
+ "description": "Returns the most recent health report produced for this deployment\nby the `:health-check` endpoint. Idempotent and side-effect free.\n",
3465
+ "tags": [
3466
+ "Blueprints"
3467
+ ],
3468
+ "parameters": [
3469
+ {
3470
+ "in": "path",
3471
+ "name": "blueprint_id",
3472
+ "required": true,
3473
+ "schema": {
3474
+ "$ref": "#/components/schemas/BlueprintID"
3475
+ }
3476
+ },
3477
+ {
3478
+ "in": "path",
3479
+ "name": "job_id",
3480
+ "required": true,
3481
+ "schema": {
3482
+ "$ref": "#/components/schemas/BlueprintJobID"
3483
+ }
3484
+ }
3485
+ ],
3486
+ "responses": {
3487
+ "200": {
3488
+ "description": "Latest health report",
3489
+ "content": {
3490
+ "application/json": {
3491
+ "schema": {
3492
+ "$ref": "#/components/schemas/DeploymentHealthReport"
3493
+ }
3494
+ }
3495
+ }
3496
+ },
3497
+ "404": {
3498
+ "description": "No health report exists for this deployment yet."
3499
+ }
3500
+ }
3501
+ }
3502
+ },
3189
3503
  "/v3/blueprint-manifest/blueprints/{blueprint_id}/lineage": {
3190
3504
  "get": {
3191
3505
  "operationId": "getBlueprintLineageV3",
@@ -3874,6 +4188,34 @@
3874
4188
  }
3875
4189
  ]
3876
4190
  },
4191
+ "BlueprintNote": {
4192
+ "type": "object",
4193
+ "description": "A single internal note on a blueprint.",
4194
+ "required": [
4195
+ "id",
4196
+ "text",
4197
+ "created_at"
4198
+ ],
4199
+ "properties": {
4200
+ "id": {
4201
+ "type": "string",
4202
+ "description": "Server-generated note id.",
4203
+ "example": "3f1c9b0e-2f3a-4a1f-9a3e-6f2b8c7d1e40"
4204
+ },
4205
+ "text": {
4206
+ "type": "string",
4207
+ "description": "Plain-text note body.",
4208
+ "example": "Adjusted the meter-reading journey for the §14a rollout."
4209
+ },
4210
+ "created_at": {
4211
+ "type": "string",
4212
+ "format": "date-time"
4213
+ },
4214
+ "created_by": {
4215
+ "$ref": "#/components/schemas/CallerIdentity"
4216
+ }
4217
+ }
4218
+ },
3877
4219
  "BlueprintID": {
3878
4220
  "type": "string",
3879
4221
  "description": "ID of a blueprint",
@@ -3911,6 +4253,13 @@
3911
4253
  }
3912
4254
  }
3913
4255
  },
4256
+ "notes": {
4257
+ "type": "array",
4258
+ "description": "Internal collaboration notes, oldest first. Append-only: each entry is\nstamped with its author and creation time server-side and is never\nrewritten, so the history of who noted what stays intact. Written via\n`addBlueprintNote` / `deleteBlueprintNote`, not by `updateBlueprint`.\n\nAvailable on every blueprint including marketplace ones (whose\n`description` is read-only), and never included in the published\nmarketplace package — see `buildMetadata` in\n`services/blueprint-v3/published-blueprint.ts`. Carried to a\ndestination org only when an install/sync passes\n`options.sync_notes: true`.\n",
4259
+ "items": {
4260
+ "$ref": "#/components/schemas/BlueprintNote"
4261
+ }
4262
+ },
3914
4263
  "version": {
3915
4264
  "type": "string"
3916
4265
  },
@@ -5108,6 +5457,344 @@
5108
5457
  }
5109
5458
  }
5110
5459
  },
5460
+ "HealthFinding": {
5461
+ "type": "object",
5462
+ "required": [
5463
+ "check_id",
5464
+ "code",
5465
+ "severity",
5466
+ "resource_type",
5467
+ "lineage_id",
5468
+ "message"
5469
+ ],
5470
+ "properties": {
5471
+ "check_id": {
5472
+ "type": "string",
5473
+ "enum": [
5474
+ "live_readability",
5475
+ "referential_integrity",
5476
+ "install_completeness",
5477
+ "schema_consistency",
5478
+ "mapping_integrity",
5479
+ "execution_readiness",
5480
+ "catalog_hygiene",
5481
+ "spec_conformance"
5482
+ ]
5483
+ },
5484
+ "code": {
5485
+ "type": "string",
5486
+ "enum": [
5487
+ "missing_in_destination",
5488
+ "fetch_error",
5489
+ "no_readback",
5490
+ "unreplaced_source_reference",
5491
+ "broken_internal_reference",
5492
+ "dropped_at_install",
5493
+ "orphaned_group_reference",
5494
+ "uuid_group_label",
5495
+ "unreachable_attribute_purpose",
5496
+ "duplicate_attribute_name",
5497
+ "duplicate_headline",
5498
+ "broken_mapping_reference",
5499
+ "stale_mapping_version",
5500
+ "mapping_slot_mismatch",
5501
+ "mapping_parity_mismatch",
5502
+ "stale_lineage",
5503
+ "broken_trigger_reference",
5504
+ "broken_action_reference",
5505
+ "broken_workflow_step",
5506
+ "invalid_mapping_target",
5507
+ "invalid_mapping_source",
5508
+ "invalid_mapping_version",
5509
+ "unknown_mapping_attribute",
5510
+ "workflow_edge_limit",
5511
+ "dead_purpose_reference",
5512
+ "broken_portal_reference",
5513
+ "orphaned_portal_block",
5514
+ "broken_closing_reason",
5515
+ "broken_journey_settings",
5516
+ "unresolved_assignee",
5517
+ "current_write_invalid",
5518
+ "duplicate_live_resource",
5519
+ "missing_file_content",
5520
+ "file_etag_mismatch",
5521
+ "incomplete_webhook",
5522
+ "broken_template_reference",
5523
+ "orphaned_price",
5524
+ "duplicate_price",
5525
+ "inactive_price_in_use",
5526
+ "cross_org_reference"
5527
+ ]
5528
+ },
5529
+ "severity": {
5530
+ "type": "string",
5531
+ "enum": [
5532
+ "error",
5533
+ "warning",
5534
+ "info"
5535
+ ]
5536
+ },
5537
+ "resource_type": {
5538
+ "type": "string"
5539
+ },
5540
+ "lineage_id": {
5541
+ "type": "string"
5542
+ },
5543
+ "target_id": {
5544
+ "type": "string"
5545
+ },
5546
+ "resource_name": {
5547
+ "type": "string",
5548
+ "description": "Human-readable name of the affected resource"
5549
+ },
5550
+ "message": {
5551
+ "type": "string"
5552
+ },
5553
+ "verdict": {
5554
+ "type": "string",
5555
+ "description": "Mechanical root-cause classification and suggested fix, when determinable"
5556
+ },
5557
+ "evidence": {
5558
+ "type": "object",
5559
+ "description": "Check-specific evidence, e.g. the JSON path and referenced id of a broken reference.",
5560
+ "properties": {
5561
+ "path": {
5562
+ "type": "string"
5563
+ },
5564
+ "referenced_id": {
5565
+ "type": "string"
5566
+ },
5567
+ "referenced_type": {
5568
+ "type": "string"
5569
+ },
5570
+ "referenced_name": {
5571
+ "type": "string",
5572
+ "description": "Human-readable name or logical slug of the referenced source resource"
5573
+ },
5574
+ "referenced_lineage_id": {
5575
+ "type": "string",
5576
+ "description": "Logical source lineage identity of the referenced resource"
5577
+ },
5578
+ "expected_target_id": {
5579
+ "type": "string",
5580
+ "description": "Destination id that should have replaced the source reference"
5581
+ },
5582
+ "reference_kind": {
5583
+ "type": "string",
5584
+ "description": "Human-readable description of the exact field carrying the reference"
5585
+ },
5586
+ "operation": {
5587
+ "type": "string"
5588
+ },
5589
+ "rejection_reason": {
5590
+ "type": "string"
5591
+ },
5592
+ "error_message": {
5593
+ "type": "string"
5594
+ },
5595
+ "response_status": {
5596
+ "type": "integer"
5597
+ }
5598
+ }
5599
+ }
5600
+ }
5601
+ },
5602
+ "HealthCheckCoverage": {
5603
+ "type": "object",
5604
+ "required": [
5605
+ "check_id",
5606
+ "status",
5607
+ "scope",
5608
+ "resources_considered",
5609
+ "details"
5610
+ ],
5611
+ "properties": {
5612
+ "check_id": {
5613
+ "type": "string",
5614
+ "enum": [
5615
+ "live_readability",
5616
+ "referential_integrity",
5617
+ "install_completeness",
5618
+ "schema_consistency",
5619
+ "mapping_integrity",
5620
+ "execution_readiness",
5621
+ "spec_conformance"
5622
+ ]
5623
+ },
5624
+ "status": {
5625
+ "type": "string",
5626
+ "enum": [
5627
+ "completed",
5628
+ "partial",
5629
+ "skipped",
5630
+ "not_applicable"
5631
+ ]
5632
+ },
5633
+ "scope": {
5634
+ "type": "string",
5635
+ "enum": [
5636
+ "tracked_resources",
5637
+ "org_wide",
5638
+ "source_comparison"
5639
+ ]
5640
+ },
5641
+ "resources_considered": {
5642
+ "type": "integer"
5643
+ },
5644
+ "details": {
5645
+ "type": "array",
5646
+ "items": {
5647
+ "type": "string"
5648
+ }
5649
+ }
5650
+ }
5651
+ },
5652
+ "HealthResourceTypeCoverage": {
5653
+ "type": "object",
5654
+ "required": [
5655
+ "resource_type",
5656
+ "tracked",
5657
+ "readable_by_lineage",
5658
+ "missing_by_lineage",
5659
+ "read_errors",
5660
+ "unchecked",
5661
+ "specialized_checks",
5662
+ "known_blind_spots"
5663
+ ],
5664
+ "properties": {
5665
+ "resource_type": {
5666
+ "type": "string"
5667
+ },
5668
+ "tracked": {
5669
+ "type": "integer"
5670
+ },
5671
+ "readable_by_lineage": {
5672
+ "type": "integer"
5673
+ },
5674
+ "missing_by_lineage": {
5675
+ "type": "integer"
5676
+ },
5677
+ "read_errors": {
5678
+ "type": "integer"
5679
+ },
5680
+ "unchecked": {
5681
+ "type": "integer"
5682
+ },
5683
+ "specialized_checks": {
5684
+ "type": "array",
5685
+ "items": {
5686
+ "type": "string",
5687
+ "enum": [
5688
+ "live_readability",
5689
+ "referential_integrity",
5690
+ "install_completeness",
5691
+ "schema_consistency",
5692
+ "mapping_integrity",
5693
+ "execution_readiness",
5694
+ "spec_conformance"
5695
+ ]
5696
+ }
5697
+ },
5698
+ "known_blind_spots": {
5699
+ "type": "array",
5700
+ "description": "Type-specific contracts the current scanner explicitly does not claim to validate.",
5701
+ "items": {
5702
+ "type": "string"
5703
+ }
5704
+ }
5705
+ }
5706
+ },
5707
+ "HealthScanCoverage": {
5708
+ "type": "object",
5709
+ "required": [
5710
+ "checks",
5711
+ "resource_types"
5712
+ ],
5713
+ "properties": {
5714
+ "checks": {
5715
+ "type": "array",
5716
+ "items": {
5717
+ "$ref": "#/components/schemas/HealthCheckCoverage"
5718
+ }
5719
+ },
5720
+ "resource_types": {
5721
+ "type": "array",
5722
+ "items": {
5723
+ "$ref": "#/components/schemas/HealthResourceTypeCoverage"
5724
+ }
5725
+ }
5726
+ }
5727
+ },
5728
+ "DeploymentHealthReport": {
5729
+ "type": "object",
5730
+ "required": [
5731
+ "status",
5732
+ "job_id",
5733
+ "blueprint_instance_id",
5734
+ "destination_org_id",
5735
+ "generated_at"
5736
+ ],
5737
+ "properties": {
5738
+ "status": {
5739
+ "type": "string",
5740
+ "enum": [
5741
+ "running",
5742
+ "completed",
5743
+ "failed"
5744
+ ]
5745
+ },
5746
+ "job_id": {
5747
+ "$ref": "#/components/schemas/BlueprintJobID"
5748
+ },
5749
+ "blueprint_instance_id": {
5750
+ "$ref": "#/components/schemas/BlueprintID"
5751
+ },
5752
+ "destination_org_id": {
5753
+ "type": "string"
5754
+ },
5755
+ "generated_at": {
5756
+ "type": "string",
5757
+ "format": "date-time"
5758
+ },
5759
+ "html_url": {
5760
+ "type": "string",
5761
+ "description": "Presigned link to the rendered HTML report (present once the check completed)"
5762
+ },
5763
+ "summary": {
5764
+ "type": "object",
5765
+ "properties": {
5766
+ "resources_scanned": {
5767
+ "type": "integer"
5768
+ },
5769
+ "unchecked": {
5770
+ "type": "integer"
5771
+ },
5772
+ "errors": {
5773
+ "type": "integer"
5774
+ },
5775
+ "warnings": {
5776
+ "type": "integer"
5777
+ },
5778
+ "infos": {
5779
+ "type": "integer"
5780
+ }
5781
+ }
5782
+ },
5783
+ "findings": {
5784
+ "type": "array",
5785
+ "items": {
5786
+ "$ref": "#/components/schemas/HealthFinding"
5787
+ }
5788
+ },
5789
+ "coverage": {
5790
+ "$ref": "#/components/schemas/HealthScanCoverage"
5791
+ },
5792
+ "error": {
5793
+ "type": "string",
5794
+ "description": "Failure reason when status is `failed`."
5795
+ }
5796
+ }
5797
+ },
5111
5798
  "RestoreOutcome": {
5112
5799
  "type": "object",
5113
5800
  "properties": {
@@ -5258,7 +5945,11 @@
5258
5945
  "$ref": "#/components/schemas/BlueprintID"
5259
5946
  },
5260
5947
  "installation_job_id": {
5261
- "$ref": "#/components/schemas/BlueprintJobID",
5948
+ "allOf": [
5949
+ {
5950
+ "$ref": "#/components/schemas/BlueprintJobID"
5951
+ }
5952
+ ],
5262
5953
  "description": "Install job this verification is checking, when known."
5263
5954
  },
5264
5955
  "sync_engine": {
@@ -5497,6 +6188,11 @@
5497
6188
  "items": {
5498
6189
  "type": "string"
5499
6190
  }
6191
+ },
6192
+ "sync_notes": {
6193
+ "description": "When `true`, the source blueprint's `notes` overwrite the destination\nblueprint's `notes`. Defaults to `false`, which leaves the\ndestination's notes untouched.\n",
6194
+ "type": "boolean",
6195
+ "default": false
5500
6196
  }
5501
6197
  }
5502
6198
  },
@@ -3,7 +3,7 @@ import {
3
3
  log,
4
4
  readManifest,
5
5
  writeManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/app/index.ts
4
+ import { defineCommand } from "citty";
5
+ var app_default = defineCommand({
6
+ meta: {
7
+ name: "app",
8
+ description: "Manage epilot Apps \u2014 create, deploy, and manage app manifests"
9
+ },
10
+ subCommands: {
11
+ init: () => import("./init-345HGB5B.js").then((m) => m.default),
12
+ "add-component": () => import("./add-component-CJIQYDO5.js").then((m) => m.default),
13
+ "remove-component": () => import("./remove-component-LPTHVN4P.js").then((m) => m.default),
14
+ validate: () => import("./validate-TLSOTJAY.js").then((m) => m.default),
15
+ deploy: () => import("./deploy-NRQHZ635.js").then((m) => m.default),
16
+ export: () => import("./export-ZRDJCALM.js").then((m) => m.default),
17
+ versions: () => import("./versions-VA4H3EPK.js").then((m) => m.default),
18
+ review: () => import("./review-OZTM3XBD.js").then((m) => m.default),
19
+ api: () => import("./api-5W2UMWCW.js").then((m) => m.default)
20
+ }
21
+ });
22
+ export {
23
+ app_default as default
24
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  API_LIST
4
- } from "../chunk-SKN3M7X4.js";
4
+ } from "../chunk-5D7GCYYX.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.81",
14
+ version: "0.1.83",
15
15
  description: "CLI for epilot APIs"
16
16
  },
17
17
  args: {
@@ -30,13 +30,13 @@ var main = defineCommand({
30
30
  auth: () => import("../auth-4HG7B2GC.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-GMGHDDM3.js").then((m) => m.default),
34
- upgrade: () => import("../upgrade-YMDNCJ6J.js").then((m) => m.default),
33
+ completion: () => import("../completion-N6A4VCAE.js").then((m) => m.default),
34
+ upgrade: () => import("../upgrade-5RN2XG2M.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),
38
38
  "ai-agents": () => import("../ai-agents-53M2KHPI.js").then((m) => m.default),
39
- app: () => import("../app-EULJIEDB.js").then((m) => m.default),
39
+ app: () => import("../app-TIWZ2LQC.js").then((m) => m.default),
40
40
  "audit-logs": () => import("../audit-logs-YFRK3EFU.js").then((m) => m.default),
41
41
  automation: () => import("../automation-4DEE3TUI.js").then((m) => m.default),
42
42
  billing: () => import("../billing-XX4VVOPI.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.81" : (await null).default.version;
137
+ var VERSION = true ? "0.1.83" : (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-GMGHDDM3.js");
143
+ const { handleCompletions } = await import("../completion-N6A4VCAE.js");
144
144
  handleCompletions(args[completionsIdx + 1], args[completionsIdx + 2]);
145
145
  process.exit(0);
146
146
  }
@@ -169,7 +169,7 @@ var API_LIST = [
169
169
  kebabName: "blueprint-manifest",
170
170
  title: "Blueprint Manifest API",
171
171
  serverUrl: "https://blueprint-manifest.sls.epilot.io",
172
- operationCount: 66,
172
+ operationCount: 71,
173
173
  operationIds: [
174
174
  "getJob",
175
175
  "createExport",
@@ -190,6 +190,8 @@ var API_LIST = [
190
190
  "getBlueprint",
191
191
  "updateBlueprint",
192
192
  "deleteBlueprint",
193
+ "addBlueprintNote",
194
+ "deleteBlueprintNote",
193
195
  "validateBlueprint",
194
196
  "verifyBlueprint",
195
197
  "detectPatchChanges",
@@ -225,9 +227,12 @@ var API_LIST = [
225
227
  "updateMarketplaceListingVersion",
226
228
  "publishMarketplaceListingVersion",
227
229
  "publishBlueprintV3",
230
+ "preInstallBlueprintV3",
228
231
  "installBlueprintV3",
229
232
  "restoreBlueprintDeploymentV3",
230
233
  "getRestorePreview",
234
+ "triggerDeploymentHealthCheckV3",
235
+ "getDeploymentHealthReportV3",
231
236
  "getBlueprintLineageV3",
232
237
  "createBulkInstallV3",
233
238
  "getBulkInstallV3",
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ loadCredentials,
3
4
  resolveToken
4
5
  } from "./chunk-M3M3C5WH.js";
6
+ import {
7
+ getResolvedProfile
8
+ } from "./chunk-YHQA2AVG.js";
5
9
  import {
6
10
  BOLD,
7
11
  DIM,
@@ -121,6 +125,33 @@ async function request(baseUrl, token, method, path, body) {
121
125
  }
122
126
  return text;
123
127
  }
128
+ var parseJwtPayload = (token) => {
129
+ try {
130
+ const parts = token.split(".");
131
+ if (parts.length !== 3) return null;
132
+ const payload = Buffer.from(parts[1], "base64url").toString("utf-8");
133
+ return JSON.parse(payload);
134
+ } catch {
135
+ return null;
136
+ }
137
+ };
138
+ function resolveOrgId(tokenFlag, profile) {
139
+ const token = resolveToken(tokenFlag, profile);
140
+ const claims = token ? parseJwtPayload(token) : null;
141
+ const fromToken = claims?.org_id ?? claims?.["custom:ivy_org_id"];
142
+ if (fromToken) return fromToken;
143
+ return getResolvedProfile(profile)?.org_id ?? loadCredentials()?.org_id;
144
+ }
145
+ function derivePermissionsBaseUrl(appBaseUrl) {
146
+ try {
147
+ const url = new URL(appBaseUrl);
148
+ if (!url.hostname.startsWith("app.")) return null;
149
+ url.hostname = url.hostname.replace(/^app\./, "permissions.");
150
+ return url.origin;
151
+ } catch {
152
+ return null;
153
+ }
154
+ }
124
155
  function createAppApiClient(opts) {
125
156
  const baseUrl = opts.server ?? DEFAULT_BASE_URL;
126
157
  const getToken = () => {
@@ -150,6 +181,28 @@ function createAppApiClient(opts) {
150
181
  async patchVersion(appId, version, payload) {
151
182
  await request(baseUrl, getToken(), "PATCH", `/v1/app-configurations/${appId}/versions/${version}`, payload);
152
183
  },
184
+ /**
185
+ * Upsert the app's role in the developer's own organization with the
186
+ * manifest grants. The role id is attached to the app version via
187
+ * `role_id`; on installation the App API creates a copy of it (from the
188
+ * version's grants) in the installer's organization.
189
+ */
190
+ async upsertAppRole(params) {
191
+ const permissionsBaseUrl = derivePermissionsBaseUrl(baseUrl);
192
+ if (!permissionsBaseUrl) {
193
+ throw new Error(`Cannot derive permissions API URL from ${baseUrl}`);
194
+ }
195
+ const roleId = `${params.orgId}:${params.appId}`;
196
+ await request(permissionsBaseUrl, getToken(), "PUT", `/v1/permissions/roles/${roleId}`, {
197
+ id: roleId,
198
+ organization_id: params.orgId,
199
+ type: "user_role",
200
+ slug: params.appId,
201
+ name: `Automatically created by App ${params.appName}`,
202
+ grants: params.grants
203
+ });
204
+ return roleId;
205
+ },
153
206
  async cloneVersion(appId, version) {
154
207
  return request(
155
208
  baseUrl,
@@ -358,6 +411,7 @@ export {
358
411
  validateManifest,
359
412
  readManifest,
360
413
  writeManifest,
414
+ resolveOrgId,
361
415
  createAppApiClient,
362
416
  uploadFileToPresignedUrl,
363
417
  uploadDirectoryAsZip,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  API_LIST
4
- } from "./chunk-SKN3M7X4.js";
4
+ } from "./chunk-5D7GCYYX.js";
5
5
  import {
6
6
  DIM,
7
7
  GREEN,
@@ -4,10 +4,11 @@ import {
4
4
  formatFileSize,
5
5
  log,
6
6
  readManifest,
7
+ resolveOrgId,
7
8
  uploadDirectoryAsZip,
8
9
  uploadFileToPresignedUrl,
9
10
  writeManifest
10
- } from "./chunk-4TDAAJ6H.js";
11
+ } from "./chunk-QOD77YLW.js";
11
12
  import "./chunk-M3M3C5WH.js";
12
13
  import "./chunk-YHQA2AVG.js";
13
14
  import "./chunk-7ZQ666ZQ.js";
@@ -106,10 +107,32 @@ var deploy_default = defineCommand({
106
107
  }
107
108
  if (manifest.permissions?.length || manifest.blueprint?.manifest_id) {
108
109
  if (dryRun) {
110
+ if (manifest.permissions?.length) {
111
+ log.info("[dry-run] Would upsert app role in developer org");
112
+ }
109
113
  log.info("[dry-run] Would update version permissions/blueprint");
110
114
  } else {
115
+ let roleId;
116
+ if (manifest.permissions?.length) {
117
+ const orgId = resolveOrgId(args.token, args.profile);
118
+ if (orgId) {
119
+ try {
120
+ roleId = await client.upsertAppRole({
121
+ orgId,
122
+ appId,
123
+ appName: manifest.name,
124
+ grants: manifest.permissions
125
+ });
126
+ log.success(`Upserted app role ${roleId}`);
127
+ } catch (err) {
128
+ log.warn(`Could not upsert app role: ${err.message}`);
129
+ }
130
+ } else {
131
+ log.warn("Could not resolve org id \u2014 attaching grants without a developer-org role");
132
+ }
133
+ }
111
134
  await client.patchVersion(appId, targetVersion, {
112
- ...manifest.permissions?.length ? { grants: manifest.permissions } : {},
135
+ ...manifest.permissions?.length ? { grants: manifest.permissions, ...roleId ? { role_id: roleId } : {} } : {},
113
136
  ...manifest.blueprint?.manifest_id ? { manifest_id: manifest.blueprint.manifest_id } : {}
114
137
  });
115
138
  log.success(`Updated version ${targetVersion} (permissions/blueprint)`);
@@ -4,7 +4,7 @@ import {
4
4
  log,
5
5
  toManifest,
6
6
  writeManifest
7
- } from "./chunk-4TDAAJ6H.js";
7
+ } from "./chunk-QOD77YLW.js";
8
8
  import "./chunk-M3M3C5WH.js";
9
9
  import "./chunk-YHQA2AVG.js";
10
10
  import "./chunk-7ZQ666ZQ.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  log,
4
4
  writeManifest
5
- } from "./chunk-4TDAAJ6H.js";
5
+ } from "./chunk-QOD77YLW.js";
6
6
  import "./chunk-M3M3C5WH.js";
7
7
  import "./chunk-YHQA2AVG.js";
8
8
  import "./chunk-7ZQ666ZQ.js";
@@ -3,7 +3,7 @@ import {
3
3
  log,
4
4
  readManifest,
5
5
  writeManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
@@ -3,7 +3,7 @@ import {
3
3
  createAppApiClient,
4
4
  log,
5
5
  readManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
@@ -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.81";
75
+ if (true) return "0.1.83";
76
76
  try {
77
77
  const output = execSync("npm ls -g @epilot/cli --depth=0 --json 2>/dev/null", {
78
78
  encoding: "utf-8",
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  log,
4
4
  validateManifest
5
- } from "./chunk-4TDAAJ6H.js";
5
+ } from "./chunk-QOD77YLW.js";
6
6
  import "./chunk-M3M3C5WH.js";
7
7
  import "./chunk-YHQA2AVG.js";
8
8
  import "./chunk-7ZQ666ZQ.js";
@@ -3,7 +3,7 @@ import {
3
3
  createAppApiClient,
4
4
  log,
5
5
  readManifest
6
- } from "./chunk-4TDAAJ6H.js";
6
+ } from "./chunk-QOD77YLW.js";
7
7
  import "./chunk-M3M3C5WH.js";
8
8
  import "./chunk-YHQA2AVG.js";
9
9
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epilot/cli",
3
- "version": "0.1.81",
3
+ "version": "0.1.83",
4
4
  "description": "CLI for epilot APIs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/commands/app/index.ts
4
- import { defineCommand } from "citty";
5
- var app_default = defineCommand({
6
- meta: {
7
- name: "app",
8
- description: "Manage epilot Apps \u2014 create, deploy, and manage app manifests"
9
- },
10
- subCommands: {
11
- init: () => import("./init-QZTZF2JC.js").then((m) => m.default),
12
- "add-component": () => import("./add-component-IVVCAUGY.js").then((m) => m.default),
13
- "remove-component": () => import("./remove-component-HJA5OA3H.js").then((m) => m.default),
14
- validate: () => import("./validate-QUSO4DR4.js").then((m) => m.default),
15
- deploy: () => import("./deploy-JMJFXUKQ.js").then((m) => m.default),
16
- export: () => import("./export-JDDMBBNS.js").then((m) => m.default),
17
- versions: () => import("./versions-EUTT4SNW.js").then((m) => m.default),
18
- review: () => import("./review-7M27IRW6.js").then((m) => m.default),
19
- api: () => import("./api-5W2UMWCW.js").then((m) => m.default)
20
- }
21
- });
22
- export {
23
- app_default as default
24
- };