@promptwheel/core 0.6.0
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/dist/codebase-index/index.d.ts +23 -0
- package/dist/codebase-index/index.d.ts.map +1 -0
- package/dist/codebase-index/index.js +361 -0
- package/dist/codebase-index/index.js.map +1 -0
- package/dist/codebase-index/shared.d.ts +95 -0
- package/dist/codebase-index/shared.d.ts.map +1 -0
- package/dist/codebase-index/shared.js +319 -0
- package/dist/codebase-index/shared.js.map +1 -0
- package/dist/config/defaults.d.ts +45 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +79 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/critic/shared.d.ts +49 -0
- package/dist/critic/shared.d.ts.map +1 -0
- package/dist/critic/shared.js +204 -0
- package/dist/critic/shared.js.map +1 -0
- package/dist/db/adapter.d.ts +191 -0
- package/dist/db/adapter.d.ts.map +1 -0
- package/dist/db/adapter.js +40 -0
- package/dist/db/adapter.js.map +1 -0
- package/dist/db/contract.d.ts +47 -0
- package/dist/db/contract.d.ts.map +1 -0
- package/dist/db/contract.js +258 -0
- package/dist/db/contract.js.map +1 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +7 -0
- package/dist/db/index.js.map +1 -0
- package/dist/dedup/shared.d.ts +82 -0
- package/dist/dedup/shared.d.ts.map +1 -0
- package/dist/dedup/shared.js +215 -0
- package/dist/dedup/shared.js.map +1 -0
- package/dist/exec/index.d.ts +5 -0
- package/dist/exec/index.d.ts.map +1 -0
- package/dist/exec/index.js +5 -0
- package/dist/exec/index.js.map +1 -0
- package/dist/exec/types.d.ts +64 -0
- package/dist/exec/types.d.ts.map +1 -0
- package/dist/exec/types.js +8 -0
- package/dist/exec/types.js.map +1 -0
- package/dist/formulas/shared.d.ts +42 -0
- package/dist/formulas/shared.d.ts.map +1 -0
- package/dist/formulas/shared.js +204 -0
- package/dist/formulas/shared.js.map +1 -0
- package/dist/guidelines/shared.d.ts +46 -0
- package/dist/guidelines/shared.d.ts.map +1 -0
- package/dist/guidelines/shared.js +128 -0
- package/dist/guidelines/shared.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/learnings/shared.d.ts +112 -0
- package/dist/learnings/shared.d.ts.map +1 -0
- package/dist/learnings/shared.js +402 -0
- package/dist/learnings/shared.js.map +1 -0
- package/dist/proposals/shared.d.ts +137 -0
- package/dist/proposals/shared.d.ts.map +1 -0
- package/dist/proposals/shared.js +254 -0
- package/dist/proposals/shared.js.map +1 -0
- package/dist/repos/index.d.ts +15 -0
- package/dist/repos/index.d.ts.map +1 -0
- package/dist/repos/index.js +11 -0
- package/dist/repos/index.js.map +1 -0
- package/dist/repos/projects.d.ts +41 -0
- package/dist/repos/projects.d.ts.map +1 -0
- package/dist/repos/projects.js +75 -0
- package/dist/repos/projects.js.map +1 -0
- package/dist/repos/run_steps.d.ts +152 -0
- package/dist/repos/run_steps.d.ts.map +1 -0
- package/dist/repos/run_steps.js +328 -0
- package/dist/repos/run_steps.js.map +1 -0
- package/dist/repos/runs.d.ts +92 -0
- package/dist/repos/runs.d.ts.map +1 -0
- package/dist/repos/runs.js +185 -0
- package/dist/repos/runs.js.map +1 -0
- package/dist/repos/tickets.d.ts +71 -0
- package/dist/repos/tickets.d.ts.map +1 -0
- package/dist/repos/tickets.js +158 -0
- package/dist/repos/tickets.js.map +1 -0
- package/dist/scope/shared.d.ts +67 -0
- package/dist/scope/shared.d.ts.map +1 -0
- package/dist/scope/shared.js +355 -0
- package/dist/scope/shared.js.map +1 -0
- package/dist/scout/index.d.ts +18 -0
- package/dist/scout/index.d.ts.map +1 -0
- package/dist/scout/index.js +445 -0
- package/dist/scout/index.js.map +1 -0
- package/dist/scout/kimi-runner.d.ts +21 -0
- package/dist/scout/kimi-runner.d.ts.map +1 -0
- package/dist/scout/kimi-runner.js +76 -0
- package/dist/scout/kimi-runner.js.map +1 -0
- package/dist/scout/mcp-batch-server.d.ts +37 -0
- package/dist/scout/mcp-batch-server.d.ts.map +1 -0
- package/dist/scout/mcp-batch-server.js +144 -0
- package/dist/scout/mcp-batch-server.js.map +1 -0
- package/dist/scout/openai-local-runner.d.ts +20 -0
- package/dist/scout/openai-local-runner.d.ts.map +1 -0
- package/dist/scout/openai-local-runner.js +82 -0
- package/dist/scout/openai-local-runner.js.map +1 -0
- package/dist/scout/prompt.d.ts +49 -0
- package/dist/scout/prompt.d.ts.map +1 -0
- package/dist/scout/prompt.js +153 -0
- package/dist/scout/prompt.js.map +1 -0
- package/dist/scout/runner.d.ts +101 -0
- package/dist/scout/runner.d.ts.map +1 -0
- package/dist/scout/runner.js +521 -0
- package/dist/scout/runner.js.map +1 -0
- package/dist/scout/scanner.d.ts +61 -0
- package/dist/scout/scanner.d.ts.map +1 -0
- package/dist/scout/scanner.js +315 -0
- package/dist/scout/scanner.js.map +1 -0
- package/dist/scout/types.d.ts +221 -0
- package/dist/scout/types.d.ts.map +1 -0
- package/dist/scout/types.js +44 -0
- package/dist/scout/types.js.map +1 -0
- package/dist/sectors/shared.d.ts +146 -0
- package/dist/sectors/shared.d.ts.map +1 -0
- package/dist/sectors/shared.js +408 -0
- package/dist/sectors/shared.js.map +1 -0
- package/dist/services/index.d.ts +10 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +9 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/qa.d.ts +76 -0
- package/dist/services/qa.d.ts.map +1 -0
- package/dist/services/qa.js +228 -0
- package/dist/services/qa.js.map +1 -0
- package/dist/services/scout.d.ts +164 -0
- package/dist/services/scout.d.ts.map +1 -0
- package/dist/services/scout.js +215 -0
- package/dist/services/scout.js.map +1 -0
- package/dist/spindle/shared.d.ts +14 -0
- package/dist/spindle/shared.d.ts.map +1 -0
- package/dist/spindle/shared.js +65 -0
- package/dist/spindle/shared.js.map +1 -0
- package/dist/tools/shared.d.ts +35 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +247 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/trace/shared.d.ts +147 -0
- package/dist/trace/shared.d.ts.map +1 -0
- package/dist/trace/shared.js +414 -0
- package/dist/trace/shared.js.map +1 -0
- package/dist/trajectory/shared.d.ts +69 -0
- package/dist/trajectory/shared.d.ts.map +1 -0
- package/dist/trajectory/shared.js +336 -0
- package/dist/trajectory/shared.js.map +1 -0
- package/dist/utils/id.d.ts +12 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +24 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/id.test.d.ts +5 -0
- package/dist/utils/id.test.d.ts.map +1 -0
- package/dist/utils/id.test.js +173 -0
- package/dist/utils/id.test.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json.d.ts +9 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +19 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/waves/shared.d.ts +106 -0
- package/dist/waves/shared.d.ts.map +1 -0
- package/dist/waves/shared.js +356 -0
- package/dist/waves/shared.js.map +1 -0
- package/package.json +126 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Batch Server for persistent Codex sessions
|
|
3
|
+
*
|
|
4
|
+
* A lightweight stdio MCP server that exposes batch analysis tools.
|
|
5
|
+
* Codex connects to this server and loops: get_next_batch → analyze → submit_results.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node dist/scout/mcp-batch-server.js --data <path-to-json>
|
|
9
|
+
*
|
|
10
|
+
* The JSON file contains an array of batch prompt strings.
|
|
11
|
+
*/
|
|
12
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
13
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
15
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
/**
|
|
18
|
+
* MCP server that serves batches to a Codex session.
|
|
19
|
+
*
|
|
20
|
+
* Tools exposed:
|
|
21
|
+
* - get_next_batch: Returns { batchId, prompt } or { done: true }
|
|
22
|
+
* - submit_results: Accepts { batchId, output }
|
|
23
|
+
* - signal_done: Confirms all batches processed
|
|
24
|
+
*/
|
|
25
|
+
export class McpBatchServer {
|
|
26
|
+
batches;
|
|
27
|
+
cursor = 0;
|
|
28
|
+
results = new Map();
|
|
29
|
+
doneResolve;
|
|
30
|
+
server;
|
|
31
|
+
constructor(opts) {
|
|
32
|
+
this.batches = opts.batchPrompts.map((p, i) => ({ id: i, prompt: p }));
|
|
33
|
+
this.server = new Server({ name: 'promptwheel-batch-server', version: '1.0.0' }, { capabilities: { tools: {} } });
|
|
34
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
35
|
+
tools: [
|
|
36
|
+
{
|
|
37
|
+
name: 'get_next_batch',
|
|
38
|
+
description: 'Get the next batch of code to analyze. Returns { batchId, prompt } or { done: true } when all batches are consumed.',
|
|
39
|
+
inputSchema: { type: 'object', properties: {} },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'submit_results',
|
|
43
|
+
description: 'Submit analysis results for a batch. Pass the raw JSON output from your analysis.',
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
batchId: { type: 'number', description: 'The batchId from get_next_batch' },
|
|
48
|
+
output: { type: 'string', description: 'The analysis output (JSON string with proposals)' },
|
|
49
|
+
},
|
|
50
|
+
required: ['batchId', 'output'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'signal_done',
|
|
55
|
+
description: 'Signal that all batches have been processed. Call this after the last submit_results.',
|
|
56
|
+
inputSchema: { type: 'object', properties: {} },
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
}));
|
|
60
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
61
|
+
const { name, arguments: args } = request.params;
|
|
62
|
+
switch (name) {
|
|
63
|
+
case 'get_next_batch': {
|
|
64
|
+
if (this.cursor >= this.batches.length) {
|
|
65
|
+
return { content: [{ type: 'text', text: JSON.stringify({ done: true }) }] };
|
|
66
|
+
}
|
|
67
|
+
const batch = this.batches[this.cursor++];
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: 'text', text: JSON.stringify({ batchId: batch.id, prompt: batch.prompt }) }],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
case 'submit_results': {
|
|
73
|
+
const batchId = args?.batchId;
|
|
74
|
+
const output = args?.output;
|
|
75
|
+
if (batchId === undefined || output === undefined) {
|
|
76
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'batchId and output are required' }) }], isError: true };
|
|
77
|
+
}
|
|
78
|
+
this.results.set(batchId, output);
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: 'text', text: JSON.stringify({ ok: true, received: this.results.size, total: this.batches.length }) }],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
case 'signal_done': {
|
|
84
|
+
this.doneResolve?.();
|
|
85
|
+
return { content: [{ type: 'text', text: JSON.stringify({ ok: true }) }] };
|
|
86
|
+
}
|
|
87
|
+
default:
|
|
88
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: `Unknown tool: ${name}` }) }], isError: true };
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Start the MCP server on stdio.
|
|
94
|
+
* Returns a promise that resolves with collected results when signal_done is called.
|
|
95
|
+
*/
|
|
96
|
+
async start() {
|
|
97
|
+
const donePromise = new Promise((resolve) => {
|
|
98
|
+
this.doneResolve = resolve;
|
|
99
|
+
});
|
|
100
|
+
const transport = new StdioServerTransport();
|
|
101
|
+
await this.server.connect(transport);
|
|
102
|
+
await donePromise;
|
|
103
|
+
await this.server.close();
|
|
104
|
+
return this.results;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* CLI entrypoint: node mcp-batch-server.js --data <path>
|
|
109
|
+
*
|
|
110
|
+
* The data file is a JSON array of prompt strings.
|
|
111
|
+
*/
|
|
112
|
+
async function main() {
|
|
113
|
+
const dataIdx = process.argv.indexOf('--data');
|
|
114
|
+
if (dataIdx === -1 || !process.argv[dataIdx + 1]) {
|
|
115
|
+
process.stderr.write('Usage: mcp-batch-server --data <path-to-prompts.json>\n');
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
const dataPath = process.argv[dataIdx + 1];
|
|
119
|
+
const prompts = JSON.parse(readFileSync(dataPath, 'utf-8'));
|
|
120
|
+
const server = new McpBatchServer({ batchPrompts: prompts });
|
|
121
|
+
const results = await server.start();
|
|
122
|
+
// Write results to disk so the parent process can read them.
|
|
123
|
+
// Derive the output directory from --results-dir arg or fall back to the
|
|
124
|
+
// same directory as the --data file.
|
|
125
|
+
const resultsDirIdx = process.argv.indexOf('--results-dir');
|
|
126
|
+
const resultsDir = (resultsDirIdx !== -1 && process.argv[resultsDirIdx + 1])
|
|
127
|
+
? process.argv[resultsDirIdx + 1]
|
|
128
|
+
: dirname(dataPath);
|
|
129
|
+
const resultsObj = {};
|
|
130
|
+
for (const [k, v] of results) {
|
|
131
|
+
resultsObj[String(k)] = v;
|
|
132
|
+
}
|
|
133
|
+
writeFileSync(join(resultsDir, 'results.json'), JSON.stringify(resultsObj));
|
|
134
|
+
}
|
|
135
|
+
// Run as CLI if executed directly
|
|
136
|
+
const isMainModule = process.argv[1]?.endsWith('mcp-batch-server.js') ||
|
|
137
|
+
process.argv[1]?.endsWith('mcp-batch-server.ts');
|
|
138
|
+
if (isMainModule) {
|
|
139
|
+
main().catch((err) => {
|
|
140
|
+
process.stderr.write(`MCP batch server error: ${err}\n`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=mcp-batch-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-batch-server.js","sourceRoot":"","sources":["../../src/scout/mcp-batch-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-compatible local scout backend
|
|
3
|
+
*
|
|
4
|
+
* Uses raw fetch against any OpenAI-compatible API (Ollama, vLLM, SGLang, LM Studio).
|
|
5
|
+
* Zero new dependencies — uses Node's built-in fetch.
|
|
6
|
+
*/
|
|
7
|
+
import type { ScoutBackend, RunnerOptions, RunnerResult } from './runner.js';
|
|
8
|
+
export declare class OpenAILocalScoutBackend implements ScoutBackend {
|
|
9
|
+
readonly name = "openai-local";
|
|
10
|
+
private baseUrl;
|
|
11
|
+
private model;
|
|
12
|
+
private apiKey?;
|
|
13
|
+
constructor(opts: {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
model: string;
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
});
|
|
18
|
+
run(options: RunnerOptions): Promise<RunnerResult>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=openai-local-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-local-runner.d.ts","sourceRoot":"","sources":["../../src/scout/openai-local-runner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7E,qBAAa,uBAAwB,YAAW,YAAY;IAC1D,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAM/D,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAwEzD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-compatible local scout backend
|
|
3
|
+
*
|
|
4
|
+
* Uses raw fetch against any OpenAI-compatible API (Ollama, vLLM, SGLang, LM Studio).
|
|
5
|
+
* Zero new dependencies — uses Node's built-in fetch.
|
|
6
|
+
*/
|
|
7
|
+
export class OpenAILocalScoutBackend {
|
|
8
|
+
name = 'openai-local';
|
|
9
|
+
baseUrl;
|
|
10
|
+
model;
|
|
11
|
+
apiKey;
|
|
12
|
+
constructor(opts) {
|
|
13
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
|
|
14
|
+
this.model = opts.model;
|
|
15
|
+
this.apiKey = opts.apiKey;
|
|
16
|
+
}
|
|
17
|
+
async run(options) {
|
|
18
|
+
const { prompt, timeoutMs, signal } = options;
|
|
19
|
+
const start = Date.now();
|
|
20
|
+
if (signal?.aborted) {
|
|
21
|
+
return { success: false, output: '', error: 'Aborted before start', durationMs: 0 };
|
|
22
|
+
}
|
|
23
|
+
// Combine external signal with timeout
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
26
|
+
const abortHandler = () => controller.abort();
|
|
27
|
+
signal?.addEventListener('abort', abortHandler);
|
|
28
|
+
try {
|
|
29
|
+
const headers = {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
};
|
|
32
|
+
if (this.apiKey) {
|
|
33
|
+
headers['Authorization'] = `Bearer ${this.apiKey}`;
|
|
34
|
+
}
|
|
35
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers,
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
model: this.model,
|
|
40
|
+
messages: [{ role: 'user', content: prompt }],
|
|
41
|
+
temperature: 0,
|
|
42
|
+
}),
|
|
43
|
+
signal: controller.signal,
|
|
44
|
+
});
|
|
45
|
+
const durationMs = Date.now() - start;
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const body = await response.text().catch(() => '');
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
output: '',
|
|
51
|
+
error: `HTTP ${response.status}: ${body.slice(0, 500)}`,
|
|
52
|
+
durationMs,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const data = (await response.json());
|
|
56
|
+
const content = data.choices?.[0]?.message?.content ?? '';
|
|
57
|
+
return {
|
|
58
|
+
success: true,
|
|
59
|
+
output: content,
|
|
60
|
+
durationMs,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
const durationMs = Date.now() - start;
|
|
65
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
66
|
+
const isAbort = message.includes('abort') || message.includes('AbortError');
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
output: '',
|
|
70
|
+
error: isAbort
|
|
71
|
+
? (signal?.aborted ? 'Aborted by signal' : 'Timeout exceeded')
|
|
72
|
+
: message,
|
|
73
|
+
durationMs,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
clearTimeout(timeout);
|
|
78
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=openai-local-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-local-runner.js","sourceRoot":"","sources":["../../src/scout/openai-local-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scout prompt template
|
|
3
|
+
*
|
|
4
|
+
* This prompt is sent to Claude to analyze code and generate improvement proposals.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProposalCategory } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Build the scout prompt for analyzing a batch of files
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildScoutPrompt(options: {
|
|
11
|
+
files: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}>;
|
|
15
|
+
scope: string;
|
|
16
|
+
types?: ProposalCategory[];
|
|
17
|
+
excludeTypes?: ProposalCategory[];
|
|
18
|
+
maxProposals: number;
|
|
19
|
+
minConfidence: number;
|
|
20
|
+
recentlyCompletedTitles?: string[];
|
|
21
|
+
customPrompt?: string;
|
|
22
|
+
/** Files the scout can read but must NOT propose changes to */
|
|
23
|
+
protectedFiles?: string[];
|
|
24
|
+
/** Coverage context injected to give the scout awareness of scan progress */
|
|
25
|
+
coverageContext?: {
|
|
26
|
+
sectorPath: string;
|
|
27
|
+
scannedSectors: number;
|
|
28
|
+
totalSectors: number;
|
|
29
|
+
percent: number;
|
|
30
|
+
sectorPercent: number;
|
|
31
|
+
classificationConfidence: string;
|
|
32
|
+
scanCount: number;
|
|
33
|
+
proposalYield: number;
|
|
34
|
+
sectorSummary?: string;
|
|
35
|
+
sectorDifficulty?: 'easy' | 'moderate' | 'hard';
|
|
36
|
+
sectorCategoryAffinity?: {
|
|
37
|
+
boost: string[];
|
|
38
|
+
suppress: string[];
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}): string;
|
|
42
|
+
/**
|
|
43
|
+
* Build a focused prompt for a single category
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildCategoryPrompt(category: ProposalCategory, files: Array<{
|
|
46
|
+
path: string;
|
|
47
|
+
content: string;
|
|
48
|
+
}>, maxProposals?: number): string;
|
|
49
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/scout/prompt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,eAAe,CAAC,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;QAChD,sBAAsB,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;KAClE,CAAC;CACH,GAAG,MAAM,CAqJT;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,YAAY,GAAE,MAAU,GACvB,MAAM,CAQR"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scout prompt template
|
|
3
|
+
*
|
|
4
|
+
* This prompt is sent to Claude to analyze code and generate improvement proposals.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Build the scout prompt for analyzing a batch of files
|
|
8
|
+
*/
|
|
9
|
+
export function buildScoutPrompt(options) {
|
|
10
|
+
const { files, scope, types, excludeTypes, maxProposals, minConfidence, recentlyCompletedTitles, customPrompt, protectedFiles, coverageContext, } = options;
|
|
11
|
+
const protectedNote = protectedFiles?.length
|
|
12
|
+
? `\n\n**DO NOT propose changes to these files** (read-only context): ${protectedFiles.join(', ')}\n`
|
|
13
|
+
: '';
|
|
14
|
+
const categoryFilter = types?.length
|
|
15
|
+
? `Focus ONLY on these categories: ${types.join(', ')}`
|
|
16
|
+
: excludeTypes?.length
|
|
17
|
+
? `EXCLUDE these categories: ${excludeTypes.join(', ')}`
|
|
18
|
+
: 'Consider all categories';
|
|
19
|
+
const coverageBlock = coverageContext
|
|
20
|
+
? (() => {
|
|
21
|
+
const { sectorPath, scannedSectors, totalSectors, percent, sectorPercent, classificationConfidence, scanCount, proposalYield, sectorSummary } = coverageContext;
|
|
22
|
+
const lines = [
|
|
23
|
+
`\n## Coverage Context\n`,
|
|
24
|
+
`You are scanning sector "${sectorPath}" (scan #${scanCount + 1}).`,
|
|
25
|
+
`Classification confidence: ${classificationConfidence}.${classificationConfidence === 'low' ? ' This sector has not been reliably classified — pay attention to whether files are production code, tests, config, or generated.' : ''}`,
|
|
26
|
+
`Overall codebase coverage: ${scannedSectors}/${totalSectors} sectors scanned (${sectorPercent}% of sectors, ${percent}% of files).`,
|
|
27
|
+
`This sector's historical proposal density: ${proposalYield.toFixed(1)} proposals/scan.`,
|
|
28
|
+
'',
|
|
29
|
+
];
|
|
30
|
+
if (coverageContext.sectorDifficulty === 'hard') {
|
|
31
|
+
lines.push('');
|
|
32
|
+
lines.push('**WARNING:** This sector has a HIGH failure rate. Propose only HIGH-confidence changes. Prefer simple fixes over complex refactors.');
|
|
33
|
+
}
|
|
34
|
+
if (coverageContext.sectorCategoryAffinity) {
|
|
35
|
+
const { boost, suppress } = coverageContext.sectorCategoryAffinity;
|
|
36
|
+
if (boost.length > 0) {
|
|
37
|
+
lines.push(`Categories that work well in this sector: ${boost.join(', ')}.`);
|
|
38
|
+
}
|
|
39
|
+
if (suppress.length > 0) {
|
|
40
|
+
lines.push(`Categories ${suppress.join(', ')} have low success in this sector — only propose if HIGH confidence.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (percent < 50) {
|
|
44
|
+
lines.push('Many sectors remain unscanned. Focus on high-impact issues rather than minor cleanups.');
|
|
45
|
+
}
|
|
46
|
+
if (sectorSummary) {
|
|
47
|
+
lines.push('');
|
|
48
|
+
lines.push(sectorSummary);
|
|
49
|
+
}
|
|
50
|
+
return lines.join('\n') + '\n';
|
|
51
|
+
})()
|
|
52
|
+
: '';
|
|
53
|
+
const strategicFocus = customPrompt
|
|
54
|
+
? `\n## Strategic Focus\n\n${customPrompt}\n`
|
|
55
|
+
: '';
|
|
56
|
+
const recentContext = recentlyCompletedTitles?.length
|
|
57
|
+
? `\n\nAVOID proposing work similar to these recently completed tickets:\n${recentlyCompletedTitles.map(t => `- ${t}`).join('\n')}`
|
|
58
|
+
: '';
|
|
59
|
+
const fileContents = files
|
|
60
|
+
.map(f => `### ${f.path}\n\`\`\`\n${f.content}\n\`\`\``)
|
|
61
|
+
.join('\n\n');
|
|
62
|
+
return `You are a principal engineer reviewing code. Your job is to find improvements that meaningfully move the codebase forward — not cosmetic changes.
|
|
63
|
+
|
|
64
|
+
Analyze these files from scope "${scope}" and identify the highest-impact improvements.
|
|
65
|
+
|
|
66
|
+
${categoryFilter}
|
|
67
|
+
${coverageBlock}
|
|
68
|
+
## Categories (ordered by typical impact)
|
|
69
|
+
|
|
70
|
+
- **security**: Vulnerabilities, SSRF/XSS/injection risks, auth gaps, input validation
|
|
71
|
+
- **fix**: Bugs, incorrect logic, broken edge cases, data loss risks
|
|
72
|
+
- **perf**: Performance issues, N+1 queries, unnecessary allocations, missing indexes
|
|
73
|
+
- **refactor**: Structural issues spanning multiple files, missing abstractions, DRY violations across modules
|
|
74
|
+
- **test**: Missing tests for critical paths, untested error handling, integration gaps
|
|
75
|
+
- **types**: Type safety holes that could cause runtime errors
|
|
76
|
+
- **cleanup**: Dead code removal, unused imports (ONLY if substantial)
|
|
77
|
+
- **docs**: ONLY if documentation is actively misleading or missing for public APIs
|
|
78
|
+
|
|
79
|
+
## Quality Bar
|
|
80
|
+
|
|
81
|
+
Proposals must clear a high bar. Do NOT propose:
|
|
82
|
+
- Comment rewording or typo fixes
|
|
83
|
+
- Import reordering or style-only changes
|
|
84
|
+
- Adding docs to internal code
|
|
85
|
+
- Single-line fixes that don't affect behavior
|
|
86
|
+
- Changes that only affect developer experience marginally
|
|
87
|
+
|
|
88
|
+
Each proposal should make the codebase meaningfully safer, faster, or more correct. Prefer fewer high-impact proposals over many small ones.
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Requirements
|
|
92
|
+
|
|
93
|
+
1. Each proposal MUST be:
|
|
94
|
+
- Specific and actionable (not vague)
|
|
95
|
+
- Self-contained (completable in one PR)
|
|
96
|
+
- Have at least one verification command
|
|
97
|
+
- Have confidence >= ${minConfidence}
|
|
98
|
+
- Have impact_score >= 4 (1-10 scale — most proposals should be 5+)
|
|
99
|
+
|
|
100
|
+
2. Verification commands should be:
|
|
101
|
+
- Runnable without manual setup
|
|
102
|
+
- NOT include grep/wc/file-specific test commands
|
|
103
|
+
- Use the project's actual test/build commands (e.g. npm test, pytest, cargo test, go test ./..., mvn test, mix test)
|
|
104
|
+
- Match the project's language and tooling — do NOT use npm commands for non-Node projects
|
|
105
|
+
|
|
106
|
+
3. Generate at most ${maxProposals} proposals, prioritized by impact. Fewer is better if the remaining proposals would be low-impact.
|
|
107
|
+
|
|
108
|
+
${protectedNote}${strategicFocus}${recentContext}
|
|
109
|
+
|
|
110
|
+
## Files to Analyze
|
|
111
|
+
|
|
112
|
+
${fileContents}
|
|
113
|
+
|
|
114
|
+
## Output Format
|
|
115
|
+
|
|
116
|
+
Respond with ONLY a JSON object (no markdown, no explanation):
|
|
117
|
+
|
|
118
|
+
{
|
|
119
|
+
"proposals": [
|
|
120
|
+
{
|
|
121
|
+
"category": "refactor|fix|cleanup|types|perf|security|docs|test",
|
|
122
|
+
"title": "Short actionable title (imperative mood)",
|
|
123
|
+
"description": "What needs to be done and why",
|
|
124
|
+
"acceptance_criteria": ["Criterion 1", "Criterion 2"],
|
|
125
|
+
"verification_commands": ["<project test command>"],
|
|
126
|
+
"allowed_paths": ["path/to/file.ts"],
|
|
127
|
+
"files": ["path/to/file.ts"],
|
|
128
|
+
"confidence": 75,
|
|
129
|
+
"impact_score": 5,
|
|
130
|
+
"rationale": "Why this improvement matters",
|
|
131
|
+
"estimated_complexity": "trivial|simple|moderate|complex"
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
If no improvements are needed, return: {"proposals": []}${coverageContext ? `
|
|
137
|
+
|
|
138
|
+
If this sector appears misclassified (e.g., labeled as production but contains only tests/config/generated code, or vice versa), add to the JSON:
|
|
139
|
+
"sector_reclassification": { "production": true/false, "confidence": "medium"|"high" }` : ''}`;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Build a focused prompt for a single category
|
|
143
|
+
*/
|
|
144
|
+
export function buildCategoryPrompt(category, files, maxProposals = 5) {
|
|
145
|
+
return buildScoutPrompt({
|
|
146
|
+
files,
|
|
147
|
+
scope: '*',
|
|
148
|
+
types: [category],
|
|
149
|
+
maxProposals,
|
|
150
|
+
minConfidence: 50,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/scout/prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scout runner - Executes LLM CLI backends for analysis
|
|
3
|
+
*/
|
|
4
|
+
export interface RunnerOptions {
|
|
5
|
+
/** Prompt to send to the LLM */
|
|
6
|
+
prompt: string;
|
|
7
|
+
/** Working directory */
|
|
8
|
+
cwd: string;
|
|
9
|
+
/** Timeout in ms (0 = no timeout) */
|
|
10
|
+
timeoutMs: number;
|
|
11
|
+
/** Model to use */
|
|
12
|
+
model?: string;
|
|
13
|
+
/** Cancellation signal */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Callback for raw stdout/stderr streaming */
|
|
16
|
+
onRawOutput?: (chunk: string) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface RunnerResult {
|
|
19
|
+
/** Whether execution succeeded */
|
|
20
|
+
success: boolean;
|
|
21
|
+
/** Output from the LLM */
|
|
22
|
+
output: string;
|
|
23
|
+
/** Error message if failed */
|
|
24
|
+
error?: string;
|
|
25
|
+
/** Duration in ms */
|
|
26
|
+
durationMs: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Pluggable scout backend interface
|
|
30
|
+
*/
|
|
31
|
+
export interface ScoutBackend {
|
|
32
|
+
/** Human-readable name for logging */
|
|
33
|
+
readonly name: string;
|
|
34
|
+
/** Run a scout prompt and return the result */
|
|
35
|
+
run(options: RunnerOptions): Promise<RunnerResult>;
|
|
36
|
+
/** Optional: process all batches in a single session (e.g., persistent MCP) */
|
|
37
|
+
runAll?(options: RunnerOptions[]): Promise<RunnerResult[]>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Run Claude Code CLI with a prompt
|
|
41
|
+
*/
|
|
42
|
+
export declare function runClaude(options: RunnerOptions): Promise<RunnerResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Claude Code CLI scout backend (default)
|
|
45
|
+
*/
|
|
46
|
+
export declare class ClaudeScoutBackend implements ScoutBackend {
|
|
47
|
+
readonly name = "claude";
|
|
48
|
+
run(options: RunnerOptions): Promise<RunnerResult>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Codex CLI scout backend
|
|
52
|
+
*
|
|
53
|
+
* Spawns `codex exec` in read-only sandbox mode for analysis.
|
|
54
|
+
* Uses --output-last-message for reliable output extraction.
|
|
55
|
+
*/
|
|
56
|
+
export declare class CodexScoutBackend implements ScoutBackend {
|
|
57
|
+
readonly name = "codex";
|
|
58
|
+
private apiKey?;
|
|
59
|
+
private defaultModel;
|
|
60
|
+
constructor(opts?: {
|
|
61
|
+
apiKey?: string;
|
|
62
|
+
model?: string;
|
|
63
|
+
});
|
|
64
|
+
run(options: RunnerOptions): Promise<RunnerResult>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Codex MCP scout backend — persistent single session
|
|
68
|
+
*
|
|
69
|
+
* Instead of spawning N cold `codex exec` processes, spawns ONE session
|
|
70
|
+
* that connects to our MCP batch server. Codex calls tools in a loop
|
|
71
|
+
* to pull batches and submit results. One warm session, zero cold starts.
|
|
72
|
+
*
|
|
73
|
+
* Opt-in via --codex-mcp flag.
|
|
74
|
+
*/
|
|
75
|
+
export declare class CodexMcpScoutBackend implements ScoutBackend {
|
|
76
|
+
readonly name = "codex";
|
|
77
|
+
private apiKey?;
|
|
78
|
+
private defaultModel;
|
|
79
|
+
constructor(opts?: {
|
|
80
|
+
apiKey?: string;
|
|
81
|
+
model?: string;
|
|
82
|
+
});
|
|
83
|
+
/** Single-batch fallback (not normally used — runAll is preferred) */
|
|
84
|
+
run(options: RunnerOptions): Promise<RunnerResult>;
|
|
85
|
+
/**
|
|
86
|
+
* Process all batches in a single persistent Codex session via MCP.
|
|
87
|
+
*
|
|
88
|
+
* 1. Writes batch prompts to a temp JSON file
|
|
89
|
+
* 2. Spawns `codex exec` with MCP config pointing to our batch server
|
|
90
|
+
* 3. Codex loops over get_next_batch → analyze → submit_results
|
|
91
|
+
* 4. Collects results when signal_done fires
|
|
92
|
+
*/
|
|
93
|
+
runAll(allOptions: RunnerOptions[]): Promise<RunnerResult[]>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Parse JSON from Claude's output
|
|
97
|
+
*
|
|
98
|
+
* Handles common issues like markdown code blocks
|
|
99
|
+
*/
|
|
100
|
+
export declare function parseClaudeOutput<T>(output: string): T | null;
|
|
101
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/scout/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACnD,+EAA+E;IAC/E,MAAM,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CAC5D;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA4G7E;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,YAAY;IACrD,QAAQ,CAAC,IAAI,YAAY;IAEzB,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAGnD;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACpD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;gBAEjB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAKhD,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAsIzD;AAED;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;gBAEjB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAKtD,sEAAsE;IAChE,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAMxD;;;;;;;OAOG;IACG,MAAM,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAmMnE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CA8C7D"}
|