swallowkit 2.0.0-alpha.4 → 2.0.0-alpha.6

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 (113) hide show
  1. package/dist/cli/commands/add-auth.js +37 -6
  2. package/dist/cli/commands/add-auth.js.map +1 -1
  3. package/dist/cli/commands/init.d.ts +2 -0
  4. package/dist/cli/commands/init.d.ts.map +1 -1
  5. package/dist/cli/commands/init.js +3 -1
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/cli/commands/provision.d.ts +2 -1
  8. package/dist/cli/commands/provision.d.ts.map +1 -1
  9. package/dist/cli/commands/provision.js +66 -4
  10. package/dist/cli/commands/provision.js.map +1 -1
  11. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  12. package/dist/cli/commands/scaffold.js +45 -1
  13. package/dist/cli/commands/scaffold.js.map +1 -1
  14. package/dist/cli/index.d.ts.map +1 -1
  15. package/dist/cli/index.js +15 -2
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/core/operations/create-model.d.ts +2 -0
  18. package/dist/core/operations/create-model.d.ts.map +1 -1
  19. package/dist/core/operations/create-model.js +60 -8
  20. package/dist/core/operations/create-model.js.map +1 -1
  21. package/dist/core/operations/provision-deployment.d.ts +45 -0
  22. package/dist/core/operations/provision-deployment.d.ts.map +1 -0
  23. package/dist/core/operations/provision-deployment.js +151 -0
  24. package/dist/core/operations/provision-deployment.js.map +1 -0
  25. package/dist/core/operations/provision-operations.d.ts +39 -5
  26. package/dist/core/operations/provision-operations.d.ts.map +1 -1
  27. package/dist/core/operations/provision-operations.js +609 -103
  28. package/dist/core/operations/provision-operations.js.map +1 -1
  29. package/dist/core/project/boundaries.js +3 -3
  30. package/dist/core/project/boundaries.js.map +1 -1
  31. package/dist/core/project/capabilities.d.ts +9 -0
  32. package/dist/core/project/capabilities.d.ts.map +1 -1
  33. package/dist/core/project/capabilities.js +20 -6
  34. package/dist/core/project/capabilities.js.map +1 -1
  35. package/dist/core/project/react-project.js +1 -1
  36. package/dist/core/project/state.d.ts +7 -0
  37. package/dist/core/project/state.d.ts.map +1 -1
  38. package/dist/core/project/state.js +86 -0
  39. package/dist/core/project/state.js.map +1 -1
  40. package/dist/core/project/workflows.d.ts.map +1 -1
  41. package/dist/core/project/workflows.js +43 -7
  42. package/dist/core/project/workflows.js.map +1 -1
  43. package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
  44. package/dist/core/scaffold/auth-generator.js +18 -19
  45. package/dist/core/scaffold/auth-generator.js.map +1 -1
  46. package/dist/core/scaffold/native-schema-generator.d.ts +2 -0
  47. package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
  48. package/dist/core/scaffold/native-schema-generator.js +16 -1
  49. package/dist/core/scaffold/native-schema-generator.js.map +1 -1
  50. package/dist/core/verify/index.d.ts +4 -3
  51. package/dist/core/verify/index.d.ts.map +1 -1
  52. package/dist/core/verify/index.js +98 -4
  53. package/dist/core/verify/index.js.map +1 -1
  54. package/dist/machine/contracts.d.ts +1 -0
  55. package/dist/machine/contracts.d.ts.map +1 -1
  56. package/dist/machine/errors.d.ts +3 -2
  57. package/dist/machine/errors.d.ts.map +1 -1
  58. package/dist/machine/errors.js +2 -1
  59. package/dist/machine/errors.js.map +1 -1
  60. package/dist/machine/index.d.ts.map +1 -1
  61. package/dist/machine/index.js +20 -13
  62. package/dist/machine/index.js.map +1 -1
  63. package/dist/mcp/index.d.ts +3 -2
  64. package/dist/mcp/index.d.ts.map +1 -1
  65. package/dist/mcp/index.js +76 -15
  66. package/dist/mcp/index.js.map +1 -1
  67. package/dist/utils/azure-cli.d.ts +16 -4
  68. package/dist/utils/azure-cli.d.ts.map +1 -1
  69. package/dist/utils/azure-cli.js +166 -4
  70. package/dist/utils/azure-cli.js.map +1 -1
  71. package/dist/utils/azure-diagnostics.d.ts +16 -0
  72. package/dist/utils/azure-diagnostics.d.ts.map +1 -0
  73. package/dist/utils/azure-diagnostics.js +68 -0
  74. package/dist/utils/azure-diagnostics.js.map +1 -0
  75. package/package.json +6 -3
  76. package/src/__tests__/__snapshots__/boundaries.test.ts.snap +6 -6
  77. package/src/__tests__/agent-instructions.test.ts +3 -0
  78. package/src/__tests__/agent-loop-phase34.test.ts +114 -8
  79. package/src/__tests__/azure-cli.test.ts +5 -2
  80. package/src/__tests__/fixtures/az wrapper.cmd +2 -0
  81. package/src/__tests__/fixtures/azure-cli.cjs +130 -0
  82. package/src/__tests__/fixtures/provision-runner.cjs +28 -0
  83. package/src/__tests__/generated-project-matrix.test.ts +789 -0
  84. package/src/__tests__/mcp.test.ts +71 -0
  85. package/src/__tests__/multi-auth.test.ts +115 -4
  86. package/src/__tests__/plan-apply.test.ts +111 -0
  87. package/src/__tests__/provision-runtime.test.ts +562 -0
  88. package/src/cli/commands/add-auth.ts +36 -6
  89. package/src/cli/commands/init.ts +4 -4
  90. package/src/cli/commands/provision.ts +69 -5
  91. package/src/cli/commands/scaffold.ts +65 -1
  92. package/src/cli/index.ts +12 -2
  93. package/src/core/operations/create-model.ts +51 -13
  94. package/src/core/operations/provision-deployment.ts +167 -0
  95. package/src/core/operations/provision-operations.ts +597 -145
  96. package/src/core/project/agent-templates/AGENTS.md +46 -3
  97. package/src/core/project/agent-templates/CLAUDE.md +9 -0
  98. package/src/core/project/agent-templates/copilot-instructions.md +10 -0
  99. package/src/core/project/agent-templates/shared-models.instructions.md +11 -3
  100. package/src/core/project/boundaries.ts +3 -3
  101. package/src/core/project/capabilities.ts +29 -6
  102. package/src/core/project/react-project.ts +1 -1
  103. package/src/core/project/state.ts +70 -0
  104. package/src/core/project/workflows.ts +43 -7
  105. package/src/core/scaffold/auth-generator.ts +18 -19
  106. package/src/core/scaffold/native-schema-generator.ts +16 -0
  107. package/src/core/verify/index.ts +95 -5
  108. package/src/machine/contracts.ts +1 -0
  109. package/src/machine/errors.ts +4 -2
  110. package/src/machine/index.ts +23 -16
  111. package/src/mcp/index.ts +68 -20
  112. package/src/utils/azure-cli.ts +167 -6
  113. package/src/utils/azure-diagnostics.ts +75 -0
@@ -0,0 +1,167 @@
1
+ import { runAzCliAsync } from "../../utils/azure-cli";
2
+ import { AzureCliDiagnostic, azureCliDiagnostic, redactAzureText } from "../../utils/azure-diagnostics";
3
+
4
+ export const DEPLOYMENT_QUERY = "{id:id,name:name,state:properties.provisioningState,correlationId:properties.correlationId,templateHash:properties.templateHash,timestamp:properties.timestamp,error:properties.error}";
5
+ export const DEFAULT_PROVISION_WAIT_SECONDS = 300;
6
+ export const MAX_PROVISION_WAIT_SECONDS = 3_600;
7
+
8
+ export interface DeploymentReference {
9
+ subscription: string;
10
+ resourceGroup: string;
11
+ name: string;
12
+ id?: string;
13
+ correlationId?: string;
14
+ templateHash?: string;
15
+ /** Do not mistake a previous deployment under the same name for this submission. */
16
+ previousCorrelationId?: string;
17
+ }
18
+
19
+ export interface AzureDeploymentError {
20
+ code: string;
21
+ message: string;
22
+ }
23
+
24
+ export interface DeploymentObservation {
25
+ state: "Accepted" | "Running" | "Succeeded" | "Failed" | "Canceled" | "unknown";
26
+ reference: DeploymentReference;
27
+ reason?: "not-found" | "query-failed" | "invalid-response" | "identity-changed" | "not-yet-observed" | "cancelled";
28
+ errors: AzureDeploymentError[];
29
+ diagnostic: AzureCliDiagnostic;
30
+ }
31
+
32
+ function record(value: unknown): Record<string, unknown> | null {
33
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null;
34
+ }
35
+
36
+ export function extractAzureErrors(value: unknown, secretValues: readonly string[] = []): AzureDeploymentError[] {
37
+ const result: AzureDeploymentError[] = [];
38
+ const visit = (entry: unknown, depth: number) => {
39
+ if (depth > 8 || result.length >= 20) return;
40
+ if (typeof entry === "string") {
41
+ try { visit(JSON.parse(entry), depth + 1); } catch { /* Only structured Azure errors are projected. */ }
42
+ return;
43
+ }
44
+ const item = record(entry);
45
+ if (!item) return;
46
+ if (typeof item.code === "string" && typeof item.message === "string") {
47
+ result.push({ code: redactAzureText(item.code, secretValues).slice(0, 200), message: redactAzureText(item.message, secretValues).slice(0, 2_000) });
48
+ }
49
+ if (item.error) visit(item.error, depth + 1);
50
+ if (Array.isArray(item.details)) item.details.forEach((detail) => visit(detail, depth + 1));
51
+ };
52
+ visit(value, 0);
53
+ return result;
54
+ }
55
+
56
+ export function deploymentId(reference: DeploymentReference): string {
57
+ return reference.id ?? `/subscriptions/${reference.subscription}/resourceGroups/${reference.resourceGroup}/providers/Microsoft.Resources/deployments/${reference.name}`;
58
+ }
59
+
60
+ export async function queryAzureDeployment(
61
+ reference: DeploymentReference,
62
+ options: { timeoutMs?: number; signal?: AbortSignal; secretValues?: readonly string[] } = {}
63
+ ): Promise<DeploymentObservation> {
64
+ const result = await runAzCliAsync([
65
+ "deployment", "group", "show", "--name", reference.name,
66
+ "--resource-group", reference.resourceGroup, "--subscription", reference.subscription,
67
+ "--query", DEPLOYMENT_QUERY, "-o", "json",
68
+ ], { timeout: options.timeoutMs ?? 30_000, signal: options.signal });
69
+ const diagnostic = azureCliDiagnostic(result, "deployment-state", options.secretValues);
70
+ const unknown = (reason: DeploymentObservation["reason"]): DeploymentObservation => ({
71
+ state: "unknown", reference, reason, errors: [], diagnostic,
72
+ });
73
+ if (result.status !== 0 || result.failureKind) {
74
+ if (result.failureKind === "cancelled") return unknown("cancelled");
75
+ return unknown(/DeploymentNotFound|ResourceGroupNotFound/i.test(`${result.stderr}\n${result.stdout}`) ? "not-found" : "query-failed");
76
+ }
77
+ if (result.stdoutTruncated) return unknown("invalid-response");
78
+ let parsed: Record<string, unknown> | null;
79
+ try { parsed = record(JSON.parse(result.stdout)); } catch { return unknown("invalid-response"); }
80
+ if (!parsed || typeof parsed.id !== "string" || typeof parsed.state !== "string" || typeof parsed.correlationId !== "string") {
81
+ return unknown("invalid-response");
82
+ }
83
+ if (parsed.id.toLowerCase() !== deploymentId(reference).toLowerCase()
84
+ || (reference.correlationId && parsed.correlationId !== reference.correlationId)
85
+ || (reference.templateHash && parsed.templateHash !== reference.templateHash)) {
86
+ return unknown("identity-changed");
87
+ }
88
+ if (reference.previousCorrelationId && parsed.correlationId === reference.previousCorrelationId) {
89
+ return unknown("not-yet-observed");
90
+ }
91
+ const states: Record<string, DeploymentObservation["state"]> = {
92
+ accepted: "Accepted", running: "Running", creating: "Running", updating: "Running",
93
+ succeeded: "Succeeded", failed: "Failed", canceled: "Canceled", cancelled: "Canceled",
94
+ };
95
+ const state = states[parsed.state.toLowerCase()];
96
+ if (!state) return unknown("invalid-response");
97
+ return {
98
+ state,
99
+ reference: {
100
+ ...reference,
101
+ id: parsed.id,
102
+ correlationId: parsed.correlationId,
103
+ ...(typeof parsed.templateHash === "string" ? { templateHash: parsed.templateHash } : {}),
104
+ },
105
+ errors: extractAzureErrors(parsed.error, options.secretValues),
106
+ diagnostic,
107
+ };
108
+ }
109
+
110
+ export async function waitForAzureDeployment(
111
+ reference: DeploymentReference,
112
+ options: {
113
+ deadline: number;
114
+ signal?: AbortSignal;
115
+ pollIntervalMs?: number;
116
+ onObservation?: (observation: DeploymentObservation) => void;
117
+ secretValues?: readonly string[];
118
+ queryTimeoutMs?: number;
119
+ }
120
+ ): Promise<DeploymentObservation> {
121
+ let observation: DeploymentObservation;
122
+ do {
123
+ const remaining = options.deadline - Date.now();
124
+ // Even when the wait budget is exhausted, one bounded read can identify an accepted submission.
125
+ observation = await queryAzureDeployment(reference, {
126
+ timeoutMs: remaining > 0 ? Math.min(options.queryTimeoutMs ?? 30_000, remaining) : options.queryTimeoutMs ?? 30_000,
127
+ signal: options.signal,
128
+ secretValues: options.secretValues,
129
+ });
130
+ if (observation.state !== "unknown") reference = observation.reference;
131
+ options.onObservation?.(observation);
132
+ if (observation.state === "Succeeded" || observation.state === "Failed" || observation.state === "Canceled") return observation;
133
+ if (observation.state === "unknown" && observation.reason !== "not-yet-observed" && observation.reason !== "not-found") return observation;
134
+ if (Date.now() >= options.deadline || options.signal?.aborted) return observation;
135
+ await new Promise<void>((resolve) => {
136
+ const done = () => {
137
+ clearTimeout(timer);
138
+ options.signal?.removeEventListener("abort", done);
139
+ resolve();
140
+ };
141
+ const timer = setTimeout(done, Math.min(options.pollIntervalMs ?? 5_000, Math.max(options.deadline - Date.now(), 0)));
142
+ options.signal?.addEventListener("abort", done, { once: true });
143
+ if (options.signal?.aborted) done();
144
+ });
145
+ } while (!options.signal?.aborted);
146
+ return observation;
147
+ }
148
+
149
+ export async function queryDeploymentOperationErrors(reference: DeploymentReference, secretValues: readonly string[] = [], signal?: AbortSignal): Promise<{
150
+ errors: AzureDeploymentError[];
151
+ diagnostic: AzureCliDiagnostic;
152
+ }> {
153
+ const result = await runAzCliAsync([
154
+ "deployment", "operation", "group", "list",
155
+ "--resource-group", reference.resourceGroup, "--name", reference.name, "--subscription", reference.subscription,
156
+ "--query", "[?properties.provisioningState=='Failed' || properties.provisioningState=='Canceled'].{error:properties.statusMessage}",
157
+ "-o", "json",
158
+ ], { timeout: 30_000, signal });
159
+ const errors: AzureDeploymentError[] = [];
160
+ if (result.status === 0 && !result.failureKind && !result.stdoutTruncated) {
161
+ try {
162
+ const parsed: unknown = JSON.parse(result.stdout);
163
+ if (Array.isArray(parsed)) parsed.slice(0, 20).forEach((item) => errors.push(...extractAzureErrors(item, secretValues)));
164
+ } catch { /* The separate diagnostic explicitly records an unreadable operations response. */ }
165
+ }
166
+ return { errors: errors.slice(0, 20), diagnostic: azureCliDiagnostic(result, "deployment-operations", secretValues) };
167
+ }