@assemblyline-agents/cli 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +19 -0
  3. package/authoring/skills/assembly-line-authoring/SKILL.md +61 -10
  4. package/dist/add.d.ts +4 -0
  5. package/dist/add.d.ts.map +1 -1
  6. package/dist/add.js +191 -48
  7. package/dist/add.js.map +1 -1
  8. package/dist/args.js +1 -1
  9. package/dist/args.js.map +1 -1
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +40 -8
  12. package/dist/auth.js.map +1 -1
  13. package/dist/authoring.d.ts +2 -2
  14. package/dist/authoring.d.ts.map +1 -1
  15. package/dist/authoring.js +7 -4
  16. package/dist/authoring.js.map +1 -1
  17. package/dist/channels.d.ts +21 -0
  18. package/dist/channels.d.ts.map +1 -1
  19. package/dist/channels.js +104 -0
  20. package/dist/channels.js.map +1 -1
  21. package/dist/checkpoints.js +2 -2
  22. package/dist/checkpoints.js.map +1 -1
  23. package/dist/connections.d.ts +12 -0
  24. package/dist/connections.d.ts.map +1 -0
  25. package/dist/connections.js +55 -0
  26. package/dist/connections.js.map +1 -0
  27. package/dist/deploy-definition.js +3 -3
  28. package/dist/deploy-definition.js.map +1 -1
  29. package/dist/deploy-lifecycle.d.ts +11 -1
  30. package/dist/deploy-lifecycle.d.ts.map +1 -1
  31. package/dist/deploy-lifecycle.js +65 -16
  32. package/dist/deploy-lifecycle.js.map +1 -1
  33. package/dist/deploy.d.ts +9 -1
  34. package/dist/deploy.d.ts.map +1 -1
  35. package/dist/deploy.js +234 -29
  36. package/dist/deploy.js.map +1 -1
  37. package/dist/dev.d.ts +0 -2
  38. package/dist/dev.d.ts.map +1 -1
  39. package/dist/dev.js +9 -10
  40. package/dist/dev.js.map +1 -1
  41. package/dist/eval-case-runner.js +4 -2
  42. package/dist/eval-case-runner.js.map +1 -1
  43. package/dist/eval-fixtures.d.ts +5 -5
  44. package/dist/eval-fixtures.d.ts.map +1 -1
  45. package/dist/eval-fixtures.js +48 -22
  46. package/dist/eval-fixtures.js.map +1 -1
  47. package/dist/eval-judge.js +1 -1
  48. package/dist/eval-judge.js.map +1 -1
  49. package/dist/eval.d.ts.map +1 -1
  50. package/dist/eval.js +3 -3
  51. package/dist/eval.js.map +1 -1
  52. package/dist/help.d.ts.map +1 -1
  53. package/dist/help.js +57 -7
  54. package/dist/help.js.map +1 -1
  55. package/dist/hosts.js +1 -1
  56. package/dist/hosts.js.map +1 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +98 -19
  59. package/dist/index.js.map +1 -1
  60. package/dist/init.d.ts.map +1 -1
  61. package/dist/init.js +4 -25
  62. package/dist/init.js.map +1 -1
  63. package/dist/models.d.ts +0 -3
  64. package/dist/models.d.ts.map +1 -1
  65. package/dist/models.js +1 -9
  66. package/dist/models.js.map +1 -1
  67. package/dist/operator-client.d.ts +1 -0
  68. package/dist/operator-client.d.ts.map +1 -1
  69. package/dist/operator-client.js +158 -3
  70. package/dist/operator-client.js.map +1 -1
  71. package/dist/project-env.d.ts.map +1 -1
  72. package/dist/project-env.js +2 -7
  73. package/dist/project-env.js.map +1 -1
  74. package/dist/release-history.d.ts +20 -0
  75. package/dist/release-history.d.ts.map +1 -0
  76. package/dist/release-history.js +232 -0
  77. package/dist/release-history.js.map +1 -0
  78. package/dist/secrets.d.ts +11 -0
  79. package/dist/secrets.d.ts.map +1 -1
  80. package/dist/secrets.js +66 -13
  81. package/dist/secrets.js.map +1 -1
  82. package/dist/setup.d.ts +38 -0
  83. package/dist/setup.d.ts.map +1 -0
  84. package/dist/setup.js +107 -0
  85. package/dist/setup.js.map +1 -0
  86. package/dist/state.d.ts.map +1 -1
  87. package/dist/state.js.map +1 -1
  88. package/package.json +11 -11
@@ -1,25 +1,74 @@
1
+ /** Run provider cleanup without hiding a completed or failed deploy outcome. */
2
+ export async function executeDeployCleanup(input) {
3
+ if (!input.publisher.cleanup)
4
+ return undefined;
5
+ try {
6
+ return await input.publisher.cleanup(input.artifact, input.plan) ?? undefined;
7
+ }
8
+ catch {
9
+ return {
10
+ target: input.publisher.target,
11
+ status: "degraded",
12
+ warning: "Provider cleanup did not complete. The deployment outcome is unchanged; rerun deploy cleanup through the next deployment attempt."
13
+ };
14
+ }
15
+ }
1
16
  /** Execute the provider lifecycle in the one supported hosted-deploy order. */
2
17
  export async function executeDeployLifecycle(input) {
3
18
  const lifecycle = {};
19
+ input.onProgress?.("preflight");
4
20
  const preflight = await input.publisher.preflight?.(input.artifact, input.plan);
5
21
  if (preflight)
6
22
  lifecycle.preflight = preflight;
7
- const preparation = await input.publisher.prepare?.(input.artifact, input.plan);
8
- if (preparation)
9
- lifecycle.preparation = preparation;
10
- await input.syncSecrets();
11
- const migrationStatus = input.publisher.runMigrations
12
- ? await input.publisher.runMigrations(input.artifact, input.plan, input.migrationRequest)
13
- : await input.runFallbackMigrations();
14
- const providerReceipt = input.activate === false
15
- ? {
16
- ...(preparation ?? {}),
17
- target: input.publisher.target,
18
- status: "prepared",
19
- environment: input.plan.environment,
20
- agentRevision: input.plan.agentRevision
23
+ let sandboxEnvironment;
24
+ let preparation;
25
+ let migrationStatus = "none";
26
+ let providerReceipt;
27
+ try {
28
+ if (input.reconcileSandboxEnvironment) {
29
+ input.onProgress?.("sandbox-environment");
30
+ sandboxEnvironment = await input.reconcileSandboxEnvironment();
31
+ }
32
+ input.onProgress?.("prepare");
33
+ preparation = await input.publisher.prepare?.(input.artifact, input.plan);
34
+ if (preparation)
35
+ lifecycle.preparation = preparation;
36
+ input.onProgress?.("secrets");
37
+ await input.syncSecrets();
38
+ input.onProgress?.("migrations");
39
+ migrationStatus = input.publisher.runMigrations
40
+ ? await input.publisher.runMigrations(input.artifact, input.plan, input.migrationRequest)
41
+ : await input.runFallbackMigrations();
42
+ if (input.activate !== false)
43
+ input.onProgress?.("activate");
44
+ providerReceipt = input.activate === false
45
+ ? {
46
+ ...(preparation ?? {}),
47
+ target: input.publisher.target,
48
+ status: "prepared",
49
+ environment: input.plan.environment,
50
+ agentRevision: input.plan.agentRevision
51
+ }
52
+ : await (input.publisher.activate ?? input.publisher.publish).call(input.publisher, input.artifact, input.plan);
53
+ }
54
+ catch (error) {
55
+ if (input.publisher.cleanup) {
56
+ input.onProgress?.("cleanup");
57
+ await executeDeployCleanup(input);
21
58
  }
22
- : await (input.publisher.activate ?? input.publisher.publish).call(input.publisher, input.artifact, input.plan);
23
- return { providerReceipt, migrationStatus, lifecycle };
59
+ throw error;
60
+ }
61
+ if (input.publisher.cleanup) {
62
+ input.onProgress?.("cleanup");
63
+ const cleanup = await executeDeployCleanup(input);
64
+ if (cleanup)
65
+ lifecycle.cleanup = cleanup;
66
+ }
67
+ return {
68
+ providerReceipt,
69
+ migrationStatus,
70
+ lifecycle,
71
+ ...(sandboxEnvironment ? { sandboxEnvironment } : {})
72
+ };
24
73
  }
25
74
  //# sourceMappingURL=deploy-lifecycle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-lifecycle.js","sourceRoot":"","sources":["../src/deploy-lifecycle.ts"],"names":[],"mappings":"AAcA,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAQ5C;IACC,MAAM,SAAS,GAAkC,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,SAAS;QAAE,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/C,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,WAAW;QAAE,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC;IACrD,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC;IAC1B,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,aAAa;QACnD,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC;QACzF,CAAC,CAAC,MAAM,KAAK,CAAC,qBAAqB,EAAE,CAAC;IACxC,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,KAAK,KAAK;QAC9C,CAAC,CAAC;YACE,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;YACtB,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM;YAC9B,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW;YACnC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa;SACxC;QACH,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAC9D,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,IAAI,CACX,CAAC;IACN,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AACzD,CAAC"}
1
+ {"version":3,"file":"deploy-lifecycle.js","sourceRoot":"","sources":["../src/deploy-lifecycle.ts"],"names":[],"mappings":"AAyBA,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAI1C;IACC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM;YAC9B,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,mIAAmI;SAC7I,CAAC;IACJ,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAU5C;IACC,MAAM,SAAS,GAAkC,EAAE,CAAC;IACpD,KAAK,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,SAAS;QAAE,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/C,IAAI,kBAA4D,CAAC;IACjE,IAAI,WAAiC,CAAC;IACtC,IAAI,eAAe,GAAG,MAAM,CAAC;IAC7B,IAAI,eAA8B,CAAC;IACnC,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,2BAA2B,EAAE,CAAC;YACtC,KAAK,CAAC,UAAU,EAAE,CAAC,qBAAqB,CAAC,CAAC;YAC1C,kBAAkB,GAAG,MAAM,KAAK,CAAC,2BAA2B,EAAE,CAAC;QACjE,CAAC;QACD,KAAK,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9B,WAAW,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1E,IAAI,WAAW;YAAE,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC;QACrD,KAAK,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9B,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC;QAC1B,KAAK,CAAC,UAAU,EAAE,CAAC,YAAY,CAAC,CAAC;QACjC,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,aAAa;YAC7C,CAAC,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC;YACzF,CAAC,CAAC,MAAM,KAAK,CAAC,qBAAqB,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK;YAAE,KAAK,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC;QAC7D,eAAe,GAAG,KAAK,CAAC,QAAQ,KAAK,KAAK;YACxC,CAAC,CAAC;gBACE,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;gBACtB,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM;gBAC9B,MAAM,EAAE,UAAU;gBAClB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW;gBACnC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa;aACxC;YACH,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAC9D,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,IAAI,CACX,CAAC;IACR,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YAC5B,KAAK,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC;YAC9B,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAC5B,KAAK,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,OAAO;YAAE,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3C,CAAC;IACD,OAAO;QACL,eAAe;QACf,eAAe;QACf,SAAS;QACT,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC"}
package/dist/deploy.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { type DeploymentPlan } from "@assemblyline-agents/compiler";
1
+ import { type BuildArtifact, type DeploymentPlan } from "@assemblyline-agents/compiler";
2
+ import type { SandboxEnvironmentResolution } from "@assemblyline-agents/core";
2
3
  import { type ParsedArgs } from "./args.js";
3
4
  export { parseEnvSecrets } from "./project-env.js";
4
5
  export declare function runDeployCommand(agentRoot: string, parsed: ParsedArgs): Promise<void>;
@@ -7,6 +8,13 @@ export declare function splitDeploySecrets(secrets: Record<string, string>, plan
7
8
  runtimeSecrets: Record<string, string>;
8
9
  localDeployKeys: string[];
9
10
  };
11
+ /**
12
+ * Reuse a sandbox artifact proven by a successful receipt when its provider and
13
+ * content fingerprint are unchanged. Runtime credentials stay on the host;
14
+ * only the provider-safe artifact reference crosses deploys.
15
+ */
16
+ export declare function reusableSandboxEnvironmentResolution(artifact: Pick<BuildArtifact, "root" | "manifest">, environmentName: string): SandboxEnvironmentResolution | undefined;
17
+ export declare function sandboxPassthroughEnv(env: NodeJS.ProcessEnv, names: string[]): Record<string, string>;
10
18
  export declare function runCommand(commandName: string, args: string[], options?: {
11
19
  cwd?: string;
12
20
  env?: NodeJS.ProcessEnv;
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAgBvC,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAO/F,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAqF3F;AA2HD,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,cAAc,GACnB;IAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBvE;AAwKD,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACxE,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B/D;AAcD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAG5D"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAQV,4BAA4B,EAC7B,MAAM,2BAA2B,CAAC;AAUnC,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAmB/F,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG3F;AAwKD,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,cAAc,GACnB;IAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBvE;AAqPD;;;;GAIG;AACH,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,UAAU,CAAC,EAClD,eAAe,EAAE,MAAM,GACtB,4BAA4B,GAAG,SAAS,CA0B1C;AAUD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWrG;AA4DD,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACxE,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B/D;AAeD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAG5D"}
package/dist/deploy.js CHANGED
@@ -3,15 +3,18 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { buildAgent, compileAgent, planDeployment } from "@assemblyline-agents/compiler";
6
- import { sanitizeDeployName } from "@assemblyline-agents/core";
7
- import { installSignalHandlers, listenNodeRuntime, resolveProvider } from "@assemblyline-agents/node";
6
+ import { adapterProviderMetadata, isSensitiveSandboxEnvName, sanitizeDeployName } from "@assemblyline-agents/core";
7
+ import { installSignalHandlers, listenNodeRuntime, resolveProvider, resolveSecretsEnv } from "@assemblyline-agents/node";
8
8
  import { FileStateAdapter, LocalBlobAdapter, LocalSandboxAdapter, AssemblyLineRuntime, loadRuntimeBundle } from "@assemblyline-agents/runtime";
9
9
  import { booleanFlag, buildOptions, numberFlag, stringFlag } from "./args.js";
10
10
  import { printIssues } from "./help.js";
11
11
  import { missingPackageFixLines } from "./init.js";
12
+ import { checkChannelInstallations } from "./channels.js";
13
+ import { wireConnectionEvents } from "./connections.js";
12
14
  import { resolveDeployDefinition, resolveDeployEnvironment } from "./deploy-definition.js";
13
- import { executeDeployLifecycle } from "./deploy-lifecycle.js";
15
+ import { executeDeployCleanup, executeDeployLifecycle } from "./deploy-lifecycle.js";
14
16
  import { loadProjectEnv, readEnvSecretsFile } from "./project-env.js";
17
+ import { prepareReleaseSnapshot, releaseSnapshotForReceipt, withReleaseSnapshot, } from "./release-history.js";
15
18
  export { parseEnvSecrets } from "./project-env.js";
16
19
  export async function runDeployCommand(agentRoot, parsed) {
17
20
  loadProjectEnv(agentRoot);
@@ -26,20 +29,25 @@ export async function runDeployCommand(agentRoot, parsed) {
26
29
  const manifest = compileAgent({ root: agentRoot });
27
30
  deployOptions.environment = resolveDeployEnvironment(manifest, parsed);
28
31
  printIssues(manifest.validation.issues.filter((issue) => issue.code === "provider-package-unresolved"), { agentRoot });
29
- const plan = planDeployment(manifest, deployOptions);
32
+ const plan = planDeployment(manifest, { ...deployOptions, env: await resolveDeploySecretsEnv(manifest, agentRoot) });
30
33
  const definition = resolveDeployDefinition(manifest, plan.target, parsed);
31
- plan.missingRequirements = await effectiveMissingRequirements(plan, definition);
34
+ plan.missingRequirements = await effectiveMissingRequirements(plan, definition, manifest);
32
35
  printDeployWarnings(plan);
33
36
  console.log(JSON.stringify(plan, null, 2));
34
37
  return;
35
38
  }
36
- const artifact = buildAgent(buildOptions(parsed, agentRoot));
39
+ const artifact = await buildAgent(buildOptions(parsed, agentRoot));
37
40
  deployOptions.environment = resolveDeployEnvironment(artifact.manifest, parsed);
38
- const plan = planDeployment(artifact.manifest, deployOptions);
41
+ const deployEnv = await resolveDeploySecretsEnv(artifact.manifest, agentRoot);
42
+ const plan = planDeployment(artifact.manifest, { ...deployOptions, env: deployEnv });
43
+ const controlOnlyOperation = ["activate", "rollback", "ingress-only", "destroy"]
44
+ .some((flag) => booleanFlag(parsed, flag));
45
+ if (!controlOnlyOperation)
46
+ await preflightChannelInstallations(artifact);
39
47
  const definition = resolveDeployDefinition(artifact.manifest, plan.target, parsed);
40
48
  const effectivePlan = {
41
49
  ...plan,
42
- missingRequirements: await effectiveMissingRequirements(plan, definition),
50
+ missingRequirements: await effectiveMissingRequirements(plan, definition, artifact.manifest, reusableSandboxEnvironmentResolution(artifact, plan.environment)),
43
51
  canPublish: false
44
52
  };
45
53
  effectivePlan.canPublish = !effectivePlan.dryRun && effectivePlan.missingRequirements.length === 0;
@@ -82,6 +90,7 @@ export async function runDeployCommand(agentRoot, parsed) {
82
90
  state: new FileStateAdapter(resolve(artifact.root, "deploy-state.json")),
83
91
  blob: new LocalBlobAdapter(resolve(artifact.root, "blobs")),
84
92
  sandbox: new LocalSandboxAdapter(resolve(artifact.root, "sandbox")),
93
+ env: deployEnv,
85
94
  devMode: true,
86
95
  port: numberFlag(parsed, "port") ?? 0
87
96
  });
@@ -97,7 +106,41 @@ export async function runDeployCommand(agentRoot, parsed) {
97
106
  console.log(`Local deploy prepared for revision ${effectivePlan.agentRevision}. Run assembly-line serve to keep it online.`);
98
107
  return;
99
108
  }
100
- await runProviderDeploy(artifact, effectivePlan, definition, parsed, agentRoot);
109
+ const release = !booleanFlag(parsed, "destroy") && !booleanFlag(parsed, "ingress-only")
110
+ ? prepareReleaseSnapshot(agentRoot, artifact.manifest)
111
+ : undefined;
112
+ await runProviderDeploy(artifact, effectivePlan, definition, parsed, agentRoot, release, deployEnv);
113
+ }
114
+ /**
115
+ * The env view deploy planning and secret sync work from: the process
116
+ * environment overlaid with the gateway's secrets store when one is
117
+ * configured, so declared secrets held only in the store still satisfy
118
+ * preflight and reach `--sync-secrets` without per-agent `.env` copies.
119
+ */
120
+ async function resolveDeploySecretsEnv(manifest, agentRoot) {
121
+ return resolveSecretsEnv({
122
+ manifest,
123
+ env: process.env,
124
+ artifactRoot: agentRoot,
125
+ providerRoot: fileURLToPath(new URL("..", import.meta.url)),
126
+ devMode: false
127
+ });
128
+ }
129
+ async function preflightChannelInstallations(artifact) {
130
+ const checks = await checkChannelInstallations(artifact.manifest, process.env, fetch);
131
+ for (const check of checks) {
132
+ const workspace = check.workspace ? ` (${check.workspace})` : "";
133
+ if (check.skipped) {
134
+ console.warn(`Channel preflight skipped for ${check.provider}${workspace}: ${check.detail}`);
135
+ continue;
136
+ }
137
+ if (!check.ok)
138
+ throw new Error(`Channel preflight failed for ${check.provider}${workspace}: ${check.detail}`);
139
+ console.log(`Channel preflight passed for ${check.provider}${workspace}.`);
140
+ if (check.missingOptionalScopes.length > 0) {
141
+ console.warn(`Optional ${check.provider} scopes not granted: ${check.missingOptionalScopes.join(", ")}.`);
142
+ }
143
+ }
101
144
  }
102
145
  /**
103
146
  * The canonical receipt is per environment (`deployments/<environment>.json`).
@@ -131,13 +174,16 @@ function assertDestroyAllowed(plan, parsed) {
131
174
  throw new Error(`Refusing to destroy the default environment "${plan.environment}" without --force. Alternate environments (--env <name>) are presumed disposable; the default one is not.`);
132
175
  }
133
176
  }
134
- async function effectiveMissingRequirements(plan, definition) {
177
+ async function effectiveMissingRequirements(plan, definition, manifest, reusableSandboxEnvironment) {
135
178
  let missing = plan.missingRequirements;
136
179
  // VPS runtime credentials are validated from the remote 0600 secret file
137
180
  // after optional sync. This allows repeat deploys without copying secrets
138
181
  // from the VPS back onto the operator machine.
139
182
  if (plan.target === "vps" && !plan.dryRun) {
140
- missing = missing.filter((requirement) => requirement.kind !== "env");
183
+ const sandboxKind = manifest.gateway.sandbox?.kind ?? "local";
184
+ const provisioningEnv = new Set(adapterProviderMetadata(sandboxKind, "sandbox")?.sandboxEnvironment?.provisioningEnv ?? []);
185
+ missing = missing.filter((requirement) => requirement.kind !== "env"
186
+ || (provisioningEnv.has(requirement.name) && !reusableSandboxEnvironment));
141
187
  }
142
188
  if (plan.target === "railway" && missing.some((requirement) => requirement.name === "RAILWAY_TOKEN")) {
143
189
  const railwayBin = stringOption(definition, "railwayBin") ?? "railway";
@@ -185,7 +231,7 @@ function printDeployWarnings(plan) {
185
231
  * is set and the publisher supports it. Reads `--secrets-from <path>` or the
186
232
  * project `.env`. Logs key names only — never values.
187
233
  */
188
- async function syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot) {
234
+ async function syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot, deployEnv) {
189
235
  if (!booleanFlag(parsed, "sync-secrets"))
190
236
  return;
191
237
  if (!publisher.syncSecrets) {
@@ -200,7 +246,7 @@ async function syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot)
200
246
  const fileSecrets = existsSync(secretsPath)
201
247
  ? readEnvSecretsFile(secretsPath)
202
248
  : {};
203
- const secrets = withDeclaredRuntimeEnv(fileSecrets, plan, process.env);
249
+ const secrets = withDeclaredRuntimeEnv(fileSecrets, plan, deployEnv);
204
250
  const { runtimeSecrets, localDeployKeys } = splitDeploySecrets(secrets, plan);
205
251
  if (localDeployKeys.length > 0) {
206
252
  console.log(`Kept ${localDeployKeys.length} deploy credential(s) local: ${localDeployKeys.join(", ")}`);
@@ -259,7 +305,7 @@ async function railwayCliAuthenticated(railwayBin) {
259
305
  * Every non-local target resolves through the open provider registry. Built-in
260
306
  * flags only normalize provider options; publishing follows this single path.
261
307
  */
262
- async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot) {
308
+ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot, release, deployEnv) {
263
309
  if (parsed.flags["domains-only"] !== undefined) {
264
310
  throw new Error("--domains-only was removed. Use --ingress-only.");
265
311
  }
@@ -290,9 +336,12 @@ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot)
290
336
  if (booleanFlag(parsed, "activate")) {
291
337
  if (!publisher.activate)
292
338
  throw new Error(`Deploy target ${plan.target} does not support separate activation.`);
339
+ const activate = publisher.activate;
293
340
  await publisher.preflight?.(artifact, plan);
294
- const receipt = await publisher.activate(artifact, plan);
341
+ const providerReceipt = await deployActionWithCleanup(publisher, artifact, plan, () => activate.call(publisher, artifact, plan));
342
+ const receipt = withReleaseSnapshot(providerReceipt, releaseSnapshotForReceipt(release, providerReceipt, true));
295
343
  writeDeployReceipt(artifact.root, plan, receipt);
344
+ await wireDeployedConnectionEvents(artifact.manifest, receipt);
296
345
  console.log(`${deployTargetLabel(plan.target)} prepared release activated.`);
297
346
  console.log(JSON.stringify(receipt, null, 2));
298
347
  return;
@@ -300,9 +349,12 @@ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot)
300
349
  if (booleanFlag(parsed, "rollback")) {
301
350
  if (!publisher.rollback)
302
351
  throw new Error(`Deploy target ${plan.target} does not support rollback.`);
352
+ const rollback = publisher.rollback;
303
353
  await publisher.preflight?.(artifact, plan);
304
- const receipt = await publisher.rollback(artifact, plan);
354
+ const providerReceipt = await deployActionWithCleanup(publisher, artifact, plan, () => rollback.call(publisher, artifact, plan));
355
+ const receipt = withReleaseSnapshot(providerReceipt, releaseSnapshotForReceipt(release, providerReceipt, true));
305
356
  writeDeployReceipt(artifact.root, plan, receipt);
357
+ await wireDeployedConnectionEvents(artifact.manifest, receipt);
306
358
  console.log(`${deployTargetLabel(plan.target)} release rolled back.`);
307
359
  console.log(JSON.stringify(receipt, null, 2));
308
360
  return;
@@ -310,37 +362,195 @@ async function runProviderDeploy(artifact, plan, definition, parsed, agentRoot)
310
362
  if (booleanFlag(parsed, "ingress-only")) {
311
363
  if (!publisher.reconcileIngress)
312
364
  throw new Error(`Deploy target ${plan.target} does not support ingress reconciliation.`);
365
+ const reconcileIngress = publisher.reconcileIngress;
313
366
  await publisher.preflight?.(artifact, plan);
314
- const receipt = await publisher.reconcileIngress(artifact, plan);
367
+ const receipt = await deployActionWithCleanup(publisher, artifact, plan, () => reconcileIngress.call(publisher, artifact, plan));
315
368
  writeDeployReceipt(artifact.root, plan, receipt);
316
369
  console.log(`${deployTargetLabel(plan.target)} ingress reconciled.`);
317
370
  console.log(JSON.stringify(receipt, null, 2));
318
371
  return;
319
372
  }
320
373
  const prepareOnly = booleanFlag(parsed, "prepare-only");
374
+ const reconcileSandboxEnvironment = sandboxEnvironmentReconciler(artifact, reusableSandboxEnvironmentResolution(artifact, plan.environment));
321
375
  console.log(`${prepareOnly ? "Preparing" : "Publishing"} Assembly Line revision ${plan.agentRevision} with ${plan.target}.`);
322
376
  const migrationRequest = configuredMigrationRequest(artifact, parsed);
323
- const { providerReceipt, migrationStatus, lifecycle } = await executeDeployLifecycle({
377
+ const progressStages = [
378
+ "preflight",
379
+ ...(reconcileSandboxEnvironment ? ["sandbox-environment"] : []),
380
+ "prepare",
381
+ "secrets",
382
+ "migrations",
383
+ ...(!prepareOnly ? ["activate"] : []),
384
+ ...(publisher.cleanup ? ["cleanup"] : [])
385
+ ];
386
+ const progressLabels = {
387
+ preflight: "Checking provider and host",
388
+ "sandbox-environment": "Reconciling sandbox environment",
389
+ prepare: "Uploading artifact and preparing runtime image",
390
+ secrets: "Reconciling runtime secrets",
391
+ migrations: "Running migrations",
392
+ activate: "Activating and health-checking the release",
393
+ cleanup: "Cleaning managed deployment artifacts"
394
+ };
395
+ const { providerReceipt, migrationStatus, lifecycle, sandboxEnvironment } = await executeDeployLifecycle({
324
396
  publisher,
325
397
  artifact,
326
398
  plan,
327
399
  migrationRequest,
328
400
  activate: !prepareOnly,
329
- syncSecrets: () => syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot),
330
- runFallbackMigrations: () => runConfiguredMigrations(artifact, plan, migrationRequest)
401
+ ...(reconcileSandboxEnvironment ? { reconcileSandboxEnvironment } : {}),
402
+ syncSecrets: () => syncDeploySecretsIfRequested(publisher, plan, parsed, agentRoot, deployEnv),
403
+ runFallbackMigrations: () => runConfiguredMigrations(artifact, plan, migrationRequest),
404
+ onProgress: (stage) => {
405
+ const index = progressStages.indexOf(stage);
406
+ if (index >= 0)
407
+ console.log(`[${index + 1}/${progressStages.length}] ${progressLabels[stage]}`);
408
+ }
331
409
  });
332
- const receipt = {
410
+ const providerLifecycleReceipt = {
333
411
  ...providerReceipt,
334
412
  migrationStatus,
413
+ ...(sandboxEnvironment ? { sandboxEnvironment } : {}),
335
414
  ...(Object.keys(lifecycle).length > 0 ? { lifecycle } : {})
336
415
  };
416
+ const receipt = withReleaseSnapshot(providerLifecycleReceipt, releaseSnapshotForReceipt(release, providerLifecycleReceipt, !prepareOnly));
337
417
  writeDeployReceipt(artifact.root, plan, receipt);
418
+ if (!prepareOnly)
419
+ await wireDeployedConnectionEvents(artifact.manifest, receipt);
338
420
  console.log(`${deployTargetLabel(plan.target)} deploy ${prepareOnly ? "prepared" : "completed"}.`);
339
421
  if (artifact.manifest.deploymentRequirements?.remoteExecution) {
340
422
  console.log(`Codex CLI and persistent credential storage are provisioned. Run \`assembly-line auth codex <agentRoot> --target ${plan.target} --env ${plan.environment}${prepareOnly ? " --prepared" : ""}\` to complete device authentication; OAuth tokens are not deployment secrets.`);
341
423
  }
342
424
  console.log(JSON.stringify(receipt, null, 2));
343
425
  }
426
+ async function deployActionWithCleanup(publisher, artifact, plan, action) {
427
+ try {
428
+ const receipt = await action();
429
+ const cleanup = await executeDeployCleanup({ publisher, artifact, plan });
430
+ return cleanup ? { ...receipt, cleanup } : receipt;
431
+ }
432
+ catch (error) {
433
+ await executeDeployCleanup({ publisher, artifact, plan });
434
+ throw error;
435
+ }
436
+ }
437
+ async function wireDeployedConnectionEvents(manifest, receipt) {
438
+ if (!manifest.connections.some((connection) => connection.events?.enabled))
439
+ return;
440
+ const deploymentUrl = receiptField(receipt, "deploymentUrl");
441
+ if (!deploymentUrl) {
442
+ console.warn("Connection events were not wired because the deploy target did not return a public deployment URL. Run `assembly-line connections wire <agentRoot> --url <publicUrl>` after ingress is available.");
443
+ return;
444
+ }
445
+ const result = await wireConnectionEvents({
446
+ baseUrl: deploymentUrl,
447
+ ...(process.env.ASSEMBLY_LINE_ADMIN_TOKEN ? { token: process.env.ASSEMBLY_LINE_ADMIN_TOKEN } : {}),
448
+ force: false
449
+ });
450
+ console.log("Connection event subscriptions reconciled.");
451
+ console.log(JSON.stringify(result, null, 2));
452
+ }
453
+ function receiptField(receipt, name) {
454
+ if (!receipt || typeof receipt !== "object" || Array.isArray(receipt))
455
+ return undefined;
456
+ const value = receipt[name];
457
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
458
+ }
459
+ function sandboxEnvironmentReconciler(artifact, reusableResolution) {
460
+ const definition = artifact.manifest.gateway.sandbox;
461
+ if (!definition || definition.kind === "local")
462
+ return undefined;
463
+ const sandbox = artifact.manifest.sandboxes.find((candidate) => candidate.adapter === definition.kind && candidate.environment);
464
+ const environment = sandbox?.environment;
465
+ if (!sandbox || !environment)
466
+ return undefined;
467
+ if (reusableResolution)
468
+ return async () => reusableResolution;
469
+ return async () => {
470
+ const passthroughEnv = sandboxPassthroughEnv(process.env, sandbox.env);
471
+ const provider = await resolveProvider("sandbox", definition, {
472
+ env: process.env,
473
+ fetch,
474
+ manifest: artifact.manifest,
475
+ artifactRoot: artifact.root,
476
+ providerRoot: fileURLToPath(new URL("..", import.meta.url)),
477
+ devMode: false
478
+ }, {
479
+ ...(sandbox.image ? { image: sandbox.image } : {}),
480
+ environment,
481
+ ...(Object.keys(passthroughEnv).length > 0 ? { env: passthroughEnv } : {}),
482
+ ...(sandbox.workingDirectory ? { workingDirectory: sandbox.workingDirectory } : {}),
483
+ agentId: artifact.manifest.agent.id ?? artifact.manifest.agent.name ?? "agent",
484
+ sandboxName: sandbox.name
485
+ });
486
+ if (!provider.ensureEnvironment) {
487
+ throw new Error(`Sandbox provider ${definition.kind} cannot reconcile the compiled environment for ${sandbox.name}.`);
488
+ }
489
+ return provider.ensureEnvironment({
490
+ agentId: artifact.manifest.agent.id ?? artifact.manifest.agent.name ?? "agent",
491
+ sandboxName: sandbox.name,
492
+ adapter: definition.kind,
493
+ artifactRoot: artifact.root,
494
+ environment
495
+ });
496
+ };
497
+ }
498
+ /**
499
+ * Reuse a sandbox artifact proven by a successful receipt when its provider and
500
+ * content fingerprint are unchanged. Runtime credentials stay on the host;
501
+ * only the provider-safe artifact reference crosses deploys.
502
+ */
503
+ export function reusableSandboxEnvironmentResolution(artifact, environmentName) {
504
+ const definition = artifact.manifest.gateway.sandbox;
505
+ if (!definition || definition.kind === "local")
506
+ return undefined;
507
+ const sandbox = artifact.manifest.sandboxes.find((candidate) => candidate.adapter === definition.kind && candidate.environment);
508
+ const fingerprint = sandbox?.environment?.fingerprint;
509
+ if (!fingerprint)
510
+ return undefined;
511
+ const candidates = [
512
+ environmentReceiptPath(artifact.root, environmentName),
513
+ resolve(artifact.root, "deployment.json")
514
+ ];
515
+ for (const path of candidates) {
516
+ try {
517
+ const receipt = JSON.parse(readFileSync(path, "utf8"));
518
+ if (receipt.status !== "published" || receipt.environment !== environmentName)
519
+ continue;
520
+ const resolution = receipt.sandboxEnvironment;
521
+ if (!isSandboxEnvironmentResolution(resolution))
522
+ continue;
523
+ if (resolution.provider !== definition.kind || resolution.fingerprint !== fingerprint)
524
+ continue;
525
+ return { ...resolution, action: "reused" };
526
+ }
527
+ catch {
528
+ // Missing, stale, or malformed receipts are not reuse evidence.
529
+ }
530
+ }
531
+ return undefined;
532
+ }
533
+ function isSandboxEnvironmentResolution(value) {
534
+ if (!value || typeof value !== "object" || Array.isArray(value))
535
+ return false;
536
+ const record = value;
537
+ return ["provider", "artifactKind", "fingerprint", "artifactId", "runtimeReference"]
538
+ .every((key) => typeof record[key] === "string" && record[key].length > 0)
539
+ && ["reused", "built", "external"].includes(String(record.action));
540
+ }
541
+ export function sandboxPassthroughEnv(env, names) {
542
+ const values = {};
543
+ for (const name of names) {
544
+ const value = env[name];
545
+ if (value !== undefined)
546
+ values[name] = value;
547
+ }
548
+ const sensitive = Object.keys(values).filter(isSensitiveSandboxEnvName);
549
+ if (sensitive.length > 0) {
550
+ throw new Error(`Refusing host/control-plane secrets in global sandbox env: ${sensitive.join(", ")}.`);
551
+ }
552
+ return values;
553
+ }
344
554
  function deployTargetLabel(target) {
345
555
  if (target === "railway")
346
556
  return "Railway";
@@ -358,7 +568,7 @@ function stringOption(definition, name) {
358
568
  }
359
569
  function configuredMigrationRequest(artifact, parsed) {
360
570
  const entries = migrationEntriesForArtifact(artifact);
361
- const command = stringFlag(parsed, "migration-command") ?? process.env.OPENEVE_MIGRATION_COMMAND;
571
+ const command = stringFlag(parsed, "migration-command") ?? process.env.ASSEMBLY_LINE_MIGRATION_COMMAND;
362
572
  if (entries.length > 0 && !command) {
363
573
  throw new Error("Migration files are present, but no migration runner was configured. Pass --migration-command or set ASSEMBLY_LINE_MIGRATION_COMMAND.");
364
574
  }
@@ -375,18 +585,12 @@ async function runConfiguredMigrations(artifact, plan, request) {
375
585
  console.log(`Running ${entries.length} migration file(s) with ${commandName}.`);
376
586
  const result = await runCommand(commandName, [], {
377
587
  cwd: artifact.root,
378
- // Both spellings, permanently (the env-alias mirror never soaks out) so
379
- // migration runners written against either prefix keep working.
380
588
  env: {
381
589
  ...process.env,
382
590
  ASSEMBLY_LINE_ARTIFACT_ROOT: artifact.root,
383
591
  ASSEMBLY_LINE_AGENT_REVISION: plan.agentRevision,
384
592
  ASSEMBLY_LINE_DEPLOY_ENV: plan.environment,
385
- ASSEMBLY_LINE_MIGRATION_FILES: JSON.stringify(entries),
386
- OPENEVE_ARTIFACT_ROOT: artifact.root,
387
- OPENEVE_AGENT_REVISION: plan.agentRevision,
388
- OPENEVE_DEPLOY_ENV: plan.environment,
389
- OPENEVE_MIGRATION_FILES: JSON.stringify(entries)
593
+ ASSEMBLY_LINE_MIGRATION_FILES: JSON.stringify(entries)
390
594
  }
391
595
  });
392
596
  if (result.exitCode !== 0) {
@@ -441,6 +645,7 @@ function localDeployReceipt(artifact, plan, status, deploymentUrl) {
441
645
  status,
442
646
  environment: plan.environment,
443
647
  agentRevision: plan.agentRevision,
648
+ buildRevision: plan.buildRevision ?? plan.agentRevision,
444
649
  artifactRoot: artifact.root,
445
650
  deploymentUrl,
446
651
  completedAt: new Date().toISOString()