gate-evm-tools 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +6 -2
  2. package/bin/cli.js +3 -0
  3. package/bin/delivery.cjs +11 -6
  4. package/bin/migration.js +38 -0
  5. package/dist/commands/prepare.d.ts.map +1 -1
  6. package/dist/commands/prepare.js +7 -1
  7. package/dist/commands/prepare.js.map +1 -1
  8. package/dist/core/BytecodeChecker.d.ts.map +1 -1
  9. package/dist/core/BytecodeChecker.js +27 -4
  10. package/dist/core/BytecodeChecker.js.map +1 -1
  11. package/dist/core/preparation/artifacts.d.ts.map +1 -1
  12. package/dist/core/preparation/artifacts.js +12 -5
  13. package/dist/core/preparation/artifacts.js.map +1 -1
  14. package/dist/core/preparation/index.d.ts +3 -0
  15. package/dist/core/preparation/index.d.ts.map +1 -1
  16. package/dist/core/preparation/index.js +9 -2
  17. package/dist/core/preparation/index.js.map +1 -1
  18. package/dist/core/preparation/zksync.d.ts.map +1 -1
  19. package/dist/core/preparation/zksync.js +5 -0
  20. package/dist/core/preparation/zksync.js.map +1 -1
  21. package/dist/core/validateAndGenerateCalldata.d.ts.map +1 -1
  22. package/dist/core/validateAndGenerateCalldata.js +3 -0
  23. package/dist/core/validateAndGenerateCalldata.js.map +1 -1
  24. package/dist/deployment-zksync/index.d.ts +40 -0
  25. package/dist/deployment-zksync/index.d.ts.map +1 -0
  26. package/dist/deployment-zksync/index.js +59 -0
  27. package/dist/deployment-zksync/index.js.map +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +7 -12
  30. package/dist/index.js.map +1 -1
  31. package/dist/migration/index.d.ts +76 -0
  32. package/dist/migration/index.d.ts.map +1 -0
  33. package/dist/migration/index.js +284 -0
  34. package/dist/migration/index.js.map +1 -0
  35. package/dist/types.d.ts +1 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist-cjs/core/BytecodeChecker.js +27 -4
  38. package/dist-cjs/core/BytecodeChecker.js.map +1 -1
  39. package/dist-cjs/core/preparation/artifacts.js +11 -4
  40. package/dist-cjs/core/preparation/artifacts.js.map +1 -1
  41. package/dist-cjs/core/preparation/index.js +47 -6
  42. package/dist-cjs/core/preparation/index.js.map +1 -1
  43. package/dist-cjs/core/preparation/zksync.js +5 -0
  44. package/dist-cjs/core/preparation/zksync.js.map +1 -1
  45. package/dist-cjs/deployment-zksync/index.js +67 -0
  46. package/dist-cjs/deployment-zksync/index.js.map +1 -0
  47. package/dist-cjs/migration/index.js +328 -0
  48. package/dist-cjs/migration/index.js.map +1 -0
  49. package/dist-runtime/delivery/aggregate-diagnostics.js +3 -0
  50. package/dist-runtime/delivery/aggregate-diagnostics.js.map +1 -1
  51. package/dist-runtime/delivery/aggregate-inputs.d.ts +32 -6
  52. package/dist-runtime/delivery/aggregate-inputs.js +7 -3
  53. package/dist-runtime/delivery/aggregate-inputs.js.map +1 -1
  54. package/dist-runtime/delivery/aggregate-worker.js +3 -3
  55. package/dist-runtime/delivery/aggregate-worker.js.map +1 -1
  56. package/dist-runtime/delivery/aggregate.js +2 -2
  57. package/dist-runtime/delivery/aggregate.js.map +1 -1
  58. package/dist-runtime/delivery/cli-host.d.ts +17 -0
  59. package/dist-runtime/delivery/cli-host.js +118 -0
  60. package/dist-runtime/delivery/cli-host.js.map +1 -0
  61. package/dist-runtime/delivery/cli.d.ts +114 -0
  62. package/dist-runtime/delivery/cli.js +228 -0
  63. package/dist-runtime/delivery/cli.js.map +1 -0
  64. package/dist-runtime/delivery/compiler-dependency-pins.js +30 -1
  65. package/dist-runtime/delivery/compiler-dependency-pins.js.map +1 -1
  66. package/dist-runtime/delivery/configuration-definition.js +152 -11
  67. package/dist-runtime/delivery/configuration-definition.js.map +1 -1
  68. package/dist-runtime/delivery/configuration-hre.js +1 -1
  69. package/dist-runtime/delivery/configuration-hre.js.map +1 -1
  70. package/dist-runtime/delivery/configuration.js +7 -4
  71. package/dist-runtime/delivery/configuration.js.map +1 -1
  72. package/dist-runtime/delivery/custom-format.d.ts +2 -1
  73. package/dist-runtime/delivery/custom-format.js +15 -2
  74. package/dist-runtime/delivery/custom-format.js.map +1 -1
  75. package/dist-runtime/delivery/custom.d.ts +4 -0
  76. package/dist-runtime/delivery/custom.js +21 -0
  77. package/dist-runtime/delivery/custom.js.map +1 -1
  78. package/dist-runtime/delivery/development-inputs.d.ts +23 -0
  79. package/dist-runtime/delivery/development-inputs.js +117 -0
  80. package/dist-runtime/delivery/development-inputs.js.map +1 -0
  81. package/dist-runtime/delivery/development.d.ts +1 -0
  82. package/dist-runtime/delivery/development.js +7 -1
  83. package/dist-runtime/delivery/development.js.map +1 -1
  84. package/dist-runtime/delivery/execution-records.d.ts +16 -0
  85. package/dist-runtime/delivery/execution-records.js +48 -0
  86. package/dist-runtime/delivery/execution-records.js.map +1 -0
  87. package/dist-runtime/delivery/existing-code.d.ts +3 -0
  88. package/dist-runtime/delivery/existing-code.js +20 -0
  89. package/dist-runtime/delivery/existing-code.js.map +1 -1
  90. package/dist-runtime/delivery/history-package.d.ts +2 -0
  91. package/dist-runtime/delivery/history-package.js +70 -0
  92. package/dist-runtime/delivery/history-package.js.map +1 -0
  93. package/dist-runtime/delivery/input-files.d.ts +2 -0
  94. package/dist-runtime/delivery/input-files.js +5 -0
  95. package/dist-runtime/delivery/input-files.js.map +1 -1
  96. package/dist-runtime/delivery/inputs.js +11 -6
  97. package/dist-runtime/delivery/inputs.js.map +1 -1
  98. package/dist-runtime/delivery/materialization.js +20 -1
  99. package/dist-runtime/delivery/materialization.js.map +1 -1
  100. package/dist-runtime/delivery/planning.d.ts +1 -0
  101. package/dist-runtime/delivery/planning.js +10 -2
  102. package/dist-runtime/delivery/planning.js.map +1 -1
  103. package/dist-runtime/delivery/production-finalization.js +3 -2
  104. package/dist-runtime/delivery/production-finalization.js.map +1 -1
  105. package/dist-runtime/delivery/production.d.ts +2 -0
  106. package/dist-runtime/delivery/production.js +5 -4
  107. package/dist-runtime/delivery/production.js.map +1 -1
  108. package/dist-runtime/delivery/project-files.js +6 -1
  109. package/dist-runtime/delivery/project-files.js.map +1 -1
  110. package/dist-runtime/delivery/project-rpc.d.ts +1 -1
  111. package/dist-runtime/delivery/project-rpc.js +10 -4
  112. package/dist-runtime/delivery/project-rpc.js.map +1 -1
  113. package/dist-runtime/delivery/protocol.d.ts +6 -4
  114. package/dist-runtime/delivery/protocol.js +16 -5
  115. package/dist-runtime/delivery/protocol.js.map +1 -1
  116. package/dist-runtime/delivery/query.d.ts +21 -0
  117. package/dist-runtime/delivery/query.js +58 -0
  118. package/dist-runtime/delivery/query.js.map +1 -0
  119. package/dist-runtime/delivery/release-graph.d.ts +17 -0
  120. package/dist-runtime/delivery/release-graph.js +23 -0
  121. package/dist-runtime/delivery/release-graph.js.map +1 -1
  122. package/dist-runtime/delivery/release-history-capture.js +26 -27
  123. package/dist-runtime/delivery/release-history-capture.js.map +1 -1
  124. package/dist-runtime/delivery/release-history.d.ts +2 -1
  125. package/dist-runtime/delivery/release-history.js +30 -52
  126. package/dist-runtime/delivery/release-history.js.map +1 -1
  127. package/dist-runtime/delivery/release.d.ts +22 -0
  128. package/dist-runtime/delivery/release.js +13 -3
  129. package/dist-runtime/delivery/release.js.map +1 -1
  130. package/dist-runtime/delivery/scripts.d.ts +116 -0
  131. package/dist-runtime/delivery/scripts.js +289 -0
  132. package/dist-runtime/delivery/scripts.js.map +1 -0
  133. package/dist-runtime/delivery/setup.d.ts +1 -1
  134. package/dist-runtime/delivery/setup.js +26 -36
  135. package/dist-runtime/delivery/setup.js.map +1 -1
  136. package/dist-runtime/delivery/source.d.ts +5 -2
  137. package/dist-runtime/delivery/source.js +4 -3
  138. package/dist-runtime/delivery/source.js.map +1 -1
  139. package/dist-runtime/delivery/standalone-source.d.ts +40 -0
  140. package/dist-runtime/delivery/standalone-source.js +54 -0
  141. package/dist-runtime/delivery/standalone-source.js.map +1 -0
  142. package/dist-runtime/runtime-identity.json +2 -2
  143. package/dist-runtime/workflow/lib/calls.js +21 -1
  144. package/dist-runtime/workflow/lib/calls.js.map +1 -1
  145. package/docs/configuration-runtime-observation.md +4 -2
  146. package/docs/delivery-custom-input-closure.md +2 -0
  147. package/docs/delivery-development.md +2 -0
  148. package/docs/delivery-inputs.md +2 -0
  149. package/docs/delivery-release.md +20 -2
  150. package/docs/delivery-setup.md +25 -20
  151. package/docs/delivery-source.md +4 -2
  152. package/docs/migration.md +108 -0
  153. package/docs/script-execution.md +85 -0
  154. package/package.json +42 -19
  155. package/runtime/delivery/aggregate-diagnostics.ts +2 -0
  156. package/runtime/delivery/aggregate-inputs.ts +6 -5
  157. package/runtime/delivery/aggregate-worker.ts +3 -3
  158. package/runtime/delivery/aggregate.ts +2 -2
  159. package/runtime/delivery/cli-host.ts +55 -0
  160. package/runtime/delivery/cli.ts +124 -0
  161. package/runtime/delivery/compiler-dependency-pins.ts +30 -1
  162. package/runtime/delivery/configuration-definition.ts +80 -9
  163. package/runtime/delivery/configuration-hre.ts +1 -1
  164. package/runtime/delivery/configuration.ts +7 -5
  165. package/runtime/delivery/custom-format.ts +11 -3
  166. package/runtime/delivery/custom.ts +13 -0
  167. package/runtime/delivery/development-inputs.ts +73 -0
  168. package/runtime/delivery/development.ts +4 -2
  169. package/runtime/delivery/execution-records.ts +31 -0
  170. package/runtime/delivery/existing-code.ts +12 -1
  171. package/runtime/delivery/history-package.ts +50 -0
  172. package/runtime/delivery/input-files.ts +5 -1
  173. package/runtime/delivery/inputs.ts +10 -6
  174. package/runtime/delivery/materialization.ts +8 -1
  175. package/runtime/delivery/planning.ts +10 -2
  176. package/runtime/delivery/production-finalization.ts +3 -2
  177. package/runtime/delivery/production.ts +5 -4
  178. package/runtime/delivery/project-files.ts +5 -1
  179. package/runtime/delivery/project-rpc.ts +10 -4
  180. package/runtime/delivery/protocol.ts +13 -5
  181. package/runtime/delivery/query.ts +34 -0
  182. package/runtime/delivery/release-graph.ts +17 -0
  183. package/runtime/delivery/release-history-capture.ts +21 -10
  184. package/runtime/delivery/release-history.ts +20 -19
  185. package/runtime/delivery/release.ts +7 -4
  186. package/runtime/delivery/scripts.ts +162 -0
  187. package/runtime/delivery/setup.ts +21 -31
  188. package/runtime/delivery/source.ts +7 -3
  189. package/runtime/delivery/standalone-source.ts +40 -0
  190. package/runtime/workflow/lib/calls.ts +19 -1
  191. package/dist-runtime/delivery/toolchain.d.ts +0 -3
  192. package/dist-runtime/delivery/toolchain.js +0 -52
  193. package/dist-runtime/delivery/toolchain.js.map +0 -1
  194. package/runtime/delivery/toolchain.ts +0 -48
@@ -0,0 +1,162 @@
1
+ /** Public script protocol and preparation API shared by CLI and application hosts. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import YAML from 'yaml';
6
+ import Ajv from 'ajv';
7
+ import { CustomModuleClosure } from './custom-closure';
8
+ import { strictData, pointerPart } from './data';
9
+ import { readInputBytes, parseInputDocument } from './input-files';
10
+ import { object, safeId, portablePath } from './protocol';
11
+ import { deepFreeze, semanticHash, canonicalJson } from '../workflow/lib/canonicalData';
12
+ import { writeImmutableDeliveryFile } from './development-inputs';
13
+ import { loadDeliveryPublicTarget } from './config';
14
+ export interface ContractQuery { address: string; abi: string[]; method: string; args?: unknown[]; caller?: string }
15
+ export interface ScriptStep {
16
+ id: string; dependsOn?: string[];
17
+ /** Explicit live evidence for omitted prerequisites, evaluated before the selected step. */
18
+ satisfiedBy?: Record<string, ContractQuery & { expect: unknown }>;
19
+ reads?: { files?: string[]; params?: string[]; state?: string[]; target?: string[]; chain?: boolean };
20
+ }
21
+ export interface DeliveryScript {
22
+ version: 1; description: string; inputSchema: Record<string, any>;
23
+ defaults?: Record<string, unknown>; steps: ScriptStep[];
24
+ }
25
+ export interface ScriptPorts {
26
+ resolve(key: string): unknown;
27
+ readJson(file: string): Promise<unknown>;
28
+ readBytes(file: string): Promise<unknown>;
29
+ readContract(query: ContractQuery): Promise<unknown>;
30
+ }
31
+ export interface ScriptInvocation { stepId: string; prerequisites: Array<ContractQuery & { expect: unknown }> }
32
+ export function inspectDeliveryScript(root: string, script: string) {
33
+ portablePath(script,'business script');
34
+ if(!script.startsWith('scripts/operations/')&&!/^scripts\/tasks\/[^/]+\//.test(script))throw Error('Script must be under scripts/operations or the task directory');
35
+ const closure=new CustomModuleClosure(root),loaded=closure.load(script),d=closure.normalize(loaded.module.delivery) as DeliveryScript;
36
+ object(d,'delivery script',['version','description','inputSchema','defaults','steps']);
37
+ if(d.version!==1||typeof d.description!=='string'||!d.description.trim()||!Array.isArray(d.steps)||!d.steps.length||typeof loaded.module.planOperations!=='function')throw Error('Script requires delivery v1 and planOperations(ports,input)');
38
+ object(d.inputSchema,'inputSchema');
39
+ if(d.inputSchema.type!=='object'||d.inputSchema.additionalProperties!==false)throw Error('Input schema requires object with additionalProperties:false');
40
+ const names=d.steps.map(step=>{object(step,'script step',['id','dependsOn','satisfiedBy','reads']);return safeId(step.id,'business step');});
41
+ if(new Set(names).size!==names.length)throw Error('Duplicate script step');
42
+ d.steps.forEach((s,i)=>{if(s.dependsOn!==undefined&&(!Array.isArray(s.dependsOn)||new Set(s.dependsOn).size!==s.dependsOn.length))throw Error('Invalid dependencies');for(const dep of s.dependsOn??[])if(!names.slice(0,i).includes(dep))throw Error(`Dependency ${dep} must precede ${s.id}`);});
43
+ return {definition:deepFreeze(d),closure:closure.seal()};
44
+ }
45
+ const isObject=(v:unknown):v is Record<string,any>=>!!v&&typeof v==='object'&&!Array.isArray(v);
46
+ export function mergeScriptInputs(base:Record<string,any>,over:Record<string,any>):Record<string,any>{
47
+ return Object.fromEntries([...new Set([...Object.keys(base),...Object.keys(over)])].map(k=>[k,Object.hasOwn(over,k)?isObject(base[k])&&isObject(over[k])?mergeScriptInputs(base[k],over[k]):over[k]:base[k]]));
48
+ }
49
+ function schemaDefaults(s:any):any{
50
+ if(Object.hasOwn(s,'default'))return strictData(s.default);
51
+ if(s.type==='object'){const entries=Object.entries(s.properties??{}).filter(([k])=>!(s.required??[]).includes(k)).map(([k,v])=>[k,schemaDefaults(v)]).filter(([,v])=>v!==undefined);return Object.fromEntries(entries);}
52
+ return undefined;
53
+ }
54
+ function parameterFile(root:string,file:string){portablePath(file,'parameter file');if(!/\.(json|ya?ml)$/.test(file)||file.split('/').some(p=>/^(?:\.env|rpc\.env|node_modules|\.git|\.gate-delivery|keys?|secrets?|credentials?)(?:\.|$)/i.test(p)))throw Error('Parameter file must be a public JSON/YAML business input');return readInputBytes(root,file);}
55
+ function inputSchema(raw:any):any {const s=JSON.parse(canonicalJson(raw));const visit=(v:any)=>{delete v.default;delete v['x-derived'];if(v.properties)Object.values(v.properties).forEach(visit);if(v.items)visit(v.items);};visit(s);return s;}
56
+ export function resolveScriptInputs(definition:DeliveryScript,file:unknown={},sets:string[]=[]){
57
+ object(file,'input parameters');
58
+ let values=mergeScriptInputs(mergeScriptInputs(schemaDefaults(definition.inputSchema)??{},definition.defaults??{}),strictData(file) as Record<string,any>);
59
+ const seen=new Set<string>();
60
+ for(const set of sets){const eq=set.indexOf('=');if(eq<1)throw Error('--set expects path=value');const key=set.slice(0,eq),parts=key.split('.');if(seen.has(key)||[...seen].some(p=>p.startsWith(key+'.')||key.startsWith(p+'.')))throw Error(`Conflicting --set ${key}`);seen.add(key);
61
+ let s=definition.inputSchema,v=values;
62
+ for(const [i,p]of parts.entries()){if(['__proto__','constructor','prototype'].includes(p)||s.type!=='object'||!s.properties?.[p])throw Error(`Unknown parameter ${key}`);s=s.properties[p];if(s['x-derived'])throw Error(`Derived parameter cannot be overridden: ${key}`);if(i<parts.length-1){v[p]??={};if(!isObject(v[p]))throw Error(`Non-object parameter ${p}`);v=v[p];}else{const text=set.slice(eq+1);let value:any;if(s.type==='string')value=text;else{try{value=JSON.parse(text);}catch{throw Error(`Invalid ${s.type} at ${key}`);}}v[p]=value;}}
63
+ }
64
+ const checkDerived=(s:any,v:any,p='')=>{if(s['x-derived']&&v!==undefined)throw Error(`Derived value ${p} belongs in planOperations, not input parameters`);if(isObject(v))for(const [k,x]of Object.entries(v))checkDerived(s.properties?.[k]??{},x,p+'/'+k);};checkDerived(definition.inputSchema,values);
65
+ const ajv=new Ajv({allErrors:true,strict:true});ajv.addKeyword({keyword:'x-policy',valid:true});const validate=ajv.compile(inputSchema(definition.inputSchema));
66
+ if(!validate(values))throw Error(`Script inputs: ${ajv.errorsText(validate.errors)}`);
67
+ strictData(values);return deepFreeze(values);
68
+ }
69
+ export function scriptManifest(root:string,script:string,selected?:string[]) {
70
+ const {definition,closure}=inspectDeliveryScript(root,script),ids=selected?.length?selected:definition.steps.map(s=>s.id);
71
+ if(new Set(ids).size!==ids.length||ids.some(id=>!definition.steps.some(s=>s.id===id)))throw Error('Unknown or duplicate selected step');
72
+ const steps=definition.steps.filter(s=>ids.includes(s.id)).map(s=>{
73
+ const missing=(s.dependsOn??[]).filter(dep=>!ids.includes(dep));
74
+ for(const dep of missing)if(!s.satisfiedBy?.[dep])throw Error(`Step ${s.id} requires ${dep}; explicitly select it or declare live satisfiedBy evidence`);
75
+ const reads=s.reads??{};
76
+ return {id:s.id,kind:'custom',script,input:{stepId:s.id,prerequisites:missing.map(dep=>s.satisfiedBy![dep])},reads:{files:reads.files??[],params:reads.params??Object.keys(definition.inputSchema.properties??{}),state:reads.state??[],target:reads.target??[],...(reads.chain||missing.length?{chain:true}:{})}};
77
+ });
78
+ return {definition,closure,steps,selectedSteps:steps.map(s=>s.id)};
79
+ }
80
+ /** Creates a fresh business round; no signature/approval and no GateFlow state involved. */
81
+ export function prepareStandaloneTask(input:{root:string;script:string;network:string;paramsFile?:string;sets?:string[];steps?:string[];description?:string;releaseNetworks?:string[];referenceDeploymentId?:string}){
82
+ return writeStandaloneTask(input);
83
+ }
84
+ function writeStandaloneTask(input:{root:string;script:string;network:string;paramsFile?:string;sets?:string[];steps?:string[];description?:string;releaseNetworks?:string[];referenceDeploymentId?:string;values?:Record<string,unknown>;networkOverrides?:Record<string,Record<string,unknown>>;reuseId?:string}){
85
+ const root=fs.realpathSync(input.root),script=portablePath(input.script,'script'),selected=scriptManifest(root,script,input.steps);
86
+ loadDeliveryPublicTarget(root,input.network,'dev');
87
+ for(const n of input.releaseNetworks??[])loadDeliveryPublicTarget(root,n,'prod');
88
+ const bytes=input.paramsFile?parameterFile(root,input.paramsFile):undefined;
89
+ const values=resolveScriptInputs(selected.definition,mergeScriptInputs(input.values??{},bytes?parseInputDocument(bytes,/\.ya?ml$/.test(input.paramsFile!)?'yaml':'json') as Record<string,any>:{}),input.sets);
90
+ const overrides=input.networkOverrides??{};
91
+ for(const [network,v]of Object.entries(overrides)){if(!(input.releaseNetworks??[]).includes(network))throw Error('Parameter override outside release scope');resolveScriptInputs(selected.definition,mergeScriptInputs(values,v));}
92
+ const id=input.reuseId??`${path.basename(script).replace(/\.[^.]+$/,'').replace(/[^a-zA-Z0-9_-]/g,'-').slice(0,60)}-${randomUUID()}`,base=`scripts/tasks/${id}`;
93
+ const task={version:2,id,source:'standalone',description:input.description??selected.definition.description,developmentNetwork:input.network,releaseTargetNetworks:input.releaseNetworks??[],script,selectedSteps:selected.selectedSteps,...(input.referenceDeploymentId?{referenceDeploymentId:safeId(input.referenceDeploymentId,'referenceDeploymentId')}:{})};
94
+ const schema=inputSchema(selected.definition.inputSchema);schema.$schema='http://json-schema.org/draft-07/schema#';schema['x-policy']={kind:'manual'};
95
+ const manual:Record<string,unknown>={};const leaves=(v:any,p='')=>{const entries=v&&typeof v==='object'?Object.entries(v):[];if(!entries.length)manual[p]={source:'standalone-input',value:v};else for(const[k,x]of entries)leaves(x,p+'/'+pointerPart(k));};leaves(values);
96
+ const write=(file:string,data:unknown,yaml=false)=>{const bytes=yaml?YAML.stringify(data):canonicalJson(data)+'\n';if(input.reuseId)require('./materialization').atomicDevelopmentWrite(root,`${base}/${file}`,bytes);else writeImmutableDeliveryFile(root,`${base}/${file}`,Buffer.from(bytes));};
97
+ write('task.yaml',task,true);write('manifest.yaml',{id,description:task.description,steps:selected.steps},true);write('parameters.schema.json',schema);
98
+ const targets=Object.fromEntries(Object.entries(overrides).map(([network,v])=>{const entries:Record<string,unknown>={};const visit=(value:any,p='')=>{const fields=value&&typeof value==='object'?Object.entries(value):[];if(!fields.length)entries[p]={source:'standalone-input',value};else for(const[k,x]of fields)visit(x,p+'/'+pointerPart(k));};visit(v);return [network,{manual:entries,computed:{}}];}));
99
+ write('parameters.yaml',{defaults:values,params:{[input.network]:{},...overrides}},true);write('parameters.provenance.json',{version:1,producers:{},defaults:{manual,computed:{}},targets});
100
+ const captured=selected.closure.files.map(f=>({path:f.path,digest:f.digest,base64:readInputBytes(root,f.path).toString('base64')}));
101
+ if(bytes)captured.push({path:input.paramsFile!,digest:require('./input-files').inputDigest(bytes),base64:bytes.toString('base64')});
102
+ write('inputs/preparation.snapshot.json',{schema:'gate-delivery-script-inputs',version:1,selectedSteps:selected.selectedSteps,closure:selected.closure,files:captured});
103
+ return deepFreeze({deploymentId:id,taskPath:`${base}/task.yaml`,values,steps:selected.selectedSteps});
104
+ }
105
+
106
+ /** Re-prepare the same native round before signing; historical preparations stay immutable and revoked. */
107
+ export async function reprepareStandaloneTask(input:{root:string;executionId:string;store:import('./execution-store').ExecutionStore;paramsFile?:string;sets?:string[];steps?:string[]}){
108
+ const source=JSON.parse(readInputBytes(input.root,`.gate-delivery/development/${safeId(input.executionId,'executionId')}.source.json`).toString());
109
+ const ref=source.targets?.[0]?.request?.sourceRef;if(ref?.kind!=='standalone')throw Error('Native reprepare requires a standalone source; managed rounds must use their owning host');
110
+ const task=require('./standalone-source').readStandaloneTask(input.root,ref.path) as import('./standalone-source').StandaloneDefinition;
111
+ const aggregate=JSON.parse(readInputBytes(input.root,`.gate-delivery/development/${input.executionId}.aggregate.json`).toString());
112
+ const previous=aggregate.inputs.sourceDefinitions[0].definition;
113
+ const withoutSelection=({selectedSteps,...rest}:any)=>rest;
114
+ if(canonicalJson(withoutSelection(task))!==canonicalJson(withoutSelection(previous)))throw Error('Reprepare cannot change the original task scope; create a new round');
115
+ const parameters=YAML.parse(readInputBytes(input.root,`scripts/tasks/${task.deploymentId}/parameters.yaml`).toString());
116
+ const networkOverrides=Object.fromEntries(Object.entries(parameters.params??{}).filter(([network])=>network!==task.developmentNetwork)) as Record<string,Record<string,unknown>>;
117
+ // Validate prospective inputs before revoking a usable preparation.
118
+ const selected=scriptManifest(input.root,task.script,input.steps??task.selectedSteps);
119
+ const file=input.paramsFile?parseInputDocument(parameterFile(input.root,input.paramsFile),/\.ya?ml$/.test(input.paramsFile)?'yaml':'json'):{};
120
+ const values=resolveScriptInputs(selected.definition,mergeScriptInputs(aggregate.inputs.business.parameters[0].resolved.values,file as Record<string,any>),input.sets);
121
+ for(const v of Object.values(networkOverrides))resolveScriptInputs(selected.definition,mergeScriptInputs(values,v));
122
+ const records=path.join(input.root,'.gate-delivery/executions');
123
+ if(fs.existsSync(records))for(const file of fs.readdirSync(records).filter(f=>f.endsWith('.json'))){const r=JSON.parse(readInputBytes(input.root,`.gate-delivery/executions/${file}`).toString());if(r.kind==='development'&&r.deploymentId===task.deploymentId&&r.executionId!==input.executionId&&!fs.existsSync(path.join(input.root,`.gate-delivery/development/${r.executionId}.superseded.json`)))throw Error(`Round already has replacement execution ${r.executionId}; resume it`);}
124
+ const original=await require('./development-inputs').invalidateDevelopmentPreparation(input);
125
+ return require('./materialization').withDevelopmentFileLock(input.root,async()=>{
126
+ const marker=`.gate-delivery/development/${input.executionId}.replacement.json`;
127
+ const intentHash=semanticHash({values,networkOverrides,steps:selected.selectedSteps,closure:selected.closure});
128
+ let executionId:string;
129
+ if(fs.existsSync(path.join(input.root,marker))){const prior=JSON.parse(readInputBytes(input.root,marker).toString());if(prior.intentHash!==intentHash)throw Error('Replacement preparation already reserved with different inputs; finish or resume that replacement');executionId=safeId(prior.executionId,'replacement executionId');}
130
+ else{executionId=randomUUID();writeImmutableDeliveryFile(input.root,marker,Buffer.from(canonicalJson({version:1,executionId,intentHash})+'\n'));}
131
+ return {...writeStandaloneTask({root:input.root,script:task.script,network:task.developmentNetwork,releaseNetworks:task.releaseTargetNetworks,referenceDeploymentId:task.referenceDeploymentId,description:task.description,steps:selected.selectedSteps,values,networkOverrides,reuseId:original.deploymentId}),executionId};
132
+ });
133
+ }
134
+
135
+ /** Prepare a reusable script inside an existing, genuinely confirmed GateFlow round. */
136
+ export async function prepareGateFlowScriptTask(input:{root:string;request:import('./protocol').DeliveryRequest;script:string;steps?:string[];values:Record<string,unknown>;sets?:string[];paramsFile?:string;networkInputs?:Record<string,{values:Record<string,unknown>;sets?:string[]}>}){
137
+ const source=require('./source').readOwnedDeliverySource({workspaceRoot:input.root,projectRoot:'.',request:input.request}) as import('./source').DeliverySourceBinding;
138
+ if(source.kind!=='gateflow')throw Error('GateFlow preparation requires its real source adapter');
139
+ const deploymentId=safeId(source.scope.deploymentId,'deploymentId'),base=`scripts/tasks/${deploymentId}`,definition=scriptManifest(input.root,input.script,input.steps);
140
+ const file=input.paramsFile?parseInputDocument(parameterFile(input.root,input.paramsFile),/\.ya?ml$/.test(input.paramsFile)?'yaml':'json'):{};
141
+ const values=resolveScriptInputs(definition.definition,mergeScriptInputs(file as Record<string,any>,input.values),input.sets);
142
+ for(const network of Object.keys(input.networkInputs??{}))if(!(source.scope.releaseTargetNetworks as string[]).includes(network))throw Error('Network inputs outside confirmed release scope');
143
+ const networkValues=Object.fromEntries(Object.entries(input.networkInputs??{}).map(([network,v])=>[network,resolveScriptInputs(definition.definition,mergeScriptInputs(file as Record<string,any>,v.values),v.sets)]));
144
+ const schema=inputSchema(definition.definition.inputSchema);schema.$schema='http://json-schema.org/draft-07/schema#';schema['x-policy']={kind:'manual'};
145
+ const manual:Record<string,unknown>={};const leaves=(v:any,p='')=>{const entries=v&&typeof v==='object'?Object.entries(v):[];if(!entries.length)manual[p]={source:'confirmed-requirement',value:v};else for(const[k,x]of entries)leaves(x,p+'/'+pointerPart(k));};leaves(values);
146
+ // Refuse replacing the inputs of any already prepared execution, even before the first signature.
147
+ const dir=path.join(input.root,'.gate-delivery/development');if(fs.existsSync(dir))for(const f of fs.readdirSync(dir).filter(f=>f.endsWith('.aggregate.json'))){const a=JSON.parse(fs.readFileSync(path.join(dir,f),'utf8'));if(a.inputs?.business?.deploymentId===deploymentId&&!fs.existsSync(path.join(dir,f.replace('.aggregate.json','.superseded.json'))))throw Error('Round already prepared; invalidate through the owning host or create a new round');}
148
+ const targets:Record<string,unknown>={};for(const [network,value]of Object.entries(networkValues)){const observations:Record<string,unknown>={};const visit=(v:any,p='')=>{const entries=v&&typeof v==='object'?Object.entries(v):[];if(!entries.length)observations[p]={source:'confirmed-requirement',value:v};else for(const[k,x]of entries)visit(x,p+'/'+pointerPart(k));};visit(value);targets[network]={manual:observations,computed:{}};}
149
+ const writes:{[file:string]:string}={
150
+ 'manifest.yaml':YAML.stringify({id:deploymentId,description:definition.definition.description,steps:definition.steps}),
151
+ 'parameters.schema.json':canonicalJson(schema)+'\n',
152
+ 'parameters.yaml':YAML.stringify({defaults:values,params:{[input.request.network]:{},...networkValues}}),
153
+ 'parameters.provenance.json':canonicalJson({version:1,producers:{},defaults:{manual,computed:{}},targets})+'\n',
154
+ };
155
+ await require('./materialization').withDevelopmentFileLock(input.root,async()=>{
156
+ const current=require('./source').readOwnedDeliverySource({workspaceRoot:input.root,projectRoot:'.',request:input.request});
157
+ if(current.sourceDefinitionHash!==source.sourceDefinitionHash)throw Error('Confirmed source changed while preparing');
158
+ if(fs.existsSync(dir))for(const f of fs.readdirSync(dir).filter(f=>f.endsWith('.aggregate.json'))){const a=JSON.parse(readInputBytes(input.root,`.gate-delivery/development/${f}`).toString());if(a.inputs?.business?.deploymentId===deploymentId&&!fs.existsSync(path.join(dir,f.replace('.aggregate.json','.superseded.json'))))throw Error('Round already prepared; original execution is immutable');}
159
+ for(const[file,bytes]of Object.entries(writes))require('./materialization').atomicDevelopmentWrite(input.root,`${base}/${file}`,bytes);
160
+ });
161
+ return {deploymentId,script:input.script,selectedSteps:definition.selectedSteps,values,files:Object.keys(writes).map(f=>`${base}/${f}`)};
162
+ }
@@ -4,7 +4,6 @@ import crypto from 'node:crypto';
4
4
  import { createRequire } from 'node:module';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import YAML from 'yaml';
7
- import { REVIEWED_DELIVERY_OVERRIDES } from './toolchain';
8
7
  import { object } from './protocol';
9
8
  import { deliveryProjectMarker, projectRoot, readFile, confinedFile, stat, integratedConfig, readPublicProjectNetworkSnapshots, projectSourcesDirectory } from './project';
10
9
  import { configDocument, parseDeliveryPublicTargets, validateDeliveryTarget, type DeliveryTarget } from './config';
@@ -13,11 +12,10 @@ export { loadDeliveryTarget } from './config';
13
12
  export { configureDeliveryEnvironment } from './manifest';
14
13
  export type { DeliveryTarget, DeliveryTargetConfig } from './config';
15
14
 
16
- const TOOLCHAIN: Record<string, string> = { hardhat: '2.26.3', ethers: '6.15.0', '@nomicfoundation/hardhat-ethers': '3.1.0', typescript: '5.9.3', 'ts-node': '10.9.2' };
17
- // Resolve our identity from the executing package, including an explicitly installed tarball.
18
- const toolIdentity = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../../package.json'), 'utf8'));
19
- if (toolIdentity.name !== 'gate-evm-tools' || typeof toolIdentity.version !== 'string') throw new Error('Invalid GateTool package identity');
20
- const DEPENDENCIES: Record<string, string> = { 'gate-evm-tools': toolIdentity.version, '@openzeppelin/hardhat-upgrades': '3.9.1', '@openzeppelin/upgrades-core': '1.44.2', '@openzeppelin/contracts': '5.4.0' };
15
+ // Setup checks locally available capabilities. The project owns dependency versions;
16
+ // compiler qualification separately validates the toolchain used for deployment.
17
+ const DEPENDENCIES = ['hardhat', 'ethers', '@nomicfoundation/hardhat-ethers', 'typescript', 'ts-node',
18
+ 'gate-evm-tools', '@openzeppelin/hardhat-upgrades', '@openzeppelin/upgrades-core', '@openzeppelin/contracts'];
21
19
  export interface DeliverySetupOptions {
22
20
  workspaceRoot: string;
23
21
  projectRoot: string;
@@ -73,10 +71,6 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
73
71
  const before = new Map<string, string | undefined>();
74
72
  for (const file of ['.gate-template.json', 'package.json', 'hardhat.config.ts', 'config.yaml', 'contractInfo.json']) before.set(file, readFile(root, file));
75
73
  const pkg = object(JSON.parse(before.get('package.json') ?? 'null'), 'package.json');
76
- const overrides = pkg.overrides === undefined ? {} : object(pkg.overrides, 'package overrides');
77
- for (const [name, version] of Object.entries(REVIEWED_DELIVERY_OVERRIDES)) {
78
- if (overrides[name] !== undefined && overrides[name] !== version) throw new Error(`Reviewed delivery dependency override conflict: ${name}`);
79
- }
80
74
  const declarations: Record<string, unknown> = {};
81
75
  for (const section of ['dependencies', 'devDependencies']) {
82
76
  const entries = pkg[section] === undefined ? {} : object(pkg[section], section);
@@ -85,18 +79,14 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
85
79
  declarations[name] = value;
86
80
  }
87
81
  }
88
- const required = { ...DEPENDENCIES };
82
+ const required = [...DEPENDENCIES];
83
+ let toolDeclaration: string | undefined;
89
84
  if (input.toolPackage !== undefined) {
90
85
  if (!path.isAbsolute(input.toolPackage) || !input.toolPackage.endsWith('.tgz') || !stat(input.toolPackage)?.isFile() || stat(input.toolPackage)?.isSymbolicLink()) throw new Error('toolPackage must be an explicit absolute local tarball path');
91
- required['gate-evm-tools'] = `file:${input.toolPackage}`;
92
- }
93
- if (businessUsesUpgradeable(root)) required['@openzeppelin/contracts-upgradeable'] = '5.4.0';
94
- for (const [name, version] of Object.entries({ ...TOOLCHAIN, ...required })) {
95
- const declared = declarations[name];
96
- // Preserve an existing explicit local tarball declaration when rerunning after installation.
97
- const localTool = name === 'gate-evm-tools' && input.toolPackage === undefined && typeof declared === 'string' && /^file:.*\.tgz$/.test(declared);
98
- if ((name in TOOLCHAIN && declared === undefined) || (declared !== undefined && declared !== version && !localTool)) throw new Error(`Dependency declaration conflict for ${name}: expected ${version}`);
86
+ toolDeclaration = `file:${input.toolPackage}`;
87
+ if (declarations['gate-evm-tools'] !== undefined && declarations['gate-evm-tools'] !== toolDeclaration) throw new Error('Explicit toolPackage conflicts with the project gate-evm-tools declaration');
99
88
  }
89
+ if (businessUsesUpgradeable(root)) required.push('@openzeppelin/contracts-upgradeable');
100
90
  const networks = readPublicProjectNetworkSnapshots(root, targets.map(target => target.network));
101
91
  const source = before.get('hardhat.config.ts')!;
102
92
  const withPlugin = integratedConfig(source); // Check integration conflicts even when dependencies are missing.
@@ -120,12 +110,14 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
120
110
  if (before.get('contractInfo.json') !== undefined) object(JSON.parse(before.get('contractInfo.json')!), 'contractInfo.json');
121
111
  const dependencies: DeliveryInspection['dependencies'] = [];
122
112
  const projectRequire = createRequire(path.join(root, 'package.json'));
123
- for (const [name, requested] of Object.entries({ ...TOOLCHAIN, ...required })) {
113
+ for (const name of required) {
114
+ const requested = name === 'gate-evm-tools' && toolDeclaration !== undefined ? toolDeclaration : declarations[name];
115
+ const selection = typeof requested === 'string' ? requested : 'project-selected version';
116
+ if (requested === undefined) { dependencies.push({ name, required: selection, reason: 'not declared in the project' }); continue; }
124
117
  const metadata = confinedFile(root, `node_modules/${name}/package.json`);
125
- if (!stat(metadata)) { dependencies.push({ name, required: requested, reason: 'not installed locally' }); continue; }
118
+ if (!stat(metadata)) { dependencies.push({ name, required: selection, reason: 'not installed locally' }); continue; }
126
119
  const installed = JSON.parse(fs.readFileSync(metadata, 'utf8'));
127
- const expected = name === 'gate-evm-tools' ? DEPENDENCIES[name] : requested;
128
- if (installed.name !== name || installed.version !== expected) throw new Error(`Installed dependency conflict for ${name}: expected ${expected}`);
120
+ if (installed.name !== name) throw new Error(`Installed dependency identity mismatch for ${name}`);
129
121
  if (name !== 'gate-evm-tools') {
130
122
  const entry = name === '@openzeppelin/contracts' ? `${name}/proxy/ERC1967/ERC1967Proxy.sol`
131
123
  : name === '@openzeppelin/contracts-upgradeable' ? `${name}/package.json` : name;
@@ -133,7 +125,7 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
133
125
  const resolved = fs.realpathSync(projectRequire.resolve(entry));
134
126
  if (!stat(resolved)?.isFile() || !resolved.startsWith(path.join(root, 'node_modules') + path.sep)) throw new Error('nonlocal entry');
135
127
  } catch {
136
- dependencies.push({ name, required: requested, reason: 'required entry point is missing or nonlocal' });
128
+ dependencies.push({ name, required: selection, reason: 'required entry point is missing or nonlocal' });
137
129
  }
138
130
  }
139
131
  if (name === 'gate-evm-tools') {
@@ -142,7 +134,7 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
142
134
  const resolved = projectRequire.resolve(`gate-evm-tools/${entry}`);
143
135
  if (!resolved.startsWith(path.join(root, 'node_modules') + path.sep)) throw new Error('nonlocal API');
144
136
  }
145
- } catch { dependencies.push({ name, required: requested, reason: 'installed package lacks delivery API exports; install a built delivery package' }); }
137
+ } catch { dependencies.push({ name, required: selection, reason: 'installed package lacks delivery API exports; install a built delivery package' }); }
146
138
  }
147
139
  }
148
140
  if (!dependencies.length) {
@@ -150,12 +142,10 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
150
142
  if (reason) dependencies.push({ name: 'dependency-tree', required: 'complete local dependency graph', reason });
151
143
  }
152
144
  const writes = new Map<string, string>();
153
- const missing = Object.entries(required).filter(([name]) => declarations[name] === undefined);
154
- const missingOverrides = Object.entries(REVIEWED_DELIVERY_OVERRIDES).some(([name]) => overrides[name] === undefined);
155
- if (missing.length || missingOverrides) {
145
+ if (toolDeclaration !== undefined && declarations['gate-evm-tools'] === undefined) {
156
146
  const dev = { ...(pkg.devDependencies as Record<string, unknown> ?? {}) };
157
- for (const [name, version] of missing) dev[name] = version;
158
- writes.set('package.json', JSON.stringify({ ...pkg, devDependencies: dev, overrides: { ...overrides, ...REVIEWED_DELIVERY_OVERRIDES } }, null, 2) + '\n');
147
+ dev['gate-evm-tools'] = toolDeclaration;
148
+ writes.set('package.json', JSON.stringify({ ...pkg, devDependencies: dev }, null, 2) + '\n');
159
149
  }
160
150
  if (changedYaml) writes.set('config.yaml', doc.toString());
161
151
  if (before.get('contractInfo.json') === undefined) writes.set('contractInfo.json', '{}\n');
@@ -165,7 +155,7 @@ function preflight(input: DeliverySetupOptions): { result: DeliveryInspection; w
165
155
  }
166
156
  /** Read-only, never imports the project's config/HRE or contacts an RPC. */
167
157
  export function inspectDeliveryProject(options: DeliverySetupOptions): DeliveryInspection { return preflight(options).result; }
168
- /** Stage declarations/config; caller explicitly installs dependencies then reruns to enable the plugin. */
158
+ /** Stage config; dependency selections remain project-owned except an explicit missing toolPackage. */
169
159
  export function setupDeliveryProject(options: DeliverySetupOptions): DeliveryInspection {
170
160
  const { result, writes, before } = preflight(options);
171
161
  const root = projectRoot(options.workspaceRoot, options.projectRoot);
@@ -4,6 +4,7 @@ import { createHash } from 'node:crypto';
4
4
  import { deliveryProjectMarker, projectRoot, confinedFile } from './project-files';
5
5
  import { object, parseDeliveryRequest, validateDeliveryRpc, type DeliveryRequest, type ChainIdProvider, type ProjectNetworkSnapshot } from './protocol';
6
6
  import { loadPlanCodec } from './codec';
7
+ import type { StandaloneDefinition } from './standalone-source';
7
8
  import type { Plan, PlanTask, DefinitionSelection, DefinitionSnapshot, DeepReadonly } from '../vendor/plan-codec/index.cjs';
8
9
  export type { DefinitionSelection, DefinitionSnapshot, DeepReadonly } from '../vendor/plan-codec/index.cjs';
9
10
 
@@ -20,8 +21,10 @@ export interface DeliverySourceBinding {
20
21
  workspaceRoot: string;
21
22
  projectRoot: string;
22
23
  observation: { path: string; sha256: string };
23
- invocation: { lane: string; task: PlanTask };
24
- sourceDefinition: DefinitionSnapshot;
24
+ kind: 'gateflow' | 'standalone';
25
+ scope: Readonly<Record<string, any>>;
26
+ invocation?: { lane: string; task: PlanTask };
27
+ sourceDefinition: DefinitionSnapshot | StandaloneDefinition;
25
28
  sourceDefinitionBytes: string;
26
29
  sourceDefinitionHash: string;
27
30
  prodTaskGraph?: DefinitionSnapshot;
@@ -77,6 +80,7 @@ function readSource(input: Omit<DeliverySourceOptions, 'sourceRoots'> & { source
77
80
  const workspace = projectRoot(input.workspaceRoot, '.');
78
81
  const root = projectRoot(workspace, input.projectRoot);
79
82
  deliveryProjectMarker(root);
83
+ if(request.sourceRef.kind==='standalone')return freeze((require('./standalone-source') as typeof import('./standalone-source')).standaloneSource(workspace,root,input.projectRoot,request)) as DeepReadonly<DeliverySourceBinding>;
80
84
  const bytes = actualSource(workspace, request.sourceRef.path);
81
85
  const text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
82
86
  if (input.sourceRoots === undefined) (require('./input-files') as typeof import('./input-files')).assertUnambiguousHandoff(text);
@@ -116,7 +120,7 @@ function readSource(input: Omit<DeliverySourceOptions, 'sourceRoots'> & { source
116
120
  }
117
121
  // All values came from detached request parsing and actual handoff text; freeze before exposing.
118
122
  return freeze({ request, workspaceRoot: workspace, projectRoot: root, observation: { path: request.sourceRef.path, sha256: sha256(bytes) },
119
- invocation, sourceDefinition: source.snapshot, sourceDefinitionBytes: source.bytes, sourceDefinitionHash: sha256(source.bytes),
123
+ kind:'gateflow' as const, scope:deployment, invocation, sourceDefinition: source.snapshot, sourceDefinitionBytes: source.bytes, sourceDefinitionHash: sha256(source.bytes),
120
124
  ...(production ? { prodTaskGraph: production.snapshot, prodTaskGraphBytes: production.bytes, prodTaskGraphHash: sha256(production.bytes) } : {}),
121
125
  }) as DeepReadonly<DeliverySourceBinding>;
122
126
  }
@@ -0,0 +1,40 @@
1
+ /** Native task-file adapter. No synthetic handoff, lanes, PlanTask or JSON approval. */
2
+ import path from 'node:path';
3
+ import { readInputBytes, parseInputDocument, inputDigest } from './input-files';
4
+ import { object, safeId, portablePath, type DeliveryRequest } from './protocol';
5
+ import { canonicalJson, deepFreeze, semanticHash } from '../workflow/lib/canonicalData';
6
+ export interface StandaloneDefinition {
7
+ schema: 'gate-delivery-standalone'; version: 1; deploymentId: string;
8
+ description: string; developmentNetwork: string; releaseTargetNetworks: string[];
9
+ referenceDeploymentId?: string;
10
+ script: string; selectedSteps: string[];
11
+ }
12
+ export function readStandaloneTask(root: string, relative: string): StandaloneDefinition {
13
+ portablePath(relative,'standalone task');
14
+ const t=object(parseInputDocument(readInputBytes(root,relative),'yaml'),'standalone task',
15
+ ['version','id','source','description','developmentNetwork','releaseTargetNetworks','referenceDeploymentId','script','selectedSteps']);
16
+ if(t.version!==2 || t.source!=='standalone') throw Error('Native standalone task.yaml version 2 required');
17
+ const id=safeId(t.id,'deploymentId');
18
+ if(relative!==`scripts/tasks/${id}/task.yaml`)throw Error('Noncanonical standalone task path');
19
+ if(typeof t.description!=='string'||!t.description.trim())throw Error('Explicit operation description required');
20
+ safeId(t.developmentNetwork,'developmentNetwork');portablePath(t.script,'business script');
21
+ if(!Array.isArray(t.releaseTargetNetworks)||new Set(t.releaseTargetNetworks).size!==t.releaseTargetNetworks.length)throw Error('Invalid release targets');
22
+ for(const n of t.releaseTargetNetworks){safeId(n,'release target');if(n===t.developmentNetwork)throw Error('Development network cannot be a production target');}
23
+ if(!Array.isArray(t.selectedSteps)||!t.selectedSteps.length||new Set(t.selectedSteps).size!==t.selectedSteps.length)throw Error('Selected steps required');
24
+ t.selectedSteps.forEach(s=>safeId(s,'selected step'));
25
+ if(t.referenceDeploymentId!==undefined)safeId(t.referenceDeploymentId,'referenceDeploymentId');
26
+ return deepFreeze({schema:'gate-delivery-standalone' as const,version:1 as const,deploymentId:id,description:t.description,
27
+ developmentNetwork:t.developmentNetwork as string,releaseTargetNetworks:t.releaseTargetNetworks as string[],script:t.script as string,
28
+ selectedSteps:t.selectedSteps as string[],...(t.referenceDeploymentId?{referenceDeploymentId:t.referenceDeploymentId as string}:{})});
29
+ }
30
+ export function standaloneSource(workspace:string,root:string,relativeProject:string,request:DeliveryRequest) {
31
+ const relative=path.relative(root,path.resolve(workspace,request.sourceRef.path)).split(path.sep).join('/');
32
+ const definition=readStandaloneTask(root,relative);
33
+ if(definition.deploymentId!==request.sourceRef.deploymentId)throw Error('Standalone source deployment mismatch');
34
+ if(request.purpose==='dev-execution'?request.network!==definition.developmentNetwork:!definition.releaseTargetNetworks.includes(request.network))throw Error('Target outside standalone scope');
35
+ const scope={...definition,projectRoot:relativeProject,chainFamily:'evm',framework:'hardhat2'};
36
+ const bytes=canonicalJson(definition);
37
+ return {request,workspaceRoot:workspace,projectRoot:root,kind:'standalone' as const,scope,
38
+ observation:{path:request.sourceRef.path,sha256:inputDigest(readInputBytes(workspace,request.sourceRef.path))},
39
+ sourceDefinition:definition,sourceDefinitionBytes:bytes,sourceDefinitionHash:semanticHash(definition)};
40
+ }
@@ -350,21 +350,39 @@ export const runContractViewCalls = async (
350
350
  const resolved = await resolveContract(context, step);
351
351
  const calls = resolveStepCalls(step);
352
352
  const results: Record<string, string> = {};
353
+ const typedResults: Record<string, unknown> = {};
354
+ const queries: unknown[] = [];
355
+ const provider=context.runtime.hre.network.provider;
356
+ const caller=context.signerAddress??await context.signer?.getAddress()??"0x0000000000000000000000000000000000000001";
357
+ const block:any=await provider.request({method:"eth_getBlockByNumber",params:["latest",false]});
358
+ const chainId=BigInt(await provider.request({method:"eth_chainId",params:[]}) as string).toString();
353
359
 
354
360
  for (const [index, call] of calls.entries()) {
355
361
  const args = resolveCallArgs(context, call);
356
362
  await context.validation?.call(resolved.abiName, call.method, args, call.value === undefined ? undefined : resolveWorkflowValue(context, call.value));
357
363
  context.validation?.callInterface(resolved.contract.interface.fragments, call.method, args);
358
- const value = await resolved.contract.getFunction(call.method).staticCall(...args);
364
+ const fn = resolved.contract.interface.getFunction(call.method);
365
+ let value: unknown;
366
+ if (fn && ["view", "pure"].includes(fn.stateMutability)) {
367
+ const query=await require("../../delivery/query").readScriptContract({address:resolved.address,abi:resolved.contract.interface.fragments.filter(f=>f.type==="function").map(f=>f.format("full")),method:call.method,args}, {request:(method:string,params:unknown[])=>provider.request({method,params}),chainId,block:{number:block.number,hash:block.hash},caller,source:{blockNumber:context.simulation.snapshot?.blockNumber??Number(BigInt(block.number)),blockHash:context.simulation.snapshot?.blockHash??block.hash}});
368
+ value=query.value;queries.push(query.evidence);
369
+ } else {
370
+ // Legacy view steps may statically inspect a non-view ABI. Keep that
371
+ // eth_call behavior without presenting it as a reusable view dependency.
372
+ value = await resolved.contract.getFunction(call.method).staticCall(...args);
373
+ }
359
374
  results[resultKey(call, index, calls)] = context.validation ? context.validation.stringify(value) : stringifyCallResult(value);
375
+ typedResults[resultKey(call,index,calls)] = require("../../delivery/abi").normalizeRuntimeValue(value);
360
376
  }
361
377
 
378
+ context.state.set(String(step.saveAs ?? step.id), { ...typedResults, values: Object.values(typedResults), value: Object.values(typedResults).length===1?Object.values(typedResults)[0]:Object.values(typedResults) });
362
379
  context.reporter.result("view", {
363
380
  stepId: step.id,
364
381
  kind: step.kind,
365
382
  contract: resolved.contractName,
366
383
  address: resolved.address,
367
384
  results,
385
+ queries,
368
386
  });
369
387
  };
370
388
 
@@ -1,3 +0,0 @@
1
- /** Reviewed compiler adapter dependency selections; payload checks remain authoritative.
2
- * Range-scoped entries preserve distinct dependency majors. Setup never overrides a conflicting project choice. */
3
- export declare const REVIEWED_DELIVERY_OVERRIDES: Record<string, string>;
@@ -1,52 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.REVIEWED_DELIVERY_OVERRIDES = void 0;
4
- const compiler_dependency_pins_1 = require("./compiler-dependency-pins");
5
- /** Reviewed compiler adapter dependency selections; payload checks remain authoritative.
6
- * Range-scoped entries preserve distinct dependency majors. Setup never overrides a conflicting project choice. */
7
- exports.REVIEWED_DELIVERY_OVERRIDES = {
8
- "axios": "1.20.0",
9
- "@aws-sdk/client-lambda": "3.1152.0",
10
- "@aws-sdk/core": "3.978.3",
11
- "@aws-sdk/credential-provider-env": "3.972.74",
12
- "@aws-sdk/credential-provider-http": "3.972.76",
13
- "@aws-sdk/credential-provider-ini": "3.973.19",
14
- "@aws-sdk/credential-provider-login": "3.972.81",
15
- "@aws-sdk/credential-provider-node": "3.972.86",
16
- "@aws-sdk/credential-provider-process": "3.972.74",
17
- "@aws-sdk/credential-provider-sso": "3.973.18",
18
- "@aws-sdk/credential-provider-web-identity": "3.972.80",
19
- "@aws-sdk/nested-clients": "3.997.48",
20
- "@aws-sdk/signature-v4-multi-region": "3.996.48",
21
- "@aws-sdk/token-providers": "3.1150.0",
22
- "@aws-sdk/types": "3.974.6",
23
- "@smithy/types": "4.19.0",
24
- "@smithy/signature-v4": "5.7.4",
25
- "@smithy/fetch-http-handler": "5.8.0",
26
- "@smithy/credential-provider-imds": "4.5.2",
27
- "@smithy/core": "3.36.0",
28
- "@smithy/node-http-handler": "4.12.1",
29
- "bowser": "2.14.1",
30
- "follow-redirects": "1.16.1",
31
- "undici@>=5 <6": "5.29.0",
32
- "undici@>=6 <7": "6.29.0",
33
- "tslib@>=1 <2": "1.14.1",
34
- "tslib@>=2 <3": "2.7.0",
35
- "semver@>=5 <6": "5.7.2",
36
- "semver@>=6 <7": "6.3.1",
37
- "semver@>=7 <8": "7.8.5",
38
- "ansi-regex@>=6 <7": "6.4.0"
39
- };
40
- // OZ's compiler adapter follows floating AWS/Smithy ranges. Freeze that reviewed
41
- // family closure so a fresh npm resolution cannot select unqualified payloads.
42
- // Other project dependencies keep their original constraints and payload checks.
43
- for (const key of Object.keys(compiler_dependency_pins_1.compilerDependencyPins)) {
44
- if (!key.startsWith('@aws-sdk/') && !key.startsWith('@smithy/'))
45
- continue;
46
- const at = key.lastIndexOf('@'), name = key.slice(0, at), version = key.slice(at + 1);
47
- const existing = exports.REVIEWED_DELIVERY_OVERRIDES[name];
48
- if (existing && existing !== version)
49
- throw new Error('Ambiguous reviewed compiler dependency: ' + name);
50
- exports.REVIEWED_DELIVERY_OVERRIDES[name] = version;
51
- }
52
- //# sourceMappingURL=toolchain.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"toolchain.js","sourceRoot":"","sources":["../../runtime/delivery/toolchain.ts"],"names":[],"mappings":";;;AAAA,yEAAoE;AAEpE;mHACmH;AACtG,QAAA,2BAA2B,GAA2B;IACjE,OAAO,EAAE,QAAQ;IACjB,wBAAwB,EAAE,UAAU;IACpC,eAAe,EAAE,SAAS;IAC1B,kCAAkC,EAAE,UAAU;IAC9C,mCAAmC,EAAE,UAAU;IAC/C,kCAAkC,EAAE,UAAU;IAC9C,oCAAoC,EAAE,UAAU;IAChD,mCAAmC,EAAE,UAAU;IAC/C,sCAAsC,EAAE,UAAU;IAClD,kCAAkC,EAAE,UAAU;IAC9C,2CAA2C,EAAE,UAAU;IACvD,yBAAyB,EAAE,UAAU;IACrC,oCAAoC,EAAE,UAAU;IAChD,0BAA0B,EAAE,UAAU;IACtC,gBAAgB,EAAE,SAAS;IAC3B,eAAe,EAAE,QAAQ;IACzB,sBAAsB,EAAE,OAAO;IAC/B,4BAA4B,EAAE,OAAO;IACrC,kCAAkC,EAAE,OAAO;IAC3C,cAAc,EAAE,QAAQ;IACxB,2BAA2B,EAAE,QAAQ;IACrC,QAAQ,EAAE,QAAQ;IAClB,kBAAkB,EAAE,QAAQ;IAC5B,eAAe,EAAE,QAAQ;IACzB,eAAe,EAAE,QAAQ;IACzB,cAAc,EAAE,QAAQ;IACxB,cAAc,EAAE,OAAO;IACvB,eAAe,EAAE,OAAO;IACxB,eAAe,EAAE,OAAO;IACxB,eAAe,EAAE,OAAO;IACxB,mBAAmB,EAAE,OAAO;CAC7B,CAAC;AAEF,iFAAiF;AACjF,+EAA+E;AAC/E,iFAAiF;AACjF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,iDAAsB,CAAC,EAAE,CAAC;IACtD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS;IAC1E,MAAM,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAG,mCAA2B,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,QAAQ,IAAI,QAAQ,KAAK,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,GAAG,IAAI,CAAC,CAAC;IACzG,mCAA2B,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;AAC9C,CAAC"}
@@ -1,48 +0,0 @@
1
- import { compilerDependencyPins } from './compiler-dependency-pins';
2
-
3
- /** Reviewed compiler adapter dependency selections; payload checks remain authoritative.
4
- * Range-scoped entries preserve distinct dependency majors. Setup never overrides a conflicting project choice. */
5
- export const REVIEWED_DELIVERY_OVERRIDES: Record<string, string> = {
6
- "axios": "1.20.0",
7
- "@aws-sdk/client-lambda": "3.1152.0",
8
- "@aws-sdk/core": "3.978.3",
9
- "@aws-sdk/credential-provider-env": "3.972.74",
10
- "@aws-sdk/credential-provider-http": "3.972.76",
11
- "@aws-sdk/credential-provider-ini": "3.973.19",
12
- "@aws-sdk/credential-provider-login": "3.972.81",
13
- "@aws-sdk/credential-provider-node": "3.972.86",
14
- "@aws-sdk/credential-provider-process": "3.972.74",
15
- "@aws-sdk/credential-provider-sso": "3.973.18",
16
- "@aws-sdk/credential-provider-web-identity": "3.972.80",
17
- "@aws-sdk/nested-clients": "3.997.48",
18
- "@aws-sdk/signature-v4-multi-region": "3.996.48",
19
- "@aws-sdk/token-providers": "3.1150.0",
20
- "@aws-sdk/types": "3.974.6",
21
- "@smithy/types": "4.19.0",
22
- "@smithy/signature-v4": "5.7.4",
23
- "@smithy/fetch-http-handler": "5.8.0",
24
- "@smithy/credential-provider-imds": "4.5.2",
25
- "@smithy/core": "3.36.0",
26
- "@smithy/node-http-handler": "4.12.1",
27
- "bowser": "2.14.1",
28
- "follow-redirects": "1.16.1",
29
- "undici@>=5 <6": "5.29.0",
30
- "undici@>=6 <7": "6.29.0",
31
- "tslib@>=1 <2": "1.14.1",
32
- "tslib@>=2 <3": "2.7.0",
33
- "semver@>=5 <6": "5.7.2",
34
- "semver@>=6 <7": "6.3.1",
35
- "semver@>=7 <8": "7.8.5",
36
- "ansi-regex@>=6 <7": "6.4.0"
37
- };
38
-
39
- // OZ's compiler adapter follows floating AWS/Smithy ranges. Freeze that reviewed
40
- // family closure so a fresh npm resolution cannot select unqualified payloads.
41
- // Other project dependencies keep their original constraints and payload checks.
42
- for (const key of Object.keys(compilerDependencyPins)) {
43
- if (!key.startsWith('@aws-sdk/') && !key.startsWith('@smithy/')) continue;
44
- const at = key.lastIndexOf('@'), name = key.slice(0, at), version = key.slice(at + 1);
45
- const existing = REVIEWED_DELIVERY_OVERRIDES[name];
46
- if (existing && existing !== version) throw new Error('Ambiguous reviewed compiler dependency: ' + name);
47
- REVIEWED_DELIVERY_OVERRIDES[name] = version;
48
- }