preflight-dev 3.1.0 → 3.2.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/README.md +77 -16
- package/dist/cli/init.js +0 -48
- package/dist/cli/init.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/contracts.d.ts +27 -0
- package/dist/lib/contracts.js +309 -0
- package/dist/lib/contracts.js.map +1 -0
- package/dist/lib/patterns.d.ts +38 -0
- package/dist/lib/patterns.js +176 -0
- package/dist/lib/patterns.js.map +1 -0
- package/dist/lib/triage.d.ts +2 -0
- package/dist/lib/triage.js.map +1 -1
- package/dist/profiles.js +4 -0
- package/dist/profiles.js.map +1 -1
- package/dist/tools/check-patterns.d.ts +2 -0
- package/dist/tools/check-patterns.js +33 -0
- package/dist/tools/check-patterns.js.map +1 -0
- package/dist/tools/clarify-intent.js +9 -1
- package/dist/tools/clarify-intent.js.map +1 -1
- package/dist/tools/enrich-agent-task.js +132 -3
- package/dist/tools/enrich-agent-task.js.map +1 -1
- package/dist/tools/estimate-cost.d.ts +2 -0
- package/dist/tools/estimate-cost.js +261 -0
- package/dist/tools/estimate-cost.js.map +1 -0
- package/dist/tools/generate-scorecard.js +466 -14
- package/dist/tools/generate-scorecard.js.map +1 -1
- package/dist/tools/log-correction.js +7 -1
- package/dist/tools/log-correction.js.map +1 -1
- package/dist/tools/onboard-project.js +10 -1
- package/dist/tools/onboard-project.js.map +1 -1
- package/dist/tools/preflight-check.js +16 -0
- package/dist/tools/preflight-check.js.map +1 -1
- package/dist/tools/scope-work.js +6 -0
- package/dist/tools/scope-work.js.map +1 -1
- package/dist/tools/search-contracts.d.ts +2 -0
- package/dist/tools/search-contracts.js +46 -0
- package/dist/tools/search-contracts.js.map +1 -0
- package/dist/tools/session-stats.js +2 -0
- package/dist/tools/session-stats.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +7 -0
- package/src/lib/contracts.ts +354 -0
- package/src/lib/patterns.ts +210 -0
- package/src/lib/triage.ts +2 -0
- package/src/profiles.ts +4 -0
- package/src/tools/check-patterns.ts +43 -0
- package/src/tools/clarify-intent.ts +10 -1
- package/src/tools/enrich-agent-task.ts +150 -3
- package/src/tools/estimate-cost.ts +332 -0
- package/src/tools/generate-scorecard.ts +541 -14
- package/src/tools/log-correction.ts +8 -1
- package/src/tools/onboard-project.ts +10 -1
- package/src/tools/preflight-check.ts +19 -0
- package/src/tools/scope-work.ts +7 -0
- package/src/tools/search-contracts.ts +61 -0
- package/src/tools/session-stats.ts +2 -0
|
@@ -11,6 +11,7 @@ import { findWorkspaceDocs } from "../lib/files.js";
|
|
|
11
11
|
import { getConfig } from "../lib/config.js";
|
|
12
12
|
import { searchSemantic } from "../lib/timeline-db.js";
|
|
13
13
|
import { basename, join } from "path";
|
|
14
|
+
import { loadPatterns, matchPatterns, formatPatternMatches } from "../lib/patterns.js";
|
|
14
15
|
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
16
17
|
// Helpers
|
|
@@ -201,6 +202,16 @@ export function registerPreflightCheck(server: McpServer): void {
|
|
|
201
202
|
if (force_level === "light") effectiveLevel = "ambiguous";
|
|
202
203
|
if (force_level === "full") effectiveLevel = "multi-step";
|
|
203
204
|
|
|
205
|
+
// --- Pattern matching ---
|
|
206
|
+
const patterns = loadPatterns();
|
|
207
|
+
const patternMatches = matchPatterns(prompt, patterns);
|
|
208
|
+
|
|
209
|
+
// Boost triage level if patterns match
|
|
210
|
+
if (patternMatches.length > 0 && effectiveLevel === "trivial") {
|
|
211
|
+
effectiveLevel = "ambiguous";
|
|
212
|
+
triage.reasons.push(`matches ${patternMatches.length} known correction pattern(s)`);
|
|
213
|
+
}
|
|
214
|
+
|
|
204
215
|
// --- Trivial ---
|
|
205
216
|
if (effectiveLevel === "trivial") {
|
|
206
217
|
return { content: [{ type: "text" as const, text: "✅ Preflight: clear to proceed." }] };
|
|
@@ -212,6 +223,14 @@ export function registerPreflightCheck(server: McpServer): void {
|
|
|
212
223
|
`_Reasons: ${triage.reasons.join("; ")}_`,
|
|
213
224
|
];
|
|
214
225
|
|
|
226
|
+
// --- Pattern warnings ---
|
|
227
|
+
if (patternMatches.length > 0) {
|
|
228
|
+
sections.push("");
|
|
229
|
+
for (const p of patternMatches) {
|
|
230
|
+
sections.push(`⚡ Known pitfall: "${p.pattern}" (you've corrected this ${p.frequency}x before)`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
215
234
|
// --- Clear: verify files ---
|
|
216
235
|
if (effectiveLevel === "clear") {
|
|
217
236
|
const filePaths = extractFilePaths(prompt);
|
package/src/tools/scope-work.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { getRelatedProjects } from "../lib/config.js";
|
|
|
8
8
|
import { now } from "../lib/state.js";
|
|
9
9
|
import { existsSync } from "fs";
|
|
10
10
|
import { join, normalize, resolve, basename } from "path";
|
|
11
|
+
import { loadAllContracts, searchContracts, formatContracts } from "../lib/contracts.js";
|
|
11
12
|
|
|
12
13
|
const STOP_WORDS = new Set([
|
|
13
14
|
"the", "and", "for", "with", "from", "that", "this", "should", "would", "could",
|
|
@@ -163,6 +164,11 @@ export function registerScopeWork(server: McpServer): void {
|
|
|
163
164
|
? docEntries.map(([name]) => `- \`${name}\``).join("\n")
|
|
164
165
|
: "- (none found)";
|
|
165
166
|
|
|
167
|
+
// Check contracts FIRST (fast, no vector search)
|
|
168
|
+
const contractDirs = [resolve(PROJECT_DIR), ...getRelatedProjects()];
|
|
169
|
+
const allContracts = loadAllContracts(contractDirs);
|
|
170
|
+
const matchedContracts = searchContracts(task, allContracts);
|
|
171
|
+
|
|
166
172
|
// Get cross-project context
|
|
167
173
|
const relatedContext = await searchRelatedProjectContext(task);
|
|
168
174
|
|
|
@@ -197,6 +203,7 @@ ${docLines}
|
|
|
197
203
|
${claudeMd ? "- `CLAUDE.md` exists (project instructions)" : ""}
|
|
198
204
|
${agentsMd ? "- `.claude/AGENTS.md` exists" : ""}
|
|
199
205
|
|
|
206
|
+
${matchedContracts.length > 0 ? `## 📑 Matching Contracts\n${formatContracts(matchedContracts, 8)}\n` : ""}
|
|
200
207
|
${relatedContext.length > 0 ? `## 🔗 Related Project Context\n${relatedContext.join("\n")}\n` : ""}
|
|
201
208
|
---
|
|
202
209
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { resolve, basename } from "path";
|
|
4
|
+
import { PROJECT_DIR } from "../lib/files.js";
|
|
5
|
+
import { getRelatedProjects } from "../lib/config.js";
|
|
6
|
+
import { loadAllContracts, searchContracts } from "../lib/contracts.js";
|
|
7
|
+
|
|
8
|
+
export function registerSearchContracts(server: McpServer): void {
|
|
9
|
+
server.tool(
|
|
10
|
+
"search_contracts",
|
|
11
|
+
"Search API contracts, types, and schemas across current and related projects. Fast lookup without vector search.",
|
|
12
|
+
{
|
|
13
|
+
query: z.string().describe("What to search for"),
|
|
14
|
+
scope: z.enum(["current", "related", "all"]).default("all").describe("Which projects to search"),
|
|
15
|
+
kind: z.enum(["interface", "type", "enum", "route", "schema", "event", "model", "all"]).default("all").describe("Filter by contract kind"),
|
|
16
|
+
},
|
|
17
|
+
async ({ query, scope, kind }) => {
|
|
18
|
+
const projectDirs: string[] = [];
|
|
19
|
+
|
|
20
|
+
if (scope === "current" || scope === "all") {
|
|
21
|
+
projectDirs.push(resolve(PROJECT_DIR));
|
|
22
|
+
}
|
|
23
|
+
if (scope === "related" || scope === "all") {
|
|
24
|
+
projectDirs.push(...getRelatedProjects());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (projectDirs.length === 0) {
|
|
28
|
+
return { content: [{ type: "text" as const, text: "No projects configured. Run onboard_project first." }] };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let contracts = loadAllContracts(projectDirs);
|
|
32
|
+
|
|
33
|
+
// Filter by kind
|
|
34
|
+
if (kind !== "all") {
|
|
35
|
+
contracts = contracts.filter(c => c.kind === kind);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Search
|
|
39
|
+
const results = searchContracts(query, contracts);
|
|
40
|
+
|
|
41
|
+
if (results.length === 0) {
|
|
42
|
+
return { content: [{ type: "text" as const, text: `No contracts matching "${query}" found across ${projectDirs.length} project(s).` }] };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const output = [
|
|
46
|
+
`## Contract Search: "${query}"`,
|
|
47
|
+
`Found ${results.length} matching contract(s):\n`,
|
|
48
|
+
...results.slice(0, 20).map(c => {
|
|
49
|
+
const proj = basename(c.project);
|
|
50
|
+
return `### ${c.kind} \`${c.name}\` (${proj})\nFile: \`${c.file}\`\n\`\`\`\n${c.definition}\n\`\`\``;
|
|
51
|
+
}),
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
if (results.length > 20) {
|
|
55
|
+
output.push(`\n...and ${results.length - 20} more. Narrow your query or filter by kind.`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { content: [{ type: "text" as const, text: output.join("\n") }] };
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|