patchwork-os 0.2.0-beta.10.canary.99 → 0.2.0-beta.11
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/README.md +20 -1
- package/dist/adapters/grok.js +6 -1
- package/dist/adapters/grok.js.map +1 -1
- package/dist/approvalHttp.js +61 -66
- package/dist/approvalHttp.js.map +1 -1
- package/dist/bridge.js +3 -2
- package/dist/bridge.js.map +1 -1
- package/dist/claudeOrchestrator.js +15 -0
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/commands/patchworkInit.d.ts +7 -0
- package/dist/commands/patchworkInit.js +26 -0
- package/dist/commands/patchworkInit.js.map +1 -1
- package/dist/commands/recipe.d.ts +14 -0
- package/dist/commands/recipe.js +51 -0
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.js +15 -0
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/connectors/postgres.d.ts +7 -0
- package/dist/connectors/postgres.js +16 -2
- package/dist/connectors/postgres.js.map +1 -1
- package/dist/connectors/snowflake.js +6 -0
- package/dist/connectors/snowflake.js.map +1 -1
- package/dist/connectors/tokenStorage.d.ts +8 -0
- package/dist/connectors/tokenStorage.js +42 -3
- package/dist/connectors/tokenStorage.js.map +1 -1
- package/dist/drivers/claude/api.js +15 -2
- package/dist/drivers/claude/api.js.map +1 -1
- package/dist/drivers/claude/subprocess.js +1 -29
- package/dist/drivers/claude/subprocess.js.map +1 -1
- package/dist/drivers/gemini/index.js +9 -5
- package/dist/drivers/gemini/index.js.map +1 -1
- package/dist/drivers/openai/index.js +29 -4
- package/dist/drivers/openai/index.js.map +1 -1
- package/dist/drivers/outputCap.d.ts +27 -0
- package/dist/drivers/outputCap.js +50 -0
- package/dist/drivers/outputCap.js.map +1 -0
- package/dist/featureFlags.d.ts +9 -0
- package/dist/featureFlags.js +16 -0
- package/dist/featureFlags.js.map +1 -1
- package/dist/fp/commandDescription.d.ts +6 -0
- package/dist/fp/commandDescription.js +4 -4
- package/dist/fp/commandDescription.js.map +1 -1
- package/dist/fp/policyParser.js +13 -7
- package/dist/fp/policyParser.js.map +1 -1
- package/dist/haltPushDispatch.js +7 -22
- package/dist/haltPushDispatch.js.map +1 -1
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -1
- package/dist/mcpRoutes.js +1 -1
- package/dist/mcpRoutes.js.map +1 -1
- package/dist/oauth.d.ts +13 -0
- package/dist/oauth.js +34 -1
- package/dist/oauth.js.map +1 -1
- package/dist/recipeOrchestration.js +10 -0
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipeRoutes.d.ts +39 -0
- package/dist/recipeRoutes.js +214 -12
- package/dist/recipeRoutes.js.map +1 -1
- package/dist/recipes/agentExecutor.d.ts +20 -0
- package/dist/recipes/agentExecutor.js +32 -10
- package/dist/recipes/agentExecutor.js.map +1 -1
- package/dist/recipes/chainedRunner.d.ts +41 -2
- package/dist/recipes/chainedRunner.js +134 -6
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/connectorPreflight.js +30 -0
- package/dist/recipes/connectorPreflight.js.map +1 -1
- package/dist/recipes/haltCategory.d.ts +5 -0
- package/dist/recipes/haltCategory.js +7 -1
- package/dist/recipes/haltCategory.js.map +1 -1
- package/dist/recipes/judgeVerdict.d.ts +10 -0
- package/dist/recipes/judgeVerdict.js +10 -0
- package/dist/recipes/judgeVerdict.js.map +1 -1
- package/dist/recipes/names.d.ts +5 -0
- package/dist/recipes/names.js +10 -5
- package/dist/recipes/names.js.map +1 -1
- package/dist/recipes/parser.js +32 -9
- package/dist/recipes/parser.js.map +1 -1
- package/dist/recipes/pricing/costRouter.d.ts +43 -0
- package/dist/recipes/pricing/costRouter.js +44 -0
- package/dist/recipes/pricing/costRouter.js.map +1 -0
- package/dist/recipes/pricing/priceTable.d.ts +76 -0
- package/dist/recipes/pricing/priceTable.js +144 -0
- package/dist/recipes/pricing/priceTable.js.map +1 -0
- package/dist/recipes/runBudget.d.ts +82 -32
- package/dist/recipes/runBudget.js +182 -49
- package/dist/recipes/runBudget.js.map +1 -1
- package/dist/recipes/schema.d.ts +25 -4
- package/dist/recipes/schemaGenerator.d.ts +9 -0
- package/dist/recipes/schemaGenerator.js +386 -75
- package/dist/recipes/schemaGenerator.js.map +1 -1
- package/dist/recipes/simulation/aggregateRunRisk.d.ts +43 -0
- package/dist/recipes/simulation/aggregateRunRisk.js +117 -0
- package/dist/recipes/simulation/aggregateRunRisk.js.map +1 -0
- package/dist/recipes/simulation/costProjector.d.ts +32 -0
- package/dist/recipes/simulation/costProjector.js +194 -0
- package/dist/recipes/simulation/costProjector.js.map +1 -0
- package/dist/recipes/simulation/sideEffects.d.ts +32 -0
- package/dist/recipes/simulation/sideEffects.js +62 -0
- package/dist/recipes/simulation/sideEffects.js.map +1 -0
- package/dist/recipes/simulation/simulate.d.ts +36 -0
- package/dist/recipes/simulation/simulate.js +264 -0
- package/dist/recipes/simulation/simulate.js.map +1 -0
- package/dist/recipes/simulation/simulateMockedRun.d.ts +52 -0
- package/dist/recipes/simulation/simulateMockedRun.js +72 -0
- package/dist/recipes/simulation/simulateMockedRun.js.map +1 -0
- package/dist/recipes/simulation/synthesizeMockedOutputs.d.ts +31 -0
- package/dist/recipes/simulation/synthesizeMockedOutputs.js +50 -0
- package/dist/recipes/simulation/synthesizeMockedOutputs.js.map +1 -0
- package/dist/recipes/simulation/types.d.ts +198 -0
- package/dist/recipes/simulation/types.js +30 -0
- package/dist/recipes/simulation/types.js.map +1 -0
- package/dist/recipes/stepObservation.d.ts +12 -0
- package/dist/recipes/stepObservation.js +21 -1
- package/dist/recipes/stepObservation.js.map +1 -1
- package/dist/recipes/tools/airtable.d.ts +15 -0
- package/dist/recipes/tools/airtable.js +240 -0
- package/dist/recipes/tools/airtable.js.map +1 -0
- package/dist/recipes/tools/caldiy.d.ts +13 -0
- package/dist/recipes/tools/caldiy.js +214 -0
- package/dist/recipes/tools/caldiy.js.map +1 -0
- package/dist/recipes/tools/circleci.d.ts +10 -0
- package/dist/recipes/tools/circleci.js +204 -0
- package/dist/recipes/tools/circleci.js.map +1 -0
- package/dist/recipes/tools/cloudflare.d.ts +13 -0
- package/dist/recipes/tools/cloudflare.js +211 -0
- package/dist/recipes/tools/cloudflare.js.map +1 -0
- package/dist/recipes/tools/docs.d.ts +18 -0
- package/dist/recipes/tools/docs.js +94 -0
- package/dist/recipes/tools/docs.js.map +1 -0
- package/dist/recipes/tools/elasticsearch.d.ts +11 -0
- package/dist/recipes/tools/elasticsearch.js +156 -0
- package/dist/recipes/tools/elasticsearch.js.map +1 -0
- package/dist/recipes/tools/figma.d.ts +12 -0
- package/dist/recipes/tools/figma.js +194 -0
- package/dist/recipes/tools/figma.js.map +1 -0
- package/dist/recipes/tools/grafana.d.ts +11 -0
- package/dist/recipes/tools/grafana.js +216 -0
- package/dist/recipes/tools/grafana.js.map +1 -0
- package/dist/recipes/tools/http.d.ts +1 -1
- package/dist/recipes/tools/http.js +10 -28
- package/dist/recipes/tools/http.js.map +1 -1
- package/dist/recipes/tools/index.d.ts +26 -0
- package/dist/recipes/tools/index.js +26 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/tools/monday.d.ts +22 -0
- package/dist/recipes/tools/monday.js +242 -0
- package/dist/recipes/tools/monday.js.map +1 -0
- package/dist/recipes/tools/obsidian.d.ts +15 -0
- package/dist/recipes/tools/obsidian.js +172 -0
- package/dist/recipes/tools/obsidian.js.map +1 -0
- package/dist/recipes/tools/paystack.d.ts +11 -0
- package/dist/recipes/tools/paystack.js +211 -0
- package/dist/recipes/tools/paystack.js.map +1 -0
- package/dist/recipes/tools/pipedrive.d.ts +16 -0
- package/dist/recipes/tools/pipedrive.js +233 -0
- package/dist/recipes/tools/pipedrive.js.map +1 -0
- package/dist/recipes/tools/postgres.d.ts +15 -0
- package/dist/recipes/tools/postgres.js +185 -0
- package/dist/recipes/tools/postgres.js.map +1 -0
- package/dist/recipes/tools/posthog.d.ts +16 -0
- package/dist/recipes/tools/posthog.js +219 -0
- package/dist/recipes/tools/posthog.js.map +1 -0
- package/dist/recipes/tools/redis.d.ts +9 -0
- package/dist/recipes/tools/redis.js +140 -0
- package/dist/recipes/tools/redis.js.map +1 -0
- package/dist/recipes/tools/resend.d.ts +8 -0
- package/dist/recipes/tools/resend.js +153 -0
- package/dist/recipes/tools/resend.js.map +1 -0
- package/dist/recipes/tools/salesforce.d.ts +16 -0
- package/dist/recipes/tools/salesforce.js +184 -0
- package/dist/recipes/tools/salesforce.js.map +1 -0
- package/dist/recipes/tools/sendgrid.d.ts +9 -0
- package/dist/recipes/tools/sendgrid.js +174 -0
- package/dist/recipes/tools/sendgrid.js.map +1 -0
- package/dist/recipes/tools/shopify.d.ts +16 -0
- package/dist/recipes/tools/shopify.js +265 -0
- package/dist/recipes/tools/shopify.js.map +1 -0
- package/dist/recipes/tools/snowflake.d.ts +16 -0
- package/dist/recipes/tools/snowflake.js +173 -0
- package/dist/recipes/tools/snowflake.js.map +1 -0
- package/dist/recipes/tools/stripe.js +13 -12
- package/dist/recipes/tools/stripe.js.map +1 -1
- package/dist/recipes/tools/supabase.d.ts +9 -0
- package/dist/recipes/tools/supabase.js +132 -0
- package/dist/recipes/tools/supabase.js.map +1 -0
- package/dist/recipes/tools/todoist.d.ts +15 -0
- package/dist/recipes/tools/todoist.js +227 -0
- package/dist/recipes/tools/todoist.js.map +1 -0
- package/dist/recipes/tools/twilio.d.ts +11 -0
- package/dist/recipes/tools/twilio.js +180 -0
- package/dist/recipes/tools/twilio.js.map +1 -0
- package/dist/recipes/tools/vercel.d.ts +9 -0
- package/dist/recipes/tools/vercel.js +145 -0
- package/dist/recipes/tools/vercel.js.map +1 -0
- package/dist/recipes/tools/webflow.d.ts +11 -0
- package/dist/recipes/tools/webflow.js +243 -0
- package/dist/recipes/tools/webflow.js.map +1 -0
- package/dist/recipes/tools/woocommerce.d.ts +18 -0
- package/dist/recipes/tools/woocommerce.js +259 -0
- package/dist/recipes/tools/woocommerce.js.map +1 -0
- package/dist/recipes/tools/wrapConnectorExecute.d.ts +25 -0
- package/dist/recipes/tools/wrapConnectorExecute.js +37 -0
- package/dist/recipes/tools/wrapConnectorExecute.js.map +1 -0
- package/dist/recipes/validation.js +264 -0
- package/dist/recipes/validation.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +112 -3
- package/dist/recipes/yamlRunner.js +482 -19
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/runLog.d.ts +46 -0
- package/dist/runLog.js +4 -0
- package/dist/runLog.js.map +1 -1
- package/dist/schemas/recipe.v1.json +217 -11
- package/dist/server.d.ts +3 -0
- package/dist/server.js +4 -0
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.js +3 -2
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/gitWrite.js +5 -1
- package/dist/tools/gitWrite.js.map +1 -1
- package/dist/tools/terminal.js +15 -49
- package/dist/tools/terminal.js.map +1 -1
- package/dist/transport.d.ts +1 -0
- package/dist/transport.js +7 -0
- package/dist/transport.js.map +1 -1
- package/package.json +3 -3
- package/scripts/mcp-stdio-shim.cjs +218 -84
- package/templates/recipes/incident-to-pr.yaml +187 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What-If Preview — static simulation core.
|
|
3
|
+
*
|
|
4
|
+
* `simulateFromPlan` is a PURE transform: dry-run plan → simulation report.
|
|
5
|
+
* It performs no I/O and has no clock dependency (it reuses the plan's
|
|
6
|
+
* `generatedAt`), so it is fully deterministic and unit-testable. The
|
|
7
|
+
* I/O-bearing entrypoint (`runRecipeSimulate`, which produces the plan first)
|
|
8
|
+
* lives in `src/commands/recipe.ts`.
|
|
9
|
+
*/
|
|
10
|
+
import { computeEffectiveRisks, summarizeRunRisk } from "./aggregateRunRisk.js";
|
|
11
|
+
import { classifyStepSideEffect, emptySideEffectCounts, } from "./sideEffects.js";
|
|
12
|
+
import { SIMULATION_SCHEMA_VERSION, } from "./types.js";
|
|
13
|
+
/** Chars-per-token heuristic, matching the codebase's deliberately-rough estimate. */
|
|
14
|
+
const CHARS_PER_TOKEN = 4;
|
|
15
|
+
const isTier = (v) => v === "low" || v === "medium" || v === "high";
|
|
16
|
+
/** A step is "resolved" unless it is a tool whose id was not in the registry. */
|
|
17
|
+
function stepResolved(step) {
|
|
18
|
+
if (step.type !== "tool")
|
|
19
|
+
return true;
|
|
20
|
+
return step.resolved === true;
|
|
21
|
+
}
|
|
22
|
+
function buildSteps(plan, topology) {
|
|
23
|
+
const baseRisks = plan.steps.map((s) => ({
|
|
24
|
+
id: s.id,
|
|
25
|
+
baseRisk: isTier(s.risk) ? s.risk : "low",
|
|
26
|
+
...(s.dependencies ? { dependencies: s.dependencies } : {}),
|
|
27
|
+
}));
|
|
28
|
+
const effective = computeEffectiveRisks(baseRisks, topology);
|
|
29
|
+
return plan.steps.map((s) => {
|
|
30
|
+
const resolved = stepResolved(s);
|
|
31
|
+
const isWrite = s.isWrite === true;
|
|
32
|
+
const isConnector = s.isConnector === true;
|
|
33
|
+
const baseRisk = isTier(s.risk) ? s.risk : "low";
|
|
34
|
+
const sideEffect = classifyStepSideEffect({
|
|
35
|
+
type: s.type,
|
|
36
|
+
...(s.tool !== undefined ? { tool: s.tool } : {}),
|
|
37
|
+
...(s.namespace !== undefined ? { namespace: s.namespace } : {}),
|
|
38
|
+
resolved,
|
|
39
|
+
isWrite,
|
|
40
|
+
isConnector,
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
id: s.id,
|
|
44
|
+
type: s.type,
|
|
45
|
+
...(s.tool !== undefined ? { tool: s.tool } : {}),
|
|
46
|
+
...(s.namespace !== undefined ? { namespace: s.namespace } : {}),
|
|
47
|
+
resolved,
|
|
48
|
+
...(s.optional !== undefined ? { optional: s.optional } : {}),
|
|
49
|
+
...(s.dependencies ? { dependencies: s.dependencies } : {}),
|
|
50
|
+
...(s.condition !== undefined ? { condition: s.condition } : {}),
|
|
51
|
+
baseRisk,
|
|
52
|
+
effectiveRisk: effective.get(s.id) ?? baseRisk,
|
|
53
|
+
sideEffect,
|
|
54
|
+
isWrite,
|
|
55
|
+
isConnector,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function buildCost(plan) {
|
|
60
|
+
const agentPlanSteps = plan.steps.filter((s) => s.type === "agent");
|
|
61
|
+
const agentSteps = agentPlanSteps.length;
|
|
62
|
+
const withPrompt = agentPlanSteps.filter((s) => typeof s.prompt === "string" && s.prompt.length > 0);
|
|
63
|
+
const estimatedAgentSteps = withPrompt.length;
|
|
64
|
+
if (agentSteps === 0) {
|
|
65
|
+
return {
|
|
66
|
+
basis: "unavailable",
|
|
67
|
+
agentSteps: 0,
|
|
68
|
+
estimatedAgentSteps: 0,
|
|
69
|
+
estPromptTokens: null,
|
|
70
|
+
usd: null,
|
|
71
|
+
note: "No AI/agent steps — this recipe incurs no model cost.",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (estimatedAgentSteps === 0) {
|
|
75
|
+
return {
|
|
76
|
+
basis: "unavailable",
|
|
77
|
+
agentSteps,
|
|
78
|
+
estimatedAgentSteps: 0,
|
|
79
|
+
estPromptTokens: null,
|
|
80
|
+
usd: null,
|
|
81
|
+
note: "Agent prompts are not present in the static plan for this recipe topology — cost not estimable until a mocked/sandbox run (later phase).",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const estPromptTokens = withPrompt.reduce((sum, s) => sum + Math.ceil(s.prompt.length / CHARS_PER_TOKEN), 0);
|
|
85
|
+
return {
|
|
86
|
+
basis: "heuristic",
|
|
87
|
+
agentSteps,
|
|
88
|
+
estimatedAgentSteps,
|
|
89
|
+
estPromptTokens,
|
|
90
|
+
usd: null,
|
|
91
|
+
note: "Low-confidence chars/4 token estimate over agent prompts (input only). USD is not projected at static fidelity — the default driver is a subscription/subprocess driver that is not billed; set an API driver + budget for a cost number.",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Pure transform: a dry-run plan → a What-If Preview simulation report. */
|
|
95
|
+
export function simulateFromPlan(plan) {
|
|
96
|
+
const topology = plan.triggerType === "chained" ? "chained" : "flat";
|
|
97
|
+
const gatedOnRecipeSteps = false; // P0/P4 truth: recipe steps are not gated today.
|
|
98
|
+
const steps = buildSteps(plan, topology);
|
|
99
|
+
const sideEffectCounts = emptySideEffectCounts();
|
|
100
|
+
for (const s of steps)
|
|
101
|
+
sideEffectCounts[s.sideEffect] += 1;
|
|
102
|
+
const summary = {
|
|
103
|
+
totalSteps: steps.length,
|
|
104
|
+
writeSteps: steps.filter((s) => s.isWrite).length,
|
|
105
|
+
connectorSteps: steps.filter((s) => s.isConnector).length,
|
|
106
|
+
agentSteps: steps.filter((s) => s.type === "agent").length,
|
|
107
|
+
unresolvedSteps: steps.filter((s) => !s.resolved).length,
|
|
108
|
+
sideEffectCounts,
|
|
109
|
+
connectorNamespaces: plan.connectorNamespaces ?? [],
|
|
110
|
+
};
|
|
111
|
+
const risk = summarizeRunRisk(steps.map((s) => ({
|
|
112
|
+
effectiveRisk: s.effectiveRisk,
|
|
113
|
+
sideEffect: s.sideEffect,
|
|
114
|
+
resolved: s.resolved,
|
|
115
|
+
})));
|
|
116
|
+
const projected = steps
|
|
117
|
+
.filter((s) => s.baseRisk !== "low" || s.isWrite)
|
|
118
|
+
.map((s) => ({
|
|
119
|
+
stepId: s.id,
|
|
120
|
+
...(s.tool !== undefined ? { tool: s.tool } : {}),
|
|
121
|
+
tier: s.baseRisk,
|
|
122
|
+
wouldRequireApproval: s.baseRisk !== "low",
|
|
123
|
+
reason: s.baseRisk !== "low"
|
|
124
|
+
? `${s.baseRisk}-risk ${s.sideEffect}`
|
|
125
|
+
: `write step (${s.sideEffect}), low tier`,
|
|
126
|
+
}));
|
|
127
|
+
const branches = steps
|
|
128
|
+
.filter((s) => typeof s.condition === "string" && s.condition.length > 0)
|
|
129
|
+
.map((s) => ({
|
|
130
|
+
stepId: s.id,
|
|
131
|
+
condition: s.condition,
|
|
132
|
+
outcome: "undetermined",
|
|
133
|
+
reason: "Condition is evaluated at runtime against prior step output, which is not available in a static simulation.",
|
|
134
|
+
}));
|
|
135
|
+
const cost = buildCost(plan);
|
|
136
|
+
const notes = [
|
|
137
|
+
"Static fidelity: no step is executed. Agent/LLM outputs and data-dependent branches are not resolved.",
|
|
138
|
+
"Approval projection shows the tier that WOULD apply if recipe steps were gated — they are NOT gated on the execution path today (gatedOnRecipeSteps=false).",
|
|
139
|
+
"Cost is a low-confidence estimate; USD is not projected at this phase.",
|
|
140
|
+
];
|
|
141
|
+
if (topology === "flat") {
|
|
142
|
+
notes.push("Flat recipe: risk propagates linearly (step N inherits prior steps' risk); there is no dependency DAG.");
|
|
143
|
+
}
|
|
144
|
+
if (summary.unresolvedSteps > 0) {
|
|
145
|
+
notes.push(`${summary.unresolvedSteps} step(s) reference tools unknown to the registry — their side effects could not be classified.`);
|
|
146
|
+
}
|
|
147
|
+
if (branches.length > 0) {
|
|
148
|
+
notes.push(`${branches.length} conditional branch(es) left undetermined — re-run after a mocked/sandbox phase to resolve them.`);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
schemaVersion: SIMULATION_SCHEMA_VERSION,
|
|
152
|
+
kind: "what-if-preview",
|
|
153
|
+
recipe: plan.recipe,
|
|
154
|
+
triggerType: plan.triggerType,
|
|
155
|
+
generatedAt: plan.generatedAt,
|
|
156
|
+
fidelity: "static",
|
|
157
|
+
topology,
|
|
158
|
+
gatedOnRecipeSteps,
|
|
159
|
+
steps,
|
|
160
|
+
summary,
|
|
161
|
+
risk,
|
|
162
|
+
approvals: {
|
|
163
|
+
gatedOnRecipeSteps,
|
|
164
|
+
projected,
|
|
165
|
+
note: "Recipe-runner steps are NOT gated by the approval queue today; this column is the tier that would apply if they were.",
|
|
166
|
+
},
|
|
167
|
+
cost,
|
|
168
|
+
branches,
|
|
169
|
+
lint: plan.lint,
|
|
170
|
+
notes,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Extract the step ids a `when:` condition references via `{{ ... }}`
|
|
175
|
+
* placeholders. Covers the common dotted forms the chained runner exposes
|
|
176
|
+
* (`steps.<id>.data`, `outputs.<id>`, or a bare `<id>`). A coarse regex is
|
|
177
|
+
* deliberate — we only need to know WHICH step ids the branch depends on so we
|
|
178
|
+
* can decide whether the branch is determinable from history.
|
|
179
|
+
*/
|
|
180
|
+
export function extractReferencedStepIds(condition) {
|
|
181
|
+
const ids = new Set();
|
|
182
|
+
const placeholder = /\{\{\s*([^}]+?)\s*\}\}/g;
|
|
183
|
+
let m = placeholder.exec(condition);
|
|
184
|
+
while (m !== null) {
|
|
185
|
+
const expr = (m[1] ?? "").trim();
|
|
186
|
+
// First identifier-ish token of the expression.
|
|
187
|
+
const head = /^[A-Za-z_$][\w$]*/.exec(expr)?.[0];
|
|
188
|
+
if (head) {
|
|
189
|
+
if ((head === "steps" || head === "outputs") && expr.includes(".")) {
|
|
190
|
+
// steps.<id>.data | outputs.<id>
|
|
191
|
+
const seg = /^(?:steps|outputs)\.([A-Za-z_$][\w$]*)/.exec(expr)?.[1];
|
|
192
|
+
if (seg)
|
|
193
|
+
ids.add(seg);
|
|
194
|
+
}
|
|
195
|
+
else if (head !== "env") {
|
|
196
|
+
// bare step id (env keys are not steps)
|
|
197
|
+
ids.add(head);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
m = placeholder.exec(condition);
|
|
201
|
+
}
|
|
202
|
+
return ids;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* P2 — compose the mocked report: take the static report and OVERLAY the
|
|
206
|
+
* results of the trace-seeded mocked sandbox run.
|
|
207
|
+
*
|
|
208
|
+
* - `fidelity:"mocked"` + `sampleRuns`.
|
|
209
|
+
* - each step's `mockedFrom` ("history" | "synthesized").
|
|
210
|
+
* - `branches[].outcome` recomputed: `"taken"`/`"skipped"` when EVERY step id
|
|
211
|
+
* the `when:` references is in `historyStepIds` (determinable from real
|
|
212
|
+
* data), else `"undetermined"`.
|
|
213
|
+
*
|
|
214
|
+
* Risk / side-effect / cost / approvals sections are carried over unchanged
|
|
215
|
+
* from the static report. `gatedOnRecipeSteps` stays false (P0/P4 truth).
|
|
216
|
+
*/
|
|
217
|
+
export function simulateMockedFromPlan(plan, mocked) {
|
|
218
|
+
const base = simulateFromPlan(plan);
|
|
219
|
+
const steps = base.steps.map((s) => {
|
|
220
|
+
const state = mocked.stepData.get(s.id);
|
|
221
|
+
const mockedFrom = state?.mockedFrom ??
|
|
222
|
+
(mocked.historyStepIds.has(s.id) ? "history" : "synthesized");
|
|
223
|
+
return { ...s, mockedFrom };
|
|
224
|
+
});
|
|
225
|
+
const branches = base.branches.map((b) => {
|
|
226
|
+
const refs = extractReferencedStepIds(b.condition);
|
|
227
|
+
const determinable = refs.size > 0 && [...refs].every((id) => mocked.historyStepIds.has(id));
|
|
228
|
+
if (!determinable) {
|
|
229
|
+
return {
|
|
230
|
+
...b,
|
|
231
|
+
outcome: "undetermined",
|
|
232
|
+
reason: refs.size === 0
|
|
233
|
+
? "Condition references no resolvable step output — left undetermined."
|
|
234
|
+
: "Condition references at least one step with no run history — outcome cannot be resolved from real data.",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const state = mocked.stepData.get(b.stepId);
|
|
238
|
+
const outcome = state?.skipped ? "skipped" : "taken";
|
|
239
|
+
return {
|
|
240
|
+
...b,
|
|
241
|
+
outcome,
|
|
242
|
+
reason: `Resolved from history-backed upstream output(s): ${[...refs].join(", ")}.`,
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
const notes = [
|
|
246
|
+
`Mocked fidelity: downstream templates and conditions were resolved by driving the chained runner with ${mocked.sampleRuns} prior run(s) of history. No step executed for real (stubbed deps, no persistence).`,
|
|
247
|
+
"Steps without run history were fed synthesized placeholders; their downstream effects are approximate.",
|
|
248
|
+
"Approval projection shows the tier that WOULD apply if recipe steps were gated — they are NOT gated on the execution path today (gatedOnRecipeSteps=false).",
|
|
249
|
+
"Cost remains a static estimate at this phase; USD is not projected (P3).",
|
|
250
|
+
];
|
|
251
|
+
if (base.summary.unresolvedSteps > 0) {
|
|
252
|
+
notes.push(`${base.summary.unresolvedSteps} step(s) reference tools unknown to the registry — their side effects could not be classified.`);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
...base,
|
|
256
|
+
schemaVersion: SIMULATION_SCHEMA_VERSION,
|
|
257
|
+
fidelity: "mocked",
|
|
258
|
+
sampleRuns: mocked.sampleRuns,
|
|
259
|
+
steps,
|
|
260
|
+
branches,
|
|
261
|
+
notes,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=simulate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulate.js","sourceRoot":"","sources":["../../../src/recipes/simulation/simulate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What-If Preview (P2) — trace-seeded mocked sandbox.
|
|
3
|
+
*
|
|
4
|
+
* Drives the EXISTING chained runner with a history-backed `mockedOutputs`
|
|
5
|
+
* map + fully-stubbed `ExecutionDeps`, so downstream templates and `when:`
|
|
6
|
+
* branches resolve realistically — while executing NOTHING for real.
|
|
7
|
+
*
|
|
8
|
+
* ★ ZERO real I/O + ZERO persistence is the non-negotiable safety invariant ★
|
|
9
|
+
* - `STUB_DEPS.executeTool` / `executeAgent` return synthesized placeholders
|
|
10
|
+
* and never touch a real tool / connector / LLM / fs.
|
|
11
|
+
* - `loadNestedRecipe` returns null (no nested-recipe execution).
|
|
12
|
+
* - NO `runLog`, NO `runLogDir`, NO `activityLog` are passed to
|
|
13
|
+
* `runChainedRecipe`, so nothing is persisted.
|
|
14
|
+
* - `dryRun:false` (we WANT template/condition resolution), with
|
|
15
|
+
* `mockedOutputs` covering history-backed steps; any uncovered step falls
|
|
16
|
+
* through to the STUB deps — still no real execution.
|
|
17
|
+
*
|
|
18
|
+
* Fail-soft: any error is caught and we return what we have; this never throws
|
|
19
|
+
* out to the caller (the static report is always the safe fallback upstream).
|
|
20
|
+
*/
|
|
21
|
+
import type { RecipeRunLog } from "../../runLog.js";
|
|
22
|
+
import type { ChainedRecipe, ExecutionDeps } from "../chainedRunner.js";
|
|
23
|
+
/**
|
|
24
|
+
* Stub execution deps. Returns deterministic synthesized placeholders and
|
|
25
|
+
* performs no real I/O. Exported so tests can spy on the same shape; callers
|
|
26
|
+
* normally pass the default created in `simulateMockedRun`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createStubDeps(): ExecutionDeps;
|
|
29
|
+
export interface MockedStepState {
|
|
30
|
+
ran: boolean;
|
|
31
|
+
skipped: boolean;
|
|
32
|
+
mockedFrom: "history" | "synthesized";
|
|
33
|
+
}
|
|
34
|
+
export interface MockedRunResult {
|
|
35
|
+
/** Per-step id → ran/skipped + whether its value came from history. */
|
|
36
|
+
stepData: Map<string, MockedStepState>;
|
|
37
|
+
/** Step ids that got a real historical value. */
|
|
38
|
+
historyStepIds: Set<string>;
|
|
39
|
+
/** Number of prior runs sampled. */
|
|
40
|
+
sampleRuns: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Run the mocked sandbox for `recipe`, seeded from `runLog` history.
|
|
44
|
+
*/
|
|
45
|
+
export declare function simulateMockedRun(recipe: ChainedRecipe, runLog: RecipeRunLog, opts?: {
|
|
46
|
+
maxRuns?: number;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Test seam — override the stub deps to spy that uncovered steps hit the
|
|
50
|
+
* stub (and never real execution). Defaults to `createStubDeps()`.
|
|
51
|
+
*/
|
|
52
|
+
deps?: ExecutionDeps): Promise<MockedRunResult>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What-If Preview (P2) — trace-seeded mocked sandbox.
|
|
3
|
+
*
|
|
4
|
+
* Drives the EXISTING chained runner with a history-backed `mockedOutputs`
|
|
5
|
+
* map + fully-stubbed `ExecutionDeps`, so downstream templates and `when:`
|
|
6
|
+
* branches resolve realistically — while executing NOTHING for real.
|
|
7
|
+
*
|
|
8
|
+
* ★ ZERO real I/O + ZERO persistence is the non-negotiable safety invariant ★
|
|
9
|
+
* - `STUB_DEPS.executeTool` / `executeAgent` return synthesized placeholders
|
|
10
|
+
* and never touch a real tool / connector / LLM / fs.
|
|
11
|
+
* - `loadNestedRecipe` returns null (no nested-recipe execution).
|
|
12
|
+
* - NO `runLog`, NO `runLogDir`, NO `activityLog` are passed to
|
|
13
|
+
* `runChainedRecipe`, so nothing is persisted.
|
|
14
|
+
* - `dryRun:false` (we WANT template/condition resolution), with
|
|
15
|
+
* `mockedOutputs` covering history-backed steps; any uncovered step falls
|
|
16
|
+
* through to the STUB deps — still no real execution.
|
|
17
|
+
*
|
|
18
|
+
* Fail-soft: any error is caught and we return what we have; this never throws
|
|
19
|
+
* out to the caller (the static report is always the safe fallback upstream).
|
|
20
|
+
*/
|
|
21
|
+
import { runChainedRecipe } from "../chainedRunner.js";
|
|
22
|
+
import { synthesizeMockedOutputs } from "./synthesizeMockedOutputs.js";
|
|
23
|
+
/**
|
|
24
|
+
* Stub execution deps. Returns deterministic synthesized placeholders and
|
|
25
|
+
* performs no real I/O. Exported so tests can spy on the same shape; callers
|
|
26
|
+
* normally pass the default created in `simulateMockedRun`.
|
|
27
|
+
*/
|
|
28
|
+
export function createStubDeps() {
|
|
29
|
+
return {
|
|
30
|
+
executeTool: async (tool) => `[simulated:${tool}]`,
|
|
31
|
+
executeAgent: async (_prompt) => ({
|
|
32
|
+
text: "[simulated:agent]",
|
|
33
|
+
}),
|
|
34
|
+
loadNestedRecipe: async () => null,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run the mocked sandbox for `recipe`, seeded from `runLog` history.
|
|
39
|
+
*/
|
|
40
|
+
export async function simulateMockedRun(recipe, runLog, opts = {},
|
|
41
|
+
/**
|
|
42
|
+
* Test seam — override the stub deps to spy that uncovered steps hit the
|
|
43
|
+
* stub (and never real execution). Defaults to `createStubDeps()`.
|
|
44
|
+
*/
|
|
45
|
+
deps = createStubDeps()) {
|
|
46
|
+
const { outputs, historyStepIds, sampleRuns } = synthesizeMockedOutputs(recipe.name, runLog, opts);
|
|
47
|
+
const stepData = new Map();
|
|
48
|
+
try {
|
|
49
|
+
const result = await runChainedRecipe(recipe, {
|
|
50
|
+
env: { ...process.env },
|
|
51
|
+
maxConcurrency: Math.max(1, recipe.maxConcurrency ?? 4),
|
|
52
|
+
maxDepth: recipe.maxDepth ?? 3,
|
|
53
|
+
dryRun: false,
|
|
54
|
+
mockedOutputs: outputs,
|
|
55
|
+
// NO runLog / runLogDir / activityLog — nothing is persisted.
|
|
56
|
+
}, deps);
|
|
57
|
+
for (const [id, stepResult] of result.stepResults) {
|
|
58
|
+
const skipped = stepResult.skipped === true;
|
|
59
|
+
stepData.set(id, {
|
|
60
|
+
ran: !skipped,
|
|
61
|
+
skipped,
|
|
62
|
+
mockedFrom: historyStepIds.has(id) ? "history" : "synthesized",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Fail-soft: return whatever we have (possibly empty stepData). The
|
|
68
|
+
// caller falls back to the static report shape.
|
|
69
|
+
}
|
|
70
|
+
return { stepData, historyStepIds, sampleRuns };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=simulateMockedRun.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simulateMockedRun.js","sourceRoot":"","sources":["../../../src/recipes/simulation/simulateMockedRun.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,WAAW,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC,cAAc,IAAI,GAAG;QAC1D,YAAY,EAAE,KAAK,EAAE,OAAe,EAAE,EAAE,CAAC,CAAC;YACxC,IAAI,EAAE,mBAAmB;SAC1B,CAAC;QACF,gBAAgB,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI;KACnC,CAAC;AACJ,CAAC;AAiBD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAqB,EACrB,MAAoB,EACpB,OAA6B,EAAE;AAC/B;;;GAGG;AACH,OAAsB,cAAc,EAAE;IAEtC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,uBAAuB,CACrE,MAAM,CAAC,IAAI,EACX,MAAM,EACN,IAAI,CACL,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,gBAAgB,CACnC,MAAM,EACN;YACE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAwC;YAC7D,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC;YACvD,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;YAC9B,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,OAAO;YACtB,8DAA8D;SAC/D,EACD,IAAI,CACL,CAAC;QAEF,KAAK,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,KAAK,IAAI,CAAC;YAC5C,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE;gBACf,GAAG,EAAE,CAAC,OAAO;gBACb,OAAO;gBACP,UAAU,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa;aAC/D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,gDAAgD;IAClD,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What-If Preview (P2) — synthesize a `mockedOutputs` map from run history.
|
|
3
|
+
*
|
|
4
|
+
* For a chained recipe with prior runs, walk the most recent N runs (newest
|
|
5
|
+
* first) and, for each step id, take the MOST RECENT non-truncated,
|
|
6
|
+
* non-skipped, defined `output`. The result is the `mockedOutputs` map the
|
|
7
|
+
* mocked sandbox feeds into the chained runner so downstream templates and
|
|
8
|
+
* `when:` conditions resolve against real historical values.
|
|
9
|
+
*
|
|
10
|
+
* Pure except for the single `runLog.query(...)` read. The skip rules mirror
|
|
11
|
+
* `buildMockedOutputs` (replayRun.ts): skip `status:"skipped"`, skip
|
|
12
|
+
* `output === undefined`, skip the `{"[truncated]": true}` capture envelope.
|
|
13
|
+
*/
|
|
14
|
+
import type { RecipeRunLog } from "../../runLog.js";
|
|
15
|
+
export interface SynthesizedMockedOutputs {
|
|
16
|
+
/** stepId → most-recent usable historical output. */
|
|
17
|
+
outputs: Map<string, unknown>;
|
|
18
|
+
/** Step ids that received a real historical value. */
|
|
19
|
+
historyStepIds: Set<string>;
|
|
20
|
+
/** Number of prior runs actually sampled. */
|
|
21
|
+
sampleRuns: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build a history-backed `mockedOutputs` map for `recipeName`.
|
|
25
|
+
*
|
|
26
|
+
* `runLog.query` returns newest-first, so the FIRST usable output we see for a
|
|
27
|
+
* given step id is the most recent — we never overwrite it with an older run.
|
|
28
|
+
*/
|
|
29
|
+
export declare function synthesizeMockedOutputs(recipeName: string, runLog: RecipeRunLog, opts?: {
|
|
30
|
+
maxRuns?: number;
|
|
31
|
+
}): SynthesizedMockedOutputs;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What-If Preview (P2) — synthesize a `mockedOutputs` map from run history.
|
|
3
|
+
*
|
|
4
|
+
* For a chained recipe with prior runs, walk the most recent N runs (newest
|
|
5
|
+
* first) and, for each step id, take the MOST RECENT non-truncated,
|
|
6
|
+
* non-skipped, defined `output`. The result is the `mockedOutputs` map the
|
|
7
|
+
* mocked sandbox feeds into the chained runner so downstream templates and
|
|
8
|
+
* `when:` conditions resolve against real historical values.
|
|
9
|
+
*
|
|
10
|
+
* Pure except for the single `runLog.query(...)` read. The skip rules mirror
|
|
11
|
+
* `buildMockedOutputs` (replayRun.ts): skip `status:"skipped"`, skip
|
|
12
|
+
* `output === undefined`, skip the `{"[truncated]": true}` capture envelope.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_MAX_RUNS = 20;
|
|
15
|
+
/** True when `out` is the VD-2 truncation envelope (`{"[truncated]": true}`). */
|
|
16
|
+
function isTruncated(out) {
|
|
17
|
+
return (out !== null &&
|
|
18
|
+
typeof out === "object" &&
|
|
19
|
+
out["[truncated]"] === true);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build a history-backed `mockedOutputs` map for `recipeName`.
|
|
23
|
+
*
|
|
24
|
+
* `runLog.query` returns newest-first, so the FIRST usable output we see for a
|
|
25
|
+
* given step id is the most recent — we never overwrite it with an older run.
|
|
26
|
+
*/
|
|
27
|
+
export function synthesizeMockedOutputs(recipeName, runLog, opts = {}) {
|
|
28
|
+
const maxRuns = opts.maxRuns ?? DEFAULT_MAX_RUNS;
|
|
29
|
+
const runs = runLog.query({ recipe: recipeName, limit: maxRuns });
|
|
30
|
+
const outputs = new Map();
|
|
31
|
+
const historyStepIds = new Set();
|
|
32
|
+
// runs are newest-first; first usable value per id wins (most recent).
|
|
33
|
+
for (const run of runs) {
|
|
34
|
+
for (const step of run.stepResults ?? []) {
|
|
35
|
+
if (historyStepIds.has(step.id))
|
|
36
|
+
continue;
|
|
37
|
+
if (step.status === "skipped")
|
|
38
|
+
continue;
|
|
39
|
+
const out = step.output;
|
|
40
|
+
if (out === undefined)
|
|
41
|
+
continue;
|
|
42
|
+
if (isTruncated(out))
|
|
43
|
+
continue;
|
|
44
|
+
outputs.set(step.id, out);
|
|
45
|
+
historyStepIds.add(step.id);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { outputs, historyStepIds, sampleRuns: runs.length };
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=synthesizeMockedOutputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesizeMockedOutputs.js","sourceRoot":"","sources":["../../../src/recipes/simulation/synthesizeMockedOutputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,iFAAiF;AACjF,SAAS,WAAW,CAAC,GAAY;IAC/B,OAAO,CACL,GAAG,KAAK,IAAI;QACZ,OAAO,GAAG,KAAK,QAAQ;QACtB,GAA+B,CAAC,aAAa,CAAC,KAAK,IAAI,CACzD,CAAC;AACJ,CAAC;AAWD;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAkB,EAClB,MAAoB,EACpB,OAA6B,EAAE;IAE/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IAEzC,uEAAuE;IACvE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;YACzC,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC1C,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,SAAS;YACxC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;YACxB,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YAChC,IAAI,WAAW,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC1B,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAC9D,CAAC"}
|