@skyramp/mcp 0.4.4-rc.1 → 0.4.4
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.
- package/build/index.js +239 -210
- package/build/playwright/PlaywrightTraceService.d.ts +1 -1
- package/build/playwright/blueprintDigestStore.d.ts +1 -1
- package/build/playwright/registerPlaywrightTools.d.ts +1 -1
- package/build/playwright/traceRecordingPrompt.d.ts +1 -1
- package/build/playwright/traceRecordingPrompt.js +2 -2
- package/build/prompts/local-dev/local-dev-prompts.d.ts +1 -1
- package/build/prompts/local-dev/local-dev-prompts.js +2 -2
- package/build/prompts/startTraceCollectionPrompts.d.ts +1 -1
- package/build/prompts/startTraceCollectionPrompts.js +2 -3
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +1 -1
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +2 -2
- package/build/prompts/testbot/testbot-prompts.d.ts +1 -1
- package/build/prompts/testbot/testbot-prompts.js +4 -7
- package/build/recommendation/answers.d.ts +17 -52
- package/build/recommendation/answers.js +29 -99
- package/build/recommendation/pullRequestText.d.ts +0 -2
- package/build/recommendation/pullRequestText.js +0 -16
- package/build/recommendation/registerPlan.d.ts +4 -7
- package/build/recommendation/registerPlan.js +11 -37
- package/build/recommendation/types.d.ts +4 -21
- package/build/recommendation/verifierContracts.d.ts +4 -4
- package/build/recommendation/verifierContracts.js +4 -4
- package/build/recommendation/verifiers/citedPath.d.ts +2 -2
- package/build/recommendation/verifiers/citedPath.js +2 -2
- package/build/recommendation/verifiers/issueTraceability.d.ts +5 -1
- package/build/recommendation/verifiers/issueTraceability.js +35 -4
- package/build/resources/analysisResources.d.ts +1 -1
- package/build/resources/analysisResources.js +1 -1
- package/build/resources/progressResource.d.ts +1 -1
- package/build/resources/sutSetupResource.d.ts +1 -1
- package/build/resources/sutSetupResource.js +1 -1
- package/build/resources/testbotResource.d.ts +1 -1
- package/build/resources/testbotResource.js +1 -1
- package/build/services/AnalyticsService.d.ts +1 -1
- package/build/services/FleetExecutionService.d.ts +130 -0
- package/build/services/FleetExecutionService.js +391 -0
- package/build/services/ModularizationService.d.ts +1 -1
- package/build/services/TestExecutionService.d.ts +7 -0
- package/build/services/TestExecutionService.js +21 -0
- package/build/services/TestGenerationService.d.ts +1 -1
- package/build/tool-phases.js +2 -0
- package/build/tools/auth/loginTool.d.ts +1 -1
- package/build/tools/auth/loginTool.js +2 -2
- package/build/tools/auth/logoutTool.d.ts +1 -1
- package/build/tools/auth/logoutTool.js +2 -2
- package/build/tools/code-refactor/alignAssertionsTool.d.ts +1 -1
- package/build/tools/code-refactor/alignAssertionsTool.js +1 -1
- package/build/tools/code-refactor/assertionSkillTools.d.ts +1 -1
- package/build/tools/code-refactor/assertionSkillTools.js +2 -2
- package/build/tools/code-refactor/codeReuseTool.d.ts +1 -1
- package/build/tools/code-refactor/codeReuseTool.js +2 -2
- package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +1 -1
- package/build/tools/code-refactor/enhanceAssertionsTool.js +1 -1
- package/build/tools/code-refactor/modularizationTool.d.ts +1 -1
- package/build/tools/code-refactor/modularizationTool.js +2 -2
- package/build/tools/enrichTestWithMocksTool.d.ts +1 -1
- package/build/tools/enrichTestWithMocksTool.js +2 -2
- package/build/tools/executeFleetTool.d.ts +28 -0
- package/build/tools/executeFleetTool.js +107 -0
- package/build/tools/executeSkyrampTestTool.d.ts +8 -5
- package/build/tools/executeSkyrampTestTool.js +5 -5
- package/build/tools/fixErrorTool.d.ts +1 -1
- package/build/tools/fixErrorTool.js +1 -1
- package/build/tools/generate-tests/batchMockGenerationTool.d.ts +6 -57
- package/build/tools/generate-tests/batchMockGenerationTool.js +3 -3
- package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +9 -45
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +29 -11
- package/build/tools/generate-tests/generateContractRestTool.d.ts +1 -2
- package/build/tools/generate-tests/generateContractRestTool.js +1 -1
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -2
- package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
- package/build/tools/generate-tests/generateFuzzRestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateFuzzRestTool.js +1 -1
- package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +1 -2
- package/build/tools/generate-tests/generateIntegrationRestTool.js +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -2
- package/build/tools/generate-tests/generateLoadRestTool.js +2 -1
- package/build/tools/generate-tests/generateMockRestTool.d.ts +1 -2
- package/build/tools/generate-tests/generateMockRestTool.js +3 -3
- package/build/tools/generate-tests/generateSmokeRestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateSmokeRestTool.js +1 -1
- package/build/tools/generate-tests/generateUILoadRestTool.d.ts +64 -0
- package/build/tools/generate-tests/generateUILoadRestTool.js +512 -0
- package/build/tools/generate-tests/generateUIRestTool.d.ts +6 -7
- package/build/tools/generate-tests/generateUIRestTool.js +1 -1
- package/build/tools/generate-tests/loadTestSchema.d.ts +15 -15
- package/build/tools/generate-tests/trace-reuse-guard.d.ts +1 -1
- package/build/tools/generateEnrichedIntegrationTestTool.d.ts +1 -2
- package/build/tools/generateEnrichedIntegrationTestTool.js +1 -1
- package/build/tools/localDevWorkerComposeTool.d.ts +1 -1
- package/build/tools/localDevWorkerComposeTool.js +2 -2
- package/build/tools/one-click/oneClickTool.d.ts +1 -1
- package/build/tools/one-click/oneClickTool.js +1 -1
- package/build/tools/preflightMockCheckTool.d.ts +1 -1
- package/build/tools/preflightMockCheckTool.js +3 -3
- package/build/tools/queryProxyMocksTool.d.ts +1 -1
- package/build/tools/queryProxyMocksTool.js +3 -3
- package/build/tools/submitReportTool.d.ts +111 -414
- package/build/tools/submitReportTool.js +154 -138
- package/build/tools/test-management/actionsTool.d.ts +1 -1
- package/build/tools/test-management/actionsTool.js +7 -7
- package/build/tools/test-management/analyzeChangesTool.d.ts +22 -118
- package/build/tools/test-management/analyzeChangesTool.js +4 -4
- package/build/tools/test-management/analyzeTestHealthTool.d.ts +1 -1
- package/build/tools/test-management/analyzeTestHealthTool.js +4 -4
- package/build/tools/test-management/registerTestPlanTool.d.ts +111 -743
- package/build/tools/test-management/registerTestPlanTool.js +20 -36
- package/build/tools/test-management/resolveScreenTool.d.ts +1 -1
- package/build/tools/test-management/resolveScreenTool.js +6 -2
- package/build/tools/trace/startTraceCollectionTool.d.ts +1 -1
- package/build/tools/trace/startTraceCollectionTool.js +4 -4
- package/build/tools/trace/stopTraceCollectionTool.d.ts +1 -1
- package/build/tools/trace/stopTraceCollectionTool.js +2 -2
- package/build/tools/verifyTestDependenciesTool.d.ts +1 -1
- package/build/tools/verifyTestDependenciesTool.js +1 -1
- package/build/tools/workspace/initScanWorkspaceTool.d.ts +1 -1
- package/build/tools/workspace/initScanWorkspaceTool.js +1 -1
- package/build/tools/workspace/initializeWorkspaceTool.d.ts +1 -1
- package/build/tools/workspace/initializeWorkspaceTool.js +1 -1
- package/build/types/RepositoryAnalysis.d.ts +164 -1170
- package/build/types/RepositoryAnalysis.js +12 -10
- package/build/types/StepMethod.d.ts +24 -1
- package/build/types/StepMethod.js +1 -1
- package/build/types/TestTypes.d.ts +34 -133
- package/build/types/TestTypes.js +3 -3
- package/build/types/TestbotReport.d.ts +37 -0
- package/build/types/TestbotReport.js +22 -0
- package/build/types/index.d.ts +1 -1
- package/build/types/index.js +1 -1
- package/build/utils/docker.d.ts +29 -7
- package/build/utils/docker.js +83 -27
- package/build/utils/initAgent.d.ts +3 -3
- package/build/utils/initAgent.js +58 -26
- package/build/utils/progress.d.ts +3 -4
- package/build/utils/progress.js +4 -4
- package/build/utils/utils.d.ts +1 -1
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/workspace/workspace.d.ts +117 -538
- package/build/workspace/workspace.js +2 -2
- package/package.json +6 -5
- package/plugin/prompts/testbot-task1.md +1 -1
- package/plugin/skills/repair-staged-files/SKILL.md +17 -0
- package/build/recommendation/blockerProbes.d.ts +0 -13
- package/build/recommendation/blockerProbes.js +0 -91
- package/build/recommendation/blockers.d.ts +0 -65
- package/build/recommendation/blockers.js +0 -135
|
@@ -20,7 +20,7 @@ export var ScenarioSource;
|
|
|
20
20
|
ScenarioSource["AgentEnriched"] = "agent-enriched";
|
|
21
21
|
})(ScenarioSource || (ScenarioSource = {}));
|
|
22
22
|
// ── Zod schemas ──
|
|
23
|
-
export const analysisScopeSchema = z.
|
|
23
|
+
export const analysisScopeSchema = z.enum(AnalysisScope);
|
|
24
24
|
export const paramInfoSchema = z.object({
|
|
25
25
|
name: z.string(),
|
|
26
26
|
type: z.string(),
|
|
@@ -40,15 +40,15 @@ export const endpointInteractionSchema = z.object({
|
|
|
40
40
|
type: z.enum(["success", "error", "edge-case"]),
|
|
41
41
|
request: z.object({
|
|
42
42
|
contentType: z.string().optional(),
|
|
43
|
-
body: z.record(z.any()).optional(),
|
|
44
|
-
headers: z.record(z.string()).optional(),
|
|
45
|
-
queryParams: z.record(z.any()).optional(),
|
|
43
|
+
body: z.record(z.string(), z.any()).optional(),
|
|
44
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
45
|
+
queryParams: z.record(z.string(), z.any()).optional(),
|
|
46
46
|
}),
|
|
47
47
|
response: z.object({
|
|
48
48
|
statusCode: z.number(),
|
|
49
49
|
description: z.string(),
|
|
50
|
-
body: z.record(z.any()).optional(),
|
|
51
|
-
headers: z.record(z.string()).optional(),
|
|
50
|
+
body: z.record(z.string(), z.any()).optional(),
|
|
51
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
52
52
|
cookies: z.array(cookieInfoSchema).optional(),
|
|
53
53
|
}),
|
|
54
54
|
});
|
|
@@ -83,9 +83,11 @@ export const scenarioStepSchema = z.object({
|
|
|
83
83
|
path: z.string(),
|
|
84
84
|
description: z.string(),
|
|
85
85
|
interactionType: z.enum(["success", "error", "edge-case"]),
|
|
86
|
-
requestBody: z.record(z.any()).optional(),
|
|
87
|
-
queryParams: z.record(z.any()).optional(),
|
|
88
|
-
responseBody: z
|
|
86
|
+
requestBody: z.record(z.string(), z.any()).optional(),
|
|
87
|
+
queryParams: z.record(z.string(), z.any()).optional(),
|
|
88
|
+
responseBody: z
|
|
89
|
+
.union([z.record(z.string(), z.any()), z.array(z.any())])
|
|
90
|
+
.optional(),
|
|
89
91
|
expectedStatusCode: z.number(),
|
|
90
92
|
expectedResponseFields: z.array(z.string()).optional(),
|
|
91
93
|
chainsFrom: z
|
|
@@ -192,7 +194,7 @@ export const repositoryAnalysisSchema = z.object({
|
|
|
192
194
|
contract: z.number(),
|
|
193
195
|
smoke: z.number(),
|
|
194
196
|
}),
|
|
195
|
-
testLocations: z.record(z.string()),
|
|
197
|
+
testLocations: z.record(z.string(), z.string()),
|
|
196
198
|
hasCoverageReports: z.boolean(),
|
|
197
199
|
estimatedCoverage: z.number().optional(),
|
|
198
200
|
relevantExternalTestPaths: z.array(z.string()).optional(),
|
|
@@ -37,4 +37,27 @@ export declare const STEP_METHOD_DESCRIPTION: string;
|
|
|
37
37
|
* The field itself: normalised first, then checked, so a rejection is about the
|
|
38
38
|
* verb and never about its capitalisation.
|
|
39
39
|
*/
|
|
40
|
-
export declare const stepMethodSchema: z.
|
|
40
|
+
export declare const stepMethodSchema: z.ZodPreprocess<z.ZodEnum<{
|
|
41
|
+
GET: "GET";
|
|
42
|
+
POST: "POST";
|
|
43
|
+
PUT: "PUT";
|
|
44
|
+
DELETE: "DELETE";
|
|
45
|
+
PATCH: "PATCH";
|
|
46
|
+
HEAD: "HEAD";
|
|
47
|
+
OPTIONS: "OPTIONS";
|
|
48
|
+
type: "type";
|
|
49
|
+
TRACE: "TRACE";
|
|
50
|
+
CONNECT: "CONNECT";
|
|
51
|
+
assert: "assert";
|
|
52
|
+
click: "click";
|
|
53
|
+
drag: "drag";
|
|
54
|
+
"drag-hold": "drag-hold";
|
|
55
|
+
hover: "hover";
|
|
56
|
+
inspect: "inspect";
|
|
57
|
+
navigate: "navigate";
|
|
58
|
+
press: "press";
|
|
59
|
+
release: "release";
|
|
60
|
+
tap: "tap";
|
|
61
|
+
wait: "wait";
|
|
62
|
+
OPERATION: "OPERATION";
|
|
63
|
+
}>, unknown>;
|
|
@@ -87,5 +87,5 @@ export const STEP_METHOD_DESCRIPTION = "What this step does to the system: an HT
|
|
|
87
87
|
export const stepMethodSchema = z.preprocess((value) => typeof value === "string"
|
|
88
88
|
? (normalizeStepMethod(value) ?? value.trim())
|
|
89
89
|
: value, z.enum(STEP_METHODS, {
|
|
90
|
-
|
|
90
|
+
error: () => `method ${STEP_METHOD_HELP}`,
|
|
91
91
|
}));
|
|
@@ -51,28 +51,22 @@ export declare enum RuntimeEnvironment {
|
|
|
51
51
|
DOCKER = "docker",
|
|
52
52
|
KUBERNETES = "k8s"
|
|
53
53
|
}
|
|
54
|
-
export declare const runtimeEnvironmentSchema: z.
|
|
55
|
-
export declare const runtimeEnvironmentInputSchema: z.
|
|
54
|
+
export declare const runtimeEnvironmentSchema: z.ZodEnum<typeof RuntimeEnvironment>;
|
|
55
|
+
export declare const runtimeEnvironmentInputSchema: z.ZodPreprocess<z.ZodEnum<typeof RuntimeEnvironment>, unknown>;
|
|
56
56
|
export declare function normalizeRuntimeEnvironment(value: RuntimeEnvironment | "kubernetes"): RuntimeEnvironment;
|
|
57
57
|
export interface TestConfig {
|
|
58
58
|
testType: TestType;
|
|
59
59
|
toolName: string;
|
|
60
60
|
description: string;
|
|
61
|
-
additionalFields?: Record<string, z.
|
|
61
|
+
additionalFields?: Record<string, z.ZodType>;
|
|
62
62
|
}
|
|
63
63
|
export declare const languageSchema: z.ZodObject<{
|
|
64
|
-
language: z.
|
|
64
|
+
language: z.ZodEnum<typeof ProgrammingLanguage>;
|
|
65
65
|
framework: z.ZodString;
|
|
66
|
-
},
|
|
67
|
-
language: ProgrammingLanguage;
|
|
68
|
-
framework: string;
|
|
69
|
-
}, {
|
|
70
|
-
language: ProgrammingLanguage;
|
|
71
|
-
framework: string;
|
|
72
|
-
}>;
|
|
66
|
+
}, z.core.$strip>;
|
|
73
67
|
export declare const baseSchema: z.ZodObject<{
|
|
74
68
|
deployDashboard: z.ZodDefault<z.ZodBoolean>;
|
|
75
|
-
runtime: z.ZodDefault<z.
|
|
69
|
+
runtime: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<typeof RuntimeEnvironment>, unknown>>;
|
|
76
70
|
dockerNetwork: z.ZodDefault<z.ZodString>;
|
|
77
71
|
dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
|
|
78
72
|
k8sNamespace: z.ZodDefault<z.ZodString>;
|
|
@@ -81,78 +75,35 @@ export declare const baseSchema: z.ZodObject<{
|
|
|
81
75
|
authHeader: z.ZodDefault<z.ZodString>;
|
|
82
76
|
authScheme: z.ZodDefault<z.ZodString>;
|
|
83
77
|
insecure: z.ZodDefault<z.ZodBoolean>;
|
|
84
|
-
output: z.
|
|
78
|
+
output: z.ZodOptional<z.ZodString>;
|
|
85
79
|
outputDir: z.ZodString;
|
|
86
80
|
force: z.ZodDefault<z.ZodBoolean>;
|
|
87
81
|
mockPort: z.ZodDefault<z.ZodNumber>;
|
|
88
82
|
optionalFields: z.ZodDefault<z.ZodBoolean>;
|
|
89
83
|
prompt: z.ZodString;
|
|
90
|
-
language: z.
|
|
84
|
+
language: z.ZodEnum<typeof ProgrammingLanguage>;
|
|
91
85
|
framework: z.ZodString;
|
|
92
|
-
},
|
|
93
|
-
language: ProgrammingLanguage;
|
|
94
|
-
framework: string;
|
|
95
|
-
deployDashboard: boolean;
|
|
96
|
-
runtime: RuntimeEnvironment;
|
|
97
|
-
dockerNetwork: string;
|
|
98
|
-
dockerWorkerPort: number;
|
|
99
|
-
k8sNamespace: string;
|
|
100
|
-
k8sConfig: string;
|
|
101
|
-
k8sContext: string;
|
|
102
|
-
authHeader: string;
|
|
103
|
-
authScheme: string;
|
|
104
|
-
insecure: boolean;
|
|
105
|
-
outputDir: string;
|
|
106
|
-
force: boolean;
|
|
107
|
-
mockPort: number;
|
|
108
|
-
optionalFields: boolean;
|
|
109
|
-
prompt: string;
|
|
110
|
-
output?: string | undefined;
|
|
111
|
-
}, {
|
|
112
|
-
language: ProgrammingLanguage;
|
|
113
|
-
framework: string;
|
|
114
|
-
outputDir: string;
|
|
115
|
-
prompt: string;
|
|
116
|
-
deployDashboard?: boolean | undefined;
|
|
117
|
-
runtime?: unknown;
|
|
118
|
-
dockerNetwork?: string | undefined;
|
|
119
|
-
dockerWorkerPort?: number | undefined;
|
|
120
|
-
k8sNamespace?: string | undefined;
|
|
121
|
-
k8sConfig?: string | undefined;
|
|
122
|
-
k8sContext?: string | undefined;
|
|
123
|
-
authHeader?: string | undefined;
|
|
124
|
-
authScheme?: string | undefined;
|
|
125
|
-
insecure?: boolean | undefined;
|
|
126
|
-
output?: string | undefined;
|
|
127
|
-
force?: boolean | undefined;
|
|
128
|
-
mockPort?: number | undefined;
|
|
129
|
-
optionalFields?: boolean | undefined;
|
|
130
|
-
}>;
|
|
86
|
+
}, z.core.$strip>;
|
|
131
87
|
export declare const basePlaywrightSchema: z.ZodObject<{
|
|
132
88
|
playwrightInput: z.ZodString;
|
|
133
89
|
playwrightStoragePath: z.ZodOptional<z.ZodString>;
|
|
134
90
|
playwrightSaveStoragePath: z.ZodOptional<z.ZodString>;
|
|
135
|
-
playwrightViewportSize: z.ZodDefault<z.ZodUnion<[z.ZodEnum<
|
|
136
|
-
|
|
91
|
+
playwrightViewportSize: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<{
|
|
92
|
+
"": "";
|
|
93
|
+
hd: "hd";
|
|
94
|
+
"full-hd": "full-hd";
|
|
95
|
+
"2k": "2k";
|
|
96
|
+
}>, z.ZodString]>>;
|
|
97
|
+
browser: z.ZodDefault<z.ZodEnum<{
|
|
98
|
+
chromium: "chromium";
|
|
99
|
+
firefox: "firefox";
|
|
100
|
+
webkit: "webkit";
|
|
101
|
+
}>>;
|
|
137
102
|
device: z.ZodDefault<z.ZodString>;
|
|
138
|
-
},
|
|
139
|
-
playwrightInput: string;
|
|
140
|
-
playwrightViewportSize: string;
|
|
141
|
-
browser: "chromium" | "firefox" | "webkit";
|
|
142
|
-
device: string;
|
|
143
|
-
playwrightStoragePath?: string | undefined;
|
|
144
|
-
playwrightSaveStoragePath?: string | undefined;
|
|
145
|
-
}, {
|
|
146
|
-
playwrightInput: string;
|
|
147
|
-
playwrightStoragePath?: string | undefined;
|
|
148
|
-
playwrightSaveStoragePath?: string | undefined;
|
|
149
|
-
playwrightViewportSize?: string | undefined;
|
|
150
|
-
browser?: "chromium" | "firefox" | "webkit" | undefined;
|
|
151
|
-
device?: string | undefined;
|
|
152
|
-
}>;
|
|
103
|
+
}, z.core.$strip>;
|
|
153
104
|
export declare const baseTraceSchema: z.ZodObject<{
|
|
154
105
|
deployDashboard: z.ZodDefault<z.ZodBoolean>;
|
|
155
|
-
runtime: z.ZodDefault<z.
|
|
106
|
+
runtime: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<typeof RuntimeEnvironment>, unknown>>;
|
|
156
107
|
dockerNetwork: z.ZodDefault<z.ZodString>;
|
|
157
108
|
dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
|
|
158
109
|
k8sNamespace: z.ZodDefault<z.ZodString>;
|
|
@@ -161,65 +112,21 @@ export declare const baseTraceSchema: z.ZodObject<{
|
|
|
161
112
|
authHeader: z.ZodDefault<z.ZodString>;
|
|
162
113
|
authScheme: z.ZodDefault<z.ZodString>;
|
|
163
114
|
insecure: z.ZodDefault<z.ZodBoolean>;
|
|
164
|
-
output: z.
|
|
115
|
+
output: z.ZodOptional<z.ZodString>;
|
|
165
116
|
outputDir: z.ZodString;
|
|
166
117
|
force: z.ZodDefault<z.ZodBoolean>;
|
|
167
118
|
mockPort: z.ZodDefault<z.ZodNumber>;
|
|
168
119
|
optionalFields: z.ZodDefault<z.ZodBoolean>;
|
|
169
120
|
prompt: z.ZodString;
|
|
170
|
-
language: z.
|
|
121
|
+
language: z.ZodEnum<typeof ProgrammingLanguage>;
|
|
171
122
|
framework: z.ZodString;
|
|
172
123
|
trace: z.ZodString;
|
|
173
|
-
include: z.ZodDefault<z.ZodArray<z.ZodString
|
|
174
|
-
exclude: z.ZodDefault<z.ZodArray<z.ZodString
|
|
175
|
-
},
|
|
176
|
-
language: ProgrammingLanguage;
|
|
177
|
-
framework: string;
|
|
178
|
-
deployDashboard: boolean;
|
|
179
|
-
runtime: RuntimeEnvironment;
|
|
180
|
-
dockerNetwork: string;
|
|
181
|
-
dockerWorkerPort: number;
|
|
182
|
-
k8sNamespace: string;
|
|
183
|
-
k8sConfig: string;
|
|
184
|
-
k8sContext: string;
|
|
185
|
-
authHeader: string;
|
|
186
|
-
authScheme: string;
|
|
187
|
-
insecure: boolean;
|
|
188
|
-
outputDir: string;
|
|
189
|
-
force: boolean;
|
|
190
|
-
mockPort: number;
|
|
191
|
-
optionalFields: boolean;
|
|
192
|
-
prompt: string;
|
|
193
|
-
trace: string;
|
|
194
|
-
include: string[];
|
|
195
|
-
exclude: string[];
|
|
196
|
-
output?: string | undefined;
|
|
197
|
-
}, {
|
|
198
|
-
language: ProgrammingLanguage;
|
|
199
|
-
framework: string;
|
|
200
|
-
outputDir: string;
|
|
201
|
-
prompt: string;
|
|
202
|
-
trace: string;
|
|
203
|
-
deployDashboard?: boolean | undefined;
|
|
204
|
-
runtime?: unknown;
|
|
205
|
-
dockerNetwork?: string | undefined;
|
|
206
|
-
dockerWorkerPort?: number | undefined;
|
|
207
|
-
k8sNamespace?: string | undefined;
|
|
208
|
-
k8sConfig?: string | undefined;
|
|
209
|
-
k8sContext?: string | undefined;
|
|
210
|
-
authHeader?: string | undefined;
|
|
211
|
-
authScheme?: string | undefined;
|
|
212
|
-
insecure?: boolean | undefined;
|
|
213
|
-
output?: string | undefined;
|
|
214
|
-
force?: boolean | undefined;
|
|
215
|
-
mockPort?: number | undefined;
|
|
216
|
-
optionalFields?: boolean | undefined;
|
|
217
|
-
include?: string[] | undefined;
|
|
218
|
-
exclude?: string[] | undefined;
|
|
219
|
-
}>;
|
|
124
|
+
include: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
125
|
+
exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
126
|
+
}, z.core.$strip>;
|
|
220
127
|
export declare const baseTestSchema: {
|
|
221
128
|
deployDashboard: z.ZodDefault<z.ZodBoolean>;
|
|
222
|
-
runtime: z.ZodDefault<z.
|
|
129
|
+
runtime: z.ZodDefault<z.ZodPreprocess<z.ZodEnum<typeof RuntimeEnvironment>, unknown>>;
|
|
223
130
|
dockerNetwork: z.ZodDefault<z.ZodString>;
|
|
224
131
|
dockerWorkerPort: z.ZodDefault<z.ZodNumber>;
|
|
225
132
|
k8sNamespace: z.ZodDefault<z.ZodString>;
|
|
@@ -228,33 +135,27 @@ export declare const baseTestSchema: {
|
|
|
228
135
|
authHeader: z.ZodDefault<z.ZodString>;
|
|
229
136
|
authScheme: z.ZodDefault<z.ZodString>;
|
|
230
137
|
insecure: z.ZodDefault<z.ZodBoolean>;
|
|
231
|
-
output: z.
|
|
138
|
+
output: z.ZodOptional<z.ZodString>;
|
|
232
139
|
outputDir: z.ZodString;
|
|
233
140
|
force: z.ZodDefault<z.ZodBoolean>;
|
|
234
141
|
mockPort: z.ZodDefault<z.ZodNumber>;
|
|
235
142
|
optionalFields: z.ZodDefault<z.ZodBoolean>;
|
|
236
143
|
prompt: z.ZodString;
|
|
237
|
-
language: z.
|
|
144
|
+
language: z.ZodEnum<typeof ProgrammingLanguage>;
|
|
238
145
|
framework: z.ZodString;
|
|
239
146
|
endpointURL: z.ZodString;
|
|
240
|
-
method: z.ZodDefault<z.ZodUnion<[z.
|
|
147
|
+
method: z.ZodDefault<z.ZodUnion<readonly [z.ZodEnum<typeof HttpMethod>, z.ZodLiteral<"">]>>;
|
|
241
148
|
apiSchema: z.ZodDefault<z.ZodString>;
|
|
242
149
|
pathParams: z.ZodDefault<z.ZodString>;
|
|
243
150
|
queryParams: z.ZodDefault<z.ZodString>;
|
|
244
151
|
formParams: z.ZodDefault<z.ZodString>;
|
|
245
|
-
requestData: z.
|
|
246
|
-
responseStatusCode: z.
|
|
152
|
+
requestData: z.ZodDefault<z.ZodString>;
|
|
153
|
+
responseStatusCode: z.ZodDefault<z.ZodString>;
|
|
247
154
|
};
|
|
248
155
|
export declare const codeRefactoringSchema: z.ZodObject<{
|
|
249
156
|
codeReuse: z.ZodDefault<z.ZodBoolean>;
|
|
250
157
|
modularizeCode: z.ZodDefault<z.ZodBoolean>;
|
|
251
|
-
},
|
|
252
|
-
codeReuse: boolean;
|
|
253
|
-
modularizeCode: boolean;
|
|
254
|
-
}, {
|
|
255
|
-
codeReuse?: boolean | undefined;
|
|
256
|
-
modularizeCode?: boolean | undefined;
|
|
257
|
-
}>;
|
|
158
|
+
}, z.core.$strip>;
|
|
258
159
|
/** The `testName` field for a recording-driven generation tool.
|
|
259
160
|
*
|
|
260
161
|
* Single-sourced because the description is prompt text: it is the only thing
|
package/build/types/TestTypes.js
CHANGED
|
@@ -64,14 +64,14 @@ export var RuntimeEnvironment;
|
|
|
64
64
|
RuntimeEnvironment["DOCKER"] = "docker";
|
|
65
65
|
RuntimeEnvironment["KUBERNETES"] = "k8s";
|
|
66
66
|
})(RuntimeEnvironment || (RuntimeEnvironment = {}));
|
|
67
|
-
export const runtimeEnvironmentSchema = z.
|
|
67
|
+
export const runtimeEnvironmentSchema = z.enum(RuntimeEnvironment);
|
|
68
68
|
export const runtimeEnvironmentInputSchema = z.preprocess((value) => (value === "kubernetes" ? RuntimeEnvironment.KUBERNETES : value), runtimeEnvironmentSchema);
|
|
69
69
|
export function normalizeRuntimeEnvironment(value) {
|
|
70
70
|
return value === "kubernetes" ? RuntimeEnvironment.KUBERNETES : value;
|
|
71
71
|
}
|
|
72
72
|
export const languageSchema = z.object({
|
|
73
73
|
language: z
|
|
74
|
-
.
|
|
74
|
+
.enum(ProgrammingLanguage)
|
|
75
75
|
.describe("Programming language for the generated test (default: python). Must be one of: python, typescript, javascript, java"),
|
|
76
76
|
framework: z
|
|
77
77
|
.string()
|
|
@@ -217,7 +217,7 @@ export const baseTestSchema = {
|
|
|
217
217
|
"(e.g., https://demoshop.skyramp.dev/api/v1/products). " +
|
|
218
218
|
"MUST include both the base URL and the endpoint path — never just the base URL alone."),
|
|
219
219
|
method: z
|
|
220
|
-
.union([z.
|
|
220
|
+
.union([z.enum(HttpMethod), z.literal("")])
|
|
221
221
|
.default("")
|
|
222
222
|
.describe('HTTP method to use. DEFAULT: Use empty string ("") to test ALL available methods from OpenAPI schema (recommended). Only specify a specific method (GET, POST, PUT, DELETE, etc.) if user explicitly requests testing a single method only.'),
|
|
223
223
|
apiSchema: z
|
|
@@ -13,6 +13,26 @@ export declare enum IssueFoundCategory {
|
|
|
13
13
|
Type = "type",
|
|
14
14
|
Config = "config"
|
|
15
15
|
}
|
|
16
|
+
/** Why a Fail or Skipped testResults row did not pass. Application is the code
|
|
17
|
+
* under test (or a test written to prove a defect, failing as intended);
|
|
18
|
+
* Environment is the test environment stopping the test before it reached the
|
|
19
|
+
* behaviour; TestDefect is the generated test itself being wrong. */
|
|
20
|
+
export declare enum FailureCauseKind {
|
|
21
|
+
Application = "application",
|
|
22
|
+
Environment = "environment",
|
|
23
|
+
TestDefect = "test_defect"
|
|
24
|
+
}
|
|
25
|
+
/** Which test-environment gap stopped a test: the `family` of an Environment
|
|
26
|
+
* failureCause, and the `environmentFamily` of a config issuesFound entry. */
|
|
27
|
+
export declare enum EnvironmentFamily {
|
|
28
|
+
AuthToken = "auth_token",
|
|
29
|
+
Secret = "secret",
|
|
30
|
+
DataConnection = "data_connection",
|
|
31
|
+
AppNotStarted = "app_not_started",
|
|
32
|
+
Login = "login",
|
|
33
|
+
ExternalDependency = "external_dependency",
|
|
34
|
+
RecordingReplay = "recording_replay"
|
|
35
|
+
}
|
|
16
36
|
/**
|
|
17
37
|
* Shape of the JSON report written by skyramp_submit_report and read by testbot
|
|
18
38
|
* for rendering as Markdown. All fields mirror the corresponding Zod schemas in
|
|
@@ -104,6 +124,19 @@ export interface TestbotReport {
|
|
|
104
124
|
endpoint: string;
|
|
105
125
|
status: "Pass" | "Fail" | "Skipped";
|
|
106
126
|
details: string;
|
|
127
|
+
/** Server-derived: the basename of the `testFilePath` the agent submitted,
|
|
128
|
+
* which never reaches the report. The join key to `newTestsCreated` and
|
|
129
|
+
* `testMaintenance`: match it against the basename of their `fileName`
|
|
130
|
+
* (a `newTestsCreated` row may carry a repository-relative path), plus
|
|
131
|
+
* `repository`. */
|
|
132
|
+
fileName: string;
|
|
133
|
+
/** Why a Fail or Skipped row did not pass. The submit schema requires it on
|
|
134
|
+
* those rows and refuses it on a Pass row; `family` is set exactly when
|
|
135
|
+
* `kind` is Environment. Absent in reports from MCP versions predating it. */
|
|
136
|
+
failureCause?: {
|
|
137
|
+
kind: FailureCauseKind;
|
|
138
|
+
family?: EnvironmentFamily;
|
|
139
|
+
};
|
|
107
140
|
videoPath?: string;
|
|
108
141
|
/** See newTestsCreated[].repository. */
|
|
109
142
|
repository: string;
|
|
@@ -158,6 +191,10 @@ export interface TestbotReport {
|
|
|
158
191
|
sourceFile?: string;
|
|
159
192
|
sourceSymbol?: string;
|
|
160
193
|
sourceLine?: number;
|
|
194
|
+
/** On a `config` entry that is a test-environment gap, which gap. The submit
|
|
195
|
+
* schema refuses it on any other category. Optional: a config entry need
|
|
196
|
+
* not be an environment gap, and older MCP versions never set it. */
|
|
197
|
+
environmentFamily?: EnvironmentFamily;
|
|
161
198
|
/** See newTestsCreated[].repository. */
|
|
162
199
|
repository: string;
|
|
163
200
|
}[];
|
|
@@ -8,3 +8,25 @@ export var IssueFoundCategory;
|
|
|
8
8
|
IssueFoundCategory["Type"] = "type";
|
|
9
9
|
IssueFoundCategory["Config"] = "config";
|
|
10
10
|
})(IssueFoundCategory || (IssueFoundCategory = {}));
|
|
11
|
+
/** Why a Fail or Skipped testResults row did not pass. Application is the code
|
|
12
|
+
* under test (or a test written to prove a defect, failing as intended);
|
|
13
|
+
* Environment is the test environment stopping the test before it reached the
|
|
14
|
+
* behaviour; TestDefect is the generated test itself being wrong. */
|
|
15
|
+
export var FailureCauseKind;
|
|
16
|
+
(function (FailureCauseKind) {
|
|
17
|
+
FailureCauseKind["Application"] = "application";
|
|
18
|
+
FailureCauseKind["Environment"] = "environment";
|
|
19
|
+
FailureCauseKind["TestDefect"] = "test_defect";
|
|
20
|
+
})(FailureCauseKind || (FailureCauseKind = {}));
|
|
21
|
+
/** Which test-environment gap stopped a test: the `family` of an Environment
|
|
22
|
+
* failureCause, and the `environmentFamily` of a config issuesFound entry. */
|
|
23
|
+
export var EnvironmentFamily;
|
|
24
|
+
(function (EnvironmentFamily) {
|
|
25
|
+
EnvironmentFamily["AuthToken"] = "auth_token";
|
|
26
|
+
EnvironmentFamily["Secret"] = "secret";
|
|
27
|
+
EnvironmentFamily["DataConnection"] = "data_connection";
|
|
28
|
+
EnvironmentFamily["AppNotStarted"] = "app_not_started";
|
|
29
|
+
EnvironmentFamily["Login"] = "login";
|
|
30
|
+
EnvironmentFamily["ExternalDependency"] = "external_dependency";
|
|
31
|
+
EnvironmentFamily["RecordingReplay"] = "recording_replay";
|
|
32
|
+
})(EnvironmentFamily || (EnvironmentFamily = {}));
|
package/build/types/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { TestExecutionStatus } from "./TestExecution.js";
|
|
|
2
2
|
export { DriftAction } from "./TestAnalysis.js";
|
|
3
3
|
export { TestType, HttpMethod } from "./TestTypes.js";
|
|
4
4
|
export type { TestbotReport } from "./TestbotReport.js";
|
|
5
|
-
export { IssueFoundCategory } from "./TestbotReport.js";
|
|
5
|
+
export { IssueFoundCategory, FailureCauseKind, EnvironmentFamily, } from "./TestbotReport.js";
|
|
6
6
|
export { ReuseDeclinedBy, ReuseVerificationOutcome, HelperVerificationOutcome, } from "./ReuseOutcome.js";
|
|
7
7
|
export type { ReuseOutcome, ReuseSkippedEntry, ReuseMissedEntry, HelperReuseOutcome, RetrofitOutcome, ChangedHelperEntry, ChangedHelperCaller, OrphanedHelper, } from "./ReuseOutcome.js";
|
|
8
8
|
export type { RelatedRepository, TestbotPromptOptions, } from "./TestbotPromptOptions.js";
|
package/build/types/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { TestExecutionStatus } from "./TestExecution.js";
|
|
2
2
|
export { DriftAction } from "./TestAnalysis.js";
|
|
3
3
|
export { TestType, HttpMethod } from "./TestTypes.js";
|
|
4
|
-
export { IssueFoundCategory } from "./TestbotReport.js";
|
|
4
|
+
export { IssueFoundCategory, FailureCauseKind, EnvironmentFamily, } from "./TestbotReport.js";
|
|
5
5
|
export { ReuseDeclinedBy, ReuseVerificationOutcome, HelperVerificationOutcome, } from "./ReuseOutcome.js";
|
package/build/utils/docker.d.ts
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a pull failed because the image has nothing for the requested platform. The
|
|
3
|
+
* wording depends on the daemon and its image store: a Windows daemon answers a linux-only
|
|
4
|
+
* image, even a multi-platform one, with "image operating system ... cannot be used on this
|
|
5
|
+
* platform" (observed on Windows Server 2022, Docker 29.7.2); a manifest list without the
|
|
6
|
+
* platform gives "no matching manifest"; the containerd image store says "no match for
|
|
7
|
+
* platform in manifest". Anything else -- the network, a rate limit, a full disk -- is not
|
|
8
|
+
* this.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isPlatformUnavailableError(err: unknown): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the Docker platform string for the current host architecture.
|
|
13
|
+
* Mirrors the backend's getDockerPlatform() in cmd/libs/init.go.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getDockerPlatform(): string;
|
|
1
16
|
/**
|
|
2
17
|
* Pull a Docker image by name.
|
|
3
18
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* back to linux/amd64 if the arm64 pull fails or the image doesn't land
|
|
10
|
-
* locally (Docker Desktop quirk on Apple Silicon).
|
|
19
|
+
* `dockerPlatform` defaults to the host architecture. Whether given or
|
|
20
|
+
* defaulted, a `linux/arm64` pull falls back to `linux/amd64` when the arm64
|
|
21
|
+
* pull reports no matching manifest or completes without the image landing
|
|
22
|
+
* locally (Docker Desktop quirk on Apple Silicon). Any other platform is
|
|
23
|
+
* pulled exactly, with no fallback.
|
|
11
24
|
*/
|
|
12
25
|
export declare function pullDockerImage(imageName: string, dockerPlatform?: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* The default daemon's operating system ("windows" or "linux"), or undefined when it
|
|
28
|
+
* cannot be determined. The startup prefetch pulls each image for this OS; when it is
|
|
29
|
+
* undefined the executor is pulled as linux/amd64 and the worker for the host's own
|
|
30
|
+
* architecture (getDockerPlatform). Guessing is acceptable there because the prefetch is
|
|
31
|
+
* best-effort: a wrong guess costs a download, and the run itself refuses to guess
|
|
32
|
+
* (resolvePlatform in FleetExecutionService).
|
|
33
|
+
*/
|
|
34
|
+
export declare function dockerDaemonOsType(): Promise<string | undefined>;
|
|
13
35
|
/**
|
|
14
36
|
* Check if a Docker image exists locally for the given reference (repo:tag or digest).
|
|
15
37
|
* Uses image inspect (daemon name resolution), not listImages tag scanning.
|
package/build/utils/docker.js
CHANGED
|
@@ -26,11 +26,26 @@ function isManifestMismatchError(err) {
|
|
|
26
26
|
const msg = err?.message ?? "";
|
|
27
27
|
return msg.includes("no matching manifest");
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Whether a pull failed because the image has nothing for the requested platform. The
|
|
31
|
+
* wording depends on the daemon and its image store: a Windows daemon answers a linux-only
|
|
32
|
+
* image, even a multi-platform one, with "image operating system ... cannot be used on this
|
|
33
|
+
* platform" (observed on Windows Server 2022, Docker 29.7.2); a manifest list without the
|
|
34
|
+
* platform gives "no matching manifest"; the containerd image store says "no match for
|
|
35
|
+
* platform in manifest". Anything else -- the network, a rate limit, a full disk -- is not
|
|
36
|
+
* this.
|
|
37
|
+
*/
|
|
38
|
+
export function isPlatformUnavailableError(err) {
|
|
39
|
+
const msg = err?.message ?? "";
|
|
40
|
+
return (msg.includes("no matching manifest") ||
|
|
41
|
+
msg.includes("cannot be used on this platform") ||
|
|
42
|
+
msg.includes("no match for platform in manifest"));
|
|
43
|
+
}
|
|
29
44
|
/**
|
|
30
45
|
* Returns the Docker platform string for the current host architecture.
|
|
31
46
|
* Mirrors the backend's getDockerPlatform() in cmd/libs/init.go.
|
|
32
47
|
*/
|
|
33
|
-
function getDockerPlatform() {
|
|
48
|
+
export function getDockerPlatform() {
|
|
34
49
|
return process.arch === "arm64" ? "linux/arm64" : "linux/amd64";
|
|
35
50
|
}
|
|
36
51
|
async function doPull(docker, imageName, platform) {
|
|
@@ -40,14 +55,27 @@ async function doPull(docker, imageName, platform) {
|
|
|
40
55
|
return reject(err);
|
|
41
56
|
if (!stream)
|
|
42
57
|
return reject(new Error("No stream received from docker pull"));
|
|
58
|
+
// A pull can fail INSIDE the progress stream: followProgress still finishes
|
|
59
|
+
// without an error object, and the failure appears only as an `error` field on
|
|
60
|
+
// one of the messages. Without reading them, a pull that stored nothing is
|
|
61
|
+
// logged as a success. The Go side guards the same thing (`message.Error` in
|
|
62
|
+
// RunSkyrampWorker).
|
|
63
|
+
let streamError;
|
|
43
64
|
docker.modem.followProgress(stream, (err) => {
|
|
44
65
|
if (err)
|
|
45
66
|
return reject(err);
|
|
67
|
+
if (streamError) {
|
|
68
|
+
return reject(new Error(`docker pull ${imageName} (${platform}) failed: ${streamError}`));
|
|
69
|
+
}
|
|
46
70
|
logger.info("Docker image pulled successfully", {
|
|
47
71
|
image: imageName,
|
|
48
72
|
platform,
|
|
49
73
|
});
|
|
50
74
|
resolve();
|
|
75
|
+
}, (msg) => {
|
|
76
|
+
if (msg?.error && streamError === undefined) {
|
|
77
|
+
streamError = msg.errorDetail?.message ?? msg.error;
|
|
78
|
+
}
|
|
51
79
|
});
|
|
52
80
|
});
|
|
53
81
|
});
|
|
@@ -55,39 +83,67 @@ async function doPull(docker, imageName, platform) {
|
|
|
55
83
|
/**
|
|
56
84
|
* Pull a Docker image by name.
|
|
57
85
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* back to linux/amd64 if the arm64 pull fails or the image doesn't land
|
|
64
|
-
* locally (Docker Desktop quirk on Apple Silicon).
|
|
86
|
+
* `dockerPlatform` defaults to the host architecture. Whether given or
|
|
87
|
+
* defaulted, a `linux/arm64` pull falls back to `linux/amd64` when the arm64
|
|
88
|
+
* pull reports no matching manifest or completes without the image landing
|
|
89
|
+
* locally (Docker Desktop quirk on Apple Silicon). Any other platform is
|
|
90
|
+
* pulled exactly, with no fallback.
|
|
65
91
|
*/
|
|
66
92
|
export async function pullDockerImage(imageName, dockerPlatform) {
|
|
67
93
|
const client = new Dockerode();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
94
|
+
const platform = dockerPlatform ?? getDockerPlatform();
|
|
95
|
+
// Docker Desktop on Apple Silicon serves amd64-only images under emulation, but an arm64
|
|
96
|
+
// pull of one either reports no matching manifest or completes and stores nothing. Those
|
|
97
|
+
// are the same rule, not two special cases: try these platforms in order until one
|
|
98
|
+
// actually lands.
|
|
99
|
+
const candidates = platform === "linux/arm64" ? [platform, "linux/amd64"] : [platform];
|
|
100
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
101
|
+
const candidate = candidates[i];
|
|
102
|
+
const next = candidates[i + 1];
|
|
103
|
+
try {
|
|
104
|
+
await doPull(client, imageName, candidate);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
// A manifest mismatch is the one failure another platform can answer.
|
|
108
|
+
if (next === undefined || !isManifestMismatchError(err))
|
|
109
|
+
throw err;
|
|
110
|
+
logger.info("pull failed, retrying on the next platform", {
|
|
111
|
+
image: imageName,
|
|
112
|
+
failed: candidate,
|
|
113
|
+
next,
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// A pull can end its stream cleanly and store nothing, so success is the image being
|
|
118
|
+
// present -- not the pull returning.
|
|
119
|
+
if (await dockerImageExistsLocally(imageName))
|
|
120
|
+
return;
|
|
121
|
+
if (next === undefined)
|
|
122
|
+
break;
|
|
123
|
+
logger.info("pull completed but the image is absent, retrying on the next platform", {
|
|
124
|
+
image: imageName,
|
|
125
|
+
failed: candidate,
|
|
126
|
+
next,
|
|
127
|
+
});
|
|
71
128
|
}
|
|
72
|
-
|
|
129
|
+
throw new Error(`docker pull ${imageName} (${candidates.join(", ")}) reported success but the image is not present locally`);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The default daemon's operating system ("windows" or "linux"), or undefined when it
|
|
133
|
+
* cannot be determined. The startup prefetch pulls each image for this OS; when it is
|
|
134
|
+
* undefined the executor is pulled as linux/amd64 and the worker for the host's own
|
|
135
|
+
* architecture (getDockerPlatform). Guessing is acceptable there because the prefetch is
|
|
136
|
+
* best-effort: a wrong guess costs a download, and the run itself refuses to guess
|
|
137
|
+
* (resolvePlatform in FleetExecutionService).
|
|
138
|
+
*/
|
|
139
|
+
export async function dockerDaemonOsType() {
|
|
73
140
|
try {
|
|
74
|
-
|
|
141
|
+
const info = (await new Dockerode().info());
|
|
142
|
+
return info?.OSType;
|
|
75
143
|
}
|
|
76
144
|
catch (err) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
await doPull(client, imageName, "linux/amd64");
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
throw err;
|
|
83
|
-
}
|
|
84
|
-
// On Docker Desktop/Mac, pulling an amd64-only image with linux/arm64 can
|
|
85
|
-
// complete the stream without error yet not store the image locally.
|
|
86
|
-
// Verify it actually landed, and fall back to amd64 if not.
|
|
87
|
-
if (platform === "linux/arm64" &&
|
|
88
|
-
!(await dockerImageExistsLocally(imageName))) {
|
|
89
|
-
logger.info("arm64 pull completed but image not found locally, retrying with linux/amd64", { image: imageName });
|
|
90
|
-
await doPull(client, imageName, "linux/amd64");
|
|
145
|
+
logger.warning("Could not determine the Docker daemon OS", { error: err });
|
|
146
|
+
return undefined;
|
|
91
147
|
}
|
|
92
148
|
}
|
|
93
149
|
/**
|