@runveric/cli 0.5.0 → 0.5.1

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
@@ -4,7 +4,7 @@
4
4
  production runner image — without pushing anything or signing in.**
5
5
 
6
6
  ```sh
7
- npx @runveric/cli@0.5.0 init --id yourteam/restart-web-tier
7
+ npx @runveric/cli@0.5.1 init --id yourteam/restart-web-tier
8
8
  ```
9
9
 
10
10
  ---
@@ -40,7 +40,7 @@ script outside the platform. Nothing in the product offered that. This does.
40
40
  ## Install
41
41
 
42
42
  ```sh
43
- npx @runveric/cli@0.5.0 <command> # no install
43
+ npx @runveric/cli@0.5.1 <command> # no install
44
44
  npm install -g @runveric/cli # or install the `runveric` bin
45
45
  ```
46
46
 
@@ -63,7 +63,7 @@ Pin the version your Runveric deployment shows you on its Author page rather tha
63
63
  Scaffold a PowerShell action, look at what you got, validate it, and run it locally:
64
64
 
65
65
  ```sh
66
- $ npx @runveric/cli@0.5.0 init restart-web-tier \
66
+ $ npx @runveric/cli@0.5.1 init restart-web-tier \
67
67
  --id acme/restart-web-tier \
68
68
  --interpreter powershell \
69
69
  --yes
@@ -174,9 +174,9 @@ time through the action protocol, with handlers written against
174
174
  commands, so the four verbs keep meaning what they mean.
175
175
 
176
176
  ```sh
177
- npx @runveric/cli@0.5.0 action init action-azure-disk-snapshot --key azure.disk.snapshot --name "Snapshot Disk"
177
+ npx @runveric/cli@0.5.1 action init action-azure-disk-snapshot --key azure.disk.snapshot --name "Snapshot Disk"
178
178
  cd action-azure-disk-snapshot
179
- npm install # writes package-lock.json — commit it; the publish workflow runs `npm ci`
179
+ npm install # writes package-lock.json — commit it; the publish workflow runs `npm ci --ignore-scripts`
180
180
  npm test # type-checks src/, builds dist/index.js, then validate, execute and rollback through `action test`
181
181
  ```
182
182
 
@@ -218,9 +218,11 @@ tokens.
218
218
  every message again, and the catalog's release workflow verifies and signs the image before anything
219
219
  can run it. Neither happens here, and a local pass does not claim them.
220
220
 
221
- Publishing is a tag equal to `catalog.yaml`'s `version`: the workflow builds the image from the
222
- action runtime by digest and publishes the catalog artifact; the catalog's release workflow verifies
223
- and signs it.
221
+ Publishing is a tag equal to `catalog.yaml`'s `version`, in two jobs. `build`, which can write nothing,
222
+ installs with `npm ci --ignore-scripts` (no dependency's install script runs), type-checks and builds
223
+ `dist/index.js`. `publish`, which holds the package write, installs nothing: it builds the image from the
224
+ action runtime by digest, pushes it by digest and publishes the catalog artifact. The catalog's release
225
+ workflow then verifies and signs it.
224
226
 
225
227
  ---
226
228
 
@@ -232,21 +234,21 @@ publish and verify with these commands:
232
234
 
233
235
  ```sh
234
236
  # one action's manifest, verbatim — stdout: <key>=<repository>@<digest>
235
- npx @runveric/cli@0.5.0 catalog publish-action --manifest catalog.yaml \
237
+ npx @runveric/cli@0.5.1 catalog publish-action --manifest catalog.yaml \
236
238
  --to ghcr.io/<org>/action-azure-vm-stop
237
239
 
238
240
  # an ENGINE action: its manifest and the image its workflow pushed, by digest, to the same package
239
- npx @runveric/cli@0.5.0 catalog publish-action --manifest catalog.yaml \
241
+ npx @runveric/cli@0.5.1 catalog publish-action --manifest catalog.yaml \
240
242
  --to ghcr.io/<org>/action-azure-publicip-delete-unattached \
241
243
  --image ghcr.io/<org>/action-azure-publicip-delete-unattached@sha256:<digest>
242
244
 
243
245
  # a release naming each action artifact by digest — stdout: <repository>@<digest>
244
- npx @runveric/cli@0.5.0 catalog publish-release --from release.yaml --to ghcr.io/<org>/catalog
246
+ npx @runveric/cli@0.5.1 catalog publish-release --from release.yaml --to ghcr.io/<org>/catalog
245
247
 
246
248
  # what the release workflow may sign: each engine action's image, judged by the server's rule
247
249
  # — stdout: one <repository>@<digest> per image that passed
248
- npx @runveric/cli@0.5.0 catalog verify-image --from release.yaml
249
- npx @runveric/cli@0.5.0 catalog verify-image <repository>@<digest> --key <action key> --commit <sha>
250
+ npx @runveric/cli@0.5.1 catalog verify-image --from release.yaml
251
+ npx @runveric/cli@0.5.1 catalog verify-image <repository>@<digest> --key <action key> --commit <sha>
250
252
  ```
251
253
 
252
254
  An action's package must be named after its key (`azure.vm.stop` → `action-azure-vm-stop`); the
package/dist/runveric.mjs CHANGED
@@ -848,7 +848,7 @@ SOFTWARE.
848
848
  `}__name(license,"license");var GITIGNORE=`# runveric test writes its scratch here.
849
849
  .runveric/
850
850
  *.log
851
- `;function yamlString(value){return`"${value.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}__name(yamlString,"yamlString");var LITERAL_READERS={powershell:__name(line=>singleQuoted(line,/''/g,"'"),"powershell"),bash:__name(line=>singleQuoted(line,/'\\''/g,"'"),"bash"),python:__name(line=>{const open=line.indexOf('"');const close=line.lastIndexOf('"');if(open<0||close<=open)return null;try{const value=JSON.parse(line.slice(open,close+1));return typeof value==="string"?value:null}catch{return null}},"python")};function singleQuoted(line,escaped,plain){const open=line.indexOf("'");const close=line.lastIndexOf("'");if(open<0||close<=open)return null;return line.slice(open+1,close).replace(escaped,plain)}__name(singleQuoted,"singleQuoted");function powershellLiteral(value){return`'${value.replace(/'/g,"''")}'`}__name(powershellLiteral,"powershellLiteral");function bashLiteral(value){return`'${value.replace(/'/g,`'\\''`)}'`}__name(bashLiteral,"bashLiteral");function pythonLiteral(value){return JSON.stringify(value)}__name(pythonLiteral,"pythonLiteral")}});var require_dist4=__commonJS({"../action-manifest/dist/index.js"(exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.reservedImportPaths=exports.generateImportedPackage=exports.authoredEntrypointOf=exports.authoredBodyPath=exports.powerShellDetection=exports.parseProbeOutput=exports.mapDeclaredParameters=exports.POWERSHELL_PARAM_PROBE=exports.pathSegments=exports.offsetToLocation=exports.locate=exports.interpreterForPath=exports.interpreterEntryFileList=exports.PACKAGE_INTERPRETER_EXTENSIONS=exports.PACKAGE_INTERPRETER_LAUNCH=exports.lintActionPackage=exports.sortFindings=exports.mergeFindings=exports.findingFromValidation=exports.resolveParametersFileOf=exports.resolveParametersFile=exports.readManifest=exports.checkActionPackage=exports.validateActionPackage=exports.REQUIRED_PACKAGE_FILES=exports.MANIFEST_FILE=exports.validatePackageResult=exports.PackageProtocolError=exports.normalizePackageRuntime=exports.checkOciImageReference=exports.PackageRuntimeDeclarationError=exports.PARAMETER_CONTROLS=exports.PARAMETER_PROPERTY_FIELDS=exports.PARAMETER_SCHEMA_FIELDS=exports.CREDENTIAL_SCOPE_PATTERN=exports.SPDX_ID_PATTERN=exports.DURATION_PATTERN=exports.SEMVER_PATTERN=exports.PACKAGE_ID_PATTERN=exports.MANIFEST_FIELDS=exports.RISK_LEVELS=exports.PROVIDERS=exports.ACTION_CATEGORIES=exports.isEgressDestination=exports.isSafeRelativePath=exports.sha256Hex=exports.canonicalJson=exports.validateParameterSchema=exports.validateManifest=exports.parseAndValidateManifest=void 0;exports.scaffoldActionPackage=void 0;var manifest_validator_1=require_manifest_validator();Object.defineProperty(exports,"parseAndValidateManifest",{enumerable:true,get:__name(function(){return manifest_validator_1.parseAndValidateManifest},"get")});Object.defineProperty(exports,"validateManifest",{enumerable:true,get:__name(function(){return manifest_validator_1.validateManifest},"get")});Object.defineProperty(exports,"validateParameterSchema",{enumerable:true,get:__name(function(){return manifest_validator_1.validateParameterSchema},"get")});Object.defineProperty(exports,"canonicalJson",{enumerable:true,get:__name(function(){return manifest_validator_1.canonicalJson},"get")});Object.defineProperty(exports,"sha256Hex",{enumerable:true,get:__name(function(){return manifest_validator_1.sha256Hex},"get")});Object.defineProperty(exports,"isSafeRelativePath",{enumerable:true,get:__name(function(){return manifest_validator_1.isSafeRelativePath},"get")});Object.defineProperty(exports,"isEgressDestination",{enumerable:true,get:__name(function(){return manifest_validator_1.isEgressDestination},"get")});var manifest_schema_1=require_manifest_schema();Object.defineProperty(exports,"ACTION_CATEGORIES",{enumerable:true,get:__name(function(){return manifest_schema_1.ACTION_CATEGORIES},"get")});Object.defineProperty(exports,"PROVIDERS",{enumerable:true,get:__name(function(){return manifest_schema_1.PROVIDERS},"get")});Object.defineProperty(exports,"RISK_LEVELS",{enumerable:true,get:__name(function(){return manifest_schema_1.RISK_LEVELS},"get")});Object.defineProperty(exports,"MANIFEST_FIELDS",{enumerable:true,get:__name(function(){return manifest_schema_1.MANIFEST_FIELDS},"get")});Object.defineProperty(exports,"PACKAGE_ID_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.PACKAGE_ID_PATTERN},"get")});Object.defineProperty(exports,"SEMVER_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.SEMVER_PATTERN},"get")});Object.defineProperty(exports,"DURATION_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.DURATION_PATTERN},"get")});Object.defineProperty(exports,"SPDX_ID_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.SPDX_ID_PATTERN},"get")});Object.defineProperty(exports,"CREDENTIAL_SCOPE_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.CREDENTIAL_SCOPE_PATTERN},"get")});Object.defineProperty(exports,"PARAMETER_SCHEMA_FIELDS",{enumerable:true,get:__name(function(){return manifest_schema_1.PARAMETER_SCHEMA_FIELDS},"get")});Object.defineProperty(exports,"PARAMETER_PROPERTY_FIELDS",{enumerable:true,get:__name(function(){return manifest_schema_1.PARAMETER_PROPERTY_FIELDS},"get")});Object.defineProperty(exports,"PARAMETER_CONTROLS",{enumerable:true,get:__name(function(){return manifest_schema_1.PARAMETER_CONTROLS},"get")});var package_runtime_declaration_1=require_package_runtime_declaration();Object.defineProperty(exports,"PackageRuntimeDeclarationError",{enumerable:true,get:__name(function(){return package_runtime_declaration_1.PackageRuntimeDeclarationError},"get")});Object.defineProperty(exports,"checkOciImageReference",{enumerable:true,get:__name(function(){return package_runtime_declaration_1.checkOciImageReference},"get")});Object.defineProperty(exports,"normalizePackageRuntime",{enumerable:true,get:__name(function(){return package_runtime_declaration_1.normalizePackageRuntime},"get")});var package_result_validator_1=require_package_result_validator();Object.defineProperty(exports,"PackageProtocolError",{enumerable:true,get:__name(function(){return package_result_validator_1.PackageProtocolError},"get")});Object.defineProperty(exports,"validatePackageResult",{enumerable:true,get:__name(function(){return package_result_validator_1.validatePackageResult},"get")});var package_validation_1=require_package_validation();Object.defineProperty(exports,"MANIFEST_FILE",{enumerable:true,get:__name(function(){return package_validation_1.MANIFEST_FILE},"get")});Object.defineProperty(exports,"REQUIRED_PACKAGE_FILES",{enumerable:true,get:__name(function(){return package_validation_1.REQUIRED_PACKAGE_FILES},"get")});Object.defineProperty(exports,"validateActionPackage",{enumerable:true,get:__name(function(){return package_validation_1.validateActionPackage},"get")});var check_1=require_check();Object.defineProperty(exports,"checkActionPackage",{enumerable:true,get:__name(function(){return check_1.checkActionPackage},"get")});var parameters_location_1=require_parameters_location();Object.defineProperty(exports,"readManifest",{enumerable:true,get:__name(function(){return parameters_location_1.readManifest},"get")});Object.defineProperty(exports,"resolveParametersFile",{enumerable:true,get:__name(function(){return parameters_location_1.resolveParametersFile},"get")});Object.defineProperty(exports,"resolveParametersFileOf",{enumerable:true,get:__name(function(){return parameters_location_1.resolveParametersFileOf},"get")});var findings_1=require_findings();Object.defineProperty(exports,"findingFromValidation",{enumerable:true,get:__name(function(){return findings_1.findingFromValidation},"get")});Object.defineProperty(exports,"mergeFindings",{enumerable:true,get:__name(function(){return findings_1.mergeFindings},"get")});Object.defineProperty(exports,"sortFindings",{enumerable:true,get:__name(function(){return findings_1.sortFindings},"get")});var authoring_lint_1=require_authoring_lint();Object.defineProperty(exports,"lintActionPackage",{enumerable:true,get:__name(function(){return authoring_lint_1.lintActionPackage},"get")});var interpreter_launch_1=require_interpreter_launch();Object.defineProperty(exports,"PACKAGE_INTERPRETER_LAUNCH",{enumerable:true,get:__name(function(){return interpreter_launch_1.PACKAGE_INTERPRETER_LAUNCH},"get")});Object.defineProperty(exports,"PACKAGE_INTERPRETER_EXTENSIONS",{enumerable:true,get:__name(function(){return interpreter_launch_1.PACKAGE_INTERPRETER_EXTENSIONS},"get")});Object.defineProperty(exports,"interpreterEntryFileList",{enumerable:true,get:__name(function(){return interpreter_launch_1.interpreterEntryFileList},"get")});Object.defineProperty(exports,"interpreterForPath",{enumerable:true,get:__name(function(){return interpreter_launch_1.interpreterForPath},"get")});var source_location_1=require_source_location();Object.defineProperty(exports,"locate",{enumerable:true,get:__name(function(){return source_location_1.locate},"get")});Object.defineProperty(exports,"offsetToLocation",{enumerable:true,get:__name(function(){return source_location_1.offsetToLocation},"get")});Object.defineProperty(exports,"pathSegments",{enumerable:true,get:__name(function(){return source_location_1.pathSegments},"get")});var powershell_param_detection_1=require_powershell_param_detection();Object.defineProperty(exports,"POWERSHELL_PARAM_PROBE",{enumerable:true,get:__name(function(){return powershell_param_detection_1.POWERSHELL_PARAM_PROBE},"get")});Object.defineProperty(exports,"mapDeclaredParameters",{enumerable:true,get:__name(function(){return powershell_param_detection_1.mapDeclaredParameters},"get")});Object.defineProperty(exports,"parseProbeOutput",{enumerable:true,get:__name(function(){return powershell_param_detection_1.parseProbeOutput},"get")});Object.defineProperty(exports,"powerShellDetection",{enumerable:true,get:__name(function(){return powershell_param_detection_1.powerShellDetection},"get")});var scaffold_1=require_scaffold();Object.defineProperty(exports,"authoredBodyPath",{enumerable:true,get:__name(function(){return scaffold_1.authoredBodyPath},"get")});Object.defineProperty(exports,"authoredEntrypointOf",{enumerable:true,get:__name(function(){return scaffold_1.authoredEntrypointOf},"get")});Object.defineProperty(exports,"generateImportedPackage",{enumerable:true,get:__name(function(){return scaffold_1.generateImportedPackage},"get")});Object.defineProperty(exports,"reservedImportPaths",{enumerable:true,get:__name(function(){return scaffold_1.reservedImportPaths},"get")});Object.defineProperty(exports,"scaffoldActionPackage",{enumerable:true,get:__name(function(){return scaffold_1.scaffoldActionPackage},"get")})}});var name="@runveric/cli";var version="0.5.0";var bin={runveric:"dist/runveric.mjs",rv:"dist/runveric.mjs"};var import_contracts4=__toESM(require_dist());var useColour=process.stdout.isTTY===true&&!process.env.NO_COLOR;var paint=__name(code=>text=>useColour?`\x1B[${code}m${text}\x1B[0m`:text,"paint");var style={bold:paint("1"),dim:paint("2"),red:paint("31"),green:paint("32"),yellow:paint("33"),blue:paint("34"),grey:paint("90")};function print(line=""){process.stdout.write(`${line}
851
+ `;function yamlString(value){return`"${value.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}__name(yamlString,"yamlString");var LITERAL_READERS={powershell:__name(line=>singleQuoted(line,/''/g,"'"),"powershell"),bash:__name(line=>singleQuoted(line,/'\\''/g,"'"),"bash"),python:__name(line=>{const open=line.indexOf('"');const close=line.lastIndexOf('"');if(open<0||close<=open)return null;try{const value=JSON.parse(line.slice(open,close+1));return typeof value==="string"?value:null}catch{return null}},"python")};function singleQuoted(line,escaped,plain){const open=line.indexOf("'");const close=line.lastIndexOf("'");if(open<0||close<=open)return null;return line.slice(open+1,close).replace(escaped,plain)}__name(singleQuoted,"singleQuoted");function powershellLiteral(value){return`'${value.replace(/'/g,"''")}'`}__name(powershellLiteral,"powershellLiteral");function bashLiteral(value){return`'${value.replace(/'/g,`'\\''`)}'`}__name(bashLiteral,"bashLiteral");function pythonLiteral(value){return JSON.stringify(value)}__name(pythonLiteral,"pythonLiteral")}});var require_dist4=__commonJS({"../action-manifest/dist/index.js"(exports){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.reservedImportPaths=exports.generateImportedPackage=exports.authoredEntrypointOf=exports.authoredBodyPath=exports.powerShellDetection=exports.parseProbeOutput=exports.mapDeclaredParameters=exports.POWERSHELL_PARAM_PROBE=exports.pathSegments=exports.offsetToLocation=exports.locate=exports.interpreterForPath=exports.interpreterEntryFileList=exports.PACKAGE_INTERPRETER_EXTENSIONS=exports.PACKAGE_INTERPRETER_LAUNCH=exports.lintActionPackage=exports.sortFindings=exports.mergeFindings=exports.findingFromValidation=exports.resolveParametersFileOf=exports.resolveParametersFile=exports.readManifest=exports.checkActionPackage=exports.validateActionPackage=exports.REQUIRED_PACKAGE_FILES=exports.MANIFEST_FILE=exports.validatePackageResult=exports.PackageProtocolError=exports.normalizePackageRuntime=exports.checkOciImageReference=exports.PackageRuntimeDeclarationError=exports.PARAMETER_CONTROLS=exports.PARAMETER_PROPERTY_FIELDS=exports.PARAMETER_SCHEMA_FIELDS=exports.CREDENTIAL_SCOPE_PATTERN=exports.SPDX_ID_PATTERN=exports.DURATION_PATTERN=exports.SEMVER_PATTERN=exports.PACKAGE_ID_PATTERN=exports.MANIFEST_FIELDS=exports.RISK_LEVELS=exports.PROVIDERS=exports.ACTION_CATEGORIES=exports.isEgressDestination=exports.isSafeRelativePath=exports.sha256Hex=exports.canonicalJson=exports.validateParameterSchema=exports.validateManifest=exports.parseAndValidateManifest=void 0;exports.scaffoldActionPackage=void 0;var manifest_validator_1=require_manifest_validator();Object.defineProperty(exports,"parseAndValidateManifest",{enumerable:true,get:__name(function(){return manifest_validator_1.parseAndValidateManifest},"get")});Object.defineProperty(exports,"validateManifest",{enumerable:true,get:__name(function(){return manifest_validator_1.validateManifest},"get")});Object.defineProperty(exports,"validateParameterSchema",{enumerable:true,get:__name(function(){return manifest_validator_1.validateParameterSchema},"get")});Object.defineProperty(exports,"canonicalJson",{enumerable:true,get:__name(function(){return manifest_validator_1.canonicalJson},"get")});Object.defineProperty(exports,"sha256Hex",{enumerable:true,get:__name(function(){return manifest_validator_1.sha256Hex},"get")});Object.defineProperty(exports,"isSafeRelativePath",{enumerable:true,get:__name(function(){return manifest_validator_1.isSafeRelativePath},"get")});Object.defineProperty(exports,"isEgressDestination",{enumerable:true,get:__name(function(){return manifest_validator_1.isEgressDestination},"get")});var manifest_schema_1=require_manifest_schema();Object.defineProperty(exports,"ACTION_CATEGORIES",{enumerable:true,get:__name(function(){return manifest_schema_1.ACTION_CATEGORIES},"get")});Object.defineProperty(exports,"PROVIDERS",{enumerable:true,get:__name(function(){return manifest_schema_1.PROVIDERS},"get")});Object.defineProperty(exports,"RISK_LEVELS",{enumerable:true,get:__name(function(){return manifest_schema_1.RISK_LEVELS},"get")});Object.defineProperty(exports,"MANIFEST_FIELDS",{enumerable:true,get:__name(function(){return manifest_schema_1.MANIFEST_FIELDS},"get")});Object.defineProperty(exports,"PACKAGE_ID_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.PACKAGE_ID_PATTERN},"get")});Object.defineProperty(exports,"SEMVER_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.SEMVER_PATTERN},"get")});Object.defineProperty(exports,"DURATION_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.DURATION_PATTERN},"get")});Object.defineProperty(exports,"SPDX_ID_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.SPDX_ID_PATTERN},"get")});Object.defineProperty(exports,"CREDENTIAL_SCOPE_PATTERN",{enumerable:true,get:__name(function(){return manifest_schema_1.CREDENTIAL_SCOPE_PATTERN},"get")});Object.defineProperty(exports,"PARAMETER_SCHEMA_FIELDS",{enumerable:true,get:__name(function(){return manifest_schema_1.PARAMETER_SCHEMA_FIELDS},"get")});Object.defineProperty(exports,"PARAMETER_PROPERTY_FIELDS",{enumerable:true,get:__name(function(){return manifest_schema_1.PARAMETER_PROPERTY_FIELDS},"get")});Object.defineProperty(exports,"PARAMETER_CONTROLS",{enumerable:true,get:__name(function(){return manifest_schema_1.PARAMETER_CONTROLS},"get")});var package_runtime_declaration_1=require_package_runtime_declaration();Object.defineProperty(exports,"PackageRuntimeDeclarationError",{enumerable:true,get:__name(function(){return package_runtime_declaration_1.PackageRuntimeDeclarationError},"get")});Object.defineProperty(exports,"checkOciImageReference",{enumerable:true,get:__name(function(){return package_runtime_declaration_1.checkOciImageReference},"get")});Object.defineProperty(exports,"normalizePackageRuntime",{enumerable:true,get:__name(function(){return package_runtime_declaration_1.normalizePackageRuntime},"get")});var package_result_validator_1=require_package_result_validator();Object.defineProperty(exports,"PackageProtocolError",{enumerable:true,get:__name(function(){return package_result_validator_1.PackageProtocolError},"get")});Object.defineProperty(exports,"validatePackageResult",{enumerable:true,get:__name(function(){return package_result_validator_1.validatePackageResult},"get")});var package_validation_1=require_package_validation();Object.defineProperty(exports,"MANIFEST_FILE",{enumerable:true,get:__name(function(){return package_validation_1.MANIFEST_FILE},"get")});Object.defineProperty(exports,"REQUIRED_PACKAGE_FILES",{enumerable:true,get:__name(function(){return package_validation_1.REQUIRED_PACKAGE_FILES},"get")});Object.defineProperty(exports,"validateActionPackage",{enumerable:true,get:__name(function(){return package_validation_1.validateActionPackage},"get")});var check_1=require_check();Object.defineProperty(exports,"checkActionPackage",{enumerable:true,get:__name(function(){return check_1.checkActionPackage},"get")});var parameters_location_1=require_parameters_location();Object.defineProperty(exports,"readManifest",{enumerable:true,get:__name(function(){return parameters_location_1.readManifest},"get")});Object.defineProperty(exports,"resolveParametersFile",{enumerable:true,get:__name(function(){return parameters_location_1.resolveParametersFile},"get")});Object.defineProperty(exports,"resolveParametersFileOf",{enumerable:true,get:__name(function(){return parameters_location_1.resolveParametersFileOf},"get")});var findings_1=require_findings();Object.defineProperty(exports,"findingFromValidation",{enumerable:true,get:__name(function(){return findings_1.findingFromValidation},"get")});Object.defineProperty(exports,"mergeFindings",{enumerable:true,get:__name(function(){return findings_1.mergeFindings},"get")});Object.defineProperty(exports,"sortFindings",{enumerable:true,get:__name(function(){return findings_1.sortFindings},"get")});var authoring_lint_1=require_authoring_lint();Object.defineProperty(exports,"lintActionPackage",{enumerable:true,get:__name(function(){return authoring_lint_1.lintActionPackage},"get")});var interpreter_launch_1=require_interpreter_launch();Object.defineProperty(exports,"PACKAGE_INTERPRETER_LAUNCH",{enumerable:true,get:__name(function(){return interpreter_launch_1.PACKAGE_INTERPRETER_LAUNCH},"get")});Object.defineProperty(exports,"PACKAGE_INTERPRETER_EXTENSIONS",{enumerable:true,get:__name(function(){return interpreter_launch_1.PACKAGE_INTERPRETER_EXTENSIONS},"get")});Object.defineProperty(exports,"interpreterEntryFileList",{enumerable:true,get:__name(function(){return interpreter_launch_1.interpreterEntryFileList},"get")});Object.defineProperty(exports,"interpreterForPath",{enumerable:true,get:__name(function(){return interpreter_launch_1.interpreterForPath},"get")});var source_location_1=require_source_location();Object.defineProperty(exports,"locate",{enumerable:true,get:__name(function(){return source_location_1.locate},"get")});Object.defineProperty(exports,"offsetToLocation",{enumerable:true,get:__name(function(){return source_location_1.offsetToLocation},"get")});Object.defineProperty(exports,"pathSegments",{enumerable:true,get:__name(function(){return source_location_1.pathSegments},"get")});var powershell_param_detection_1=require_powershell_param_detection();Object.defineProperty(exports,"POWERSHELL_PARAM_PROBE",{enumerable:true,get:__name(function(){return powershell_param_detection_1.POWERSHELL_PARAM_PROBE},"get")});Object.defineProperty(exports,"mapDeclaredParameters",{enumerable:true,get:__name(function(){return powershell_param_detection_1.mapDeclaredParameters},"get")});Object.defineProperty(exports,"parseProbeOutput",{enumerable:true,get:__name(function(){return powershell_param_detection_1.parseProbeOutput},"get")});Object.defineProperty(exports,"powerShellDetection",{enumerable:true,get:__name(function(){return powershell_param_detection_1.powerShellDetection},"get")});var scaffold_1=require_scaffold();Object.defineProperty(exports,"authoredBodyPath",{enumerable:true,get:__name(function(){return scaffold_1.authoredBodyPath},"get")});Object.defineProperty(exports,"authoredEntrypointOf",{enumerable:true,get:__name(function(){return scaffold_1.authoredEntrypointOf},"get")});Object.defineProperty(exports,"generateImportedPackage",{enumerable:true,get:__name(function(){return scaffold_1.generateImportedPackage},"get")});Object.defineProperty(exports,"reservedImportPaths",{enumerable:true,get:__name(function(){return scaffold_1.reservedImportPaths},"get")});Object.defineProperty(exports,"scaffoldActionPackage",{enumerable:true,get:__name(function(){return scaffold_1.scaffoldActionPackage},"get")})}});var name="@runveric/cli";var version="0.5.1";var bin={runveric:"dist/runveric.mjs",rv:"dist/runveric.mjs"};var import_contracts4=__toESM(require_dist());var useColour=process.stdout.isTTY===true&&!process.env.NO_COLOR;var paint=__name(code=>text=>useColour?`\x1B[${code}m${text}\x1B[0m`:text,"paint");var style={bold:paint("1"),dim:paint("2"),red:paint("31"),green:paint("32"),yellow:paint("33"),blue:paint("34"),grey:paint("90")};function print(line=""){process.stdout.write(`${line}
852
852
  `)}__name(print,"print");function printError(line){process.stderr.write(`${line}
853
853
  `)}__name(printError,"printError");function printFinding(finding){const badge=finding.severity==="error"?style.red(finding.advisory===true?"error (advisory)":"error"):style.yellow("warning");const at=finding.line===void 0?finding.file:`${finding.file}:${finding.line}:${finding.column??1}`;print(` ${badge} ${style.bold(at)}`);print(` ${finding.message}`);print(` ${style.green("fix:")} ${finding.fix}`);print(` ${style.grey(finding.rule)}`);print()}__name(printFinding,"printFinding");function printCheckSummary(counts){if(counts.errors===0&&counts.warnings===0){print(style.green("\u2713 No problems found."));return}const parts=[];if(counts.errors>0)parts.push(`${counts.errors} error${counts.errors===1?"":"s"}`);if(counts.warnings>0){parts.push(`${counts.warnings} warning${counts.warnings===1?"":"s"}`)}const summary=parts.join(", ");print(counts.errors>0?style.red(`\u2717 ${summary}.`):style.yellow(`${summary}.`))}__name(printCheckSummary,"printCheckSummary");function printEvent(event){const marker={info:style.grey("\xB7"),warn:style.yellow("!"),error:style.red("\u2717"),success:style.green("\u2713")}[event.level];print(` ${marker} ${event.message}`);if(event.data){print(` ${style.grey(JSON.stringify(event.data))}`)}}__name(printEvent,"printEvent");function printResult(result){const status={succeeded:style.green("succeeded"),failed:style.red("failed"),cancelled:style.yellow("cancelled")}[result.status];print();print(`${style.bold("Result")} ${status}`);print(` ${result.message}`);if(result.checks?.length){print();print(` ${style.bold("Checks")}`);for(const check of result.checks){const marker={passed:style.green("\u2713"),warning:style.yellow("!"),failed:style.red("\u2717")}[check.status];print(` ${marker} ${check.message}`);if(check.data)print(` ${style.grey(JSON.stringify(check.data))}`)}}if(result.outputs&&Object.keys(result.outputs).length>0){print();print(` ${style.bold("Outputs")}`);for(const[name3,value]of Object.entries(result.outputs)){print(` ${name3} = ${JSON.stringify(value)}`)}}if(result.rollbackCapture&&Object.keys(result.rollbackCapture).length>0){print();print(` ${style.bold("Rollback capture")} ${style.grey("(what a rollback would read)")}`);for(const[name3,value]of Object.entries(result.rollbackCapture)){print(` ${name3} = ${JSON.stringify(value)}`)}}if(result.error){print();print(` ${style.red("Error")} ${result.error.code}`);print(` ${result.error.message}`);if(result.error.retryable!==void 0){print(` ${style.grey(result.error.retryable?"retryable":"not retryable")}`)}}print()}__name(printResult,"printResult");var import_contracts2=__toESM(require_dist());import{access,mkdir,writeFile}from"fs/promises";import{dirname,join,relative,resolve}from"path";function parseActionFlags(argv,spec){const parsed={single:{},many:{},on:{},positional:[]};for(let index=0;index<argv.length;index+=1){const argument=argv[index];if(!argument.startsWith("--")){if(parsed.positional.length>=(spec.positional??0))throw new Error(`Unexpected argument: ${argument}`);parsed.positional.push(argument);continue}const separator=argument.indexOf("=");const name3=separator===-1?argument.slice(2):argument.slice(2,separator);if(spec.booleans?.includes(name3)){if(separator!==-1)throw new Error(`--${name3} takes no value.`);parsed.on[name3]=true;continue}if(!spec.values.includes(name3))throw new Error(`Unknown argument: ${argument}`);let value;if(separator!==-1){value=argument.slice(separator+1)}else{value=argv[index+1];index+=1}if(value===void 0||value===""||value.startsWith("--"))throw new Error(`--${name3} needs a value.`);if(spec.repeated?.includes(name3))(parsed.many[name3]??=[]).push(value);else if(parsed.single[name3]!==void 0)throw new Error(`--${name3} is given twice.`);else parsed.single[name3]=value}return parsed}__name(parseActionFlags,"parseActionFlags");var publish_default=`# Publishes this ENGINE action when a v* tag is pushed (docs/128 \xA78 step 4, \xA720 G4): its image, built
854
854
  # FROM the action runtime by digest and pushed BY DIGEST to this repository's own package, then the
@@ -859,25 +859,38 @@ SOFTWARE.
859
859
  # a signature for it (docs/128 \xA710 T1): the catalog repository's release workflow verifies the image
860
860
  # and signs it with a key that never leaves the platform's Key Vault. This workflow holds no OIDC
861
861
  # permission and names no signature repository.
862
+ #
863
+ # \u2605 TWO JOBS: THE ONE THAT CAN PUSH INSTALLS NOTHING (docs/128 \xA725 D5). Installing the action's
864
+ # dependencies runs code from npm, so it happens in \`build\`, which holds only \`contents: read\`, and with
865
+ # \`--ignore-scripts\`: no dependency's install script runs at all (esbuild's binary needs none \u2014 measured
866
+ # 2026-10-15). \`publish\` holds \`packages: write\`; it downloads the built \`dist/\`, builds the image, pushes
867
+ # it, and runs the pinned CLI \u2014 and installs nothing.
862
868
  name: publish
863
869
 
864
870
  on:
865
871
  push:
866
872
  tags: ["v*"]
867
873
 
868
- permissions:
869
- contents: read
870
- packages: write
874
+ # Nothing at the workflow level: each job states exactly what it holds.
875
+ permissions: {}
871
876
 
872
877
  # The registry every reference below is built on \u2014 this repository's own package lives there.
873
878
  env:
874
879
  REGISTRY: ghcr.io
875
880
 
876
881
  jobs:
877
- publish:
882
+ build:
878
883
  runs-on: ubuntu-latest
884
+ # Read the code. Nothing here can write a package.
885
+ permissions:
886
+ contents: read
879
887
  steps:
888
+ # \u2605 The workflow token is NOT left in .git/config (\`persist-credentials\` defaults to true): nothing
889
+ # after the checkout needs git credentials, and the dependencies installed below could read them there
890
+ # (docs/128 \xA724.7 C.5.1 F2).
880
891
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
892
+ with:
893
+ persist-credentials: false
881
894
 
882
895
  # Node 24, as every workflow this repository runs or plants (docs/131 D1); the action builds with
883
896
  # it too. The CLI's own engines.node names the oldest Node it supports.
@@ -887,13 +900,14 @@ jobs:
887
900
 
888
901
  # The action's own code: its package.json builds dist/index.js, the module the runtime loads as
889
902
  # /action/index.js (docs/128 \xA718.7). Nothing else of this repository reaches the image.
903
+ # \u2605 \`npm ci --ignore-scripts\`: exactly the lockfile, and no dependency's install script (\xA725 D5).
890
904
  # \u2605 TYPE-CHECKED FIRST (docs/128 \xA723.7): the build is esbuild, which strips types, so without this
891
905
  # a tag publishes code that never compiled. The typecheck needs no credential, unlike the phases
892
906
  # \`npm test\` drives, so it is the one check of the author's tests this workflow can always run.
893
907
  - name: Build the action
894
908
  run: |
895
909
  set -euo pipefail
896
- npm ci
910
+ npm ci --ignore-scripts
897
911
  npm run typecheck
898
912
  npm run build
899
913
  if [ ! -f dist/index.js ]; then
@@ -901,6 +915,38 @@ jobs:
901
915
  exit 1
902
916
  fi
903
917
 
918
+ # What the image is built from, for \`publish\`: dist/ and nothing else.
919
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
920
+ with:
921
+ name: action-dist
922
+ path: dist/
923
+ if-no-files-found: error
924
+ retention-days: 1
925
+
926
+ publish:
927
+ needs: build
928
+ runs-on: ubuntu-latest
929
+ # Read the code (catalog.yaml), and write this repository's OWN package \u2014 no OIDC token.
930
+ permissions:
931
+ contents: read
932
+ packages: write
933
+ steps:
934
+ # \u2605 The workflow token is NOT left in .git/config: the CLI from npm runs below (docs/128 \xA724.7 C.5.1 F2).
935
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
936
+ with:
937
+ persist-credentials: false
938
+
939
+ # The dist/ build wrote, from this run \u2014 \u26D4 NO \`npm ci\` HERE: nothing in this job installs anything.
940
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
941
+ with:
942
+ name: action-dist
943
+ path: dist
944
+
945
+ # Node 24, for the pinned CLI below and the inline scripts of the push step.
946
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
947
+ with:
948
+ node-version: 24
949
+
904
950
  # \u2605 FROM THE RUNTIME, BY DIGEST \u2014 filled from @runveric/contracts' ACTION_RUNTIME_IMAGE when this
905
951
  # file was planted, never typed (docs/128 \xA720 G4). One linux/amd64 manifest, as Container Apps Jobs
906
952
  # run, and no provenance index; the two labels the server reads before it runs anything: the
@@ -909,6 +955,10 @@ jobs:
909
955
  - name: Build the image
910
956
  run: |
911
957
  set -euo pipefail
958
+ if [ ! -f dist/index.js ]; then
959
+ echo "::error::The dist/ build uploaded holds no index.js \u2014 the runtime loads /action/index.js and nothing else."
960
+ exit 1
961
+ fi
912
962
  docker build --platform linux/amd64 --provenance=false \\
913
963
  --label "org.opencontainers.image.source=\${GITHUB_SERVER_URL}/\${GITHUB_REPOSITORY}" \\
914
964
  --label "org.opencontainers.image.revision=\${GITHUB_SHA}" \\
@@ -970,7 +1020,8 @@ jobs:
970
1020
  rm -f "$auth"
971
1021
  echo "ref=$REGISTRY/$package@$manifest_digest" >>"$GITHUB_OUTPUT"
972
1022
 
973
- # The CLI is pinned EXACTLY: the version below was on npm before this file named it. It refuses,
1023
+ # The CLI is pinned EXACTLY, and its one dependency is pinned exactly in its own manifest (docs/128 \xA725
1024
+ # D4): the version below was on npm before this file named it. It refuses,
974
1025
  # before anything is pushed, an image outside this package and one the server's rule refuses \u2014
975
1026
  # another action's, another commit's, an index, not linux/amd64 \u2014 and a definition+version
976
1027
  # manifest whose version: is not this tag.
@@ -1003,7 +1054,7 @@ jobs:
1003
1054
  `);files.set("test/prior-result.json",`${JSON.stringify(recordedExecute(),null,2)}
1004
1055
  `);files.set("README.md",readme(input,repository));files.set(".gitignore","node_modules/\ndist/\n");const values=(0,import_contracts.workflowValues)({name,version});for(const[path,text]of Object.entries(engine_action_repository_default)){files.set(path,(0,import_contracts.renderTemplate)(`templates/engine-action-repository/${path}`,text,values))}return files}__name(scaffoldEngineAction,"scaffoldEngineAction");function packageJson(repository,name3){const phase=__name((phase2,extra="")=>`${CLI_BIN} action test --phase ${phase2} --params-file test/params.json${extra}`,"phase");return`${JSON.stringify({name:repository,private:true,description:`${name3} \u2014 ${import_contracts.BRAND_ARTICLE} ${import_contracts.BRAND_SHORT_NAME} engine action. Published from this repository by .github/workflows/publish.yml.`,scripts:{typecheck:"tsc -p tsconfig.json",build:"esbuild src/index.ts --bundle --platform=node --target=node22 --format=cjs --outfile=dist/index.js",test:["npm run typecheck","npm run build",phase("validate"),phase("execute"),phase("rollback"," --prior-result test/prior-result.json")].join(" && ")},dependencies:{[name2]:version2},devDependencies:{[name]:version,esbuild:version3,typescript:version4},engines:{node:">=22"}},null,2)}
1005
1056
  `}__name(packageJson,"packageJson");function tsconfigJson(){return`${JSON.stringify({compilerOptions:{strict:true,noEmit:true,target:"es2022",module:"nodenext",moduleResolution:"nodenext",types:[],skipLibCheck:true},include:["src"]},null,2)}
1006
- `}__name(tsconfigJson,"tsconfigJson");function actionSource(name3){return[`import { defineAction, type ValidationCheck } from "${name2}";`,"","/**",` * ${name3} \u2014 ${import_contracts.BRAND_ARTICLE} ${import_contracts.BRAND_SHORT_NAME} engine action.`," *"," * validate reports facts about each target; the engine decides what they mean."," * execute acts on ONE target \u2014 after making a restore point durable."," * rollback restores from that restore point, and nothing else."," *"," * `ctx.azure` is a TokenCredential for exactly the audiences catalog.yaml declares, usable with the"," * official Azure SDK clients. Every TODO below is yours."," */","export default defineAction({"," async validate(ctx) {"," return Object.fromEntries("," ctx.targets.map((target): [string, ValidationCheck[]] => ["," target.ref,"," // TODO: read the resource and report what an approver needs to know \u2014 a REFUSE check stops"," // the run, a DECIDE check asks the requester.",' [{ level: "info", title: `${String(target.parameters.resource)} is ready to act on.` }],'," ]),"," );"," },",""," async execute(ctx) {"," const { ref, parameters } = ctx.target;",' if (ctx.dryRun) return { status: "succeeded", message: `Would act on ${ref}.` };',""," // \u2605 THE RESTORE POINT FIRST. It returns only once the engine has made it durable, and the engine"," // refuses a destructive success it never acknowledged one for. Record what rollback needs."," await ctx.saveRestorePoint({"," resourceGroup: String(parameters.resourceGroup),"," resource: String(parameters.resource),"," });",' await ctx.emit({ level: "info", message: `Acting on ${ref}.` });'," // TODO: act on the resource.",' return { status: "succeeded", message: `Acted on ${ref}.`, data: { ref } };'," },",""," async rollback(ctx) {"," const recorded = ctx.restorePoint;",' if (typeof recorded?.resource !== "string") {',' return { status: "failed", message: "No restore point was recorded, so there is nothing to restore from." };'," }"," // TODO: put the resource back as the restore point recorded it.",' return { status: "succeeded", message: `Restored ${recorded.resource} from its restore point.` };'," },","});",""].join("\n")}__name(actionSource,"actionSource");function recordedExecute(){return{restorePoint:{resourceGroup:SKELETON_PARAMETERS.resourceGroup,resource:SKELETON_PARAMETERS.resource},outcome:{status:"succeeded",message:`Acted on ${SKELETON_PARAMETERS.resource}.`}}}__name(recordedExecute,"recordedExecute");function catalogYaml(input){const quoted=__name(value=>JSON.stringify(value),"quoted");return["# The manifest the catalog reads. The catalog repository's release workflow publishes it with the","# image .github/workflows/publish.yml builds; every TODO is yours before the first tag.",'declares: "definition+version"',`key: ${quoted(input.key)}`,`name: ${quoted(input.name)}`,'summary: "TODO: one sentence an operator reads in the catalog."','description: "TODO: what the action does, what it refuses, and what a rollback restores."','category: "storage"',`connectorKey: ${quoted(import_contracts.ENGINE_CONNECTOR_KEY)}`,'riskLevel: "high"','maintainer: "TODO: the team that answers for this action"',"execution:",' kind: "engine"',` contract: ${quoted(import_contracts.ACTION_PROTOCOL_V1)}`," # host:port \u2014 the ONLY destinations the job may reach. Empty: it reaches nothing. When your code",' # calls Azure Resource Manager, add "management.azure.com:443".'," egress: []"," audiences:",` - ${quoted(ARM_AUDIENCE)}`,"capabilities:"," verified: false"," rollback: true"," approvalDefault: true"," dryRun: true"," destructive: true","# A beta: offered only to the workspaces that asked for betas. The tag that publishes it equals it.",`version: ${quoted(import_contracts.FIRST_ACTION_VERSION)}`,"params:",' - id: "resourceGroup"',' label: "Resource group"',' control: "text"',' hint: "The resource group that holds the resource"'," required: true"," source:",' discover: "azure/resourceGroup"'," # The target: listed from ARM by the type it declares, inside the group chosen above.",' - id: "resource"',' label: "Resource"',' control: "text"',' hint: "The resource to act on"'," required: true"," source:",' discover: "azure/arm"',` resourceType: ${quoted(SKELETON_RESOURCE_TYPE)}`," dependsOn:",' - "resourceGroup"',"requiredPermissions:",' - role: "Reader"',' scope: "Subscription"',' kind: "Built-in role"',"workflow:",' - n: "01"',' title: "Check"',' body: "TODO: what validate reads, and what it refuses."',' - n: "02"',' title: "Record"',' body: "Make a restore point durable before anything changes."',' - n: "03"',' title: "Act"',' body: "TODO: what execute changes; a rollback restores it from the restore point."',""].join("\n")}__name(catalogYaml,"catalogYaml");function readme(input,repository){return[`# ${input.name}`,"",`\`${input.key}\` \u2014 ${import_contracts.BRAND_ARTICLE} ${import_contracts.BRAND_SHORT_NAME} engine action. Its code is \`src/index.ts\`, its manifest`,"`catalog.yaml`. It runs as its own image, one isolated job per phase, built `FROM` the action runtime.","","## The loop","","```sh","npm install # the first time: writes package-lock.json \u2014 commit it (the publish workflow runs `npm ci`)","npm test # type-checks src/, builds dist/index.js, then validate, execute and rollback through a local engine","```","",`\`npm test\` runs each phase with \`${CLI_BIN} action test\`: your built \`dist/index.js\`, the real action runtime`,"and every message checked by the protocol's own parsers \u2014 with a local engine that acknowledges","checkpoints and names targets the way the platform does. One phase by hand:","","```sh",`npx ${CLI_BIN} action test --phase validate --param resourceGroup=rg-example --param resource=example`,`npx ${CLI_BIN} action test --phase execute --params-file test/params.json --dry-run`,`npx ${CLI_BIN} action test --phase execute --params-file test/params.json --azure-token-from-az`,"```","","`--azure-token-from-az` hands the action ONE token for Azure Resource Manager from your own `az login`,","held in memory for that run and never written or printed. Without it the action gets no credential.","",`**This is a development loop, not the gate.** When the action runs in ${import_contracts.BRAND_SHORT_NAME}, the engine judges every`,"message again, and the catalog's release workflow verifies and signs the image before anything can","run it.","","## Before the first tag","","- Replace every TODO in `catalog.yaml` and `src/index.ts`.","- `execution.egress` is empty, so the job reaches nothing. When the code calls Azure Resource Manager,",' add `"management.azure.com:443"`.',"- `resourceType` is the ARM type the picker lists for the `resource` parameter.","- `requiredPermissions` says what the connection's identity needs; Reader at the subscription reads only.","","## Publishing","",`Push a tag equal to \`catalog.yaml\`'s \`version\` (\`${import_contracts.FIRST_ACTION_VERSION}\` first). \`.github/workflows/publish.yml\``,"type-checks `src/` and builds `dist/index.js`, builds the image FROM the action runtime by digest, pushes it by digest to",`this repository's package (\`${repository}\`), and publishes the catalog artifact; it prints the line`,"for the catalog repository's `release.yaml`, whose release workflow verifies and signs the image.","","Do not edit `.github/workflows/publish.yml`: it is planted from the product's templates, and the","template sync replaces it.",""].join("\n")}__name(readme,"readme");var ACTION_INIT_USAGE="action init [directory] --key <provider.resource.verb> --name <text>";async function runActionInit(argv){const flags=parseActionFlags(argv,{values:["key","name"],positional:1});const key=flags.single.key?.trim();if(!key)throw new Error('--key is required: the action key, <provider>.<resource>.<verb> \u2014 e.g. --key "azure.disk.snapshot".');const refusal=(0,import_contracts2.actionKeyRefusal)(key);if(refusal!==null)throw new Error(refusal);const name3=flags.single.name?.trim();if(!name3)throw new Error('--name is required: what an operator sees in the catalog \u2014 e.g. --name "Snapshot Disk".');const directory=resolve(flags.positional[0]??(0,import_contracts2.actionRepositoryName)(key));const files=scaffoldEngineAction({key,name:name3});const existing=[];for(const path of files.keys()){if(await access(join(directory,path)).then(()=>true,()=>false))existing.push(path)}if(existing.length>0){throw new Error(`${directory} already has ${existing.join(", ")}. action init never overwrites \u2014 remove ${existing.length===1?"it":"them"}, or run it somewhere else. Nothing was written.`)}for(const[path,contents]of files){const target=join(directory,path);await mkdir(dirname(target),{recursive:true});await writeFile(target,contents,{flag:"wx"}).catch(error=>{throw error.code==="EEXIST"?new Error(`${target} appeared while action init was writing. It never overwrites; it stopped there.`):error})}const below=relative(process.cwd(),directory);const shown=below===""?".":below.startsWith("..")?directory:below;print();print(`${style.green("\u2713")} Created ${style.bold(shown)} \u2014 the engine action ${style.bold(key)}`);print();for(const path of files.keys())print(` ${style.grey(path)}`);print();print("It builds and passes its own test before you change anything:");print();print(` ${style.bold("cd")} ${shown}`);print(` ${style.bold("npm install")} ${style.grey("# writes package-lock.json \u2014 commit it; the publish workflow runs npm ci")}`);print(` ${style.bold("npm test")} ${style.grey("# validate, execute and rollback, through a local engine")}`);print()}__name(runActionInit,"runActionInit");var import_action_runtime=__toESM(require_dist3());var import_contracts3=__toESM(require_dist());import{execFile}from"child_process";import{access as access2,readFile}from"fs/promises";import{createRequire}from"module";import{join as join2,resolve as resolve2}from"path";import{promisify}from"util";import{parse as parseYaml}from"yaml";var runProgram=promisify(execFile);var ACTION_TEST_USAGE="action test --phase validate|execute|rollback [--param <name=value>]\u2026 [--params-file <path>]\n [--prior-result <path>] [--dry-run] [--azure-token-from-az] [--dir <path>]";var PHASES={validate:"validate",execute:"run",rollback:"rollback"};var CATALOG_PROVIDER="azure";var LOCAL_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000";var LOCAL_DEADLINE_MS=15*60*1e3;var LOCAL_RUN="local-test";var CLI_BIN2=Object.keys(bin)[0];var LOCAL_TOKEN_HOLDER={noun:"action",whereDeclared:`\`${CLI_BIN2} action test\` hands an action at most one token: Azure Resource Manager's, from your own az login, when run with --azure-token-from-az. In ${import_contracts3.BRAND_SHORT_NAME}, the engine mints one for each audience catalog.yaml declares in execution.audiences.`,whyNoMore:"The token from your az login expired during this test; run it again."};async function runActionTest(argv){const flags=parseActionFlags(argv,{values:["phase","param","params-file","prior-result","dir"],repeated:["param"],booleans:["dry-run","azure-token-from-az"]});const phase=flags.single.phase;if(phase===void 0||!Object.hasOwn(PHASES,phase)){throw new Error(`--phase is ${phase===void 0?"required":`"${phase}", which is not a phase`}: ${Object.keys(PHASES).join(", ")} \u2014 one at a time.`)}if(flags.single["prior-result"]!==void 0&&phase!=="rollback"){throw new Error("--prior-result is what a rollback reads; it means nothing to a "+phase+".")}const directory=resolve2(flags.single.dir??".");const manifest=await engineManifest(directory);const entry=join2(directory,"dist","index.js");if(!await access2(entry).then(()=>true,()=>false)){throw new Error("dist/index.js does not exist. Build first (npm run build): the runtime loads that one file and nothing else.")}const parameters=await parametersOf(manifest.params,flags.single["params-file"],flags.many.param??[]);const parameterSchema=(0,import_contracts3.catalogParameterSchema)(manifest.params);let tokens2=[];let subscription=LOCAL_SUBSCRIPTION_ID;if(flags.on["azure-token-from-az"]){if(!manifest.audiences.includes(ARM_AUDIENCE)){throw new Error(`--azure-token-from-az hands the action a token for ${ARM_AUDIENCE}, and catalog.yaml's execution.audiences does not declare it (${manifest.audiences.join(", ")||"none"}). The engine would mint none for it either.`)}const fromAz=await armTokenFromAz();tokens2=[fromAz.token];subscription=fromAz.subscription}const target=(0,import_contracts3.engineRunTarget)({key:manifest.key,parameterSchema,provider:CATALOG_PROVIDER,parameters,providerScopeId:subscription});const prior=phase==="rollback"?await priorOf(flags.single["prior-result"]):{restorePoint:null,priorResult:null};const invocation=invocationFor(PHASES[phase],manifest,target,flags.on["dry-run"]===true,tokens2,prior);let definition;try{definition=(0,import_action_runtime.actionOf)(createRequire(entry)(entry),"dist/index.js")}catch(error){throw new Error(`dist/index.js could not be loaded as an action: ${messageOf(error)}`)}const secrets=tokens2.map(token2=>token2.token);const shown=__name(value=>(0,import_contracts3.redactJwtShaped)((0,import_contracts3.redactSecrets)(value,secrets)),"shown");print();print(`${style.bold("action test")} ${manifest.key} ${manifest.version} ${style.grey(`phase ${phase}${flags.on["dry-run"]?", dry run":""}`)}`);print(` target ${target.ref}`);print(` credential ${tokens2.length>0?`ONE token for Azure Resource Manager from your az login ${style.grey(`(subscription ${subscription}) \u2014 YOUR access, not ${import_contracts3.BRAND_SHORT_NAME}'s, held in memory only`)}`:style.grey(`none \u2014 the subscription is a placeholder; --azure-token-from-az hands the action your az login's ARM token`)}`);print(` network ${manifest.egress.length>0?`${style.yellow("open")} ${style.grey(`\u2014 execution.egress (${manifest.egress.join(", ")}) is NOT enforced here; the sandbox enforces it`)}`:`${style.yellow("open")} ${style.grey("\u2014 execution.egress is empty, so the sandbox lets this action reach nothing; nothing here enforces that")}`}`);print(` engine ${style.grey("local: the protocol's parsers on every message, every checkpoint acknowledged")}`);print();print(style.bold("Events"));const engine=new LocalEngine(invocation,shown);let failure=null;try{await(0,import_action_runtime.runAction)(definition,new import_action_runtime.LoopbackTransport(engine),{tokenHolder:LOCAL_TOKEN_HOLDER})}catch(error){failure=messageOf(error)}if(engine.events===0)print(style.grey(" (the action emitted nothing)"));const code=verdict(phase,manifest,invocation,engine,shown,failure);print(style.grey(`A development loop, not the gate: when the action runs in ${import_contracts3.BRAND_SHORT_NAME}, the engine judges every message again, and the catalog's release workflow verifies and signs its image first.`));print();return code}__name(runActionTest,"runActionTest");var LocalEngine=class LocalEngine2{static{__name(this,"LocalEngine")}sent;shown;events=0;violation=null;acknowledged=null;parsed=null;constructor(sent,shown){this.sent=sent;this.shown=shown}async invocation(){return this.sent}async event(body){const event=this.judged(()=>(0,import_contracts3.parseActionEvent)(body,this.sent.limits,this.events));this.events+=1;printEvent((0,import_contracts3.redactJwtShaped)(event))}async checkpoint(body){const checkpoint=this.judged(()=>(0,import_contracts3.parseActionCheckpoint)(body,this.sent.limits));this.acknowledged=checkpoint.record;print(` ${style.green("\u2713")} restore point acknowledged ${style.grey(JSON.stringify(this.shown(checkpoint.record)))}`);return{acknowledged:true}}async report(body){this.parsed=this.judged(()=>(0,import_contracts3.parseActionReport)(body,this.sent))}judged(parse){try{return parse()}catch(error){this.violation??=messageOf(error);throw error}}};function verdict(phase,manifest,invocation,engine,shown,failure){if(engine.violation!==null){printError(style.red(`
1057
+ `}__name(tsconfigJson,"tsconfigJson");function actionSource(name3){return[`import { defineAction, type ValidationCheck } from "${name2}";`,"","/**",` * ${name3} \u2014 ${import_contracts.BRAND_ARTICLE} ${import_contracts.BRAND_SHORT_NAME} engine action.`," *"," * validate reports facts about each target; the engine decides what they mean."," * execute acts on ONE target \u2014 after making a restore point durable."," * rollback restores from that restore point, and nothing else."," *"," * `ctx.azure` is a TokenCredential for exactly the audiences catalog.yaml declares, usable with the"," * official Azure SDK clients. Every TODO below is yours."," */","export default defineAction({"," async validate(ctx) {"," return Object.fromEntries("," ctx.targets.map((target): [string, ValidationCheck[]] => ["," target.ref,"," // TODO: read the resource and report what an approver needs to know \u2014 a REFUSE check stops"," // the run, a DECIDE check asks the requester.",' [{ level: "info", title: `${String(target.parameters.resource)} is ready to act on.` }],'," ]),"," );"," },",""," async execute(ctx) {"," const { ref, parameters } = ctx.target;",' if (ctx.dryRun) return { status: "succeeded", message: `Would act on ${ref}.` };',""," // \u2605 THE RESTORE POINT FIRST. It returns only once the engine has made it durable, and the engine"," // refuses a destructive success it never acknowledged one for. Record what rollback needs."," await ctx.saveRestorePoint({"," resourceGroup: String(parameters.resourceGroup),"," resource: String(parameters.resource),"," });",' await ctx.emit({ level: "info", message: `Acting on ${ref}.` });'," // TODO: act on the resource.",' return { status: "succeeded", message: `Acted on ${ref}.`, data: { ref } };'," },",""," async rollback(ctx) {"," const recorded = ctx.restorePoint;",' if (typeof recorded?.resource !== "string") {',' return { status: "failed", message: "No restore point was recorded, so there is nothing to restore from." };'," }"," // TODO: put the resource back as the restore point recorded it.",' return { status: "succeeded", message: `Restored ${recorded.resource} from its restore point.` };'," },","});",""].join("\n")}__name(actionSource,"actionSource");function recordedExecute(){return{restorePoint:{resourceGroup:SKELETON_PARAMETERS.resourceGroup,resource:SKELETON_PARAMETERS.resource},outcome:{status:"succeeded",message:`Acted on ${SKELETON_PARAMETERS.resource}.`}}}__name(recordedExecute,"recordedExecute");function catalogYaml(input){const quoted=__name(value=>JSON.stringify(value),"quoted");return["# The manifest the catalog reads. The catalog repository's release workflow publishes it with the","# image .github/workflows/publish.yml builds; every TODO is yours before the first tag.",'declares: "definition+version"',`key: ${quoted(input.key)}`,`name: ${quoted(input.name)}`,'summary: "TODO: one sentence an operator reads in the catalog."','description: "TODO: what the action does, what it refuses, and what a rollback restores."','category: "storage"',`connectorKey: ${quoted(import_contracts.ENGINE_CONNECTOR_KEY)}`,'riskLevel: "high"','maintainer: "TODO: the team that answers for this action"',"execution:",' kind: "engine"',` contract: ${quoted(import_contracts.ACTION_PROTOCOL_V1)}`," # host:port \u2014 the ONLY destinations the job may reach. Empty: it reaches nothing. When your code",' # calls Azure Resource Manager, add "management.azure.com:443".'," egress: []"," audiences:",` - ${quoted(ARM_AUDIENCE)}`,"capabilities:"," verified: false"," rollback: true"," approvalDefault: true"," dryRun: true"," destructive: true","# A beta: offered only to the workspaces that asked for betas. The tag that publishes it equals it.",`version: ${quoted(import_contracts.FIRST_ACTION_VERSION)}`,"params:",' - id: "resourceGroup"',' label: "Resource group"',' control: "text"',' hint: "The resource group that holds the resource"'," required: true"," source:",' discover: "azure/resourceGroup"'," # The target: listed from ARM by the type it declares, inside the group chosen above.",' - id: "resource"',' label: "Resource"',' control: "text"',' hint: "The resource to act on"'," required: true"," source:",' discover: "azure/arm"',` resourceType: ${quoted(SKELETON_RESOURCE_TYPE)}`," dependsOn:",' - "resourceGroup"',"requiredPermissions:",' - role: "Reader"',' scope: "Subscription"',' kind: "Built-in role"',"workflow:",' - n: "01"',' title: "Check"',' body: "TODO: what validate reads, and what it refuses."',' - n: "02"',' title: "Record"',' body: "Make a restore point durable before anything changes."',' - n: "03"',' title: "Act"',' body: "TODO: what execute changes; a rollback restores it from the restore point."',""].join("\n")}__name(catalogYaml,"catalogYaml");function readme(input,repository){return[`# ${input.name}`,"",`\`${input.key}\` \u2014 ${import_contracts.BRAND_ARTICLE} ${import_contracts.BRAND_SHORT_NAME} engine action. Its code is \`src/index.ts\`, its manifest`,"`catalog.yaml`. It runs as its own image, one isolated job per phase, built `FROM` the action runtime.","","## The loop","","```sh","npm install # the first time: writes package-lock.json \u2014 commit it (the publish workflow runs `npm ci --ignore-scripts`)","npm test # type-checks src/, builds dist/index.js, then validate, execute and rollback through a local engine","```","",`\`npm test\` runs each phase with \`${CLI_BIN} action test\`: your built \`dist/index.js\`, the real action runtime`,"and every message checked by the protocol's own parsers \u2014 with a local engine that acknowledges","checkpoints and names targets the way the platform does. One phase by hand:","","```sh",`npx ${CLI_BIN} action test --phase validate --param resourceGroup=rg-example --param resource=example`,`npx ${CLI_BIN} action test --phase execute --params-file test/params.json --dry-run`,`npx ${CLI_BIN} action test --phase execute --params-file test/params.json --azure-token-from-az`,"```","","`--azure-token-from-az` hands the action ONE token for Azure Resource Manager from your own `az login`,","held in memory for that run and never written or printed. Without it the action gets no credential.","",`**This is a development loop, not the gate.** When the action runs in ${import_contracts.BRAND_SHORT_NAME}, the engine judges every`,"message again, and the catalog's release workflow verifies and signs the image before anything can","run it.","","## Before the first tag","","- Replace every TODO in `catalog.yaml` and `src/index.ts`.","- `execution.egress` is empty, so the job reaches nothing. When the code calls Azure Resource Manager,",' add `"management.azure.com:443"`.',"- `resourceType` is the ARM type the picker lists for the `resource` parameter.","- `requiredPermissions` says what the connection's identity needs; Reader at the subscription reads only.","","## Publishing","",`Push a tag equal to \`catalog.yaml\`'s \`version\` (\`${import_contracts.FIRST_ACTION_VERSION}\` first). \`.github/workflows/publish.yml\``,"runs two jobs. `build`, which can write nothing, installs with `npm ci --ignore-scripts` (no dependency's install","script runs), type-checks `src/` and builds `dist/index.js`. `publish` installs nothing: it builds the image FROM the",`action runtime by digest, pushes it by digest to this repository's package (\`${repository}\`), and publishes the`,"catalog artifact; it prints the line for the catalog repository's `release.yaml`, whose release workflow verifies and","signs the image.","","Do not edit `.github/workflows/publish.yml`: it is planted from the product's templates, and the","template sync replaces it.",""].join("\n")}__name(readme,"readme");var ACTION_INIT_USAGE="action init [directory] --key <provider.resource.verb> --name <text>";async function runActionInit(argv){const flags=parseActionFlags(argv,{values:["key","name"],positional:1});const key=flags.single.key?.trim();if(!key)throw new Error('--key is required: the action key, <provider>.<resource>.<verb> \u2014 e.g. --key "azure.disk.snapshot".');const refusal=(0,import_contracts2.actionKeyRefusal)(key);if(refusal!==null)throw new Error(refusal);const name3=flags.single.name?.trim();if(!name3)throw new Error('--name is required: what an operator sees in the catalog \u2014 e.g. --name "Snapshot Disk".');const directory=resolve(flags.positional[0]??(0,import_contracts2.actionRepositoryName)(key));const files=scaffoldEngineAction({key,name:name3});const existing=[];for(const path of files.keys()){if(await access(join(directory,path)).then(()=>true,()=>false))existing.push(path)}if(existing.length>0){throw new Error(`${directory} already has ${existing.join(", ")}. action init never overwrites \u2014 remove ${existing.length===1?"it":"them"}, or run it somewhere else. Nothing was written.`)}for(const[path,contents]of files){const target=join(directory,path);await mkdir(dirname(target),{recursive:true});await writeFile(target,contents,{flag:"wx"}).catch(error=>{throw error.code==="EEXIST"?new Error(`${target} appeared while action init was writing. It never overwrites; it stopped there.`):error})}const below=relative(process.cwd(),directory);const shown=below===""?".":below.startsWith("..")?directory:below;print();print(`${style.green("\u2713")} Created ${style.bold(shown)} \u2014 the engine action ${style.bold(key)}`);print();for(const path of files.keys())print(` ${style.grey(path)}`);print();print("It builds and passes its own test before you change anything:");print();print(` ${style.bold("cd")} ${shown}`);print(` ${style.bold("npm install")} ${style.grey("# writes package-lock.json \u2014 commit it; the publish workflow runs npm ci --ignore-scripts")}`);print(` ${style.bold("npm test")} ${style.grey("# type-checks src/, builds, then validate, execute and rollback through a local engine")}`);print()}__name(runActionInit,"runActionInit");var import_action_runtime=__toESM(require_dist3());var import_contracts3=__toESM(require_dist());import{execFile}from"child_process";import{access as access2,readFile}from"fs/promises";import{createRequire}from"module";import{join as join2,resolve as resolve2}from"path";import{promisify}from"util";import{parse as parseYaml}from"yaml";var runProgram=promisify(execFile);var ACTION_TEST_USAGE="action test --phase validate|execute|rollback [--param <name=value>]\u2026 [--params-file <path>]\n [--prior-result <path>] [--dry-run] [--azure-token-from-az] [--dir <path>]";var PHASES={validate:"validate",execute:"run",rollback:"rollback"};var CATALOG_PROVIDER="azure";var LOCAL_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000";var LOCAL_DEADLINE_MS=15*60*1e3;var LOCAL_RUN="local-test";var CLI_BIN2=Object.keys(bin)[0];var LOCAL_TOKEN_HOLDER={noun:"action",whereDeclared:`\`${CLI_BIN2} action test\` hands an action at most one token: Azure Resource Manager's, from your own az login, when run with --azure-token-from-az. In ${import_contracts3.BRAND_SHORT_NAME}, the engine mints one for each audience catalog.yaml declares in execution.audiences.`,whyNoMore:"The token from your az login expired during this test; run it again."};async function runActionTest(argv){const flags=parseActionFlags(argv,{values:["phase","param","params-file","prior-result","dir"],repeated:["param"],booleans:["dry-run","azure-token-from-az"]});const phase=flags.single.phase;if(phase===void 0||!Object.hasOwn(PHASES,phase)){throw new Error(`--phase is ${phase===void 0?"required":`"${phase}", which is not a phase`}: ${Object.keys(PHASES).join(", ")} \u2014 one at a time.`)}if(flags.single["prior-result"]!==void 0&&phase!=="rollback"){throw new Error("--prior-result is what a rollback reads; it means nothing to a "+phase+".")}const directory=resolve2(flags.single.dir??".");const manifest=await engineManifest(directory);const entry=join2(directory,"dist","index.js");if(!await access2(entry).then(()=>true,()=>false)){throw new Error("dist/index.js does not exist. Build first (npm run build): the runtime loads that one file and nothing else.")}const parameters=await parametersOf(manifest.params,flags.single["params-file"],flags.many.param??[]);const parameterSchema=(0,import_contracts3.catalogParameterSchema)(manifest.params);let tokens2=[];let subscription=LOCAL_SUBSCRIPTION_ID;if(flags.on["azure-token-from-az"]){if(!manifest.audiences.includes(ARM_AUDIENCE)){throw new Error(`--azure-token-from-az hands the action a token for ${ARM_AUDIENCE}, and catalog.yaml's execution.audiences does not declare it (${manifest.audiences.join(", ")||"none"}). The engine would mint none for it either.`)}const fromAz=await armTokenFromAz();tokens2=[fromAz.token];subscription=fromAz.subscription}const target=(0,import_contracts3.engineRunTarget)({key:manifest.key,parameterSchema,provider:CATALOG_PROVIDER,parameters,providerScopeId:subscription});const prior=phase==="rollback"?await priorOf(flags.single["prior-result"]):{restorePoint:null,priorResult:null};const invocation=invocationFor(PHASES[phase],manifest,target,flags.on["dry-run"]===true,tokens2,prior);let definition;try{definition=(0,import_action_runtime.actionOf)(createRequire(entry)(entry),"dist/index.js")}catch(error){throw new Error(`dist/index.js could not be loaded as an action: ${messageOf(error)}`)}const secrets=tokens2.map(token2=>token2.token);const shown=__name(value=>(0,import_contracts3.redactJwtShaped)((0,import_contracts3.redactSecrets)(value,secrets)),"shown");print();print(`${style.bold("action test")} ${manifest.key} ${manifest.version} ${style.grey(`phase ${phase}${flags.on["dry-run"]?", dry run":""}`)}`);print(` target ${target.ref}`);print(` credential ${tokens2.length>0?`ONE token for Azure Resource Manager from your az login ${style.grey(`(subscription ${subscription}) \u2014 YOUR access, not ${import_contracts3.BRAND_SHORT_NAME}'s, held in memory only`)}`:style.grey(`none \u2014 the subscription is a placeholder; --azure-token-from-az hands the action your az login's ARM token`)}`);print(` network ${manifest.egress.length>0?`${style.yellow("open")} ${style.grey(`\u2014 execution.egress (${manifest.egress.join(", ")}) is NOT enforced here; the sandbox enforces it`)}`:`${style.yellow("open")} ${style.grey("\u2014 execution.egress is empty, so the sandbox lets this action reach nothing; nothing here enforces that")}`}`);print(` engine ${style.grey("local: the protocol's parsers on every message, every checkpoint acknowledged")}`);print();print(style.bold("Events"));const engine=new LocalEngine(invocation,shown);let failure=null;try{await(0,import_action_runtime.runAction)(definition,new import_action_runtime.LoopbackTransport(engine),{tokenHolder:LOCAL_TOKEN_HOLDER})}catch(error){failure=messageOf(error)}if(engine.events===0)print(style.grey(" (the action emitted nothing)"));const code=verdict(phase,manifest,invocation,engine,shown,failure);print(style.grey(`A development loop, not the gate: when the action runs in ${import_contracts3.BRAND_SHORT_NAME}, the engine judges every message again, and the catalog's release workflow verifies and signs its image first.`));print();return code}__name(runActionTest,"runActionTest");var LocalEngine=class LocalEngine2{static{__name(this,"LocalEngine")}sent;shown;events=0;violation=null;acknowledged=null;parsed=null;constructor(sent,shown){this.sent=sent;this.shown=shown}async invocation(){return this.sent}async event(body){const event=this.judged(()=>(0,import_contracts3.parseActionEvent)(body,this.sent.limits,this.events));this.events+=1;printEvent((0,import_contracts3.redactJwtShaped)(event))}async checkpoint(body){const checkpoint=this.judged(()=>(0,import_contracts3.parseActionCheckpoint)(body,this.sent.limits));this.acknowledged=checkpoint.record;print(` ${style.green("\u2713")} restore point acknowledged ${style.grey(JSON.stringify(this.shown(checkpoint.record)))}`);return{acknowledged:true}}async report(body){this.parsed=this.judged(()=>(0,import_contracts3.parseActionReport)(body,this.sent))}judged(parse){try{return parse()}catch(error){this.violation??=messageOf(error);throw error}}};function verdict(phase,manifest,invocation,engine,shown,failure){if(engine.violation!==null){printError(style.red(`
1007
1058
  The engine would refuse this run: ${shown(engine.violation)}`));return 1}const report=engine.parsed;if(report===null){printError(style.red(`
1008
1059
  The action ended without a report${failure?`: ${shown(failure)}`:""}.`));return 1}if("checks"in report){let refusals=0;let questions=0;for(const{ref,checks}of report.checks){print();print(`${style.bold("Checks")} ${ref}`);for(const check of(0,import_contracts3.settleDecisionChecks)(checks,invocation.decisions)){if(check.level==="error")refusals+=1;if(check.decision!==void 0&&check.level!=="error")questions+=1;printCheck(shown(check))}}print();print(refusals>0?style.red(`A plan would be REFUSED: ${refusals} check${refusals===1?"":"s"} at error.`):questions>0?style.yellow(`A plan would ask the requester ${questions} question${questions===1?"":"s"} before it runs.`):style.green("A plan would proceed."));print();return 0}let outcome=report.outcome;if(phase==="execute"){const refused=(0,import_contracts3.destructiveSuccessRefusal)({key:manifest.key,destructive:manifest.destructive,dryRun:invocation.execution.dryRun,outcome,acknowledgedCheckpoint:engine.acknowledged!==null,restorePoint:invocation.restorePoint});if(refused!==null){printOutcome(shown(outcome),"reported");printError(style.red(`The engine does not accept that success: ${refused.message}`));outcome=refused}}printOutcome(shown(outcome),"outcome");if(phase==="execute"&&outcome.status==="succeeded"&&!invocation.execution.dryRun){print(style.grey("Recorded \u2014 what a rollback reads; save it as the file --prior-result names:"));print(JSON.stringify(shown({restorePoint:engine.acknowledged,outcome}),null,2));print()}return outcome.status==="succeeded"?0:1}__name(verdict,"verdict");function printCheck(check){const marker={info:style.grey("\xB7"),warn:style.yellow("!"),error:style.red("\u2717")}[check.level];const what=check.refusal?style.red(` refusal ${check.refusal}`):check.decision?style.yellow(` decision ${check.decision}`):"";print(` ${marker} ${check.title}${what}`)}__name(printCheck,"printCheck");function printOutcome(outcome,label){const status={succeeded:style.green("succeeded"),failed:style.red("failed"),cancelled:style.yellow("cancelled")}[outcome.status];print();print(`${style.bold(label==="outcome"?"Outcome":"Reported")} ${status}`);print(` ${outcome.message}`);if(outcome.data)print(` ${style.grey(JSON.stringify(outcome.data))}`);print()}__name(printOutcome,"printOutcome");function invocationFor(phase,manifest,target,dryRun,tokens2,prior){const base={protocol:manifest.contract,action:{key:manifest.key,version:manifest.version,image:`local.invalid/${(0,import_contracts3.actionRepositoryName)(manifest.key)}@sha256:${"0".repeat(64)}`},execution:{id:LOCAL_RUN,tenantId:LOCAL_RUN,correlationId:LOCAL_RUN,dryRun},targets:[target],credentials:{tokens:tokens2},limits:{deadline:new Date(Date.now()+LOCAL_DEADLINE_MS).toISOString(),...import_contracts3.ACTION_PROTOCOL_LIMITS}};return(0,import_contracts3.parseActionInvocation)(phase==="validate"?{...base,phase,mode:"plan",decisions:{phase:"plan"},restorePoint:null,priorResult:null}:phase==="run"?{...base,phase,decisions:{phase:"run",recorded:[]},restorePoint:null,priorResult:null}:{...base,phase,decisions:{phase:"run",recorded:[]},restorePoint:prior.restorePoint,priorResult:prior.priorResult})}__name(invocationFor,"invocationFor");async function engineManifest(directory){const path=join2(directory,"catalog.yaml");const text=await readFile(path,"utf8").catch(()=>null);if(text===null){throw new Error(`There is no catalog.yaml in ${directory}. \`${CLI_BIN2} action test\` runs an engine action's repository; \`${CLI_BIN2} action init\` writes one.`)}const document=objectOf(parseYaml(text),"catalog.yaml");const execution=document.execution;if(typeof execution!=="object"||execution===null||execution.kind!=="engine"){throw new Error(`catalog.yaml declares no execution: { kind: engine }, so it is not an engine action. \`${CLI_BIN2} test\` runs an action package.`)}const declared=execution;const destructive=document.capabilities?.destructive;if(typeof destructive!=="boolean"){throw new Error("catalog.yaml must state capabilities.destructive (true or false): the engine's write-ahead rule reads it.")}return{key:stringOf(document.key,"catalog.yaml's key"),version:stringOf(document.version,"catalog.yaml's version"),contract:stringOf(declared.contract,"catalog.yaml's execution.contract"),audiences:stringsOf(declared.audiences,"catalog.yaml's execution.audiences"),egress:stringsOf(declared.egress,"catalog.yaml's execution.egress"),destructive,params:Array.isArray(document.params)?document.params:[]}}__name(engineManifest,"engineManifest");async function parametersOf(params,file,pairs){const declared=new Map(params.map(param=>[param.id,param]));const parameters={};const set=__name((name3,value)=>{if(!declared.has(name3)){throw new Error(`"${name3}" is not a parameter of this action. catalog.yaml declares: ${[...declared.keys()].join(", ")||"(none)"}.`)}parameters[name3]=value},"set");if(file!==void 0){for(const[name3,value]of Object.entries(await jsonObjectFile(file)))set(name3,value)}for(const pair of pairs){const separator=pair.indexOf("=");if(separator<=0)throw new Error(`--param expects name=value; got "${pair}".`);const name3=pair.slice(0,separator);const raw=pair.slice(separator+1);set(name3,declared.get(name3)?.control==="switch"?raw==="true":raw)}const missing=params.filter(param=>param.required&&(parameters[param.id]===void 0||parameters[param.id]===""));if(missing.length>0){throw new Error(`These parameters are required and have no value: ${missing.map(param=>param.id).join(", ")}. Give them with --param ${missing[0].id}=\u2026 (repeatable), or --params-file.`)}return parameters}__name(parametersOf,"parametersOf");async function priorOf(file){if(file===void 0)return{restorePoint:null,priorResult:null};const recorded=await jsonObjectFile(file);const restorePoint=recorded.restorePoint??null;const data=recorded.outcome?.data??null;return{restorePoint:restorePoint===null?null:objectOf(restorePoint,`${file}'s restorePoint`),priorResult:data===null?null:objectOf(data,`${file}'s outcome.data`)}}__name(priorOf,"priorOf");async function armTokenFromAz(){let stdout;try{({stdout}=await runProgram("az",["account","get-access-token","--resource",ARM_AUDIENCE,"--output","json"],{maxBuffer:1024*1024}))}catch(error){const failure=error;throw new Error(failure.code==="ENOENT"?"--azure-token-from-az needs the Azure CLI (az), and it is not installed. Install it and run `az login`.":`\`az account get-access-token\` failed \u2014 run \`az login\` and try again. ${String(failure.stderr??"").trim().split("\n")[0]??""}`)}let answer;try{answer=JSON.parse(stdout)}catch{throw new Error("`az account get-access-token` did not answer JSON.")}if(typeof answer.accessToken!=="string"||answer.accessToken.length===0||typeof answer.subscription!=="string"){throw new Error("`az account get-access-token` returned no token or no subscription. Run `az login` and try again.")}const expiresAt=answer.expires_on!==void 0&&Number.isFinite(Number(answer.expires_on))?new Date(Number(answer.expires_on)*1e3):new Date(String(answer.expiresOn).replace(" ","T"));if(Number.isNaN(expiresAt.getTime()))throw new Error("`az account get-access-token` returned no readable expiry.");return{token:{audience:ARM_AUDIENCE,token:answer.accessToken,expiresOn:expiresAt.toISOString()},subscription:answer.subscription}}__name(armTokenFromAz,"armTokenFromAz");async function jsonObjectFile(file){const text=await readFile(resolve2(file),"utf8").catch(()=>null);if(text===null)throw new Error(`Could not read ${file}.`);let parsed;try{parsed=JSON.parse(text)}catch{throw new Error(`${file} is not valid JSON.`)}return objectOf(parsed,file)}__name(jsonObjectFile,"jsonObjectFile");function objectOf(value,what){if(typeof value!=="object"||value===null||Array.isArray(value))throw new Error(`${what} must be an object.`);return value}__name(objectOf,"objectOf");function stringOf(value,what){if(typeof value!=="string"||value.length===0)throw new Error(`${what} must be a non-empty string.`);return value}__name(stringOf,"stringOf");function stringsOf(value,what){if(!Array.isArray(value)||!value.every(entry=>typeof entry==="string"))throw new Error(`${what} must be a list of strings.`);return value}__name(stringsOf,"stringsOf");function messageOf(error){return error instanceof Error?error.message:String(error)}__name(messageOf,"messageOf");var ACTION_USAGE=`runveric action \u2014 author an engine action: code that runs as its own image (docs/128 \xA723)
1009
1060