@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.
Files changed (169) hide show
  1. package/dist/codebase-index/index.d.ts +23 -0
  2. package/dist/codebase-index/index.d.ts.map +1 -0
  3. package/dist/codebase-index/index.js +361 -0
  4. package/dist/codebase-index/index.js.map +1 -0
  5. package/dist/codebase-index/shared.d.ts +95 -0
  6. package/dist/codebase-index/shared.d.ts.map +1 -0
  7. package/dist/codebase-index/shared.js +319 -0
  8. package/dist/codebase-index/shared.js.map +1 -0
  9. package/dist/config/defaults.d.ts +45 -0
  10. package/dist/config/defaults.d.ts.map +1 -0
  11. package/dist/config/defaults.js +79 -0
  12. package/dist/config/defaults.js.map +1 -0
  13. package/dist/critic/shared.d.ts +49 -0
  14. package/dist/critic/shared.d.ts.map +1 -0
  15. package/dist/critic/shared.js +204 -0
  16. package/dist/critic/shared.js.map +1 -0
  17. package/dist/db/adapter.d.ts +191 -0
  18. package/dist/db/adapter.d.ts.map +1 -0
  19. package/dist/db/adapter.js +40 -0
  20. package/dist/db/adapter.js.map +1 -0
  21. package/dist/db/contract.d.ts +47 -0
  22. package/dist/db/contract.d.ts.map +1 -0
  23. package/dist/db/contract.js +258 -0
  24. package/dist/db/contract.js.map +1 -0
  25. package/dist/db/index.d.ts +6 -0
  26. package/dist/db/index.d.ts.map +1 -0
  27. package/dist/db/index.js +7 -0
  28. package/dist/db/index.js.map +1 -0
  29. package/dist/dedup/shared.d.ts +82 -0
  30. package/dist/dedup/shared.d.ts.map +1 -0
  31. package/dist/dedup/shared.js +215 -0
  32. package/dist/dedup/shared.js.map +1 -0
  33. package/dist/exec/index.d.ts +5 -0
  34. package/dist/exec/index.d.ts.map +1 -0
  35. package/dist/exec/index.js +5 -0
  36. package/dist/exec/index.js.map +1 -0
  37. package/dist/exec/types.d.ts +64 -0
  38. package/dist/exec/types.d.ts.map +1 -0
  39. package/dist/exec/types.js +8 -0
  40. package/dist/exec/types.js.map +1 -0
  41. package/dist/formulas/shared.d.ts +42 -0
  42. package/dist/formulas/shared.d.ts.map +1 -0
  43. package/dist/formulas/shared.js +204 -0
  44. package/dist/formulas/shared.js.map +1 -0
  45. package/dist/guidelines/shared.d.ts +46 -0
  46. package/dist/guidelines/shared.d.ts.map +1 -0
  47. package/dist/guidelines/shared.js +128 -0
  48. package/dist/guidelines/shared.js.map +1 -0
  49. package/dist/index.d.ts +35 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +51 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/learnings/shared.d.ts +112 -0
  54. package/dist/learnings/shared.d.ts.map +1 -0
  55. package/dist/learnings/shared.js +402 -0
  56. package/dist/learnings/shared.js.map +1 -0
  57. package/dist/proposals/shared.d.ts +137 -0
  58. package/dist/proposals/shared.d.ts.map +1 -0
  59. package/dist/proposals/shared.js +254 -0
  60. package/dist/proposals/shared.js.map +1 -0
  61. package/dist/repos/index.d.ts +15 -0
  62. package/dist/repos/index.d.ts.map +1 -0
  63. package/dist/repos/index.js +11 -0
  64. package/dist/repos/index.js.map +1 -0
  65. package/dist/repos/projects.d.ts +41 -0
  66. package/dist/repos/projects.d.ts.map +1 -0
  67. package/dist/repos/projects.js +75 -0
  68. package/dist/repos/projects.js.map +1 -0
  69. package/dist/repos/run_steps.d.ts +152 -0
  70. package/dist/repos/run_steps.d.ts.map +1 -0
  71. package/dist/repos/run_steps.js +328 -0
  72. package/dist/repos/run_steps.js.map +1 -0
  73. package/dist/repos/runs.d.ts +92 -0
  74. package/dist/repos/runs.d.ts.map +1 -0
  75. package/dist/repos/runs.js +185 -0
  76. package/dist/repos/runs.js.map +1 -0
  77. package/dist/repos/tickets.d.ts +71 -0
  78. package/dist/repos/tickets.d.ts.map +1 -0
  79. package/dist/repos/tickets.js +158 -0
  80. package/dist/repos/tickets.js.map +1 -0
  81. package/dist/scope/shared.d.ts +67 -0
  82. package/dist/scope/shared.d.ts.map +1 -0
  83. package/dist/scope/shared.js +355 -0
  84. package/dist/scope/shared.js.map +1 -0
  85. package/dist/scout/index.d.ts +18 -0
  86. package/dist/scout/index.d.ts.map +1 -0
  87. package/dist/scout/index.js +445 -0
  88. package/dist/scout/index.js.map +1 -0
  89. package/dist/scout/kimi-runner.d.ts +21 -0
  90. package/dist/scout/kimi-runner.d.ts.map +1 -0
  91. package/dist/scout/kimi-runner.js +76 -0
  92. package/dist/scout/kimi-runner.js.map +1 -0
  93. package/dist/scout/mcp-batch-server.d.ts +37 -0
  94. package/dist/scout/mcp-batch-server.d.ts.map +1 -0
  95. package/dist/scout/mcp-batch-server.js +144 -0
  96. package/dist/scout/mcp-batch-server.js.map +1 -0
  97. package/dist/scout/openai-local-runner.d.ts +20 -0
  98. package/dist/scout/openai-local-runner.d.ts.map +1 -0
  99. package/dist/scout/openai-local-runner.js +82 -0
  100. package/dist/scout/openai-local-runner.js.map +1 -0
  101. package/dist/scout/prompt.d.ts +49 -0
  102. package/dist/scout/prompt.d.ts.map +1 -0
  103. package/dist/scout/prompt.js +153 -0
  104. package/dist/scout/prompt.js.map +1 -0
  105. package/dist/scout/runner.d.ts +101 -0
  106. package/dist/scout/runner.d.ts.map +1 -0
  107. package/dist/scout/runner.js +521 -0
  108. package/dist/scout/runner.js.map +1 -0
  109. package/dist/scout/scanner.d.ts +61 -0
  110. package/dist/scout/scanner.d.ts.map +1 -0
  111. package/dist/scout/scanner.js +315 -0
  112. package/dist/scout/scanner.js.map +1 -0
  113. package/dist/scout/types.d.ts +221 -0
  114. package/dist/scout/types.d.ts.map +1 -0
  115. package/dist/scout/types.js +44 -0
  116. package/dist/scout/types.js.map +1 -0
  117. package/dist/sectors/shared.d.ts +146 -0
  118. package/dist/sectors/shared.d.ts.map +1 -0
  119. package/dist/sectors/shared.js +408 -0
  120. package/dist/sectors/shared.js.map +1 -0
  121. package/dist/services/index.d.ts +10 -0
  122. package/dist/services/index.d.ts.map +1 -0
  123. package/dist/services/index.js +9 -0
  124. package/dist/services/index.js.map +1 -0
  125. package/dist/services/qa.d.ts +76 -0
  126. package/dist/services/qa.d.ts.map +1 -0
  127. package/dist/services/qa.js +228 -0
  128. package/dist/services/qa.js.map +1 -0
  129. package/dist/services/scout.d.ts +164 -0
  130. package/dist/services/scout.d.ts.map +1 -0
  131. package/dist/services/scout.js +215 -0
  132. package/dist/services/scout.js.map +1 -0
  133. package/dist/spindle/shared.d.ts +14 -0
  134. package/dist/spindle/shared.d.ts.map +1 -0
  135. package/dist/spindle/shared.js +65 -0
  136. package/dist/spindle/shared.js.map +1 -0
  137. package/dist/tools/shared.d.ts +35 -0
  138. package/dist/tools/shared.d.ts.map +1 -0
  139. package/dist/tools/shared.js +247 -0
  140. package/dist/tools/shared.js.map +1 -0
  141. package/dist/trace/shared.d.ts +147 -0
  142. package/dist/trace/shared.d.ts.map +1 -0
  143. package/dist/trace/shared.js +414 -0
  144. package/dist/trace/shared.js.map +1 -0
  145. package/dist/trajectory/shared.d.ts +69 -0
  146. package/dist/trajectory/shared.d.ts.map +1 -0
  147. package/dist/trajectory/shared.js +336 -0
  148. package/dist/trajectory/shared.js.map +1 -0
  149. package/dist/utils/id.d.ts +12 -0
  150. package/dist/utils/id.d.ts.map +1 -0
  151. package/dist/utils/id.js +24 -0
  152. package/dist/utils/id.js.map +1 -0
  153. package/dist/utils/id.test.d.ts +5 -0
  154. package/dist/utils/id.test.d.ts.map +1 -0
  155. package/dist/utils/id.test.js +173 -0
  156. package/dist/utils/id.test.js.map +1 -0
  157. package/dist/utils/index.d.ts +6 -0
  158. package/dist/utils/index.d.ts.map +1 -0
  159. package/dist/utils/index.js +6 -0
  160. package/dist/utils/index.js.map +1 -0
  161. package/dist/utils/json.d.ts +9 -0
  162. package/dist/utils/json.d.ts.map +1 -0
  163. package/dist/utils/json.js +19 -0
  164. package/dist/utils/json.js.map +1 -0
  165. package/dist/waves/shared.d.ts +106 -0
  166. package/dist/waves/shared.d.ts.map +1 -0
  167. package/dist/waves/shared.js +356 -0
  168. package/dist/waves/shared.js.map +1 -0
  169. 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"}