@skyramp/mcp 0.2.8 → 0.2.150-rc.ldw
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/commands/commandLibrary.d.ts +1 -0
- package/build/commands/commandLibrary.js +20 -14
- package/build/commands/commandLibrary.test.d.ts +1 -0
- package/build/commands/commandLibrary.test.js +59 -0
- package/build/commands/localDevTestChangesCommand.d.ts +15 -0
- package/build/commands/localDevTestChangesCommand.js +188 -0
- package/build/index.js +77 -13
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +9 -8
- package/build/prompts/local-dev/local-dev-plan.d.ts +25 -0
- package/build/prompts/local-dev/local-dev-plan.js +419 -0
- package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
- package/build/prompts/local-dev/local-dev-prompts.js +157 -0
- package/build/prompts/prompt-utils.d.ts +8 -0
- package/build/prompts/prompt-utils.js +33 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +3 -1
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +3 -1
- package/build/prompts/sut-setup/shared.d.ts +20 -0
- package/build/prompts/sut-setup/shared.js +69 -7
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +0 -28
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +16 -1
- package/build/prompts/testbot/testbot-prompts.d.ts +0 -5
- package/build/prompts/testbot/testbot-prompts.js +4 -34
- package/build/resources/testbotResource.js +2 -1
- package/build/services/AnalyticsService.d.ts +1 -1
- package/build/services/TestExecutionService.d.ts +2 -1
- package/build/services/TestExecutionService.js +15 -10
- package/build/services/TestExecutionService.test.js +75 -1
- package/build/services/TestGenerationService.d.ts +2 -2
- package/build/tool-phases.js +4 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.js +47 -18
- package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
- package/build/tools/enrichTestWithMocksTool.js +726 -0
- package/build/tools/enrichTestWithMocksTool.test.d.ts +1 -0
- package/build/tools/enrichTestWithMocksTool.test.js +266 -0
- package/build/tools/executeSkyrampTestTool.d.ts +4 -0
- package/build/tools/executeSkyrampTestTool.js +48 -24
- package/build/tools/executeSkyrampTestTool.test.d.ts +1 -0
- package/build/tools/executeSkyrampTestTool.test.js +16 -0
- package/build/tools/generate-tests/batchMockGenerationTool.d.ts +85 -0
- package/build/tools/generate-tests/batchMockGenerationTool.js +432 -0
- package/build/tools/generate-tests/generateContractRestTool.js +2 -2
- package/build/tools/generate-tests/generateMockRestTool.d.ts +129 -6
- package/build/tools/generate-tests/generateMockRestTool.js +234 -22
- package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
- package/build/tools/generateEnrichedIntegrationTestTool.d.ts +24 -0
- package/build/tools/generateEnrichedIntegrationTestTool.js +225 -0
- package/build/tools/generateEnrichedIntegrationTestTool.test.d.ts +1 -0
- package/build/tools/generateEnrichedIntegrationTestTool.test.js +44 -0
- package/build/tools/localDevWorkflowFixes.test.d.ts +1 -0
- package/build/tools/localDevWorkflowFixes.test.js +255 -0
- package/build/tools/one-click/oneClickTool.d.ts +10 -0
- package/build/tools/one-click/oneClickTool.js +177 -21
- package/build/tools/one-click/oneClickTool.test.d.ts +1 -0
- package/build/tools/one-click/oneClickTool.test.js +172 -0
- package/build/tools/preflightMockCheckTool.d.ts +2 -0
- package/build/tools/preflightMockCheckTool.js +96 -0
- package/build/tools/submitReportTool.d.ts +14 -14
- package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
- package/build/tools/test-management/analyzeChangesTool.js +59 -38
- package/build/tools/trace/startTraceCollectionTool.js +3 -3
- package/build/tools/workspace/initializeWorkspaceTool.js +2 -9
- package/build/tools/workspace/initializeWorkspaceTool.test.js +9 -4
- package/build/types/OneClickCommands.d.ts +1 -1
- package/build/types/RepositoryAnalysis.d.ts +117 -0
- package/build/types/RepositoryAnalysis.js +16 -2
- package/build/types/TestExecution.d.ts +1 -0
- package/build/types/TestTypes.d.ts +20 -8
- package/build/types/TestTypes.js +19 -5
- package/build/utils/analyze-openapi.js +18 -1
- package/build/utils/analyze-openapi.test.d.ts +1 -0
- package/build/utils/analyze-openapi.test.js +19 -0
- package/build/utils/branchDiff.d.ts +17 -1
- package/build/utils/branchDiff.js +96 -14
- package/build/utils/branchDiff.test.d.ts +1 -0
- package/build/utils/branchDiff.test.js +109 -0
- package/build/utils/docker.test.js +1 -1
- package/build/utils/featureFlags.d.ts +20 -1
- package/build/utils/featureFlags.js +26 -2
- package/build/utils/featureFlags.test.js +57 -2
- package/build/utils/grpcMockValidation.d.ts +1 -0
- package/build/utils/grpcMockValidation.js +49 -0
- package/build/utils/grpcMockValidation.test.d.ts +1 -0
- package/build/utils/grpcMockValidation.test.js +41 -0
- package/build/utils/httpMethodValidation.d.ts +4 -0
- package/build/utils/httpMethodValidation.js +13 -0
- package/build/utils/mockCompatibility.d.ts +49 -0
- package/build/utils/mockCompatibility.js +82 -0
- package/build/utils/mockCompatibility.test.d.ts +1 -0
- package/build/utils/mockCompatibility.test.js +79 -0
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/workspace/workspace.d.ts +49 -35
- package/build/workspace/workspace.js +10 -5
- package/build/workspace/workspace.test.js +65 -6
- package/package.json +2 -2
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PromptPlan-based local-dev workflow — 6 phases.
|
|
3
|
+
*
|
|
4
|
+
* Phases: ANALYZE → RECOMMEND → GENERATE → VERIFY → DEPLOY → EXECUTE
|
|
5
|
+
*
|
|
6
|
+
* Key design decisions:
|
|
7
|
+
* - Mock files are generated in the same language as tests (from workspace config) with get_all_mocks()/getAllMocks()
|
|
8
|
+
* - Tests import get_all_mocks()/getAllMocks() from each mock file, collect into MOCK_SERVICES, deploy collectively
|
|
9
|
+
* - NO YAML mock files, NO CLI commands — ONLY MCP tools
|
|
10
|
+
* - Execution uses skyramp_execute_test MCP tool exclusively
|
|
11
|
+
* - Enriched tests apply mocks at runtime through their language-specific Skyramp client helper
|
|
12
|
+
*/
|
|
13
|
+
import { PromptPlan } from "../test-recommendation/promptPlan.js";
|
|
14
|
+
// ── The Plan ─────────────────────────────────────────────────────────────────
|
|
15
|
+
export const localDevPlan = new PromptPlan()
|
|
16
|
+
// ─── Phase 1: Analyze ───────────────────────────────────────────────────────
|
|
17
|
+
.addPhase("analyze", "Analyze Changes", {
|
|
18
|
+
headerLevel: "##",
|
|
19
|
+
stepFormat: "hash",
|
|
20
|
+
})
|
|
21
|
+
.step("ANALYZE_DIFF", "Analyze branch diff", (ctx) => `Call \`skyramp_analyze_changes\` with:
|
|
22
|
+
- \`repositoryPath\`: "${ctx.repositoryPath}"
|
|
23
|
+
- \`scope\`: "branch_diff"
|
|
24
|
+
- \`baseBranch\`: "${ctx.baseCommit}"
|
|
25
|
+
- \`includeUncommitted\`: true
|
|
26
|
+
- \`topN\`: ${ctx.maxRecommendations}
|
|
27
|
+
- \`maxGenerate\`: ${ctx.maxGenerate}${ctx.stateOutputFile ? `\n- \`stateOutputFile\`: "${ctx.stateOutputFile}"` : ""}
|
|
28
|
+
|
|
29
|
+
**IMPORTANT — This is a local-dev workflow, NOT a testbot run.** IGNORE any suggestions about \`skyramp_analyze_test_health\`, \`skyramp_actions\`, or \`skyramp_recommend_tests\`. Proceed directly to dependency discovery.
|
|
30
|
+
|
|
31
|
+
**Cross-check recommendations against the actual diff.** \`skyramp_analyze_changes\` can return scenario recommendations for endpoints that do not exist in the changed files (wrong-repo suggestions, hallucinated paths). Before acting on any recommendation, verify that the referenced endpoint or file path appears in the diff output. Discard any recommendation whose endpoint is not traceable to a changed file — use those only as inspiration, not as authoritative coverage guidance.
|
|
32
|
+
|
|
33
|
+
If 0 endpoints detected but changed files contain application code: manually trace changed files upward to discover which API endpoint(s) they serve.
|
|
34
|
+
|
|
35
|
+
If \`skyramp_analyze_changes\` returns an error: retry once for transient errors. If it fails again, report the error and stop.
|
|
36
|
+
|
|
37
|
+
**If the analysis output is too large to inspect**: do not switch to direct shell commands. Use the inline recommendations returned by \`skyramp_analyze_changes\`, fetch the focused MCP resources for this session (summary, endpoints, scenarios, and diff), or rerun with a smaller \`topN\` / \`maxGenerate\` budget so the workflow remains MCP-driven.`)
|
|
38
|
+
.step("DISCOVER_DEPS", "Discover downstream dependencies", (_ctx) => `For each changed endpoint, read the implementation code and identify ALL outbound service calls:
|
|
39
|
+
|
|
40
|
+
**HTTP/REST** — look for: \`HTTParty\`, \`fetch\`, \`axios\`, \`http.NewRequestWithContext\`, SDK client calls
|
|
41
|
+
**gRPC** — look for: proto-generated stubs, \`.Stub.new()\`, \`pb.New<Service>Client(conn)\`
|
|
42
|
+
**Kafka/Events** — look for: \`Kafka.new\`, \`deliver_message\`, \`producer.Send\`, event publishing
|
|
43
|
+
|
|
44
|
+
**gRPC dependency handling:** Record the service hostname, port, and RPC method in the dependency map — do NOT read .proto files yet. Proto files are only needed for mock generation. Defer proto reading until Phase 3 after \`skyramp_preflight_mock_check\` so advisory warnings are visible before generation.
|
|
45
|
+
|
|
46
|
+
Classify each dependency as **third-party**, **first-party/local service**, **infrastructure**, or **service under test** before deciding whether to mock it. By default, only third-party downstream services are mocked; first-party/local services and infrastructure remain real unless the user explicitly requests them in service routing.
|
|
47
|
+
|
|
48
|
+
Record as a **dependency map**:
|
|
49
|
+
\`\`\`
|
|
50
|
+
service_name:
|
|
51
|
+
protocol: http | grpc | kafka
|
|
52
|
+
port: <port from env var or config>
|
|
53
|
+
interactions: [method, path, request shape, response shape]
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
Downstream dependency handling must be explicit: HTTP/REST, gRPC, and Kafka dependencies can be mocked by Skyramp when selected for mocking. For unselected first-party/local services and infrastructure, use the real local service and document why it is real. For Kafka selected for mocking, call \`skyramp_mock_generation\` with \`protocol: "kafka"\`, \`endpointURL\` as broker \`host:port\`, and \`kafkaTopic\` as the topic name. The \`skyramp_execute_test\` tool handles execution and integration mock deployment from enriched test files.
|
|
57
|
+
|
|
58
|
+
**Auth discovery (do this NOW, not later):**
|
|
59
|
+
- Read the endpoint's auth middleware/filters to understand the token format (e.g., Base64 of "client_id:secret", JWT, API key)
|
|
60
|
+
- Read docker-compose env vars for valid credentials
|
|
61
|
+
- Determine the correct token value ONCE for execution, but do not write literal token values into generated test files
|
|
62
|
+
|
|
63
|
+
**Existing test discovery (do this NOW, not later):**
|
|
64
|
+
- Search the repo for existing tests that exercise the same endpoint: look in \`spec/\`, \`tests/skyramp/\`, \`spec/skyramp_local_dev/\`, and any \`*_spec.rb\` / \`*_test.py\` files whose path or name matches the endpoint.
|
|
65
|
+
- Read any matches before generating new tests. Extract: request body shape, required fields, auth header value, and expected response fields already exercised.
|
|
66
|
+
- **Auth token precedence — use in this order:**
|
|
67
|
+
1. **Captured scenario or trace data** — if a recorded trace or captured scenario file contains an Authorization header for this specific scenario, use that value as the execution token source. Do not paste it into generated test source.
|
|
68
|
+
2. **Existing matching test file for the same scenario or client** — if a test file exercises this endpoint AND clearly targets the same client/fixture (same scenario name, same client_id, same credential class), reuse that credential for execution via \`skyramp_execute_test.token\` or \`SKYRAMP_TEST_TOKEN\`, not as a hardcoded fallback in new tests.
|
|
69
|
+
3. **Derive from env/middleware** — only if neither of the above exists: read docker-compose env vars for valid credentials and the auth middleware for token format, then compute the token once.
|
|
70
|
+
Do NOT recompute the token when a literal value exists from step 1 or 2. The same endpoint can be exercised by different client credentials that load different fixture data from stubs — using the wrong credential produces a test that passes structurally but asserts against the wrong fixture.`)
|
|
71
|
+
.done()
|
|
72
|
+
// ─── Phase 2: Recommend ─────────────────────────────────────────────────────
|
|
73
|
+
.addPhase("recommend", "Recommend Scenarios", {
|
|
74
|
+
headerLevel: "##",
|
|
75
|
+
stepFormat: "hash",
|
|
76
|
+
})
|
|
77
|
+
.step("ENUMERATE_SCENARIOS", "Enumerate bug-catching scenarios", (_ctx) => `Based on the analysis output, enumerate an **exhaustive** list of bug-catching scenarios BEFORE generating any code. This is a planning step — produce the scenario list, not test files. Rank scenarios by the production bug they would catch; test type is only the implementation mechanism.
|
|
78
|
+
|
|
79
|
+
For each endpoint under test:
|
|
80
|
+
|
|
81
|
+
**Integration test scenarios:**
|
|
82
|
+
|
|
83
|
+
1. **Read the implementation code** (handler, orchestrator, adapter). For every \`if/else\`, \`case/when\`, \`rescue/catch\`, conditional return, or early exit — that's a scenario.
|
|
84
|
+
|
|
85
|
+
2. **For each mocked downstream service**, enumerate ALL distinct responses:
|
|
86
|
+
- Success (200/201) — happy path
|
|
87
|
+
- Validation rejection (400/422) — service says "no"
|
|
88
|
+
- Auth failure (401/403) — credentials wrong or expired
|
|
89
|
+
- Not found (404) — resource doesn't exist
|
|
90
|
+
- Timeout / unavailable (503/504) — service is down
|
|
91
|
+
|
|
92
|
+
3. **For DB/state interactions**, enumerate:
|
|
93
|
+
- Uniqueness violations (duplicate email, duplicate name)
|
|
94
|
+
- Foreign key failures, constraint violations
|
|
95
|
+
|
|
96
|
+
4. **For auth/input paths**, enumerate:
|
|
97
|
+
- Missing auth entirely, invalid auth
|
|
98
|
+
- Missing required fields, invalid field values
|
|
99
|
+
|
|
100
|
+
5. **For API and downstream contracts**, include scenarios only when they catch a realistic bug:
|
|
101
|
+
- Provider contract: response field added/renamed/removed, type/nullable mismatch, status-code semantic drift.
|
|
102
|
+
- Consumer contract: our code sends the wrong downstream request body/header/path, or parses a response field that may be missing/renamed.
|
|
103
|
+
|
|
104
|
+
6. **For full API flows**, treat API E2E coverage as integration coverage:
|
|
105
|
+
- **API full-flow coverage is integration coverage** in this workflow. Do NOT label API-only workflows as E2E.
|
|
106
|
+
- When a changed behavior spans multiple API calls, downstream services, DB state, async side effects, or a cross-service workflow, include full-scenario integration tests that cover each distinct workflow path (happy path, error paths, side-effect variations).
|
|
107
|
+
- Example: order creation with identity validation, inventory lookup, pricing calculation, payment authorization, fulfillment scheduling, and message-broker side effects is a cross-service workflow — generate an integration test for the happy path AND one for each high-value failure branch (e.g., payment rejection, identity validation failure), not a separate API E2E test type.
|
|
108
|
+
|
|
109
|
+
7. **For UI tests**, only include them when frontend behavior is in scope:
|
|
110
|
+
- UI tests are only for frontend changes, a changed UI route, or a browser-observable user flow tied to the diff.
|
|
111
|
+
- Do NOT generate UI tests for backend-only diffs, API-only service changes, or workflows that have no discoverable frontend surface.
|
|
112
|
+
- If UI coverage is applicable, record the browser flow with browser tools, export it with \`skyramp_export_zip\`, and generate the test with \`skyramp_ui_test_generation\`.
|
|
113
|
+
|
|
114
|
+
**Prioritization (applies across ALL test types):**
|
|
115
|
+
|
|
116
|
+
8. **Rank by bug-catching value, not by test type**: security paths > data-loss or money-moving behavior > externally visible API shape breakage > important business branches > dependency failures > edge cases. Prefer the cheapest reliable test type that catches the bug. Do NOT generate a contract test just to satisfy a quota, and do NOT generate an integration test if a focused contract catches the same bug more directly.
|
|
117
|
+
|
|
118
|
+
9. **Output a unified scenario table** (do NOT generate code yet):
|
|
119
|
+
|
|
120
|
+
| # | What this verifies | Best Test Type | Scenario Name | Mock Config | Expected Response | Priority |
|
|
121
|
+
|---|---------------------|----------------|---------------|-------------|-------------------|----------|
|
|
122
|
+
| 1 | Order creation applies downstream pricing rules | integration | happy-path-with-pricing | All required downstream success | 201 + calculated totals | high |
|
|
123
|
+
| 2 | Payment rejection rolls back order creation | integration | payment-rejects | Payment service → 422 | expected error + no persisted order | high |
|
|
124
|
+
| 3 | Public order response shape does not regress | provider-contract | order-response-shape | N/A | required fields typed | medium |
|
|
125
|
+
| 4 | Payment request shape remains compatible | consumer-contract | payment-request-shape | N/A | validates request body + parses response | medium |
|
|
126
|
+
| 5 | Complete API order workflow remains coherent | integration | order-creation-full-flow | All downstreams for the cross-service workflow | final response + side effects observed | high |
|
|
127
|
+
| 6 | Frontend checkout flow still works after UI changes | ui | checkout-ui-flow | Browser trace + applicable API mocks | visible success/error state | high when frontend changed |
|
|
128
|
+
| ...| ... | ... | ... | ... | ... | ... |
|
|
129
|
+
|
|
130
|
+
**IMPORTANT:** Only proceed to the next phase once you have the complete scenario list. The total number should reflect distinct bug-catching outcomes and API boundaries — skip redundant tests even if they are a different type.`)
|
|
131
|
+
.done()
|
|
132
|
+
// ─── Phase 3: Generate ──────────────────────────────────────────────────────
|
|
133
|
+
.addPhase("generate", "Generate Mocks & Tests", {
|
|
134
|
+
headerLevel: "##",
|
|
135
|
+
stepFormat: "hash",
|
|
136
|
+
})
|
|
137
|
+
.step("GENERATE_MOCKS_AND_TESTS", "Generate highest-value tests", (ctx) => `**Preferred: Use batch tools when available.**
|
|
138
|
+
- Call \`skyramp_batch_mock_generation\` with all mock specs in one array instead of individual \`skyramp_mock_generation\` calls.
|
|
139
|
+
- For Python, TypeScript, JavaScript, and Java integration tests, call \`skyramp_generate_enriched_integration_test\` instead of separate generate + enrich calls when generated mocks must be wired into the test.
|
|
140
|
+
- Call \`skyramp_enhance_assertions\` with \`autoApply: true\` for compact output format — the returned instructions must still be applied by you to the test file.
|
|
141
|
+
|
|
142
|
+
**Run \`skyramp_preflight_mock_check\` FIRST, before reading any .proto files or constructing any mock spec.**
|
|
143
|
+
- For each gRPC service in the dependency map, preflight surfaces advisory issues such as persistent pre-existing gRPC connections. gRPC mocks may target the real downstream service port (for example, \`partner-accounts:50051\`).
|
|
144
|
+
- For REST services, preflight confirms the mock URL uses a Docker-service hostname. If it returns \`REST_LOOPBACK_URL\`, fix \`endpointURL\` to the original service origin (for example, \`http://ams:4000\`), not \`localhost\` or \`host.docker.internal\`.
|
|
145
|
+
- For Docker gRPC mocks, ensure the real downstream service container is stopped, apply mocks before the SUT starts, restart the SUT after applying mocks, and verify the worker has the original endpoint host alias from \`endpointURL\` (for example, \`partner-accounts\`).
|
|
146
|
+
|
|
147
|
+
Work through the scenario list from Phase 2 in **bug-catching priority order**. The budget is ${ctx.maxGenerate} total tests across all types.
|
|
148
|
+
|
|
149
|
+
**Selection rule:** Generate the tests most likely to catch real regressions and edge-case bugs. Choose integration, provider contract, consumer contract, or UI based on which one best proves the behavior. There is no required quota by test type. If the highest-value ${ctx.maxGenerate} scenarios are all integration tests, generate integrations; if focused contracts catch the riskiest issues more directly, generate contracts. For API-only full-flow coverage, choose integration and model the whole scenario in one scenario trace; reserve UI tests for frontend changes or browser-observable flows.
|
|
150
|
+
|
|
151
|
+
**Coverage floor:** If Phase 2 identifies multiple high-priority scenarios, generate and execute each high-priority scenario up to ${ctx.maxGenerate}. Do not stop after the first passing test while other high-priority scenarios remain ungenerated or unexecuted.
|
|
152
|
+
|
|
153
|
+
**Side-effect rule:** Integration scenarios must account for all downstream side effects discovered for that scenario. Generate mocks only for side-effect dependencies selected for mocking by service routing, protocol routing, or the default third-party policy. If a Kafka-compatible broker is a real local infrastructure service, keep it real and document that decision instead of generating Kafka mocks. Full-scenario integration tests should cover the complete API workflow from trigger request through downstream calls and final observable result.
|
|
154
|
+
|
|
155
|
+
**Outbound assertion rule:** If the behavior being tested depends on what the service under test sends to a mocked dependency, the test must prove the outbound interaction, not just the final SUT response. For REST mocks, provide \`requestData\` for the expected body and \`requestAware: true\`; for gRPC, include the expected request fields in the scenario's verification notes when the mock/test API can assert them; for Kafka producers, use \`requestData\` and include the Kafka mock in \`MOCK_SERVICES\`. If Skyramp cannot assert the outbound body/header/path/event payload for the selected protocol, mark that scenario **Blocked — outbound assertion unsupported** instead of reporting a green pass.
|
|
156
|
+
|
|
157
|
+
**REST mock routing rule:** Generated REST mock files may contain a fallback like \`URL = skyramp.get_base_url(..., "http://localhost:8080")\`. Do not manually edit the generated mock file for local-dev routing. The enrichment step parses the mock generation \`# Command\` line and overwrites each deployable REST mock's \`mock.url\` with the original service origin from \`endpointURL\` (for example, \`http://ams:4000\` or \`http://billing:5001\`). If the command target itself is loopback, regenerate the mock with the original Docker service hostname.
|
|
158
|
+
|
|
159
|
+
**Mock semantics rule:** Kafka mock generation must use \`kafkaTopic\` for the topic name; do not pass \`method: "produce"\` or \`method: "consume"\`. Use exactly one of \`requestData\` for producer validation or \`responseData\` for consumer messages. Core Skyramp infers Kafka \`produce\` from \`request_body\` and \`consume\` from \`response_body\`; passing both or neither is invalid. Kafka mock files are generated, included in \`MOCK_SERVICES\`, included in \`MOCK_TARGET_URLS\`, and applied by the language-specific apply helper after enrichment sets \`mock.url\` to the original broker \`host:port\` from the generation command. If a gRPC failure scenario depends on \`GRPC::Unavailable\`, \`DeadlineExceeded\`, \`NOT_FOUND\`, or another status error, gRPC status errors cannot be represented as normal responseData. Use a supported failure mechanism if available; otherwise record the scenario as blocked instead of generating a mock body like \`{ "error": "UNAVAILABLE" }\`.
|
|
160
|
+
|
|
161
|
+
For each selected scenario, follow the workflow matching its best test type:
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
**For \`integration\` scenarios:**
|
|
166
|
+
|
|
167
|
+
**A — Generate mock files for each downstream service:**
|
|
168
|
+
Call \`skyramp_batch_mock_generation\` once with all downstream services as specs in a single array. Fields per spec type:
|
|
169
|
+
|
|
170
|
+
REST spec fields:
|
|
171
|
+
- \`protocol\`: "rest"
|
|
172
|
+
- \`endpointURL\`: full URL using the ORIGINAL Docker service hostname and port (e.g., \`http://identity-service:4000/api/internal/v1/users/validate\`). NEVER use \`localhost\`, \`127.0.0.1\`, \`0.0.0.0\`, \`host.docker.internal\`, or the Skyramp worker address. The worker parses the hostname from this URL (e.g. \`identity-service\`) and adds it as a Docker network alias on the worker container so the SUT's DNS resolves to the mock — always use the real Docker service hostname. Preflight returns a blocking \`REST_LOOPBACK_URL\` warning for deployable REST mocks that violate this.
|
|
173
|
+
- Dynamic path segments: if the service under test generates an id at runtime (order id, resource id, UUID, user id), use a Skyramp route parameter in the mock path (e.g., \`/orders/:order_id/payment_authorizations\`) rather than a sentinel value like \`order_test\`, \`resource_placeholder\`, or a sample UUID.
|
|
174
|
+
- \`method\`: HTTP method
|
|
175
|
+
- \`responseData\`: realistic JSON response for THIS scenario
|
|
176
|
+
- \`requestAware\`: true
|
|
177
|
+
- \`requestData\`: required when this scenario's bug-catching value depends on outbound request-body correctness. It must contain the exact fields the service under test should send to the downstream service (for example, \`billing_email\`, not an adjacent field such as \`adverse_action_email\`). For response-only downstream scenarios where body correctness is not what "What this verifies" covers, omit \`requestData\` unless it is needed for request-aware routing. If required request-body matching cannot be generated for the mock, record the scenario as blocked instead of producing a status-only test.
|
|
178
|
+
|
|
179
|
+
gRPC spec fields:
|
|
180
|
+
- \`protocol\`: "grpc"
|
|
181
|
+
- \`endpointURL\`: original Docker service target as \`host:port\` (e.g., \`profile-service:50051\`), without \`http://\`
|
|
182
|
+
- \`protoPath\`: absolute or repo-relative path to the .proto defining the service
|
|
183
|
+
- \`grpcServiceName\`: the gRPC service name from the proto
|
|
184
|
+
- \`method\`: RPC method name, or empty string to generate all methods for the service
|
|
185
|
+
- \`protobufExtraFiles\` / \`protobufExtraImportPath\`: include imports needed to compile the proto
|
|
186
|
+
- \`responseData\`: realistic JSON/protobuf-shaped response for THIS scenario
|
|
187
|
+
|
|
188
|
+
Kafka spec fields:
|
|
189
|
+
- \`protocol\`: "kafka"
|
|
190
|
+
- \`endpointURL\`: original broker target as \`host:port\` (e.g., \`broker:9092\`), without \`http://\`
|
|
191
|
+
- \`kafkaTopic\`: topic name
|
|
192
|
+
- \`requestData\`: producer message schema/shape when validating published messages
|
|
193
|
+
- \`responseData\`: message payload to inject for consumer scenarios
|
|
194
|
+
|
|
195
|
+
All specs share these fields:
|
|
196
|
+
- \`outputDir\`: "${ctx.repositoryPath}/tests/skyramp/mocks/"
|
|
197
|
+
- \`runtime\`: "docker"
|
|
198
|
+
- \`dockerNetwork\`: from workspace config
|
|
199
|
+
- \`output\`: (optional) **REQUIRED whenever two or more mock files for the same endpoint and HTTP method would land in the same \`outputDir\`** — whether they come from the same batch call or separate \`skyramp_mock_generation\` calls (e.g., a 201 success mock and a 500 error mock both targeting \`PUT /accounts/:id/billing_preferences\`). Without a distinct \`output\` name, the later file silently overwrites the earlier one. Use scenario-descriptive names like \`billing_preferences_success_mock.py\` and \`billing_preferences_error_mock.py\`. Before calling any mock generation tool, check the target \`outputDir\` for existing files with the default name the tool would produce; if a collision is possible, set \`output\` explicitly.
|
|
200
|
+
|
|
201
|
+
For producer side effects, include the Kafka mock file in the integration test enrichment alongside REST/gRPC mocks so \`MOCK_SERVICES\` proves the event path was exercised.
|
|
202
|
+
|
|
203
|
+
**B — Generate the integration test:**
|
|
204
|
+
Call \`skyramp_batch_scenario_test_generation\`:
|
|
205
|
+
- \`destination\`: app hostname (e.g., "localhost")
|
|
206
|
+
- \`baseURL\`: app URL (e.g., "http://localhost:3000")
|
|
207
|
+
- \`steps\`: target the SERVICE UNDER TEST, NOT downstream ports
|
|
208
|
+
- In the \`prompt\` parameter:
|
|
209
|
+
- Describe the scenario and expected outcome
|
|
210
|
+
- Include the auth header discovered in Phase 1
|
|
211
|
+
- Describe the mock response data from step A for each downstream service
|
|
212
|
+
|
|
213
|
+
Then call \`skyramp_integration_test_generation\`:
|
|
214
|
+
- Pass ONLY \`scenarioFile\` (mutually exclusive with endpointURL/apiSchema)
|
|
215
|
+
- \`outputDir\`: "${ctx.repositoryPath}/tests/skyramp/"
|
|
216
|
+
- \`output\`: descriptive name (e.g., "order_happy_path_integration_test.py")
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
**For \`provider-contract\` scenarios:**
|
|
221
|
+
|
|
222
|
+
Call \`skyramp_contract_test_generation\` with:
|
|
223
|
+
- \`endpointURL\`: full URL of OUR endpoint (e.g., "http://localhost:3000/api/v1/orders")
|
|
224
|
+
- \`method\`: the HTTP method
|
|
225
|
+
- \`responseData\`: the FULL expected response shape including ALL new fields from this diff
|
|
226
|
+
- \`outputDir\`: "${ctx.repositoryPath}/tests/skyramp/"
|
|
227
|
+
|
|
228
|
+
Provider contracts assert: status codes, required fields present, field types correct, nullable vs non-nullable.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
**For \`consumer-contract\` scenarios:**
|
|
233
|
+
|
|
234
|
+
Call \`skyramp_contract_test_generation\` with:
|
|
235
|
+
- \`endpointURL\`: the downstream service URL using the original Docker service hostname (e.g., "http://identity-service:4000/api/internal/v1/users/validate")
|
|
236
|
+
- \`method\`: what OUR code sends
|
|
237
|
+
- \`requestData\`: the request body OUR code constructs (from reading the implementation)
|
|
238
|
+
- \`responseData\`: what OUR code expects back (the shape it parses)
|
|
239
|
+
- \`outputDir\`: "${ctx.repositoryPath}/tests/skyramp/"
|
|
240
|
+
|
|
241
|
+
Consumer contract tests have mocks wired **inline by default** — the generated test file includes \`MockV2\` creation and \`client.apply_mock(mock)\` directly in the test function. **No separate \`skyramp_enrich_test_with_mocks\` call is needed for contract tests.** The mock defines the expected downstream response shape and the test validates the contract against it.
|
|
242
|
+
|
|
243
|
+
Consumer contract tests are incomplete until they invoke real consumer/SUT code that triggers the outbound request. A generated stub that calls \`client.send_request\` directly against the mock only proves the mock responds; it does not prove the application sends the right body/header/path. If you cannot wire real consumer code, do not execute or report the contract as PASS — mark the scenario **Blocked — consumer wiring unavailable**.
|
|
244
|
+
|
|
245
|
+
Consumer contracts catch: wrong outbound request body/header/path, field renamed downstream, new required header added, response shape changed, status code semantics changed.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
**For \`ui\` scenarios:**
|
|
250
|
+
|
|
251
|
+
Generate UI tests only when the diff includes frontend changes, a changed UI route, or a browser-observable user flow:
|
|
252
|
+
- Use browser interaction tools to record the relevant user flow, then call \`skyramp_export_zip\` to export the Playwright trace zip.
|
|
253
|
+
- Call \`skyramp_ui_test_generation\` with:
|
|
254
|
+
- \`playwrightInput\`: absolute path to the exported trace zip
|
|
255
|
+
- \`outputDir\`: the matching frontend service \`testDirectory\` from workspace config; if no frontend service is configured, use "${ctx.repositoryPath}/tests/skyramp/" and document that fallback
|
|
256
|
+
- \`language\` / \`framework\`: from the matching frontend service in workspace config
|
|
257
|
+
- The UI test must assert visible user-facing outcomes, not backend implementation details.
|
|
258
|
+
- Do NOT generate UI tests for backend-only diffs; cover API-only full-flow behavior with full-scenario integration tests instead.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
**Rules (all test types):**
|
|
263
|
+
- All \`outputDir\` values MUST be absolute paths inside the repository — NEVER \`/tmp\`.
|
|
264
|
+
- ONE test file per scenario row.
|
|
265
|
+
- **API full-flow scenarios** — generate as integration tests using scenario traces that include every API step needed to exercise the workflow. Do not label API-only workflows as E2E; if frontend browser coverage is in scope, use UI.
|
|
266
|
+
- **UI scenarios** — generate only for frontend changes or browser-observable flows; otherwise record a gap instead of inventing UI coverage.
|
|
267
|
+
- **Idempotent test data** — use unique values that won't collide on re-run (UUID suffixes for emails, random names, timestamps). Do NOT use static emails like "test@example.com" that will hit uniqueness constraints.
|
|
268
|
+
- **Auth headers** — generated tests should read auth from \`SKYRAMP_TEST_TOKEN\` only. Do not add literal token fallbacks to test files; pass the discovered token via \`skyramp_execute_test.token\` or the MCP server environment before execution. A 401 caused by an unset token is an execution setup bug, not a reason to hardcode credentials.
|
|
269
|
+
- **Contract responseData** — always provide the FULL expected shape so the test asserts on field presence, types, and values — not just status codes.
|
|
270
|
+
- **Assertion depth (integration tests)** — every integration test must assert the specific fields that prove the scenario's "What this verifies" column, not just the HTTP status code. Use \`skyramp.get_response_value(response, "field.path")\` to assert field values from the Expected Response column of the scenario table. Example: for a "customer config applied" scenario, assert \`skyramp.get_response_value(response, "tax_exempt") == True\` and \`skyramp.get_response_value(response, "default_compliance_state") == "<expected_value>"\` where \`<expected_value>\` is the actual value the mock returns for that scenario (e.g., a jurisdiction code like \`"CA"\`, a status string, or a numeric value — derive it from the mock's responseData, not from a guess). Status-code-only assertions never satisfy this rule.
|
|
271
|
+
- **No hollow tests** — never execute or report a generated test as PASS if it contains unresolved placeholders such as \`TODO\`, a standalone \`pass\` statement in a test body, \`NotImplemented\`, "replace with real consumer code", or an executable consumer-contract stub that directly calls the mocked endpoint instead of application/consumer code. A direct-mock stub may remain only when it is explicitly skipped or strict xfail and a separate executable real consumer/SUT test exists. Implement the missing check or mark the scenario blocked.
|
|
272
|
+
- Failure recovery: retry once, then skip and log in issuesFound.
|
|
273
|
+
|
|
274
|
+
Keep advancing in bug-catching priority order until the highest-value scenarios have test files (up to ${ctx.maxGenerate} total).`)
|
|
275
|
+
.step("ENRICH_TESTS", "Wire mock imports into integration test files", (ctx) => `For each **integration** test file only, call \`skyramp_enrich_test_with_mocks\` with:
|
|
276
|
+
- \`testFile\`: absolute path to the generated test file
|
|
277
|
+
- \`scenarioName\`: name from the scenario table
|
|
278
|
+
- \`mockFiles\`: absolute paths to the mock files generated in step A (e.g., ["${ctx.repositoryPath}/tests/skyramp/mocks/validate_POST_mock.py"])
|
|
279
|
+
- \`traceComments\`: (optional) how mock values flow through implementation to assertions
|
|
280
|
+
|
|
281
|
+
This injects import statements from the generated mock files — no data duplication. The test imports directly from the mock files.
|
|
282
|
+
|
|
283
|
+
**Skip contract tests** — consumer contract tests already have mocks wired inline by the generation tool (\`client.apply_mock(mock)\` embedded in the test function). Provider contract tests don't use mocks at all.`)
|
|
284
|
+
.done()
|
|
285
|
+
// ─── Phase 4: Verify ───────────────────────────────────────────────────────
|
|
286
|
+
.addPhase("verify", "Verify Tests", { headerLevel: "##", stepFormat: "hash" })
|
|
287
|
+
.step("VALIDATE_MOCKS", "Confirm test setup is complete", (ctx) => `Verify:
|
|
288
|
+
|
|
289
|
+
1. Every scenario from Phase 2 has a corresponding test file in \`${ctx.repositoryPath}/tests/skyramp/\`
|
|
290
|
+
2. For integration tests with selected downstream mocks: mock files exist in \`mocks/\` for each selected service/protocol and test files import them via a non-empty \`MOCK_SERVICES\` plus the language-specific apply helper (\`apply_all_mocks(client)\` for Python or \`applyAllMocks(client)\` for TypeScript/JavaScript/Java); if \`MOCK_SERVICES = {}\` or any expected mock import is missing for a mocked dependency, return to \`GENERATE_MOCKS_AND_TESTS\` or \`ENRICH_TESTS\` before any edits or execution
|
|
291
|
+
3. For consumer contract tests: mocks are wired inline (\`client.apply_mock(mock)\` present in the test function) — no separate mock files needed
|
|
292
|
+
4. For provider contract tests: no mocks — test hits the real endpoint directly
|
|
293
|
+
5. Test files use idempotent data (UUID-suffixed emails, random values — not hardcoded strings)
|
|
294
|
+
6. Auth headers are present in all test requests
|
|
295
|
+
7. **Integration tests have scenario-driven assertions** — each test asserts the specific response fields that prove the "What this verifies" column from the scenario table, not only the status code. If a test only asserts \`response.status_code == 201\` (or equivalent) without any field-level assertion on the behavior being tested, it is incomplete. Add \`skyramp.get_response_value()\` assertions for the key fields before executing.
|
|
296
|
+
8. **Outbound side effects are verified** — for every selected REST/gRPC/Kafka mock whose request body/header/path/event payload is the behavior under test, the mock spec or test includes a request/event assertion. If the toolchain cannot express that assertion, mark the scenario blocked instead of treating a response-only test as coverage.
|
|
297
|
+
9. **No unresolved stubs** — no generated test file contains \`TODO\`, a standalone \`pass\` statement in a test body, \`NotImplemented\`, "replace with real consumer code", or an executable consumer-contract test that only calls the mock directly. A skipped or strict xfail direct-mock reference is allowed only when the file also contains a separate executable real consumer/SUT test. These are blocking defects, not passing tests.
|
|
298
|
+
|
|
299
|
+
**If any mock file is missing for integration tests:** re-run \`skyramp_mock_generation\` for that service/endpoint.`)
|
|
300
|
+
.step("ENHANCE_ASSERTIONS", "Enhance assertions for each test file", (ctx) => `For each test file in \`${ctx.repositoryPath}/tests/skyramp/\`, call \`skyramp_enhance_assertions\` with:
|
|
301
|
+
- \`testFile\`: the test file path
|
|
302
|
+
- \`testType\`: "integration", "contract", or "ui" (match the scenario table)
|
|
303
|
+
- \`enhanceType\`: "generation"
|
|
304
|
+
|
|
305
|
+
The tool returns instructions — it does NOT edit the file automatically. Apply every returned instruction yourself: read the test file and add the suggested assertions. For assertions on server-generated IDs (e.g., account IDs, order IDs), prefer a domain prefix check (e.g., \`.startswith("acc_")\`) over \`is not None\` when the application uses a known ID format.`)
|
|
306
|
+
.step("CROSS_REFERENCE", "Cross-reference scenarios vs test files", (_ctx) => `Compare the scenario table from Phase 2 against the generated test files:
|
|
307
|
+
|
|
308
|
+
1. For each generated scenario, verify a corresponding test file exists with the correct SCENARIO_NAME or generated test name.
|
|
309
|
+
2. For integration tests, verify MOCK_SERVICES is non-empty and exactly matches the scenario's mock configuration. Empty MOCK_SERVICES is invalid for any scenario with downstream mocks.
|
|
310
|
+
3. For contract tests, verify responseData covers the full shape (all fields, types, nullability).
|
|
311
|
+
4. For UI tests, verify the trace maps to a real frontend change or browser-observable flow and includes visible assertions.
|
|
312
|
+
5. Verify the generated set covers the highest-risk bug-catching targets from the scenario table regardless of test type, including full API workflows as integration scenarios when applicable.
|
|
313
|
+
6. Document any gaps:
|
|
314
|
+
- Scenarios without test files → add to issuesFound with reason (generation failed, protocol unsupported, frontend not present, etc.)
|
|
315
|
+
- Test files without matching scenarios → investigate and either map to a scenario or remove
|
|
316
|
+
|
|
317
|
+
**Only proceed to Deploy when all generable scenarios have verified test files.**`)
|
|
318
|
+
.done()
|
|
319
|
+
// ─── Phase 5: Deploy ────────────────────────────────────────────────────────
|
|
320
|
+
.addPhase("deploy", "Deploy", { headerLevel: "##", stepFormat: "hash" })
|
|
321
|
+
.step("START_ENVIRONMENT", "Bring up the service under test", (ctx) => `If a \`docker-compose\` file is present in the repository, the service under test and its real infrastructure (DB, cache, real broker, real first-party services) must be running — **but mocked downstream services must NOT be running.**
|
|
322
|
+
|
|
323
|
+
**Why this matters:** The Skyramp worker intercepts traffic via Docker DNS alias hijacking — it registers itself as the DNS alias for each mocked service's hostname on the Docker network. If the real service container is also up on the same hostname and port, the two will conflict: traffic may reach the real service instead of the mock, or port binding will fail entirely. This is the most common cause of mocks not being applied correctly.
|
|
324
|
+
|
|
325
|
+
Steps:
|
|
326
|
+
1. Run \`docker compose ps\` in \`${ctx.repositoryPath}\` to check current container state.
|
|
327
|
+
2. Identify which docker-compose service names correspond to services selected for mocking (e.g., if \`ams\` is selected for mocking, do not start the \`ams\` container).
|
|
328
|
+
3. Stop any mocked service containers that are already running:
|
|
329
|
+
\`docker compose stop <mocked-service-1> <mocked-service-2> ...\`
|
|
330
|
+
4. Rebuild and bring up only the SUT and its real dependencies — start selectively:
|
|
331
|
+
\`docker compose up -d --build <sut-service> <db> <cache> <broker> <real-first-party-services>\`
|
|
332
|
+
Do **not** run plain \`docker compose up -d\` when it would start mocked downstream services or reuse a stale SUT image. If the compose file cannot start selectively, start the minimum required profile/services and then re-check that mocked service containers are stopped before executing tests. If the SUT service has no compose \`build\` context, record that local code cannot be rebuilt by compose before execution.
|
|
333
|
+
5. Wait for health checks to pass and verify the service under test responds (e.g., curl the health endpoint or send a minimal request).
|
|
334
|
+
|
|
335
|
+
The \`skyramp_execute_test\` tool runs the enriched test in the language runner. The enriched test applies selected mocks at runtime through its language-specific helper before exercising the service.
|
|
336
|
+
|
|
337
|
+
**Do NOT proceed to Execute until: (a) the service under test responds, and (b) all mocked service containers are confirmed stopped.**`)
|
|
338
|
+
.subStep("DEPLOY_GRPC", "Handle gRPC dependencies", (_ctx) => `If the dependency map from Phase 1 includes gRPC services selected for mocking:
|
|
339
|
+
|
|
340
|
+
To regenerate a single missing gRPC mock, call \`skyramp_mock_generation\` with \`protocol: "grpc"\`.
|
|
341
|
+
- Use \`endpointURL\` as the original Docker service target in \`host:port\` form, for example \`profile-service:50051\`.
|
|
342
|
+
- Provide \`protoPath\` for the .proto containing the service and \`grpcServiceName\` for the service name.
|
|
343
|
+
- Provide \`protobufExtraFiles\` and \`protobufExtraImportPath\` when the service proto imports other files.
|
|
344
|
+
- Do NOT replace a gRPC dependency with a REST fallback mock unless the implementation actually calls that REST fallback in the scenario under test.
|
|
345
|
+
- If a gRPC scenario cannot be mocked because required proto/schema details are unavailable, record that exact gap in issuesFound and do not fabricate an HTTP mock.
|
|
346
|
+
|
|
347
|
+
For services like profile-service that expose multiple gRPC RPCs (get_profile, get_preferences, refresh_metrics), each RPC is a separate dependency that may need its own gRPC mock. Document each RPC's mock decision separately.`)
|
|
348
|
+
.subStep("DEPLOY_KAFKA", "Handle Kafka dependencies", (_ctx) => `If the dependency map from Phase 1 includes Kafka producers or consumers selected for mocking:
|
|
349
|
+
|
|
350
|
+
To regenerate a single missing Kafka mock, call \`skyramp_mock_generation\` with \`protocol: "kafka"\`.
|
|
351
|
+
- Use \`endpointURL\` as the original broker target in \`host:port\` form, for example \`broker:9092\`.
|
|
352
|
+
- Provide \`kafkaTopic\` with the topic name.
|
|
353
|
+
- Use \`requestData\` as the producer message schema/shape when validating published messages.
|
|
354
|
+
- Use \`responseData\` as the message payload to inject for consumer scenarios.
|
|
355
|
+
- Use a real Kafka-compatible broker when it is local infrastructure or when the scenario explicitly needs infrastructure behavior that the Kafka mock cannot model, and document that decision in issuesFound. If Kafka is selected for mocking, provide exactly one of \`requestData\` or \`responseData\` and enrich the integration test so the Kafka mock is applied with the rest of the mock set.`)
|
|
356
|
+
.done()
|
|
357
|
+
// ─── Phase 6: Execute ───────────────────────────────────────────────────────
|
|
358
|
+
.addPhase("execute", "Execute & Report", {
|
|
359
|
+
headerLevel: "##",
|
|
360
|
+
stepFormat: "hash",
|
|
361
|
+
})
|
|
362
|
+
.step("EXECUTE_TESTS", "Execute tests via skyramp_execute_test MCP tool", (ctx) => `**You MUST use the \`skyramp_execute_test\` MCP tool for every test file.**
|
|
363
|
+
|
|
364
|
+
**NEVER use any of these alternatives:**
|
|
365
|
+
- \`skyramp execute test\` CLI command
|
|
366
|
+
- Direct language runtimes (\`python3\`, \`pytest\`, \`node\`, \`npx jest\`, etc.)
|
|
367
|
+
- Any shell command to run tests
|
|
368
|
+
|
|
369
|
+
**If \`skyramp_execute_test\` is unavailable** (tool not found, MCP disconnected, or context compaction removed it): do NOT fall back to any direct runtime. Stop execution immediately, list the test files that could not be executed, and tell the user: "The skyramp_execute_test tool is unavailable. Please reconnect the Skyramp MCP server and re-run. Do not use pytest or any direct runtime — doing so bypasses mock deployment and Skyramp telemetry."
|
|
370
|
+
|
|
371
|
+
The \`skyramp_execute_test\` MCP tool handles execution. For enriched integration tests, it runs the test in a container; the test's generated helper reads \`MOCK_SERVICES\`, clears stale mocks, and applies selected mocks before requests execute. Contract tests run without \`MOCK_SERVICES\`.
|
|
372
|
+
|
|
373
|
+
**Pre-execution gate:** Before every integration test execution, inspect the test file. If it does not contain \`MOCK_SERVICES\` and the language-specific apply helper (\`apply_all_mocks(client)\` for Python or \`applyAllMocks(client)\` for TypeScript/JavaScript/Java), or if it contains an empty \`MOCK_SERVICES\` collection for a scenario with downstream mocks, do NOT execute it. Call \`skyramp_enrich_test_with_mocks\` first and re-check the file. If \`MOCK_SERVICES\` is non-empty, execution is invalid until every real service selected for mocking is stopped.
|
|
374
|
+
|
|
375
|
+
**No-hollow-pass gate:** Before executing any generated test, inspect it for unresolved placeholders or stub-only behavior. Do NOT execute or report PASS for files containing \`TODO\`, a standalone \`pass\` statement in a test body, \`NotImplemented\`, "replace with real consumer code", or executable consumer-contract code that calls the mocked endpoint directly without invoking application/consumer code. Skipped or strict xfail direct-mock reference stubs may remain only when a separate executable real consumer/SUT test exists; the skipped or strict xfail stub never counts as PASS. Strict xfail must fail the run on XPASS (for pytest, \`@pytest.mark.xfail(strict=True)\`). Fix the test or report the scenario as blocked.
|
|
376
|
+
|
|
377
|
+
**Execution — one call per test file:**
|
|
378
|
+
\`\`\`
|
|
379
|
+
skyramp_execute_test({
|
|
380
|
+
testFile: "${ctx.repositoryPath}/tests/skyramp/<scenario>_test.py",
|
|
381
|
+
language: "<from workspace config>",
|
|
382
|
+
testType: "<'integration', 'contract', or 'ui' — match the scenario table>",
|
|
383
|
+
workspacePath: "${ctx.repositoryPath}",
|
|
384
|
+
token: "",
|
|
385
|
+
})
|
|
386
|
+
\`\`\`
|
|
387
|
+
|
|
388
|
+
That's it. Pass \`token: ""\` so the executor injects \`SKYRAMP_TEST_TOKEN\` from the environment when auth is configured. For provider contract tests, omit \`contractMode\` or pass \`contractMode: "provider"\` so \`SKYRAMP_TEST_BASE_URL\` is injected. For consumer contract tests with inline mocks, pass \`contractMode: "consumer"\`. For integration tests, mock deployment is automatic because the enriched test helper reads \`MOCK_SERVICES\`, clears stale mocks, and applies them before exercising the service. Provider contract tests hit the service under test directly; consumer contract tests use any inline mocks generated in the contract test itself; UI tests replay the generated browser workflow.
|
|
389
|
+
|
|
390
|
+
**On failure:**
|
|
391
|
+
1. Read the error output to diagnose the root cause.
|
|
392
|
+
2. "401 Unauthorized" → auth token missing or wrong. Do not hardcode a token into the test; pass the correct token through \`skyramp_execute_test.token\` or set \`SKYRAMP_TEST_TOKEN\` in the MCP execution environment, then retry once.
|
|
393
|
+
3. "Connection refused" → Skyramp worker not running or network mismatch. Check docker and retry.
|
|
394
|
+
4. Syntax/import error → fix the test file and retry **once**.
|
|
395
|
+
5. Mock deployment error → fix mock wiring or generated mock files once. Do NOT delete mock imports, empty \`MOCK_SERVICES\`, or switch selected mocked downstreams to live Compose stubs just to get a green test. If the retry still fails, record \`status: "Fail"\` or blocked with the exact mock deployment error.
|
|
396
|
+
6. **Timeout / no response** → if \`skyramp_execute_test\` does not return within the tool's timeout window, record \`status: "Timeout"\` with the test file path and do not retry automatically. Report to the user: the test may still be running or the worker may be unresponsive. Do not infer pass or fail from a timeout.
|
|
397
|
+
7. **Application bug** → if the failure is a DB constraint violation, a null reference, a business logic error, or any error clearly originating in the application under test (not in Skyramp tooling or mock wiring), record \`status: "Fail — app bug"\` with the exact error. Do NOT modify the application code. Report it as a real regression caught by the test.
|
|
398
|
+
8. If it still fails after one retry for non-app-bug errors, record \`status: "Fail"\` with details and move on.
|
|
399
|
+
|
|
400
|
+
**IMPORTANT: Execute tests SEQUENTIALLY (one at a time).** Do NOT send multiple \`skyramp_execute_test\` calls in parallel — concurrent execution overwhelms the stdio transport and causes MCP disconnection. Wait for each test to complete before starting the next.
|
|
401
|
+
|
|
402
|
+
**Completion gate:** Do not report success after only one passing test if more generated test files or high-priority scenario rows remain. A passing integration test with selected mocked downstreams is not valid if the test has empty \`MOCK_SERVICES\`, if required selected mocks were removed and replaced by live Compose stubs, or if the scenario's value depends on an outbound request/event that was not asserted. Execute every generated test file and report any high-priority scenarios that could not be generated or executed, including the reason.`)
|
|
403
|
+
.step("REPORT_RESULTS", "Report results to user", (_ctx) => `Present a summary to the user covering:
|
|
404
|
+
|
|
405
|
+
- **What changed**: 2-3 sentence summary of the diff
|
|
406
|
+
- **Mock scope**: list every downstream dependency and its disposition — (a) mocked via Skyramp, (b) real/live local stub with reason, or (c) skipped with reason. Flag explicitly if the actual scope differs from what the user requested (e.g., user said "mock all" but service X remained real because the protocol or SDK path is unsupported). For gRPC mocks, report the endpoint host:port and whether the worker alias matched the original host.
|
|
407
|
+
- **Mock deployment**: which services are mocked on which ports
|
|
408
|
+
- **Tests created**: file path, type, scenario description
|
|
409
|
+
- **Full-flow coverage**: which API workflows were covered as integration scenarios, and which UI flows were generated only because frontend changes were present
|
|
410
|
+
- **Results table**: one row per test — test name, scenario, status (PASS / FAIL / Timeout / Blocked), duration, failure detail
|
|
411
|
+
- **Failure classification**: for every non-passing test, distinguish the root cause:
|
|
412
|
+
- **App bug** — failure originates in the application under test (DB constraint, null reference, business logic error). The test did its job; this is a real regression to fix.
|
|
413
|
+
- **Skyramp/mock issue** — failure from mock deployment, worker connectivity, or tool error. The app may be correct; the test infrastructure needs fixing.
|
|
414
|
+
- **Generated test issue** — failure from wrong auth, missing field, or incorrect assertion in the generated test itself.
|
|
415
|
+
- **Timeout** — execution did not complete; pass/fail is unknown.
|
|
416
|
+
- **Issues found**: unmockable deps, generation failures, connection errors, gaps
|
|
417
|
+
|
|
418
|
+
Do NOT write results to a file — report inline to the user.`)
|
|
419
|
+
.done();
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type Service } from "../../workspace/workspace.js";
|
|
3
|
+
export declare function getLocalDevPrompt(baseCommit: string, repositoryPath: string, sandboxWorkerUrl?: string, maxRecommendations?: number, maxGenerate?: number, services?: Service[], stateOutputFile?: string, servicesToMock?: string[], realServices?: string[], mockProtocols?: string[]): string;
|
|
4
|
+
export declare function registerLocalDevPrompt(server: McpServer): void;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { logger } from "../../utils/logger.js";
|
|
4
|
+
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
5
|
+
import { buildServiceContext, escapeXml, readWorkspaceServices, } from "../prompt-utils.js";
|
|
6
|
+
import { localDevPlan } from "./local-dev-plan.js";
|
|
7
|
+
const LOCAL_DEV_MAX_RECOMMENDATIONS = 8;
|
|
8
|
+
const LOCAL_DEV_MAX_TESTS_TO_GENERATE = 5;
|
|
9
|
+
/**
|
|
10
|
+
* Build an XML block that tells the agent which downstream services to mock
|
|
11
|
+
* vs. which are real (already running in the local environment).
|
|
12
|
+
*/
|
|
13
|
+
function buildServiceRoutingBlock(servicesToMock, realServices, mockProtocols) {
|
|
14
|
+
if (!servicesToMock?.length && !realServices?.length && !mockProtocols?.length)
|
|
15
|
+
return "";
|
|
16
|
+
const lines = ["<SERVICE_ROUTING>"];
|
|
17
|
+
if (servicesToMock?.length) {
|
|
18
|
+
// "all" is a sentinel meaning "mock every discovered downstream dependency".
|
|
19
|
+
// Emit it as a dedicated flag so the agent doesn't treat it as a literal service name.
|
|
20
|
+
const mockAll = servicesToMock.includes("all");
|
|
21
|
+
const namedServices = servicesToMock.filter((s) => s !== "all");
|
|
22
|
+
if (mockAll) {
|
|
23
|
+
lines.push(` <MOCK_ALL_DOWNSTREAM>true</MOCK_ALL_DOWNSTREAM>`);
|
|
24
|
+
}
|
|
25
|
+
if (namedServices.length > 0) {
|
|
26
|
+
lines.push(` <MOCK_SERVICES>${namedServices.map(escapeXml).join(", ")}</MOCK_SERVICES>`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (realServices?.length) {
|
|
30
|
+
lines.push(` <REAL_SERVICES>${realServices.map(escapeXml).join(", ")}</REAL_SERVICES>`);
|
|
31
|
+
}
|
|
32
|
+
if (mockProtocols?.length) {
|
|
33
|
+
lines.push(` <MOCK_PROTOCOLS>${mockProtocols.map(escapeXml).join(", ")}</MOCK_PROTOCOLS>`);
|
|
34
|
+
}
|
|
35
|
+
lines.push("</SERVICE_ROUTING>");
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
export function getLocalDevPrompt(baseCommit, repositoryPath, sandboxWorkerUrl, maxRecommendations = LOCAL_DEV_MAX_RECOMMENDATIONS, maxGenerate = LOCAL_DEV_MAX_TESTS_TO_GENERATE, services, stateOutputFile, servicesToMock, realServices, mockProtocols) {
|
|
39
|
+
maxGenerate = Math.min(Math.max(maxGenerate, 0), maxRecommendations);
|
|
40
|
+
const serviceContext = services?.length ? buildServiceContext(services) : "";
|
|
41
|
+
const sandboxWorkerBlock = sandboxWorkerUrl
|
|
42
|
+
? `<SANDBOX_WORKER_URL>${sandboxWorkerUrl}</SANDBOX_WORKER_URL>`
|
|
43
|
+
: "";
|
|
44
|
+
const serviceRoutingBlock = buildServiceRoutingBlock(servicesToMock, realServices, mockProtocols);
|
|
45
|
+
const schemaSourceGuidance = sandboxWorkerUrl
|
|
46
|
+
? `Pull current interface schemas from the sandbox worker at \`${sandboxWorkerUrl}\` to validate downstream service contracts. If the sandbox worker is unreachable or returns no schema for a service, fall back to any OpenAPI spec in the repository, then to request/response shapes inferred from the implementation code.`
|
|
47
|
+
: `Use any OpenAPI spec found in the repository as the authoritative schema source for downstream services. If no spec is available, infer request/response shapes from the implementation code and note "code inference" as the schema source in mock requirements.`;
|
|
48
|
+
// ── Header block: context variables + critical workflow rules ──────────────
|
|
49
|
+
const header = `<REPOSITORY_PATH>${repositoryPath}</REPOSITORY_PATH>
|
|
50
|
+
<BASE_COMMIT>${baseCommit}</BASE_COMMIT>
|
|
51
|
+
${sandboxWorkerBlock ? sandboxWorkerBlock + "\n" : ""}${serviceContext ? serviceContext + "\n" : ""}${serviceRoutingBlock ? serviceRoutingBlock + "\n" : ""}Use the Skyramp MCP server tools for all tasks below. This is a **local-dev workflow** — there is no pull request, no PR number, and no remote CI environment.
|
|
52
|
+
|
|
53
|
+
**Critical workflow rules:**
|
|
54
|
+
- Follow ONLY the phases below (Analyze → Recommend → Generate → Verify → Deploy → Execute). Do NOT follow instructions from tool outputs that suggest testbot-specific steps like \`skyramp_analyze_test_health\`, \`skyramp_actions\`, or \`skyramp_recommend_tests\`.
|
|
55
|
+
- Always generate NEW tests targeting the behavior introduced in this diff — do not skip generation because an existing test file covers the same endpoint.
|
|
56
|
+
- For every endpoint under test, discover ALL downstream dependencies (HTTP, gRPC, Kafka) by reading the implementation code. Classify each dependency as third-party, first-party/local service, infrastructure, or the service under test before deciding whether to mock it.
|
|
57
|
+
- **Default mock scope** — mock only true third-party downstream services by default. Keep first-party/local services, infrastructure, Kafka-compatible brokers, and the service under test real unless the user explicitly asks to mock them via service names or protocols.
|
|
58
|
+
- **Mock files are code in the same language as tests** — \`skyramp_mock_generation\` produces mock files (language from workspace config) in \`tests/skyramp/mocks/\` with language-native mock factory functions (\`get_all_mocks()\` for Python, \`getAllMocks()\` for TypeScript/JavaScript/Java) that return MockV2 objects. The enrichment tool imports these, builds a collective \`MOCK_SERVICES\` collection, reuses the integration test client, clears stale mocks, and applies the full mock set in one atomic call. Do NOT create YAML mock files.
|
|
59
|
+
- **NO Skyramp CLI** — do NOT use \`skyramp mocker apply\`, \`skyramp mocker generate\`, or any other Skyramp CLI command. Use ONLY MCP tools for Skyramp operations.
|
|
60
|
+
- **NO duplicate mock data** — the generated mock files are the single source of truth. Do NOT duplicate response bodies or status codes in the test file. The test references mock files, not copies of them.
|
|
61
|
+
- **Mock generation → enrich flow (integration tests only)** — use \`skyramp_mock_generation\` to generate mock files, then call \`skyramp_enrich_test_with_mocks\` to wire mock references into the test. The enrichment uses the same data from generation — never invent different values. Consumer contract tests do NOT need enrichment — mocks are wired inline by the generation tool.
|
|
62
|
+
- **MANDATORY enrichment gate** — after every \`skyramp_integration_test_generation\` call for a scenario with any generated mock files, immediately call \`skyramp_enrich_test_with_mocks\` before reading, editing, enhancing, or executing that test. Do not batch all enrichment for later.
|
|
63
|
+
- **Enrichment validation** — an integration test that has downstream mocks but lacks \`MOCK_SERVICES\` and the language-specific apply helper (\`apply_all_mocks(client)\` for Python or \`applyAllMocks(client)\` for TypeScript/JavaScript/Java) is incomplete. Stop and enrich it; never call \`skyramp_execute_test\` on an incomplete integration test.
|
|
64
|
+
- **Do not delete mocks to pass** — if mock deployment fails, do NOT remove mock imports, empty \`MOCK_SERVICES\`, switch mocked downstreams to live Compose stubs, or report the resulting test as passed. Fix the mock wiring once; if still blocked, report the scenario as failed/blocked with the mock deployment error.
|
|
65
|
+
- **Mocked services must not be running** — before execution, stop every Docker container for a service selected for mocking (\`docker compose stop <mocked-service>\`). The Skyramp worker takes over that service's DNS alias on the Docker network; a real container running on the same hostname and port will conflict, causing traffic to reach the real service instead of the mock or causing port binding failure. Bring up only the SUT and its real infrastructure (DB, cache, real broker, real first-party services); do NOT run \`docker compose up -d\` without immediately stopping mocked service containers.
|
|
66
|
+
- **Mock URL format** — the \`endpointURL\` in \`skyramp_mock_generation\` MUST use the original Docker service hostname (e.g., \`http://identity-service:4000\`, \`http://profile-service:50052\`). The Skyramp executor uses DNS alias hijacking — it takes over the service's DNS name on the Docker network so the service under test's requests are intercepted transparently. NEVER use \`localhost\`, \`127.0.0.1\`, \`0.0.0.0\`, \`host.docker.internal\`, or the worker address as the mock URL. For REST mocks, \`skyramp_preflight_mock_check\` returns blocking \`REST_LOOPBACK_URL\` when a deployable mock uses these hosts.
|
|
67
|
+
- **REST mock routing** — Generated REST mock files may contain a fallback \`URL\` value such as \`http://localhost:8080\`; do not manually edit those files. The enrichment tool uses the mock generation \`# Command\` target to set each REST mock's \`mock.url\` back to the original Docker service origin before \`apply_mock()\`. If the command target is loopback, regenerate the mock with the original service hostname.
|
|
68
|
+
- **gRPC mock routing** — gRPC mocks may target the real downstream service port (e.g., \`partner-accounts:50051\`). Apply gRPC mocks before the SUT starts or restart the SUT after applying them, and verify the Skyramp worker has the original endpoint host alias from \`endpointURL\` (\`partner-accounts\`, not the protobuf service name like \`PartnerAccountsService\`).
|
|
69
|
+
- **Execution** — ALWAYS use \`skyramp_execute_test\` MCP tool to run tests. NEVER use direct language runtimes (\`python3\`, \`pytest\`, \`node\`, \`npx jest\`, etc.) or Skyramp CLI commands.
|
|
70
|
+
- **Generated test hardening** — before execution, make generated tests rerunnable and assertion-rich: use \`int(os.getenv("SKYRAMP_WORKER_PORT", "35142"))\` instead of a hardcoded worker port, keep auth token lookup environment-only (\`os.getenv("SKYRAMP_TEST_TOKEN")\`) with no literal fallback token in test source; pass the discovered token via \`skyramp_execute_test.token\` or the MCP server \`SKYRAMP_TEST_TOKEN\` environment before execution, use \`json.dumps({...})\` for JSON request bodies instead of f-string triple-quoted strings, use unique data for persistent DBs (UUID-suffixed emails/names), access \`ResponseV2\` via \`.status_code\` and \`skyramp.get_response_value(...)\` (never \`.json()\`), remember \`check_schema\` validates concrete field values (not just shape — a wrong value fails the assertion), and assert the changed behavior rather than status code alone.
|
|
71
|
+
- **Outbound side-effect proof** — when a scenario is meant to verify what the service under test sends to a mocked dependency, require a REST request body/header/path assertion, a Kafka producer payload assertion, or a documented gRPC request assertion. If Skyramp cannot express the outbound assertion, mark the scenario blocked instead of reporting a response-only test as passing.
|
|
72
|
+
- **No hollow green tests** — unresolved placeholders (\`TODO\`, a standalone \`pass\` statement in a test body, \`NotImplemented\`, or "replace with real consumer code") and executable consumer-contract stubs that call only the mock are blocking defects. Skipped or strict xfail direct-mock reference stubs are allowed only when paired with a separate executable real consumer/SUT test. Implement the missing application/consumer call or report the scenario blocked; do not execute or report it as PASS.
|
|
73
|
+
- **Downstream dependency handling is explicit** — HTTP/REST, gRPC, and Kafka dependencies can be mocked with Skyramp when selected for mocking. For gRPC, call \`skyramp_mock_generation\` with \`protocol: "grpc"\`, \`endpointURL\` as \`host:port\`, plus \`protoPath\` and \`grpcServiceName\`. For Kafka, call \`skyramp_mock_generation\` with \`protocol: "kafka"\`, \`endpointURL\` as broker \`host:port\`, and \`kafkaTopic\` as the topic name.
|
|
74
|
+
- **Service routing** — if a \`<SERVICE_ROUTING>\` block is provided above, respect it strictly. Resolve routing in this order:
|
|
75
|
+
1. \`REAL_SERVICES\` wins over every other rule. A real service should receive real traffic even if its service name or protocol is also listed for mocking.
|
|
76
|
+
2. \`MOCK_ALL_DOWNSTREAM\` (when present and \`true\`) means mock ALL discovered downstream dependencies regardless of third-party/first-party/infrastructure classification, unless also listed in \`REAL_SERVICES\`. Document each service decision in the dependency map.
|
|
77
|
+
3. \`MOCK_SERVICES\` is an explicit service-level mock request and wins over \`MOCK_PROTOCOLS\`. Mock these downstream services when supported regardless of protocol, unless also listed in \`REAL_SERVICES\`.
|
|
78
|
+
4. \`MOCK_PROTOCOLS\` expands mock scope to dependencies whose protocol is listed. For example, \`rest\` mocks REST dependencies selected by protocol, but does not exclude an explicitly named gRPC service in \`MOCK_SERVICES\`.
|
|
79
|
+
5. Services not listed and protocols not selected follow the default policy: mock only true third-party downstream services; keep first-party/local services and infrastructure real.
|
|
80
|
+
|
|
81
|
+
---`;
|
|
82
|
+
// ── Render the plan phases ────────────────────────────────────────────────
|
|
83
|
+
const ctx = {
|
|
84
|
+
repositoryPath,
|
|
85
|
+
baseCommit,
|
|
86
|
+
maxRecommendations,
|
|
87
|
+
maxGenerate,
|
|
88
|
+
stateOutputFile,
|
|
89
|
+
sandboxWorkerUrl,
|
|
90
|
+
schemaSourceGuidance,
|
|
91
|
+
serviceRoutingBlock,
|
|
92
|
+
serviceContext,
|
|
93
|
+
};
|
|
94
|
+
const planBody = localDevPlan.render(ctx);
|
|
95
|
+
return `${header}\n\n${planBody}`;
|
|
96
|
+
}
|
|
97
|
+
export function registerLocalDevPrompt(server) {
|
|
98
|
+
logger.info("Registering local-dev prompt");
|
|
99
|
+
server.registerPrompt("skyramp_local_dev", {
|
|
100
|
+
description: "Run Skyramp local-dev workflow: diff from a base commit, discover downstream dependencies, document mock requirements, generate mocks and backend tests, execute them against a local environment, and report results.",
|
|
101
|
+
argsSchema: {
|
|
102
|
+
baseCommit: z
|
|
103
|
+
.string()
|
|
104
|
+
.describe("Base commit reference to diff against — accepts a branch name (e.g. 'main'), a commit SHA (e.g. 'abc123f'), or a tag (e.g. 'v1.2.0'). The diff is computed between this ref and the current working tree (committed plus uncommitted changes)."),
|
|
105
|
+
repositoryPath: z
|
|
106
|
+
.string()
|
|
107
|
+
.refine((value) => path.isAbsolute(value), {
|
|
108
|
+
message: "repositoryPath must be an absolute path",
|
|
109
|
+
})
|
|
110
|
+
.describe("Absolute path to the repository being analyzed."),
|
|
111
|
+
sandboxWorkerUrl: z
|
|
112
|
+
.string()
|
|
113
|
+
.optional()
|
|
114
|
+
.describe("URL of the Skyramp sandbox worker deployed in the customer's environment. When provided, the agent queries it for current interface schemas to validate downstream service contracts and enrich mock requirements."),
|
|
115
|
+
maxRecommendations: z
|
|
116
|
+
.number()
|
|
117
|
+
.default(LOCAL_DEV_MAX_RECOMMENDATIONS)
|
|
118
|
+
.describe("Maximum number of test recommendations to request."),
|
|
119
|
+
maxGenerate: z
|
|
120
|
+
.number()
|
|
121
|
+
.default(LOCAL_DEV_MAX_TESTS_TO_GENERATE)
|
|
122
|
+
.describe("Maximum number of tests to generate."),
|
|
123
|
+
stateOutputFile: z
|
|
124
|
+
.string()
|
|
125
|
+
.optional()
|
|
126
|
+
.describe("Absolute path where skyramp_analyze_changes should write its state file."),
|
|
127
|
+
mockProtocols: z
|
|
128
|
+
.string()
|
|
129
|
+
.optional()
|
|
130
|
+
.describe("Comma-separated protocols to mock, such as 'rest', 'grpc', or 'kafka'. Omit to mock only true third-party downstream services by default."),
|
|
131
|
+
servicesToMock: z
|
|
132
|
+
.string()
|
|
133
|
+
.optional()
|
|
134
|
+
.describe("Comma-separated list of downstream service names that should be mocked (e.g. 'payments,tax-service,identity-provider'). Pass the sentinel value 'all' (alone or mixed with names, e.g. 'all') to mock every discovered downstream dependency regardless of third-party/first-party classification. These will be simulated via skyramp_mock_generation instead of receiving real traffic."),
|
|
135
|
+
realServices: z
|
|
136
|
+
.string()
|
|
137
|
+
.optional()
|
|
138
|
+
.describe("Comma-separated list of downstream service names that are already running locally and should receive real traffic (e.g. 'postgres,redis,envoy'). These will NOT be mocked."),
|
|
139
|
+
},
|
|
140
|
+
}, async (args) => {
|
|
141
|
+
const services = await readWorkspaceServices(args.repositoryPath);
|
|
142
|
+
const parseCsv = (v) => v ? v.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
|
|
143
|
+
const prompt = getLocalDevPrompt(args.baseCommit, args.repositoryPath, args.sandboxWorkerUrl, args.maxRecommendations, args.maxGenerate, services.length ? services : undefined, args.stateOutputFile, parseCsv(args.servicesToMock), parseCsv(args.realServices), parseCsv(args.mockProtocols));
|
|
144
|
+
AnalyticsService.pushMCPToolEvent("skyramp_local_dev_prompt", undefined, {}).catch(() => { });
|
|
145
|
+
return {
|
|
146
|
+
messages: [
|
|
147
|
+
{
|
|
148
|
+
role: "user",
|
|
149
|
+
content: {
|
|
150
|
+
type: "text",
|
|
151
|
+
text: prompt,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|