@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,137 @@
1
+ /**
2
+ * Proposals shared algorithms — pure functions for proposal validation,
3
+ * review, scoring, balancing, and formatting.
4
+ *
5
+ * No filesystem, database, or LLM I/O. MCP and CLI import these and
6
+ * wrap with their own I/O and UX layers.
7
+ */
8
+ /** Raw proposal as received from LLM output (all fields optional). */
9
+ export interface RawProposal {
10
+ category?: string;
11
+ title?: string;
12
+ description?: string;
13
+ acceptance_criteria?: string[];
14
+ verification_commands?: string[];
15
+ allowed_paths?: string[];
16
+ files?: string[];
17
+ confidence?: number;
18
+ impact_score?: number;
19
+ rationale?: string;
20
+ estimated_complexity?: string;
21
+ risk?: string;
22
+ touched_files_estimate?: number;
23
+ rollback_note?: string;
24
+ }
25
+ /** Proposal with all required fields validated and defaults applied. */
26
+ export interface ValidatedProposal {
27
+ category: string;
28
+ title: string;
29
+ description: string;
30
+ acceptance_criteria: string[];
31
+ verification_commands: string[];
32
+ allowed_paths: string[];
33
+ files: string[];
34
+ confidence: number;
35
+ impact_score: number;
36
+ rationale: string;
37
+ estimated_complexity: string;
38
+ risk: string;
39
+ touched_files_estimate: number;
40
+ rollback_note: string;
41
+ }
42
+ /** Result of adversarial review — revised scores for a single proposal. */
43
+ export interface ReviewedProposal {
44
+ title: string;
45
+ confidence: number;
46
+ impact_score: number;
47
+ review_note?: string;
48
+ }
49
+ export declare const PROPOSALS_DEFAULTS: {
50
+ /** Maximum deferred proposals to keep across cycles */
51
+ readonly MAX_DEFERRED: 20;
52
+ /** Maximum ratio of test-only proposals in a batch */
53
+ readonly MAX_TEST_RATIO: 0.4;
54
+ /** Default impact score when not provided */
55
+ readonly DEFAULT_IMPACT: 5;
56
+ /** Minimum confidence to pass (0 = fundamentally flawed) */
57
+ readonly MIN_CONFIDENCE: 1;
58
+ /** Default minimum impact score filter */
59
+ readonly DEFAULT_MIN_IMPACT: 3;
60
+ /** Dedup similarity threshold */
61
+ readonly DEDUP_THRESHOLD: 0.6;
62
+ };
63
+ /** Fields required for a proposal to pass schema validation. */
64
+ export declare const REQUIRED_FIELDS: (keyof ValidatedProposal)[];
65
+ /**
66
+ * Validate that a raw proposal has all required fields.
67
+ * Returns a comma-separated string of missing fields, or null if valid.
68
+ */
69
+ export declare function validateProposalSchema(raw: RawProposal): string | null;
70
+ /**
71
+ * Normalize a raw proposal into a validated proposal with defaults applied.
72
+ * Caller must ensure schema validation passed first.
73
+ */
74
+ export declare function normalizeProposal(raw: RawProposal): ValidatedProposal;
75
+ /** Minimal proposal shape accepted by the review prompt builder. */
76
+ export interface ReviewableProposal {
77
+ title: string;
78
+ category: string;
79
+ confidence: number;
80
+ impact_score?: number;
81
+ files: string[];
82
+ description: string;
83
+ verification_commands?: string[];
84
+ risk?: string;
85
+ }
86
+ /**
87
+ * Build a prompt for adversarial (second-pass) review of proposals.
88
+ *
89
+ * The prompt asks the LLM to critically evaluate each proposal and revise
90
+ * confidence/impact scores. Setting confidence=0 means "fundamentally flawed".
91
+ *
92
+ * Works with both TicketProposal (CLI) and ValidatedProposal (MCP).
93
+ */
94
+ export declare function buildProposalReviewPrompt(proposals: ReviewableProposal[]): string;
95
+ /**
96
+ * Parse the <reviewed-proposals> XML block from an LLM response.
97
+ * Returns null if parsing fails.
98
+ */
99
+ export declare function parseReviewedProposals(response: string): ReviewedProposal[] | null;
100
+ /**
101
+ * Apply reviewed scores to the original proposals.
102
+ * Matches by title (case-insensitive). Unmatched proposals keep original scores.
103
+ * Returns a new array (does not mutate originals).
104
+ */
105
+ export declare function applyReviewToProposals<T extends {
106
+ title: string;
107
+ confidence: number;
108
+ impact_score?: number;
109
+ }>(proposals: T[], reviewed: ReviewedProposal[]): T[];
110
+ /**
111
+ * Score proposals by impact × confidence and return the top N.
112
+ * Does not mutate the input array.
113
+ */
114
+ export declare function scoreAndRank<T extends {
115
+ confidence: number;
116
+ impact_score?: number;
117
+ }>(proposals: T[], maxCount?: number): T[];
118
+ /**
119
+ * Balance test vs non-test proposals by capping the ratio of test-only proposals.
120
+ *
121
+ * If test proposals exceed maxTestRatio, keeps only the highest-impact tests
122
+ * (minimum 1). Does not mutate the input.
123
+ */
124
+ export declare function balanceProposals<T extends {
125
+ category: string;
126
+ impact_score?: number | null;
127
+ }>(proposals: T[], maxTestRatio?: number): T[];
128
+ /**
129
+ * Format a validated proposal into a structured ticket description.
130
+ */
131
+ export declare function formatProposalDescription(p: ValidatedProposal): string;
132
+ /**
133
+ * Compute ticket priority from impact score and confidence.
134
+ * Priority = round(impact × confidence / 10)
135
+ */
136
+ export declare function computePriority(impactScore: number, confidence: number): number;
137
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/proposals/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Proposals shared algorithms — pure functions for proposal validation,
3
+ * review, scoring, balancing, and formatting.
4
+ *
5
+ * No filesystem, database, or LLM I/O. MCP and CLI import these and
6
+ * wrap with their own I/O and UX layers.
7
+ */
8
+ // ---------------------------------------------------------------------------
9
+ // Constants
10
+ // ---------------------------------------------------------------------------
11
+ export const PROPOSALS_DEFAULTS = {
12
+ /** Maximum deferred proposals to keep across cycles */
13
+ MAX_DEFERRED: 20,
14
+ /** Maximum ratio of test-only proposals in a batch */
15
+ MAX_TEST_RATIO: 0.4,
16
+ /** Default impact score when not provided */
17
+ DEFAULT_IMPACT: 5,
18
+ /** Minimum confidence to pass (0 = fundamentally flawed) */
19
+ MIN_CONFIDENCE: 1,
20
+ /** Default minimum impact score filter */
21
+ DEFAULT_MIN_IMPACT: 3,
22
+ /** Dedup similarity threshold */
23
+ DEDUP_THRESHOLD: 0.6,
24
+ };
25
+ /** Fields required for a proposal to pass schema validation. */
26
+ export const REQUIRED_FIELDS = [
27
+ 'category', 'title', 'description', 'allowed_paths',
28
+ 'files', 'confidence', 'verification_commands',
29
+ 'risk', 'touched_files_estimate', 'rollback_note',
30
+ ];
31
+ // ---------------------------------------------------------------------------
32
+ // Schema validation
33
+ // ---------------------------------------------------------------------------
34
+ /**
35
+ * Validate that a raw proposal has all required fields.
36
+ * Returns a comma-separated string of missing fields, or null if valid.
37
+ */
38
+ export function validateProposalSchema(raw) {
39
+ const missing = [];
40
+ // Hard-required: no sensible default possible
41
+ if (!raw.category || typeof raw.category !== 'string')
42
+ missing.push('category');
43
+ if (!raw.title || typeof raw.title !== 'string')
44
+ missing.push('title');
45
+ if (!raw.description || typeof raw.description !== 'string')
46
+ missing.push('description');
47
+ if (!Array.isArray(raw.allowed_paths))
48
+ missing.push('allowed_paths');
49
+ if (typeof raw.confidence !== 'number')
50
+ missing.push('confidence');
51
+ if (!raw.risk || typeof raw.risk !== 'string')
52
+ missing.push('risk');
53
+ // Soft-required: normalizeProposal provides safe defaults for these.
54
+ // We still validate type when present, but missing is not fatal.
55
+ if (raw.files !== null && raw.files !== undefined && !Array.isArray(raw.files))
56
+ missing.push('files');
57
+ if (raw.verification_commands !== null && raw.verification_commands !== undefined && !Array.isArray(raw.verification_commands))
58
+ missing.push('verification_commands');
59
+ if (raw.touched_files_estimate !== null && raw.touched_files_estimate !== undefined && typeof raw.touched_files_estimate !== 'number')
60
+ missing.push('touched_files_estimate');
61
+ if (raw.rollback_note !== null && raw.rollback_note !== undefined && typeof raw.rollback_note !== 'string')
62
+ missing.push('rollback_note');
63
+ return missing.length > 0 ? missing.join(', ') : null;
64
+ }
65
+ /**
66
+ * Normalize a raw proposal into a validated proposal with defaults applied.
67
+ * Caller must ensure schema validation passed first.
68
+ */
69
+ export function normalizeProposal(raw) {
70
+ return {
71
+ category: raw.category,
72
+ title: raw.title,
73
+ description: raw.description,
74
+ acceptance_criteria: raw.acceptance_criteria ?? [],
75
+ verification_commands: raw.verification_commands ?? [],
76
+ allowed_paths: raw.allowed_paths ?? [],
77
+ files: raw.files ?? [],
78
+ confidence: raw.confidence,
79
+ impact_score: raw.impact_score ?? PROPOSALS_DEFAULTS.DEFAULT_IMPACT,
80
+ rationale: raw.rationale ?? '',
81
+ estimated_complexity: raw.estimated_complexity ?? 'moderate',
82
+ risk: raw.risk,
83
+ touched_files_estimate: raw.touched_files_estimate ?? (raw.allowed_paths?.length ?? 1),
84
+ rollback_note: raw.rollback_note ?? 'git revert',
85
+ };
86
+ }
87
+ /**
88
+ * Build a prompt for adversarial (second-pass) review of proposals.
89
+ *
90
+ * The prompt asks the LLM to critically evaluate each proposal and revise
91
+ * confidence/impact scores. Setting confidence=0 means "fundamentally flawed".
92
+ *
93
+ * Works with both TicketProposal (CLI) and ValidatedProposal (MCP).
94
+ */
95
+ export function buildProposalReviewPrompt(proposals) {
96
+ const parts = [
97
+ '# Adversarial Proposal Review',
98
+ '',
99
+ 'You previously generated the proposals below. Now review them critically as a skeptical senior engineer.',
100
+ 'For each proposal, evaluate:',
101
+ '',
102
+ '1. **Is the confidence inflated?** Would you bet your reputation on this score?',
103
+ '2. **Will the verification commands actually validate the change?** Or are they too generic (e.g. just `npm test`)?',
104
+ '3. **Missing edge cases?** What could break that you didn\'t consider?',
105
+ '4. **Feasibility:** Can this actually be implemented within the file set listed, or does it require changes elsewhere?',
106
+ '',
107
+ '## Proposals to Review',
108
+ '',
109
+ ];
110
+ for (let i = 0; i < proposals.length; i++) {
111
+ const p = proposals[i];
112
+ parts.push(`### ${i + 1}. ${p.title}`, `- **Category:** ${p.category}`, `- **Confidence:** ${p.confidence}`, `- **Impact:** ${p.impact_score ?? PROPOSALS_DEFAULTS.DEFAULT_IMPACT}/10`, `- **Files:** ${p.files.join(', ') || '(none listed)'}`, `- **Risk:** ${p.risk ?? '(not specified)'}`, `- **Verification:** ${(p.verification_commands ?? []).join(', ') || '(none)'}`, `- **Description:** ${p.description}`, '');
113
+ }
114
+ parts.push('## Output', '', 'For each proposal, revise the `confidence` (0-100) and `impact_score` (1-10).', 'If a proposal is fundamentally flawed, set its confidence to 0.', 'Optionally add a `review_note` (string) explaining your reasoning.', '', 'Call `promptwheel_ingest_event` with type `PROPOSALS_REVIEWED` and payload:', '`{ "reviewed_proposals": [{ "title": "...", "confidence": N, "impact_score": N, "review_note": "..." }, ...] }`', '', 'Example payload:', '```json', '{', ' "reviewed_proposals": [', ' { "title": "Add missing null check", "confidence": 75, "impact_score": 6, "review_note": "Solid but verify edge case X" },', ' { "title": "Refactor auth module", "confidence": 0, "impact_score": 2, "review_note": "Requires changes outside allowed_paths" }', ' ]', '}', '```');
115
+ return parts.join('\n');
116
+ }
117
+ // ---------------------------------------------------------------------------
118
+ // Parse reviewed proposals
119
+ // ---------------------------------------------------------------------------
120
+ /**
121
+ * Parse the <reviewed-proposals> XML block from an LLM response.
122
+ * Returns null if parsing fails.
123
+ */
124
+ export function parseReviewedProposals(response) {
125
+ const match = response.match(/<reviewed-proposals>\s*([\s\S]*?)\s*<\/reviewed-proposals>/);
126
+ if (!match)
127
+ return null;
128
+ let jsonStr = match[1].trim();
129
+ // Strip markdown code fences if present
130
+ jsonStr = jsonStr.replace(/^```(?:json)?\s*/, '').replace(/\s*```$/, '');
131
+ try {
132
+ const parsed = JSON.parse(jsonStr);
133
+ if (!Array.isArray(parsed))
134
+ return null;
135
+ const results = [];
136
+ for (const item of parsed) {
137
+ if (typeof item.title !== 'string')
138
+ continue;
139
+ results.push({
140
+ title: item.title,
141
+ confidence: typeof item.confidence === 'number' ? item.confidence : 50,
142
+ impact_score: typeof item.impact_score === 'number' ? item.impact_score : PROPOSALS_DEFAULTS.DEFAULT_IMPACT,
143
+ review_note: typeof item.review_note === 'string' ? item.review_note : undefined,
144
+ });
145
+ }
146
+ return results.length > 0 ? results : null;
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ // ---------------------------------------------------------------------------
153
+ // Apply review results
154
+ // ---------------------------------------------------------------------------
155
+ /**
156
+ * Apply reviewed scores to the original proposals.
157
+ * Matches by title (case-insensitive). Unmatched proposals keep original scores.
158
+ * Returns a new array (does not mutate originals).
159
+ */
160
+ export function applyReviewToProposals(proposals, reviewed) {
161
+ const reviewMap = new Map();
162
+ for (const r of reviewed) {
163
+ reviewMap.set(r.title.toLowerCase(), r);
164
+ }
165
+ return proposals.map(p => {
166
+ const review = reviewMap.get(p.title.toLowerCase());
167
+ if (!review)
168
+ return p;
169
+ return {
170
+ ...p,
171
+ confidence: review.confidence,
172
+ impact_score: review.impact_score,
173
+ };
174
+ });
175
+ }
176
+ // ---------------------------------------------------------------------------
177
+ // Scoring and ranking
178
+ // ---------------------------------------------------------------------------
179
+ /**
180
+ * Score proposals by impact × confidence and return the top N.
181
+ * Does not mutate the input array.
182
+ */
183
+ export function scoreAndRank(proposals, maxCount) {
184
+ const scored = [...proposals]
185
+ .map(p => ({
186
+ proposal: p,
187
+ score: (p.impact_score ?? PROPOSALS_DEFAULTS.DEFAULT_IMPACT) * p.confidence,
188
+ }))
189
+ .sort((a, b) => b.score - a.score);
190
+ const capped = maxCount !== undefined ? scored.slice(0, maxCount) : scored;
191
+ return capped.map(s => s.proposal);
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // Test balance
195
+ // ---------------------------------------------------------------------------
196
+ /**
197
+ * Balance test vs non-test proposals by capping the ratio of test-only proposals.
198
+ *
199
+ * If test proposals exceed maxTestRatio, keeps only the highest-impact tests
200
+ * (minimum 1). Does not mutate the input.
201
+ */
202
+ export function balanceProposals(proposals, maxTestRatio = PROPOSALS_DEFAULTS.MAX_TEST_RATIO) {
203
+ const tests = proposals.filter(p => (p.category || '').toLowerCase() === 'test');
204
+ const nonTests = proposals.filter(p => (p.category || '').toLowerCase() !== 'test');
205
+ const total = proposals.length;
206
+ const maxTests = Math.floor(total * maxTestRatio);
207
+ if (tests.length <= maxTests)
208
+ return [...proposals];
209
+ // Sort tests by impact descending, keep only the top N
210
+ const sortedTests = [...tests].sort((a, b) => (b.impact_score ?? PROPOSALS_DEFAULTS.DEFAULT_IMPACT) - (a.impact_score ?? PROPOSALS_DEFAULTS.DEFAULT_IMPACT));
211
+ // Hard-cap tests — even if ALL proposals are tests, keep at most maxTests (min 1)
212
+ const allowedTests = Math.max(maxTests, 1);
213
+ const keptTests = sortedTests.slice(0, allowedTests);
214
+ return [...nonTests, ...keptTests];
215
+ }
216
+ // ---------------------------------------------------------------------------
217
+ // Description formatting
218
+ // ---------------------------------------------------------------------------
219
+ /**
220
+ * Format a validated proposal into a structured ticket description.
221
+ */
222
+ export function formatProposalDescription(p) {
223
+ const parts = [
224
+ p.description,
225
+ '',
226
+ '## Acceptance Criteria',
227
+ ...p.acceptance_criteria.map(c => `- ${c}`),
228
+ '',
229
+ '## Details',
230
+ `**Risk:** ${p.risk}`,
231
+ `**Complexity:** ${p.estimated_complexity}`,
232
+ `**Confidence:** ${p.confidence}%`,
233
+ `**Impact:** ${p.impact_score}/10`,
234
+ `**Estimated files:** ${p.touched_files_estimate}`,
235
+ '',
236
+ '## Rollback',
237
+ p.rollback_note,
238
+ ];
239
+ if (p.rationale) {
240
+ parts.push('', '## Rationale', p.rationale);
241
+ }
242
+ if (p.files.length > 0) {
243
+ parts.push('', '## Files', ...p.files.map(f => `- \`${f}\``));
244
+ }
245
+ return parts.join('\n');
246
+ }
247
+ /**
248
+ * Compute ticket priority from impact score and confidence.
249
+ * Priority = round(impact × confidence / 10)
250
+ */
251
+ export function computePriority(impactScore, confidence) {
252
+ return Math.round(impactScore * confidence / 10);
253
+ }
254
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/proposals/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Repository exports
3
+ *
4
+ * Repositories provide database operations using the DatabaseAdapter interface.
5
+ * They handle row mapping and business logic validation.
6
+ */
7
+ export * as projects from './projects.js';
8
+ export * as tickets from './tickets.js';
9
+ export * as runs from './runs.js';
10
+ export * as runSteps from './run_steps.js';
11
+ export type { Project } from './projects.js';
12
+ export type { Ticket, TicketStatus, TicketCategory } from './tickets.js';
13
+ export type { Run, RunStatus, RunType, RunSummary } from './runs.js';
14
+ export type { RunStep, StepStatus, StepKind, StepCounts, StepSummary, } from './run_steps.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/repos/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,YAAY,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACrE,YAAY,EACV,OAAO,EACP,UAAU,EACV,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Repository exports
3
+ *
4
+ * Repositories provide database operations using the DatabaseAdapter interface.
5
+ * They handle row mapping and business logic validation.
6
+ */
7
+ export * as projects from './projects.js';
8
+ export * as tickets from './tickets.js';
9
+ export * as runs from './runs.js';
10
+ export * as runSteps from './run_steps.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repos/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Project repository - Database operations for projects
3
+ */
4
+ import type { DatabaseAdapter } from '../db/adapter.js';
5
+ export interface Project {
6
+ id: string;
7
+ name: string;
8
+ repoUrl: string | null;
9
+ rootPath: string;
10
+ createdAt: Date;
11
+ updatedAt: Date;
12
+ }
13
+ /**
14
+ * Get project by ID
15
+ */
16
+ export declare function getById(db: DatabaseAdapter, id: string): Promise<Project | null>;
17
+ /**
18
+ * Get project by repository root path
19
+ */
20
+ export declare function getByRepoRoot(db: DatabaseAdapter, rootPath: string): Promise<Project | null>;
21
+ /**
22
+ * Ensure a project exists for a repository
23
+ * Returns existing project or creates new one
24
+ *
25
+ * This is idempotent - calling twice with same rootPath returns same project
26
+ */
27
+ export declare function ensureForRepo(db: DatabaseAdapter, opts: {
28
+ name: string;
29
+ rootPath: string;
30
+ id?: string;
31
+ repoUrl?: string | null;
32
+ }): Promise<Project>;
33
+ /**
34
+ * List all projects
35
+ */
36
+ export declare function list(db: DatabaseAdapter): Promise<Project[]>;
37
+ /**
38
+ * Delete a project and all related data
39
+ */
40
+ export declare function remove(db: DatabaseAdapter, id: string): Promise<void>;
41
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/repos/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAsBD;;GAEG;AACH,wBAAsB,OAAO,CAC3B,EAAE,EAAE,eAAe,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAMzB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,eAAe,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAMzB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,eAAe,EACnB,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GACA,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAKlE;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3E"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Project repository - Database operations for projects
3
+ */
4
+ import { nanoid } from '../utils/id.js';
5
+ function rowToProject(row) {
6
+ return {
7
+ id: row.id,
8
+ name: row.name,
9
+ repoUrl: row.repo_url,
10
+ rootPath: row.root_path,
11
+ createdAt: new Date(row.created_at),
12
+ updatedAt: new Date(row.updated_at),
13
+ };
14
+ }
15
+ /**
16
+ * Get project by ID
17
+ */
18
+ export async function getById(db, id) {
19
+ const result = await db.query('SELECT * FROM projects WHERE id = $1', [id]);
20
+ return result.rows[0] ? rowToProject(result.rows[0]) : null;
21
+ }
22
+ /**
23
+ * Get project by repository root path
24
+ */
25
+ export async function getByRepoRoot(db, rootPath) {
26
+ const result = await db.query('SELECT * FROM projects WHERE root_path = $1', [rootPath]);
27
+ return result.rows[0] ? rowToProject(result.rows[0]) : null;
28
+ }
29
+ /**
30
+ * Ensure a project exists for a repository
31
+ * Returns existing project or creates new one
32
+ *
33
+ * This is idempotent - calling twice with same rootPath returns same project
34
+ */
35
+ export async function ensureForRepo(db, opts) {
36
+ // Check if already exists by rootPath
37
+ const existing = await getByRepoRoot(db, opts.rootPath);
38
+ if (existing) {
39
+ return existing;
40
+ }
41
+ // Create new project (use ON CONFLICT to handle race conditions / worktree paths)
42
+ const id = opts.id ?? `proj_${nanoid(6)}`;
43
+ await db.query(`INSERT INTO projects (id, name, repo_url, root_path)
44
+ VALUES ($1, $2, $3, $4)
45
+ ON CONFLICT (id) DO NOTHING`, [id, opts.name, opts.repoUrl ?? null, opts.rootPath]);
46
+ const created = await getById(db, id);
47
+ if (!created) {
48
+ throw new Error('Failed to create project');
49
+ }
50
+ return created;
51
+ }
52
+ /**
53
+ * List all projects
54
+ */
55
+ export async function list(db) {
56
+ const result = await db.query('SELECT * FROM projects ORDER BY updated_at DESC');
57
+ return result.rows.map(rowToProject);
58
+ }
59
+ /**
60
+ * Delete a project and all related data
61
+ */
62
+ export async function remove(db, id) {
63
+ await db.withTransaction(async (tx) => {
64
+ // Delete in order respecting foreign keys
65
+ // Use project_id directly on runs to catch scout runs with NULL ticket_id
66
+ await tx.query('DELETE FROM run_events WHERE run_id IN (SELECT id FROM runs WHERE project_id = $1)', [id]);
67
+ await tx.query('DELETE FROM artifacts WHERE run_id IN (SELECT id FROM runs WHERE project_id = $1)', [id]);
68
+ await tx.query('DELETE FROM leases WHERE ticket_id IN (SELECT id FROM tickets WHERE project_id = $1)', [id]);
69
+ await tx.query('DELETE FROM runs WHERE project_id = $1', [id]);
70
+ await tx.query('DELETE FROM learnings WHERE project_id = $1', [id]);
71
+ await tx.query('DELETE FROM tickets WHERE project_id = $1', [id]);
72
+ await tx.query('DELETE FROM projects WHERE id = $1', [id]);
73
+ });
74
+ }
75
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/repos/projects.ts"],"names":[],"mappings":"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"}