@orchestraworks/cli 0.5.8 → 0.7.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 (91) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/api/approval.js +3 -3
  3. package/dist/cli/commands/outpost/local.js +3 -3
  4. package/dist/cli/commands/outpost/machine-names.d.ts +17 -0
  5. package/dist/cli/commands/outpost/machine-names.js +22 -0
  6. package/dist/cli/commands/outpost/up.js +7 -5
  7. package/dist/cli/commands/worker/enroll.d.ts +4 -3
  8. package/dist/cli/commands/worker/enroll.js +4 -3
  9. package/dist/cli/core/auth.d.ts +11 -1
  10. package/dist/cli/core/auth.js +21 -4
  11. package/dist/cli/core/session-body.d.ts +1 -1
  12. package/dist/cli/core/session-body.js +1 -1
  13. package/dist/cli/firstRun.js +2 -2
  14. package/dist/cli/main.js +4 -3
  15. package/dist/constructs/environment.d.ts +24 -11
  16. package/dist/constructs/environment.js +76 -12
  17. package/dist/constructs/secret.d.ts +17 -7
  18. package/dist/constructs/secret.js +24 -16
  19. package/dist/core/labels.d.ts +32 -6
  20. package/dist/core/labels.js +70 -8
  21. package/dist/engine/diff.js +38 -11
  22. package/dist/engine/gateway-key-reconcile.d.ts +1 -2
  23. package/dist/engine/gateway-key-reconcile.js +19 -15
  24. package/dist/engine/pipeline-reconcile.js +2 -2
  25. package/dist/engine/pipeline-workflow-reconcile.js +15 -9
  26. package/dist/engine/reconcile.js +48 -15
  27. package/dist/engine/refusals.d.ts +0 -5
  28. package/dist/engine/refusals.js +1 -5
  29. package/dist/engine/secrets-apply.d.ts +10 -14
  30. package/dist/engine/secrets-apply.js +12 -17
  31. package/dist/engine/workflow-reconcile.d.ts +1 -1
  32. package/dist/generated/cli-commands.json +170 -34
  33. package/dist/generated/providers.d.ts +40 -0
  34. package/dist/generated/providers.js +30 -0
  35. package/docs/REFERENCE.md +9 -7
  36. package/node_modules/@orchestraworks/client/dist/esm/models/ApiErrorDetail.d.ts +1 -1
  37. package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.d.ts +7 -0
  38. package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.js +3 -0
  39. package/node_modules/@orchestraworks/client/dist/esm/models/CreateSecretRequest.d.ts +4 -3
  40. package/node_modules/@orchestraworks/client/dist/esm/models/Environment.d.ts +7 -0
  41. package/node_modules/@orchestraworks/client/dist/esm/models/Environment.js +3 -0
  42. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentCredential.d.ts +38 -0
  43. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentCredential.js +45 -0
  44. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpec.d.ts +1 -1
  45. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpecRequest.d.ts +1 -1
  46. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.d.ts +1 -1
  47. package/node_modules/@orchestraworks/client/dist/esm/models/InjectionRecipe.d.ts +6 -0
  48. package/node_modules/@orchestraworks/client/dist/esm/models/InjectionRecipe.js +2 -0
  49. package/node_modules/@orchestraworks/client/dist/esm/models/OAuthTokenRequest.d.ts +1 -1
  50. package/node_modules/@orchestraworks/client/dist/esm/models/Secret.d.ts +1 -7
  51. package/node_modules/@orchestraworks/client/dist/esm/models/Secret.js +0 -4
  52. package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.d.ts +7 -0
  53. package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.js +3 -0
  54. package/node_modules/@orchestraworks/client/dist/esm/models/UpdateSecretRequest.d.ts +4 -3
  55. package/node_modules/@orchestraworks/client/dist/esm/models/index.d.ts +1 -0
  56. package/node_modules/@orchestraworks/client/dist/esm/models/index.js +1 -0
  57. package/node_modules/@orchestraworks/client/dist/models/ApiErrorDetail.d.ts +1 -1
  58. package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.d.ts +7 -0
  59. package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.js +3 -0
  60. package/node_modules/@orchestraworks/client/dist/models/CreateSecretRequest.d.ts +4 -3
  61. package/node_modules/@orchestraworks/client/dist/models/Environment.d.ts +7 -0
  62. package/node_modules/@orchestraworks/client/dist/models/Environment.js +3 -0
  63. package/node_modules/@orchestraworks/client/dist/models/EnvironmentCredential.d.ts +38 -0
  64. package/node_modules/@orchestraworks/client/dist/models/EnvironmentCredential.js +52 -0
  65. package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpec.d.ts +1 -1
  66. package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpecRequest.d.ts +1 -1
  67. package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.d.ts +1 -1
  68. package/node_modules/@orchestraworks/client/dist/models/InjectionRecipe.d.ts +6 -0
  69. package/node_modules/@orchestraworks/client/dist/models/InjectionRecipe.js +2 -0
  70. package/node_modules/@orchestraworks/client/dist/models/OAuthTokenRequest.d.ts +1 -1
  71. package/node_modules/@orchestraworks/client/dist/models/Secret.d.ts +1 -7
  72. package/node_modules/@orchestraworks/client/dist/models/Secret.js +0 -4
  73. package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.d.ts +7 -0
  74. package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.js +3 -0
  75. package/node_modules/@orchestraworks/client/dist/models/UpdateSecretRequest.d.ts +4 -3
  76. package/node_modules/@orchestraworks/client/dist/models/index.d.ts +1 -0
  77. package/node_modules/@orchestraworks/client/dist/models/index.js +1 -0
  78. package/node_modules/@orchestraworks/client/package.json +1 -1
  79. package/package.json +4 -4
  80. package/skills/orchestra/SKILL.md +132 -18
  81. package/skills/orchestra-fdk/references/authoring.md +511 -20
  82. package/skills/orchestra-fdk/references/environment.md +49 -12
  83. package/skills/orchestra-fdk/references/integrations/code-repo.md +26 -5
  84. package/skills/orchestra-fdk/references/phases/1-discover.md +1 -1
  85. package/skills/orchestra-fdk/references/phases/2-plan.md +1 -1
  86. package/skills/orchestra-fdk/references/troubleshooting.md +3 -2
  87. package/templates/bug-fix/main.ts +7 -4
  88. package/templates/engineering-team/lib/environment.ts +6 -3
  89. package/templates/engineering-team/package.json +1 -1
  90. package/templates/todo-factory/main.ts +7 -4
  91. package/templates/todo-factory/package.json +1 -1
@@ -6,7 +6,7 @@
6
6
  import { CONNECTOR_SECRET_WIRE_FIELDS, connectorImmutableFields, } from "../constructs/connector.js";
7
7
  import { isEnvImportMarker, parseEnvImportMarker } from "../constructs/references.js";
8
8
  import { isGatewayKeyRecipe } from "../core/gateway-key-recipe.js";
9
- import { createLabels, labelsPatch, MANAGED_BY_LABEL_KEY, stampManagedBy } from "../core/labels.js";
9
+ import { createLabels, labelsPatch, MANAGED_BY_LABEL_KEY, oldMarkersMoved, stampManagedBy } from "../core/labels.js";
10
10
  import { isRefToken, parseRefToken, refToken } from "../core/tokens.js";
11
11
  import { ApplyError, credentialValueWritten, defaultPrint, createTeamResolver, describeTargetOrganization, failing, getBySlugOrUndefined, modelSettingsUnchanged, stampTeam, standbyCapacityUnchanged, subsetDeepEqual, } from "./apply-core.js";
12
12
  import { preApprovalLevers, typedAtTerminalRemedy, } from "../cli/core/approval-policy.js";
@@ -22,7 +22,7 @@ import { applyCeremonyBackedConnection, isCeremonyBackedConnection, } from "./co
22
22
  import { assertManagedChatConnectionForDesired } from "./connection-readiness.js";
23
23
  import { removedConfigurationNotice } from "./connector-configuration.js";
24
24
  import { PreflightError, PreflightRefusalError, readConnection, RedactedRefError, reservedProviderSecretIds, resolveSecretRef, validateConnectionImport, validateRefShape, } from "./preflight.js";
25
- import { allRootSourceLabels, commandLineOccurrencesFor, containsCommandLineRecipe, declaredSecretHosts, decideSecretWrite, metadataHostsChange, metadataInjectionChange, pendingSecretWrite, reconcileInjection, replacesLiveCredentialValue, resolveSecretValueSource, } from "./secrets-apply.js";
25
+ import { allRootSourceLabels, commandLineOccurrencesFor, containsCommandLineRecipe, declaredSecretInjection, decideSecretWrite, metadataInjectionChange, pendingSecretWrite, reconcileInjection, replacesLiveCredentialValue, resolveSecretValueSource, } from "./secrets-apply.js";
26
26
  import { collectCommandLineValues, } from "./command-line-values.js";
27
27
  // These live in the leaf module `engine/apply-core.ts` so the per-kind reconcile lanes can share them
28
28
  // without importing this monolith, which imports THEM — a cycle. Re-exported here so `engine/reconcile`
@@ -185,7 +185,7 @@ export async function reconcile(plan, apis, opts, appliedOut) {
185
185
  await applyComputeProvider(resource, apis, outcomes, applied, opts.onComputeProviderKey);
186
186
  break;
187
187
  case "environment":
188
- await applyEnvironment(resource, apis, outcomes, applied, reserved, teams);
188
+ await applyEnvironment(resource, apis, outcomes, applied, connections, reserved, teams);
189
189
  break;
190
190
  case "skill":
191
191
  await applySkill(resource, apis, outcomes, applied, teams);
@@ -376,14 +376,14 @@ async function applySecrets(plan, apis, opts, env, outcomes, applied, teams, gat
376
376
  ? undefined
377
377
  : resolveSecretValueSource(resource.valueFrom, env);
378
378
  // Diffed against the live recipe so a value-less recipe edit still PATCHes instead of silently no-oping.
379
- const desiredInjection = resource.payload.injection;
380
- const injectionChange = metadataInjectionChange(desiredInjection, live?.injection);
381
- const hostsChange = metadataHostsChange(declaredSecretHosts(resource.payload), live?.hosts);
379
+ const injectionChange = metadataInjectionChange(declaredSecretInjection(resource.payload), live?.injection);
380
+ // A marker an apply before the rename stamped moves to the new prefix even when nothing else changes.
381
+ const labelsMove = oldMarkersMoved(live?.labels);
382
382
  const decision = decideSecretWrite(resolvedValue, live !== undefined, {
383
383
  slug,
384
384
  envName,
385
385
  injectionChange,
386
- hostsChange,
386
+ ...(labelsMove !== undefined ? { labelsChange: { labels: labelsMove } } : {}),
387
387
  commandLinePending,
388
388
  });
389
389
  if (decision.kind === "skip-empty") {
@@ -399,6 +399,7 @@ async function applySecrets(plan, apis, opts, env, outcomes, applied, teams, gat
399
399
  value: resolvedValue,
400
400
  id: live?.id,
401
401
  liveInjection: live?.injection,
402
+ labelsMove,
402
403
  replacesLiveValue: replacesLiveCredentialValue(resource.valueFrom, decision.kind === "overwrite" ? "overwrite" : "create"),
403
404
  });
404
405
  }
@@ -481,8 +482,7 @@ async function applySecrets(plan, apis, opts, env, outcomes, applied, teams, gat
481
482
  }
482
483
  // Write phase — creates and overwrites, in plan order.
483
484
  for (const p of secretPlans) {
484
- const desiredInjection = p.resource.payload.injection;
485
- const desiredHosts = declaredSecretHosts(p.resource.payload);
485
+ const desiredInjection = declaredSecretInjection(p.resource.payload);
486
486
  if (p.decision.kind === "create") {
487
487
  const placement = {};
488
488
  stampTeam(placement, p.team);
@@ -498,7 +498,6 @@ async function applySecrets(plan, apis, opts, env, outcomes, applied, teams, gat
498
498
  ...placement,
499
499
  // Live is absent, so never a `null` clear here.
500
500
  ...(desiredInjection !== undefined ? { injection: desiredInjection } : {}),
501
- ...(desiredHosts !== undefined ? { hosts: desiredHosts } : {}),
502
501
  };
503
502
  const created = await failing(() => apis.secrets.createSecret({ createSecretRequest: body }), { kind: "secret", slug: p.slug, op: "create" }, outcomes);
504
503
  p.id = created.id;
@@ -513,16 +512,16 @@ async function applySecrets(plan, apis, opts, env, outcomes, applied, teams, gat
513
512
  description: p.resource.payload.description,
514
513
  value: p.value,
515
514
  ...(injection !== undefined ? { injection } : {}),
516
- ...(desiredHosts !== undefined ? { hosts: desiredHosts } : {}),
515
+ ...(p.labelsMove !== undefined ? { labels: p.labelsMove } : {}),
517
516
  };
518
517
  await failing(() => apis.secrets.updateSecret({ id: p.id, updateSecretRequest: body }), { kind: "secret", slug: p.slug, op: "update" }, outcomes);
519
518
  }
520
519
  else if (p.decision.kind === "metadata-update") {
521
- // The secret exists with no fresh value but its recipe or hosts changed: a value-less PATCH carrying
522
- // only the changed fields.
520
+ // The secret exists with no fresh value but its recipe changed or an old marker moves: a value-less PATCH
521
+ // carrying the recipe and the label move alone.
523
522
  const body = {
524
523
  ...(p.decision.injection !== undefined ? { injection: p.decision.injection } : {}),
525
- ...(p.decision.hosts !== undefined ? { hosts: p.decision.hosts } : {}),
524
+ ...(p.decision.labels !== undefined ? { labels: p.decision.labels } : {}),
526
525
  };
527
526
  await failing(() => apis.secrets.updateSecret({ id: p.id, updateSecretRequest: body }), { kind: "secret", slug: p.slug, op: "update" }, outcomes);
528
527
  }
@@ -839,7 +838,26 @@ function connectionExpectFor(imports, ref) {
839
838
  }
840
839
  return { provider, install: Object.keys(install).length > 0 ? install : undefined };
841
840
  }
842
- async function applyEnvironment(resource, apis, outcomes, applied, reserved, teams) {
841
+ /** The prefix an env value carries before a credential reference, which the egress edge reads. */
842
+ const ENV_REFERENCE_PREFIX = "orchestra:";
843
+ const CREDENTIAL_REFERENCE = /^(secret|connection)\/(.+)$/;
844
+ /**
845
+ * `secret/<ref>` or `connection/<ref>` with its ref, a reference token or an import as written, resolved to
846
+ * the live id: the edge and the platform read an exact id, never a slug. Text naming neither is left as it is.
847
+ */
848
+ async function resolveCredentialReference(text, label, apis, applied, connections) {
849
+ const match = CREDENTIAL_REFERENCE.exec(text);
850
+ if (match === null)
851
+ return text;
852
+ const [, kind, ref] = match;
853
+ if (kind === "connection")
854
+ return `connection/${await connections.resolve(ref)}`;
855
+ if (isRefToken(ref))
856
+ return `secret/${resolveManagedToken(ref, applied)}`;
857
+ validateRefShape(ref, label);
858
+ return `secret/${(await resolveSecretRef(apis, { value: ref, sourceLabel: label })).id}`;
859
+ }
860
+ async function applyEnvironment(resource, apis, outcomes, applied, connections, reserved, teams) {
843
861
  const body = clonePayload(resource.payload);
844
862
  const team = await teams.desired(body.teamId, { kind: "environment", slug: resource.slug, op: "get" }, outcomes);
845
863
  stampTeam(body, team);
@@ -884,6 +902,21 @@ async function applyEnvironment(resource, apis, outcomes, applied, reserved, tea
884
902
  reservedProviderSecretIds: await reserved(),
885
903
  }, outcomes);
886
904
  }
905
+ // Each credential an env value or a default names becomes its id before anything is written.
906
+ const env = (launchSpec.env ?? {});
907
+ for (const [name, value] of Object.entries(env)) {
908
+ if (!value.startsWith(ENV_REFERENCE_PREFIX))
909
+ continue;
910
+ const label = `environment '${envPath}' env '${name}'`;
911
+ env[name] =
912
+ ENV_REFERENCE_PREFIX +
913
+ (await resolveCredentialReference(value.slice(ENV_REFERENCE_PREFIX.length), label, apis, applied, connections));
914
+ }
915
+ const defaults = (body.credentials ?? []);
916
+ for (const [index, entry] of defaults.entries()) {
917
+ const label = `environment '${envPath}' credentials[${index}]`;
918
+ entry.credential = await resolveCredentialReference(String(entry.credential), label, apis, applied, connections);
919
+ }
887
920
  // A declared record's token, or an imported slug, becomes the record's id; `null` stays, naming hosted
888
921
  // compute.
889
922
  const providerRef = launchSpec.computeProviderId;
@@ -144,10 +144,5 @@ export declare function byokUnsetSourceMessage(slug: string, modelProvider: stri
144
144
  * apply lane reaches through {@link refusalOf}.
145
145
  */
146
146
  export declare function gatewayKeyPairRefusal(keySlug: string, secretSlug: string, pair: LiveGatewayKeyPair, team: DesiredTeam | undefined, pairContext: TeamIdentityRefusal["pairContext"] | undefined): RefusalVerdict | null;
147
- /**
148
- * Lives here rather than in the gateway-key lane because the classifier's message names it and this module
149
- * must stay a leaf; the lane re-exports it.
150
- */
151
- export declare const PENDING_GATEWAY_KEY_TOKEN_LABEL_KEY = "sfdk.pendingGatewayKeyToken";
152
147
  /** The named refusal for a mint that succeeded but whose paired-Secret token write did not. */
153
148
  export declare function pendingGatewayKeyTokenRotationMessage(slug: string, secretSlug: string): string;
@@ -12,6 +12,7 @@
12
12
  // nothing rather than guessing. No verdict can carry a credential: the classifiers read source RECIPES.
13
13
  import { connectorImmutableFields } from "../constructs/connector.js";
14
14
  import { isGatewayKeyRecipe } from "../core/gateway-key-recipe.js";
15
+ import { PENDING_GATEWAY_KEY_TOKEN_LABEL_KEY } from "../core/labels.js";
15
16
  import { ApplyError, classifyTeamIdentity, subsetDeepEqual, teamIdentityConflict, } from "./apply-core.js";
16
17
  import { isPartiallySuppliedRecipe, missingRootEnvNames, pendingCredentialWrite, } from "./secrets-apply.js";
17
18
  import { managedChatConnectionRefusalMessage } from "./connection-readiness.js";
@@ -266,11 +267,6 @@ function pairedSecretAbsentMessage(slug, secretSlug) {
266
267
  return (`gateway key '${slug}': the key already exists but its paired secret '${secretSlug}' does not, so ` +
267
268
  `there is no token to write and none can be recovered. ${gatewayKeyRotationRemedy(slug)}`);
268
269
  }
269
- /**
270
- * Lives here rather than in the gateway-key lane because the classifier's message names it and this module
271
- * must stay a leaf; the lane re-exports it.
272
- */
273
- export const PENDING_GATEWAY_KEY_TOKEN_LABEL_KEY = "sfdk.pendingGatewayKeyToken";
274
270
  /** The named refusal for a mint that succeeded but whose paired-Secret token write did not. */
275
271
  export function pendingGatewayKeyTokenRotationMessage(slug, secretSlug) {
276
272
  return (`gateway key '${slug}': its paired secret '${secretSlug}' still carries the pending marker ` +
@@ -129,21 +129,17 @@ export declare function metadataInjectionChange(desired: InjectionRecipe | undef
129
129
  injection: InjectionRecipe | null;
130
130
  } | undefined;
131
131
  /**
132
- * The hosts delta for the value-less PATCH path, compared EXACTLY rather than as a subset: a live row at `[]`
133
- * after the platform added the column must take a declared list, and a declared `[]` must clear a live one.
134
- * `undefined` when the plan states no hosts at all (a plan written before the field) or they already match.
132
+ * A declared secret's recipe as the plan carries it, its hosts inside it. A plan written while hosts sat beside the
133
+ * recipe has them moved in, so it applies as it did; with no recipe they were never presentable and are dropped.
135
134
  */
136
- export declare function metadataHostsChange(desired: readonly string[] | undefined, live: readonly string[] | undefined): {
137
- hosts: string[];
138
- } | undefined;
139
- /** A declared secret's hosts as the plan carries them; `undefined` for a plan written before the field. */
140
- export declare function declaredSecretHosts(payload: unknown): string[] | undefined;
135
+ export declare function declaredSecretInjection(payload: unknown): InjectionRecipe | undefined;
141
136
  /**
142
137
  * The write kinds carry value-free identifiers for the confirmation prompt, never the value itself.
143
138
  * - `overwrite` — values are never readable, so any supplied value overwrites.
144
139
  * - `noop-resolve` — resolve the id and write nothing, which protects the live credential from an
145
140
  * empty overwrite.
146
- * - `metadata-update` — a recipe or hosts edit changes no secret VALUE, so it must not be dropped as a noop.
141
+ * - `metadata-update` — a recipe edit, its hosts included, changes no secret VALUE, so it must not be dropped as
142
+ * a noop.
147
143
  * - `skip-empty` — the reconcile engine turns this into the named preflight error.
148
144
  */
149
145
  export type SecretDecision = {
@@ -159,13 +155,13 @@ export type SecretDecision = {
159
155
  } | {
160
156
  kind: "metadata-update";
161
157
  injection?: InjectionRecipe | null;
162
- hosts?: string[];
158
+ labels?: Record<string, string | null>;
163
159
  } | {
164
160
  kind: "skip-empty";
165
161
  };
166
162
  /**
167
- * `meta.injectionChange` and `meta.hostsChange` steer only the no-value-plus-exists branch, since a fresh
168
- * value already writes the recipe and the hosts through the create/overwrite body.
163
+ * `meta.injectionChange` and `meta.labelsChange` steer only the no-value-plus-exists branch, since a fresh value
164
+ * already writes the recipe and the label move through the create/overwrite body.
169
165
  *
170
166
  * `meta.commandLinePending` is the value-free branch, and it is load-bearing: a `cli:`-backed recipe has no
171
167
  * bytes yet when this runs, because the collection pass deliberately happens AFTER the confirmation this
@@ -179,8 +175,8 @@ export declare function decideSecretWrite(resolvedValue: string | undefined, exi
179
175
  injectionChange?: {
180
176
  injection: InjectionRecipe | null;
181
177
  };
182
- hostsChange?: {
183
- hosts: string[];
178
+ labelsChange?: {
179
+ labels: Record<string, string | null>;
184
180
  };
185
181
  commandLinePending?: boolean;
186
182
  }): SecretDecision;
@@ -306,25 +306,20 @@ export function metadataInjectionChange(desired, live) {
306
306
  return live !== undefined ? { injection: null } : undefined;
307
307
  }
308
308
  /**
309
- * The hosts delta for the value-less PATCH path, compared EXACTLY rather than as a subset: a live row at `[]`
310
- * after the platform added the column must take a declared list, and a declared `[]` must clear a live one.
311
- * `undefined` when the plan states no hosts at all (a plan written before the field) or they already match.
309
+ * A declared secret's recipe as the plan carries it, its hosts inside it. A plan written while hosts sat beside the
310
+ * recipe has them moved in, so it applies as it did; with no recipe they were never presentable and are dropped.
312
311
  */
313
- export function metadataHostsChange(desired, live) {
314
- if (desired === undefined)
312
+ export function declaredSecretInjection(payload) {
313
+ const { injection, hosts } = payload;
314
+ if (injection === undefined)
315
315
  return undefined;
316
- const current = live ?? [];
317
- const same = desired.length === current.length && desired.every((host, index) => host === current[index]);
318
- return same ? undefined : { hosts: [...desired] };
319
- }
320
- /** A declared secret's hosts as the plan carries them; `undefined` for a plan written before the field. */
321
- export function declaredSecretHosts(payload) {
322
- const hosts = payload.hosts;
323
- return Array.isArray(hosts) ? hosts : undefined;
316
+ if (injection.hosts !== undefined || !Array.isArray(hosts))
317
+ return injection;
318
+ return { ...injection, hosts: [...hosts] };
324
319
  }
325
320
  /**
326
- * `meta.injectionChange` and `meta.hostsChange` steer only the no-value-plus-exists branch, since a fresh
327
- * value already writes the recipe and the hosts through the create/overwrite body.
321
+ * `meta.injectionChange` and `meta.labelsChange` steer only the no-value-plus-exists branch, since a fresh value
322
+ * already writes the recipe and the label move through the create/overwrite body.
328
323
  *
329
324
  * `meta.commandLinePending` is the value-free branch, and it is load-bearing: a `cli:`-backed recipe has no
330
325
  * bytes yet when this runs, because the collection pass deliberately happens AFTER the confirmation this
@@ -346,8 +341,8 @@ export function decideSecretWrite(resolvedValue, exists, meta) {
346
341
  if (!exists) {
347
342
  return { kind: "skip-empty" };
348
343
  }
349
- if (meta.injectionChange !== undefined || meta.hostsChange !== undefined) {
350
- return { kind: "metadata-update", ...meta.injectionChange, ...meta.hostsChange };
344
+ if (meta.injectionChange !== undefined || meta.labelsChange !== undefined) {
345
+ return { kind: "metadata-update", ...meta.injectionChange, ...meta.labelsChange };
351
346
  }
352
347
  return { kind: "noop-resolve" };
353
348
  }
@@ -77,7 +77,7 @@ export declare function resolveWorkflow(payload: WorkflowPayload, resolvers: Wor
77
77
  export declare function workflowChanges(desired: ResolvedWorkflow, live: LiveWorkflow): WorkflowFieldChange[];
78
78
  export interface ReconcileWorkflowsOptions {
79
79
  resolvers: WorkflowResolvers;
80
- /** The factory whose `sfdk.managedBy` stamp marks the entries apply pins. */
80
+ /** The factory whose managed-by stamp marks the entries apply pins. */
81
81
  factory: string;
82
82
  /** Preview only: every write is fenced. */
83
83
  dryRun?: boolean;
@@ -22819,6 +22819,26 @@
22819
22819
  }
22820
22820
  }
22821
22821
  },
22822
+ "credentials": {
22823
+ "schema": {
22824
+ "kind": "array",
22825
+ "items": {
22826
+ "kind": "object",
22827
+ "fields": {
22828
+ "credential": {
22829
+ "schema": {
22830
+ "kind": "scalar"
22831
+ }
22832
+ },
22833
+ "replace": {
22834
+ "schema": {
22835
+ "kind": "scalar"
22836
+ }
22837
+ }
22838
+ }
22839
+ }
22840
+ }
22841
+ },
22822
22842
  "kind": {
22823
22843
  "schema": {
22824
22844
  "kind": "scalar"
@@ -23188,6 +23208,26 @@
23188
23208
  }
23189
23209
  }
23190
23210
  },
23211
+ "credentials": {
23212
+ "schema": {
23213
+ "kind": "array",
23214
+ "items": {
23215
+ "kind": "object",
23216
+ "fields": {
23217
+ "credential": {
23218
+ "schema": {
23219
+ "kind": "scalar"
23220
+ }
23221
+ },
23222
+ "replace": {
23223
+ "schema": {
23224
+ "kind": "scalar"
23225
+ }
23226
+ }
23227
+ }
23228
+ }
23229
+ }
23230
+ },
23191
23231
  "kind": {
23192
23232
  "schema": {
23193
23233
  "kind": "scalar"
@@ -23614,6 +23654,26 @@
23614
23654
  }
23615
23655
  }
23616
23656
  },
23657
+ "credentials": {
23658
+ "schema": {
23659
+ "kind": "array",
23660
+ "items": {
23661
+ "kind": "object",
23662
+ "fields": {
23663
+ "credential": {
23664
+ "schema": {
23665
+ "kind": "scalar"
23666
+ }
23667
+ },
23668
+ "replace": {
23669
+ "schema": {
23670
+ "kind": "scalar"
23671
+ }
23672
+ }
23673
+ }
23674
+ }
23675
+ }
23676
+ },
23617
23677
  "kind": {
23618
23678
  "schema": {
23619
23679
  "kind": "scalar"
@@ -24075,6 +24135,26 @@
24075
24135
  }
24076
24136
  }
24077
24137
  },
24138
+ "credentials": {
24139
+ "schema": {
24140
+ "kind": "array",
24141
+ "items": {
24142
+ "kind": "object",
24143
+ "fields": {
24144
+ "credential": {
24145
+ "schema": {
24146
+ "kind": "scalar"
24147
+ }
24148
+ },
24149
+ "replace": {
24150
+ "schema": {
24151
+ "kind": "scalar"
24152
+ }
24153
+ }
24154
+ }
24155
+ }
24156
+ }
24157
+ },
24078
24158
  "kind": {
24079
24159
  "schema": {
24080
24160
  "kind": "scalar"
@@ -24503,6 +24583,26 @@
24503
24583
  }
24504
24584
  }
24505
24585
  },
24586
+ "credentials": {
24587
+ "schema": {
24588
+ "kind": "array",
24589
+ "items": {
24590
+ "kind": "object",
24591
+ "fields": {
24592
+ "credential": {
24593
+ "schema": {
24594
+ "kind": "scalar"
24595
+ }
24596
+ },
24597
+ "replace": {
24598
+ "schema": {
24599
+ "kind": "scalar"
24600
+ }
24601
+ }
24602
+ }
24603
+ }
24604
+ }
24605
+ },
24506
24606
  "provisionSpec": {
24507
24607
  "schema": {
24508
24608
  "kind": "object",
@@ -24862,6 +24962,26 @@
24862
24962
  }
24863
24963
  }
24864
24964
  },
24965
+ "credentials": {
24966
+ "schema": {
24967
+ "kind": "array",
24968
+ "items": {
24969
+ "kind": "object",
24970
+ "fields": {
24971
+ "credential": {
24972
+ "schema": {
24973
+ "kind": "scalar"
24974
+ }
24975
+ },
24976
+ "replace": {
24977
+ "schema": {
24978
+ "kind": "scalar"
24979
+ }
24980
+ }
24981
+ }
24982
+ }
24983
+ }
24984
+ },
24865
24985
  "kind": {
24866
24986
  "schema": {
24867
24987
  "kind": "scalar"
@@ -46431,7 +46551,7 @@
46431
46551
  "required": true,
46432
46552
  "repeatable": false,
46433
46553
  "credential": true,
46434
- "description": "Secret value. This is write-only and is never returned by management APIs."
46554
+ "description": "Secret value. This is write-only and is never returned by management APIs. For git over HTTPS, store base64 of <user>:<token> as the value, such as the output of printf 'x-access-token:%s' \"$TOKEN\" | base64 | tr -d '\\n' for a GitHub token, and present it as Authorization: Basic ${secret}."
46435
46555
  },
46436
46556
  {
46437
46557
  "name": "expires-at",
@@ -46531,6 +46651,14 @@
46531
46651
  "kind": "scalar"
46532
46652
  }
46533
46653
  }
46654
+ },
46655
+ "hosts": {
46656
+ "schema": {
46657
+ "kind": "array",
46658
+ "items": {
46659
+ "kind": "scalar"
46660
+ }
46661
+ }
46534
46662
  }
46535
46663
  }
46536
46664
  }
@@ -46640,18 +46768,18 @@
46640
46768
  "kind": "scalar"
46641
46769
  }
46642
46770
  }
46771
+ },
46772
+ "hosts": {
46773
+ "schema": {
46774
+ "kind": "array",
46775
+ "items": {
46776
+ "kind": "scalar"
46777
+ }
46778
+ }
46643
46779
  }
46644
46780
  }
46645
46781
  }
46646
46782
  },
46647
- "hosts": {
46648
- "schema": {
46649
- "kind": "array",
46650
- "items": {
46651
- "kind": "scalar"
46652
- }
46653
- }
46654
- },
46655
46783
  "usableBy": {
46656
46784
  "schema": {
46657
46785
  "kind": "array",
@@ -47095,18 +47223,18 @@
47095
47223
  "kind": "scalar"
47096
47224
  }
47097
47225
  }
47226
+ },
47227
+ "hosts": {
47228
+ "schema": {
47229
+ "kind": "array",
47230
+ "items": {
47231
+ "kind": "scalar"
47232
+ }
47233
+ }
47098
47234
  }
47099
47235
  }
47100
47236
  }
47101
47237
  },
47102
- "hosts": {
47103
- "schema": {
47104
- "kind": "array",
47105
- "items": {
47106
- "kind": "scalar"
47107
- }
47108
- }
47109
- },
47110
47238
  "usableBy": {
47111
47239
  "schema": {
47112
47240
  "kind": "array",
@@ -47571,18 +47699,18 @@
47571
47699
  "kind": "scalar"
47572
47700
  }
47573
47701
  }
47702
+ },
47703
+ "hosts": {
47704
+ "schema": {
47705
+ "kind": "array",
47706
+ "items": {
47707
+ "kind": "scalar"
47708
+ }
47709
+ }
47574
47710
  }
47575
47711
  }
47576
47712
  }
47577
47713
  },
47578
- "hosts": {
47579
- "schema": {
47580
- "kind": "array",
47581
- "items": {
47582
- "kind": "scalar"
47583
- }
47584
- }
47585
- },
47586
47714
  "usableBy": {
47587
47715
  "schema": {
47588
47716
  "kind": "array",
@@ -47968,7 +48096,7 @@
47968
48096
  "required": false,
47969
48097
  "repeatable": false,
47970
48098
  "credential": true,
47971
- "description": "Secret value. This is write-only and is never returned by management APIs."
48099
+ "description": "Secret value. This is write-only and is never returned by management APIs. For git over HTTPS, store base64 of <user>:<token> as the value, such as the output of printf 'x-access-token:%s' \"$TOKEN\" | base64 | tr -d '\\n' for a GitHub token, and present it as Authorization: Basic ${secret}."
47972
48100
  },
47973
48101
  {
47974
48102
  "name": "expires-at",
@@ -48045,6 +48173,14 @@
48045
48173
  "kind": "scalar"
48046
48174
  }
48047
48175
  }
48176
+ },
48177
+ "hosts": {
48178
+ "schema": {
48179
+ "kind": "array",
48180
+ "items": {
48181
+ "kind": "scalar"
48182
+ }
48183
+ }
48048
48184
  }
48049
48185
  }
48050
48186
  }
@@ -48154,18 +48290,18 @@
48154
48290
  "kind": "scalar"
48155
48291
  }
48156
48292
  }
48293
+ },
48294
+ "hosts": {
48295
+ "schema": {
48296
+ "kind": "array",
48297
+ "items": {
48298
+ "kind": "scalar"
48299
+ }
48300
+ }
48157
48301
  }
48158
48302
  }
48159
48303
  }
48160
48304
  },
48161
- "hosts": {
48162
- "schema": {
48163
- "kind": "array",
48164
- "items": {
48165
- "kind": "scalar"
48166
- }
48167
- }
48168
- },
48169
48305
  "usableBy": {
48170
48306
  "schema": {
48171
48307
  "kind": "array",