swallowkit 2.0.0-alpha.6 → 2.0.0-alpha.8

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 (32) hide show
  1. package/dist/cli/commands/provision.d.ts +2 -0
  2. package/dist/cli/commands/provision.d.ts.map +1 -1
  3. package/dist/cli/commands/provision.js +214 -109
  4. package/dist/cli/commands/provision.js.map +1 -1
  5. package/dist/cli/index.js +1 -1
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/core/operations/provision-deployment.d.ts +7 -0
  8. package/dist/core/operations/provision-deployment.d.ts.map +1 -1
  9. package/dist/core/operations/provision-deployment.js +16 -3
  10. package/dist/core/operations/provision-deployment.js.map +1 -1
  11. package/dist/core/operations/provision-operations.d.ts +4 -0
  12. package/dist/core/operations/provision-operations.d.ts.map +1 -1
  13. package/dist/core/operations/provision-operations.js +8 -3
  14. package/dist/core/operations/provision-operations.js.map +1 -1
  15. package/dist/core/project/capabilities.js +3 -3
  16. package/dist/core/project/capabilities.js.map +1 -1
  17. package/dist/core/project/workflows.d.ts.map +1 -1
  18. package/dist/core/project/workflows.js +2 -0
  19. package/dist/core/project/workflows.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/__tests__/agent-instructions.test.ts +2 -0
  22. package/src/__tests__/fixtures/azure-cli.cjs +10 -1
  23. package/src/__tests__/provision-runtime.test.ts +137 -2
  24. package/src/cli/commands/provision.ts +220 -108
  25. package/src/cli/index.ts +2 -2
  26. package/src/core/operations/provision-deployment.ts +17 -1
  27. package/src/core/operations/provision-operations.ts +17 -5
  28. package/src/core/project/agent-templates/AGENTS.md +4 -0
  29. package/src/core/project/agent-templates/CLAUDE.md +2 -0
  30. package/src/core/project/agent-templates/copilot-instructions.md +2 -0
  31. package/src/core/project/capabilities.ts +3 -3
  32. package/src/core/project/workflows.ts +2 -0
@@ -20,7 +20,7 @@ import { deletePlanState, listProvisionRuns, loadPlanState, loadProvisionRun, lo
20
20
  import { hashFileIfExists } from "./file-session";
21
21
  import {
22
22
  DEFAULT_PROVISION_WAIT_SECONDS, DEPLOYMENT_QUERY, DeploymentObservation, DeploymentReference,
23
- MAX_PROVISION_WAIT_SECONDS, queryAzureDeployment, queryDeploymentOperationErrors, waitForAzureDeployment,
23
+ MAX_PROVISION_WAIT_SECONDS, queryAzureDeployment, queryDeploymentOperationErrors, UNBOUNDED_WAIT_TRANSIENT_RETRIES, waitForAzureDeployment,
24
24
  } from "./provision-deployment";
25
25
  import {
26
26
  MIGRATION_MANIFEST_PATH,
@@ -625,6 +625,8 @@ export interface ApplyProvisionOptions {
625
625
  planId: string;
626
626
  approve?: boolean;
627
627
  waitSeconds?: number;
628
+ /** Human CLI: keep polling until Azure reaches a terminal state instead of using the bounded wait budget. */
629
+ waitUntilComplete?: boolean;
628
630
  }
629
631
 
630
632
  export interface ApplyProvisionResult {
@@ -848,7 +850,10 @@ export async function applyProvisionOperation(options: ApplyProvisionOptions): P
848
850
  );
849
851
  }
850
852
 
851
- const result = await executeProvisionPlan(plan, { approve: options.approve, waitSeconds: options.waitSeconds, retryHint: MACHINE_RETRY_HINT, projectRoot });
853
+ const result = await executeProvisionPlan(plan, {
854
+ approve: options.approve, waitSeconds: options.waitSeconds, waitUntilComplete: options.waitUntilComplete,
855
+ retryHint: MACHINE_RETRY_HINT, projectRoot,
856
+ });
852
857
  if (result.status === "complete") {
853
858
  try { deletePlanState(plan.planId, projectRoot); } catch {
854
859
  result.warnings.push("Azure and migration bookkeeping completed, but the old preview could not be removed. The completed execution checkpoint prevents replay.");
@@ -863,11 +868,17 @@ export async function applyProvisionOperation(options: ApplyProvisionOptions): P
863
868
  */
864
869
  export async function executeProvisionPlan(
865
870
  plan: ProvisionPlanData,
866
- options: { approve?: boolean; retryHint?: string; projectRoot?: string; waitSeconds?: number; signal?: AbortSignal; pollIntervalMs?: number } = {}
871
+ options: {
872
+ approve?: boolean; retryHint?: string; projectRoot?: string; waitSeconds?: number;
873
+ /** Human CLI only: no overall deadline; each az call stays bounded and the checkpoint stays resumable. */
874
+ waitUntilComplete?: boolean;
875
+ signal?: AbortSignal; pollIntervalMs?: number;
876
+ } = {}
867
877
  ): Promise<ApplyProvisionResult> {
868
878
  const projectRoot = options.projectRoot ?? process.cwd();
869
879
  const retryHint = options.retryHint ?? MACHINE_RETRY_HINT;
870
- const waitSeconds = validateWaitSeconds(options.waitSeconds);
880
+ const waitUntilComplete = options.waitUntilComplete === true && options.waitSeconds === undefined;
881
+ const waitSeconds = waitUntilComplete ? 0 : validateWaitSeconds(options.waitSeconds);
871
882
  if (!options.approve) {
872
883
  throw new MachineCommandError(
873
884
  "approval-required",
@@ -937,7 +948,7 @@ export async function executeProvisionPlan(
937
948
  options.signal?.addEventListener("abort", externalAbort, { once: true });
938
949
  if (options.signal?.aborted) controller.abort();
939
950
  const signal = controller.signal;
940
- const deadline = Date.now() + waitSeconds * 1_000;
951
+ const deadline = waitUntilComplete ? Number.POSITIVE_INFINITY : Date.now() + waitSeconds * 1_000;
941
952
  const persist = () => {
942
953
  if (!run) return;
943
954
  run.warnings = run.warnings.slice(-20);
@@ -958,6 +969,7 @@ export async function executeProvisionPlan(
958
969
  ...(signal.aborted ? {} : { signal }),
959
970
  ...(signal.aborted ? { queryTimeoutMs: 5_000 } : {}),
960
971
  pollIntervalMs: options.pollIntervalMs,
972
+ ...(waitUntilComplete ? { transientRetries: UNBOUNDED_WAIT_TRANSIENT_RETRIES } : {}),
961
973
  secretValues,
962
974
  onObservation: (value) => {
963
975
  run!.observation = value;
@@ -224,6 +224,10 @@ required.
224
224
 
225
225
  Never invent or implicitly grant human approval.
226
226
 
227
+ Humans normally invoke `swallowkit provision` directly. Its invocation requests
228
+ execution without an additional confirmation. Agents must still use the
229
+ machine/MCP approval flow and must not switch to normal CLI to bypass it.
230
+
227
231
  ## Model Changes
228
232
 
229
233
  For an existing model change, the normal pattern is:
@@ -24,6 +24,8 @@ Always-on rules:
24
24
  after apply).
25
25
  - Use plan/apply for deterministic generation.
26
26
  - Respect all `requires-human` states and provisioning approval gates.
27
+ - Normal `swallowkit provision` is for humans. Agents must not use it to bypass
28
+ the machine/MCP approval flow.
27
29
  - Provision timeouts/Ctrl+C do not prove Azure failed. Inspect the original
28
30
  execution checkpoint with `machine inspect provision --plan <runId>`; resume
29
31
  `machine apply provision --plan <runId> --approve` only after explicit human
@@ -23,6 +23,8 @@ Key rules:
23
23
  after apply).
24
24
  - Use plan/apply for deterministic generation.
25
25
  - Respect `requires-human` states and other human approval gates.
26
+ - Normal `swallowkit provision` is a human-facing deployment command. Agents must
27
+ use the machine/MCP approval flow, not normal CLI as an approval bypass.
26
28
  - Provision timeouts/Ctrl+C do not prove Azure failed. Read `status`, `outcome`,
27
29
  and `nextActions`; inspect the original run with `machine inspect provision
28
30
  --plan <runId>`, then resume `machine apply provision --plan <runId> --approve`
@@ -233,12 +233,12 @@ export function inspectCapabilities(): CapabilitiesContract {
233
233
  "(regular CLI) configure-mcp [--version auto|latest|<semver>] — re-select the MCP launcher version in .mcp.json",
234
234
  ],
235
235
  provisioning: {
236
- execution: "Submit Bicep once with az deployment group create --no-wait, then bounded state polling (default 300 seconds, configurable 0-3600). Azure CLI invocations are bounded separately. Warning-only stderr with exit 0 is not a failure; output capture limits do not terminate az.",
236
+ execution: "Submit Bicep once with az deployment group create --no-wait, then bounded state polling (default 300 seconds, configurable 0-3600) for machine/MCP; the human `swallowkit provision` command waits until Azure reaches a terminal state. Azure CLI invocations are bounded separately. Warning-only stderr with exit 0 is not a failure; output capture limits do not terminate az.",
237
237
  completion: "status complete/outcome succeeded requires Azure Succeeded plus verified migration tags and local ledger completion. Running/Accepted -> in-progress; unreadable/not-found state -> blocked/outcome unknown; bookkeeping interruption after Azure Succeeded -> blocked/outcome partial; Failed/Canceled -> failed with Azure causes.",
238
238
  tracking: "Approved runs persist before Azure writes under .swallowkit/state/provision/. runId equals the original planId and preserves the subscription, RG, deployment ID/correlation, fingerprints and migration state. inspect provision is read-only; apply provision --plan resumes without re-submitting attempted deployments. Ctrl+C/termination may leave Azure running; never cancel/delete without explicit consent.",
239
239
  recovery: "For an older untracked baseline, plan provision --resume-deployment <name> compares the existing ARM template and non-secure parameters to the local Bicep/parameters. It observes that deployment and only tags/records it after Succeeded. Mismatches, unreadable evidence, secure parameters or non-baseline migrations block; do not use reconcile just to repair bookkeeping.",
240
- diagnostics: "Results include bounded/redacted stdout/stderr, omitted-output flags, exit code, signal, failure kind, elapsed time and deployment identity. Deployment output values are not returned. Never print --debug output, keys, tokens or connection strings.",
241
- approval: "Initial apply and every resume require explicit human approval. A passing local command or an ok envelope is not proof of completed Azure provisioning; inspect status, outcome and nextActions.",
240
+ diagnostics: "Machine/MCP results include bounded/redacted stdout/stderr, omitted-output flags, exit code, signal, failure kind, elapsed time and deployment identity, but no deployment outputs. Normal CLI shows named resource information and CI/CD setup guidance after success. Never print --debug output, keys, tokens or connection strings.",
241
+ approval: "Machine/MCP initial apply and every resume require explicit human approval. A human invoking normal provision or provision --resume explicitly requests execution without another confirmation prompt. Agents must not switch to normal CLI to bypass approval. A passing local command or an ok envelope is not proof of completed Azure provisioning; inspect status, outcome and nextActions.",
242
242
  },
243
243
  verifyChecks: {
244
244
  defaultChecks: ["structure", "drift", "typecheck", "backend-build"],
@@ -211,6 +211,8 @@ Goal: bootstrap Azure once, then apply only pending versioned infrastructure mig
211
211
  \`status: "requires-human"\` and \`requiresApproval: true\` by design.
212
212
  - Never pass \`--approve\` to \`apply provision\` unless a human explicitly
213
213
  instructed you to provision in this session.
214
+ - This plan/apply workflow is for agents. Humans normally run \`swallowkit provision\`
215
+ directly; do not switch to that command to bypass the agent approval gate.
214
216
  - Inspect infra locally first — no \`az\` calls are needed for inspection.
215
217
  - Never edit an applied migration. Create a corrective migration instead.
216
218
  - Never use \`--reconcile\` for an ordinary model or resource addition.