preflight-dev 3.1.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/LICENSE +21 -0
- package/README.md +172 -0
- package/bin/cli.js +11 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.js +154 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +122 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.js +118 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/embeddings.d.ts +11 -0
- package/dist/lib/embeddings.js +88 -0
- package/dist/lib/embeddings.js.map +1 -0
- package/dist/lib/files.d.ts +15 -0
- package/dist/lib/files.js +60 -0
- package/dist/lib/files.js.map +1 -0
- package/dist/lib/git-extractor.d.ts +9 -0
- package/dist/lib/git-extractor.js +116 -0
- package/dist/lib/git-extractor.js.map +1 -0
- package/dist/lib/git.d.ts +29 -0
- package/dist/lib/git.js +86 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/session-parser.d.ts +45 -0
- package/dist/lib/session-parser.js +267 -0
- package/dist/lib/session-parser.js.map +1 -0
- package/dist/lib/state.d.ts +21 -0
- package/dist/lib/state.js +86 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/timeline-db.d.ts +67 -0
- package/dist/lib/timeline-db.js +380 -0
- package/dist/lib/timeline-db.js.map +1 -0
- package/dist/lib/triage.d.ts +29 -0
- package/dist/lib/triage.js +193 -0
- package/dist/lib/triage.js.map +1 -0
- package/dist/profiles.d.ts +3 -0
- package/dist/profiles.js +65 -0
- package/dist/profiles.js.map +1 -0
- package/dist/tools/audit-workspace.d.ts +2 -0
- package/dist/tools/audit-workspace.js +86 -0
- package/dist/tools/audit-workspace.js.map +1 -0
- package/dist/tools/checkpoint.d.ts +2 -0
- package/dist/tools/checkpoint.js +108 -0
- package/dist/tools/checkpoint.js.map +1 -0
- package/dist/tools/clarify-intent.d.ts +2 -0
- package/dist/tools/clarify-intent.js +180 -0
- package/dist/tools/clarify-intent.js.map +1 -0
- package/dist/tools/enrich-agent-task.d.ts +2 -0
- package/dist/tools/enrich-agent-task.js +97 -0
- package/dist/tools/enrich-agent-task.js.map +1 -0
- package/dist/tools/generate-scorecard.d.ts +2 -0
- package/dist/tools/generate-scorecard.js +617 -0
- package/dist/tools/generate-scorecard.js.map +1 -0
- package/dist/tools/log-correction.d.ts +2 -0
- package/dist/tools/log-correction.js +76 -0
- package/dist/tools/log-correction.js.map +1 -0
- package/dist/tools/onboard-project.d.ts +2 -0
- package/dist/tools/onboard-project.js +179 -0
- package/dist/tools/onboard-project.js.map +1 -0
- package/dist/tools/preflight-check.d.ts +2 -0
- package/dist/tools/preflight-check.js +229 -0
- package/dist/tools/preflight-check.js.map +1 -0
- package/dist/tools/prompt-score.d.ts +2 -0
- package/dist/tools/prompt-score.js +132 -0
- package/dist/tools/prompt-score.js.map +1 -0
- package/dist/tools/scan-sessions.d.ts +2 -0
- package/dist/tools/scan-sessions.js +182 -0
- package/dist/tools/scan-sessions.js.map +1 -0
- package/dist/tools/scope-work.d.ts +2 -0
- package/dist/tools/scope-work.js +214 -0
- package/dist/tools/scope-work.js.map +1 -0
- package/dist/tools/search-history.d.ts +2 -0
- package/dist/tools/search-history.js +130 -0
- package/dist/tools/search-history.js.map +1 -0
- package/dist/tools/sequence-tasks.d.ts +2 -0
- package/dist/tools/sequence-tasks.js +165 -0
- package/dist/tools/sequence-tasks.js.map +1 -0
- package/dist/tools/session-handoff.d.ts +2 -0
- package/dist/tools/session-handoff.js +113 -0
- package/dist/tools/session-handoff.js.map +1 -0
- package/dist/tools/session-health.d.ts +2 -0
- package/dist/tools/session-health.js +111 -0
- package/dist/tools/session-health.js.map +1 -0
- package/dist/tools/session-stats.d.ts +2 -0
- package/dist/tools/session-stats.js +112 -0
- package/dist/tools/session-stats.js.map +1 -0
- package/dist/tools/sharpen-followup.d.ts +2 -0
- package/dist/tools/sharpen-followup.js +192 -0
- package/dist/tools/sharpen-followup.js.map +1 -0
- package/dist/tools/timeline-view.d.ts +2 -0
- package/dist/tools/timeline-view.js +165 -0
- package/dist/tools/timeline-view.js.map +1 -0
- package/dist/tools/token-audit.d.ts +2 -0
- package/dist/tools/token-audit.js +227 -0
- package/dist/tools/token-audit.js.map +1 -0
- package/dist/tools/verify-completion.d.ts +2 -0
- package/dist/tools/verify-completion.js +154 -0
- package/dist/tools/verify-completion.js.map +1 -0
- package/dist/tools/what-changed.d.ts +2 -0
- package/dist/tools/what-changed.js +40 -0
- package/dist/tools/what-changed.js.map +1 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
- package/src/cli/init.ts +133 -0
- package/src/index.ts +135 -0
- package/src/lib/config.ts +157 -0
- package/src/lib/embeddings.ts +118 -0
- package/src/lib/files.ts +59 -0
- package/src/lib/git-extractor.ts +137 -0
- package/src/lib/git.ts +89 -0
- package/src/lib/session-parser.ts +325 -0
- package/src/lib/state.ts +86 -0
- package/src/lib/timeline-db.ts +490 -0
- package/src/lib/triage.ts +255 -0
- package/src/profiles.ts +70 -0
- package/src/templates/config.yml +23 -0
- package/src/templates/triage.yml +27 -0
- package/src/tools/audit-workspace.ts +97 -0
- package/src/tools/checkpoint.ts +119 -0
- package/src/tools/clarify-intent.ts +191 -0
- package/src/tools/enrich-agent-task.ts +108 -0
- package/src/tools/generate-scorecard.ts +673 -0
- package/src/tools/log-correction.ts +89 -0
- package/src/tools/onboard-project.ts +214 -0
- package/src/tools/preflight-check.ts +263 -0
- package/src/tools/prompt-score.ts +150 -0
- package/src/tools/scan-sessions.ts +209 -0
- package/src/tools/scope-work.ts +238 -0
- package/src/tools/search-history.ts +145 -0
- package/src/tools/sequence-tasks.ts +182 -0
- package/src/tools/session-handoff.ts +125 -0
- package/src/tools/session-health.ts +107 -0
- package/src/tools/session-stats.ts +134 -0
- package/src/tools/sharpen-followup.ts +200 -0
- package/src/tools/timeline-view.ts +181 -0
- package/src/tools/token-audit.ts +259 -0
- package/src/tools/verify-completion.ts +159 -0
- package/src/tools/what-changed.ts +48 -0
- package/src/types.ts +87 -0
package/dist/profiles.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Profile system — controls which tools are registered
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// minimal: No vectors. Pure JSONL parsing + git state. ~5MB install.
|
|
5
|
+
// standard: Local embeddings (Xenova) + LanceDB. Auto-downloads model on
|
|
6
|
+
// first use. Zero config. ~200MB after model download. DEFAULT.
|
|
7
|
+
// full: Everything in standard + OpenAI option for higher quality embeddings.
|
|
8
|
+
// =============================================================================
|
|
9
|
+
import { getConfig } from "./lib/config.js";
|
|
10
|
+
const MINIMAL_TOOLS = new Set([
|
|
11
|
+
"preflight_check",
|
|
12
|
+
"clarify_intent",
|
|
13
|
+
"check_session_health",
|
|
14
|
+
"session_stats",
|
|
15
|
+
"prompt_score",
|
|
16
|
+
]);
|
|
17
|
+
// Standard IS the default — includes embeddings + timeline.
|
|
18
|
+
// LanceDB is embedded (no server), Xenova downloads model silently on first use.
|
|
19
|
+
const STANDARD_TOOLS = new Set([
|
|
20
|
+
// Main entry point
|
|
21
|
+
"preflight_check",
|
|
22
|
+
// All 14 prompt discipline tools
|
|
23
|
+
"scope_work",
|
|
24
|
+
"clarify_intent",
|
|
25
|
+
"enrich_agent_task",
|
|
26
|
+
"sharpen_followup",
|
|
27
|
+
"token_audit",
|
|
28
|
+
"sequence_tasks",
|
|
29
|
+
"checkpoint",
|
|
30
|
+
"check_session_health",
|
|
31
|
+
"log_correction",
|
|
32
|
+
"audit_workspace",
|
|
33
|
+
"session_handoff",
|
|
34
|
+
"what_changed",
|
|
35
|
+
"verify_completion",
|
|
36
|
+
// Lightweight tools
|
|
37
|
+
"session_stats",
|
|
38
|
+
"prompt_score",
|
|
39
|
+
"generate_scorecard",
|
|
40
|
+
// Timeline tools — local embeddings, zero config
|
|
41
|
+
"onboard_project",
|
|
42
|
+
"search_history",
|
|
43
|
+
"timeline_view",
|
|
44
|
+
"scan_sessions",
|
|
45
|
+
]);
|
|
46
|
+
// Full = standard + OpenAI embedding option (needs API key)
|
|
47
|
+
// Identical tool set — the difference is config, not features.
|
|
48
|
+
const FULL_TOOLS = new Set([
|
|
49
|
+
...STANDARD_TOOLS,
|
|
50
|
+
]);
|
|
51
|
+
export function getProfile() {
|
|
52
|
+
return getConfig().profile;
|
|
53
|
+
}
|
|
54
|
+
export function isToolEnabled(toolName) {
|
|
55
|
+
const profile = getProfile();
|
|
56
|
+
switch (profile) {
|
|
57
|
+
case "minimal":
|
|
58
|
+
return MINIMAL_TOOLS.has(toolName);
|
|
59
|
+
case "standard":
|
|
60
|
+
return STANDARD_TOOLS.has(toolName);
|
|
61
|
+
case "full":
|
|
62
|
+
return FULL_TOOLS.has(toolName);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=profiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.js","sourceRoot":"","sources":["../src/profiles.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,uDAAuD;AACvD,gFAAgF;AAChF,sEAAsE;AACtE,yEAAyE;AACzE,0EAA0E;AAC1E,kFAAkF;AAClF,gFAAgF;AAEhF,OAAO,EAAE,SAAS,EAAgB,MAAM,iBAAiB,CAAC;AAE1D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,iBAAiB;IACjB,gBAAgB;IAChB,sBAAsB;IACtB,eAAe;IACf,cAAc;CACf,CAAC,CAAC;AAEH,4DAA4D;AAC5D,iFAAiF;AACjF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,mBAAmB;IACnB,iBAAiB;IACjB,iCAAiC;IACjC,YAAY;IACZ,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;IAClB,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,sBAAsB;IACtB,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,cAAc;IACd,mBAAmB;IACnB,oBAAoB;IACpB,eAAe;IACf,cAAc;IACd,oBAAoB;IACpB,iDAAiD;IACjD,iBAAiB;IACjB,gBAAgB;IAChB,eAAe;IACf,eAAe;CAChB,CAAC,CAAC;AAEH,4DAA4D;AAC5D,+DAA+D;AAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,GAAG,cAAc;CAClB,CAAC,CAAC;AAEH,MAAM,UAAU,UAAU;IACxB,OAAO,SAAS,EAAE,CAAC,OAAO,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,KAAK,UAAU;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { run } from "../lib/git.js";
|
|
2
|
+
import { findWorkspaceDocs } from "../lib/files.js";
|
|
3
|
+
/** Extract top-level work areas from file paths generically */
|
|
4
|
+
function detectWorkAreas(files) {
|
|
5
|
+
const areas = new Set();
|
|
6
|
+
for (const f of files) {
|
|
7
|
+
if (!f || f.startsWith("."))
|
|
8
|
+
continue;
|
|
9
|
+
// Use first 1-2 path segments as the area
|
|
10
|
+
const parts = f.split("/");
|
|
11
|
+
if (parts.length >= 2) {
|
|
12
|
+
// For test-like directories, just use "tests"
|
|
13
|
+
if (/^(tests?|__tests__|spec)$/i.test(parts[0])) {
|
|
14
|
+
areas.add("tests");
|
|
15
|
+
}
|
|
16
|
+
else if (parts.length >= 3) {
|
|
17
|
+
// e.g. app/api/foo → "app/api", src/components/Bar → "src/components"
|
|
18
|
+
areas.add(`${parts[0]}/${parts[1]}`);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
areas.add(parts[0]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// Root-level files: group by extension category
|
|
26
|
+
if (/\.(json|ya?ml|toml|lock)$/.test(f))
|
|
27
|
+
areas.add("config");
|
|
28
|
+
else
|
|
29
|
+
areas.add("root");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return areas;
|
|
33
|
+
}
|
|
34
|
+
export function registerAuditWorkspace(server) {
|
|
35
|
+
server.tool("audit_workspace", `Audit workspace documentation freshness vs actual project state. Compares .claude/ workspace docs against recent git commits to find stale or missing documentation. Call after completing a batch of work or at session end.`, {}, async () => {
|
|
36
|
+
const docs = findWorkspaceDocs();
|
|
37
|
+
const recentFiles = run("git diff --name-only HEAD~10 2>/dev/null || echo ''").split("\n").filter(Boolean);
|
|
38
|
+
const sections = [];
|
|
39
|
+
// Doc freshness
|
|
40
|
+
const docStatus = [];
|
|
41
|
+
const currentTime = Date.now();
|
|
42
|
+
for (const [name, info] of Object.entries(docs)) {
|
|
43
|
+
const ageHours = Math.round((currentTime - info.mtime.getTime()) / 3600000);
|
|
44
|
+
const stale = ageHours > 4;
|
|
45
|
+
docStatus.push({ name, ageHours, stale, size: info.size });
|
|
46
|
+
}
|
|
47
|
+
// Use bullet list format (renders everywhere)
|
|
48
|
+
sections.push(`## Workspace Doc Freshness\n${docStatus.length > 0
|
|
49
|
+
? docStatus.map(d => `- .claude/${d.name} — ${d.ageHours}h old ${d.stale ? "🔴 STALE" : "🟢 Fresh"}`).join("\n")
|
|
50
|
+
: "No workspace docs found."}`);
|
|
51
|
+
// Detect work areas generically from git diffs
|
|
52
|
+
const workAreas = detectWorkAreas(recentFiles);
|
|
53
|
+
// Check which areas lack docs
|
|
54
|
+
const docNames = Object.keys(docs).join(" ").toLowerCase();
|
|
55
|
+
const undocumented = [...workAreas].filter(area => {
|
|
56
|
+
const areaLower = area.toLowerCase();
|
|
57
|
+
// Check if any doc name contains the area name (or key parts)
|
|
58
|
+
const keywords = areaLower.split("/").filter(Boolean);
|
|
59
|
+
return !keywords.some(kw => docNames.includes(kw));
|
|
60
|
+
});
|
|
61
|
+
if (undocumented.length > 0) {
|
|
62
|
+
sections.push(`## Undocumented Work Areas\nRecent commits touched these areas but no workspace docs cover them:\n${undocumented.map(a => `- ❌ **${a}**`).join("\n")}`);
|
|
63
|
+
}
|
|
64
|
+
// Check for gap trackers or similar tracking docs
|
|
65
|
+
const trackingDocs = Object.entries(docs).filter(([n]) => /gap|track|progress/i.test(n));
|
|
66
|
+
if (trackingDocs.length > 0) {
|
|
67
|
+
const testFilesCount = parseInt(run("find tests -name '*.spec.ts' -o -name '*.test.ts' 2>/dev/null | wc -l").trim()) || 0;
|
|
68
|
+
sections.push(`## Tracking Docs\n${trackingDocs.map(([n]) => {
|
|
69
|
+
const age = docStatus.find(d => d.name === n)?.ageHours ?? "?";
|
|
70
|
+
return `- .claude/${n} — last updated ${age}h ago`;
|
|
71
|
+
}).join("\n")}\nTest files on disk: ${testFilesCount}`);
|
|
72
|
+
}
|
|
73
|
+
// Summary
|
|
74
|
+
const staleCount = docStatus.filter(d => d.stale).length;
|
|
75
|
+
const recs = [];
|
|
76
|
+
if (staleCount > 0)
|
|
77
|
+
recs.push(`⚠️ ${staleCount} docs are stale. Update them before ending this session.`);
|
|
78
|
+
else
|
|
79
|
+
recs.push("✅ Workspace docs are fresh.");
|
|
80
|
+
if (undocumented.length > 0)
|
|
81
|
+
recs.push(`⚠️ ${undocumented.length} work areas have no docs. Consider creating docs for: ${undocumented.join(", ")}`);
|
|
82
|
+
sections.push(`## Recommendation\n${recs.join("\n")}`);
|
|
83
|
+
return { content: [{ type: "text", text: sections.join("\n\n") }] };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=audit-workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-workspace.js","sourceRoot":"","sources":["../../src/tools/audit-workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { writeFileSync, existsSync, mkdirSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { run, getBranch, getStatus, getLastCommit, getStagedFiles } from "../lib/git.js";
|
|
5
|
+
import { PROJECT_DIR } from "../lib/files.js";
|
|
6
|
+
import { appendLog, now } from "../lib/state.js";
|
|
7
|
+
export function registerCheckpoint(server) {
|
|
8
|
+
server.tool("checkpoint", `Save a session checkpoint before context compaction hits. Commits current work, writes session state to workspace docs, and creates a resumption note. Call this proactively when session is getting long, or when the session-health hook warns about turn count. This is your "save game" before compaction wipes context.`, {
|
|
9
|
+
summary: z.string().describe("What was accomplished so far in this session"),
|
|
10
|
+
next_steps: z.string().describe("What still needs to be done"),
|
|
11
|
+
current_blockers: z.string().optional().describe("Any issues or blockers encountered"),
|
|
12
|
+
commit_mode: z.enum(["staged", "tracked", "all"]).optional().describe("What to commit: 'staged' (only staged files), 'tracked' (modified tracked files), 'all' (git add -A). Default: 'tracked'"),
|
|
13
|
+
}, async ({ summary, next_steps, current_blockers, commit_mode }) => {
|
|
14
|
+
const mode = commit_mode || "tracked";
|
|
15
|
+
const branch = getBranch();
|
|
16
|
+
const dirty = getStatus();
|
|
17
|
+
const lastCommit = getLastCommit();
|
|
18
|
+
const timestamp = now();
|
|
19
|
+
// Write checkpoint file
|
|
20
|
+
const checkpointDir = join(PROJECT_DIR, ".claude");
|
|
21
|
+
if (!existsSync(checkpointDir))
|
|
22
|
+
mkdirSync(checkpointDir, { recursive: true });
|
|
23
|
+
const checkpointFile = join(checkpointDir, "last-checkpoint.md");
|
|
24
|
+
const checkpointContent = `# Session Checkpoint
|
|
25
|
+
**Time**: ${timestamp}
|
|
26
|
+
**Branch**: ${branch}
|
|
27
|
+
**Last Commit**: ${lastCommit}
|
|
28
|
+
|
|
29
|
+
## Accomplished
|
|
30
|
+
${summary}
|
|
31
|
+
|
|
32
|
+
## Next Steps
|
|
33
|
+
${next_steps}
|
|
34
|
+
|
|
35
|
+
${current_blockers ? `## Blockers\n${current_blockers}\n` : ""}
|
|
36
|
+
## Uncommitted Work (at checkpoint time)
|
|
37
|
+
\`\`\`
|
|
38
|
+
${dirty || "clean"}
|
|
39
|
+
\`\`\`
|
|
40
|
+
`;
|
|
41
|
+
writeFileSync(checkpointFile, checkpointContent);
|
|
42
|
+
appendLog("checkpoint-log.jsonl", {
|
|
43
|
+
timestamp,
|
|
44
|
+
branch,
|
|
45
|
+
summary,
|
|
46
|
+
next_steps,
|
|
47
|
+
blockers: current_blockers || null,
|
|
48
|
+
dirty_files: dirty ? dirty.split("\n").filter(Boolean).length : 0,
|
|
49
|
+
commit_mode: mode,
|
|
50
|
+
});
|
|
51
|
+
// Commit based on mode
|
|
52
|
+
let commitResult = "no uncommitted changes";
|
|
53
|
+
if (dirty) {
|
|
54
|
+
const shortSummary = summary.split("\n")[0].slice(0, 72);
|
|
55
|
+
const commitMsg = `checkpoint: ${shortSummary}`;
|
|
56
|
+
let addCmd = "git add -u";
|
|
57
|
+
switch (mode) {
|
|
58
|
+
case "staged": {
|
|
59
|
+
const staged = getStagedFiles();
|
|
60
|
+
if (!staged) {
|
|
61
|
+
commitResult = "nothing staged — skipped commit (use 'tracked' or 'all' mode, or stage files first)";
|
|
62
|
+
}
|
|
63
|
+
addCmd = "true"; // noop, already staged
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "all":
|
|
67
|
+
addCmd = "git add -A";
|
|
68
|
+
break;
|
|
69
|
+
case "tracked":
|
|
70
|
+
default:
|
|
71
|
+
addCmd = "git add -u";
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (commitResult === "no uncommitted changes") {
|
|
75
|
+
// Stage the checkpoint file too
|
|
76
|
+
run(`git add "${checkpointFile}"`);
|
|
77
|
+
const result = run(`${addCmd} && git commit -m "${commitMsg.replace(/"/g, '\\"')}" 2>&1`);
|
|
78
|
+
if (result.includes("commit failed") || result.includes("nothing to commit")) {
|
|
79
|
+
// Rollback: unstage if commit failed
|
|
80
|
+
run("git reset HEAD 2>/dev/null");
|
|
81
|
+
commitResult = `commit failed: ${result}`;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
commitResult = result;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
content: [{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: `## Checkpoint Saved ✅
|
|
92
|
+
**File**: .claude/last-checkpoint.md
|
|
93
|
+
**Branch**: ${branch}
|
|
94
|
+
**Commit mode**: ${mode}
|
|
95
|
+
**Commit**: ${commitResult}
|
|
96
|
+
|
|
97
|
+
### What's saved:
|
|
98
|
+
- Summary of work done
|
|
99
|
+
- Next steps for continuation
|
|
100
|
+
${current_blockers ? "- Current blockers\n" : ""}- Working tree state at checkpoint time
|
|
101
|
+
|
|
102
|
+
### To resume after compaction:
|
|
103
|
+
Tell the next session/continuation: "Read .claude/last-checkpoint.md for where I left off"`,
|
|
104
|
+
}],
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../src/tools/checkpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { run, getBranch, getStatus, getRecentCommits, getDiffFiles, getStagedFiles } from "../lib/git.js";
|
|
3
|
+
import { findWorkspaceDocs, PROJECT_DIR } from "../lib/files.js";
|
|
4
|
+
import { searchSemantic } from "../lib/timeline-db.js";
|
|
5
|
+
import { getRelatedProjects } from "../lib/config.js";
|
|
6
|
+
import { existsSync, readFileSync } from "fs";
|
|
7
|
+
import { join, basename } from "path";
|
|
8
|
+
/** Parse test failures from common report formats without fragile shell pipelines */
|
|
9
|
+
function getTestFailures() {
|
|
10
|
+
// Try playwright JSON report
|
|
11
|
+
const reportPath = join(PROJECT_DIR, "playwright-report", "results.json");
|
|
12
|
+
if (existsSync(reportPath)) {
|
|
13
|
+
try {
|
|
14
|
+
const data = JSON.parse(readFileSync(reportPath, "utf-8"));
|
|
15
|
+
const failures = [];
|
|
16
|
+
const walk = (suites) => {
|
|
17
|
+
for (const suite of suites || []) {
|
|
18
|
+
for (const spec of suite.specs || []) {
|
|
19
|
+
if (spec.ok === false)
|
|
20
|
+
failures.push(spec.title);
|
|
21
|
+
}
|
|
22
|
+
walk(suite.suites);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
walk(data.suites);
|
|
26
|
+
return failures.length ? failures.join("\n") : "all passing";
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return "report exists but could not parse";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Try jest/vitest JSON output
|
|
33
|
+
for (const p of ["test-results.json", "jest-results.json"]) {
|
|
34
|
+
const fp = join(PROJECT_DIR, p);
|
|
35
|
+
if (existsSync(fp)) {
|
|
36
|
+
try {
|
|
37
|
+
const data = JSON.parse(readFileSync(fp, "utf-8"));
|
|
38
|
+
const failed = data.testResults
|
|
39
|
+
?.filter((t) => t.status === "failed")
|
|
40
|
+
?.map((t) => t.name) || [];
|
|
41
|
+
return failed.length ? failed.join("\n") : "all passing";
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return "no test report found";
|
|
49
|
+
}
|
|
50
|
+
/** Extract intent signals using weighted pattern matching */
|
|
51
|
+
function extractSignals(msg, context) {
|
|
52
|
+
const signals = [];
|
|
53
|
+
const lower = msg.toLowerCase();
|
|
54
|
+
const patterns = [
|
|
55
|
+
[/\b(fix|repair|broken|failing|error|bug|crash|issue)\b/, "FIX", 2],
|
|
56
|
+
[/\b(test|spec|suite|playwright|jest|vitest|e2e)\b/, "TESTS", 2],
|
|
57
|
+
[/\b(commit|push|pr|merge|rebase|cherry.?pick)\b/, "GIT", 2],
|
|
58
|
+
[/\b(add|create|new|build|implement|feature)\b/, "CREATE", 1],
|
|
59
|
+
[/\b(remove|delete|clean|strip|drop|deprecate)\b/, "REMOVE", 1],
|
|
60
|
+
[/\b(check|verify|confirm|status|review|audit)\b/, "VERIFY", 1],
|
|
61
|
+
[/\b(refactor|rename|move|reorganize|extract)\b/, "REFACTOR", 1],
|
|
62
|
+
[/\b(deploy|release|ship|publish)\b/, "DEPLOY", 1],
|
|
63
|
+
[/\b(everything|all|entire|whole)\b/, "⚠️ UNBOUNDED", 3],
|
|
64
|
+
];
|
|
65
|
+
const matched = [];
|
|
66
|
+
for (const [re, label, weight] of patterns) {
|
|
67
|
+
if (re.test(lower))
|
|
68
|
+
matched.push({ label, weight, hint: "" });
|
|
69
|
+
}
|
|
70
|
+
// Add contextual hints
|
|
71
|
+
if (matched.some(m => m.label === "FIX")) {
|
|
72
|
+
if (context.hasTypeErrors)
|
|
73
|
+
signals.push("FIX: Type errors detected — likely the target.");
|
|
74
|
+
if (context.hasTestFailures)
|
|
75
|
+
signals.push("FIX: Test failures detected — check test output.");
|
|
76
|
+
if (!context.hasTypeErrors && !context.hasTestFailures)
|
|
77
|
+
signals.push("FIX: No obvious errors — ask what's broken.");
|
|
78
|
+
}
|
|
79
|
+
if (matched.some(m => m.label === "TESTS"))
|
|
80
|
+
signals.push("TESTS: Check failing tests and test files below.");
|
|
81
|
+
if (matched.some(m => m.label === "GIT"))
|
|
82
|
+
signals.push("GIT: Check dirty files and branch state.");
|
|
83
|
+
if (matched.some(m => m.label === "CREATE"))
|
|
84
|
+
signals.push("CREATE: Check workspace priorities for planned work.");
|
|
85
|
+
if (matched.some(m => m.label === "REMOVE"))
|
|
86
|
+
signals.push("REMOVE: Clarify what 'them/it' refers to before deleting.");
|
|
87
|
+
if (matched.some(m => m.label === "VERIFY"))
|
|
88
|
+
signals.push("VERIFY: Use git/test state to answer.");
|
|
89
|
+
if (matched.some(m => m.label === "REFACTOR"))
|
|
90
|
+
signals.push("REFACTOR: Identify scope boundaries before starting.");
|
|
91
|
+
if (matched.some(m => m.label === "DEPLOY"))
|
|
92
|
+
signals.push("DEPLOY: Verify all checks pass first.");
|
|
93
|
+
if (matched.some(m => m.label === "⚠️ UNBOUNDED"))
|
|
94
|
+
signals.push("⚠️ UNBOUNDED: Narrow down using workspace priorities.");
|
|
95
|
+
if (!signals.length)
|
|
96
|
+
signals.push("UNCLEAR: Ask ONE clarifying question before proceeding.");
|
|
97
|
+
return signals;
|
|
98
|
+
}
|
|
99
|
+
/** Search for relevant cross-project context */
|
|
100
|
+
async function searchCrossProjectContext(userMessage) {
|
|
101
|
+
const relatedProjects = getRelatedProjects();
|
|
102
|
+
if (relatedProjects.length === 0)
|
|
103
|
+
return [];
|
|
104
|
+
// Generate search queries for schemas, types, contracts, APIs
|
|
105
|
+
const queries = [
|
|
106
|
+
`${userMessage} type interface schema`,
|
|
107
|
+
`${userMessage} API endpoint contract`,
|
|
108
|
+
`${userMessage} enum constant definition`,
|
|
109
|
+
`${userMessage} class function method`,
|
|
110
|
+
];
|
|
111
|
+
const contextItems = [];
|
|
112
|
+
for (const query of queries) {
|
|
113
|
+
try {
|
|
114
|
+
const results = await searchSemantic(query, {
|
|
115
|
+
project_dirs: relatedProjects,
|
|
116
|
+
type: "commit", // Focus on code changes
|
|
117
|
+
limit: 3,
|
|
118
|
+
});
|
|
119
|
+
for (const result of results) {
|
|
120
|
+
const projectName = basename(result.project);
|
|
121
|
+
const content = result.content.slice(0, 200);
|
|
122
|
+
const sourceInfo = result.source_file ? ` at ${result.source_file}` : "";
|
|
123
|
+
contextItems.push(`**From ${projectName}:** ${content}${sourceInfo}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Skip if search fails
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return contextItems.slice(0, 5); // Limit to top 5 context items
|
|
131
|
+
}
|
|
132
|
+
export function registerClarifyIntent(server) {
|
|
133
|
+
server.tool("clarify_intent", `Clarify a vague user instruction by gathering project context. Call BEFORE executing when the user's prompt is missing specific files, actions, scope, or done conditions. Returns git state, test failures, recent changes, and workspace priorities.`, {
|
|
134
|
+
user_message: z.string().describe("The user's raw message/instruction to clarify"),
|
|
135
|
+
suspected_area: z.string().optional().describe("Best guess area: 'tests', 'git', 'ui', 'api', 'schema'"),
|
|
136
|
+
}, async ({ user_message, suspected_area }) => {
|
|
137
|
+
const sections = [];
|
|
138
|
+
const branch = getBranch();
|
|
139
|
+
const status = getStatus();
|
|
140
|
+
const recentCommits = getRecentCommits(5);
|
|
141
|
+
const recentFiles = getDiffFiles("HEAD~3");
|
|
142
|
+
const staged = getStagedFiles();
|
|
143
|
+
const dirtyCount = status ? status.split("\n").filter(Boolean).length : 0;
|
|
144
|
+
sections.push(`## Git State\nBranch: ${branch}\nDirty files: ${dirtyCount}\n${status ? `\`\`\`\n${status}\n\`\`\`` : "Working tree clean"}\nStaged: ${staged || "nothing"}\n\nRecent commits:\n\`\`\`\n${recentCommits}\n\`\`\`\n\nRecently changed files:\n\`\`\`\n${recentFiles}\n\`\`\``);
|
|
145
|
+
// Gather test/type state when relevant
|
|
146
|
+
const area = (suspected_area || "").toLowerCase();
|
|
147
|
+
let hasTypeErrors = false;
|
|
148
|
+
let hasTestFailures = false;
|
|
149
|
+
if (!area || area.includes("test") || area.includes("fix") || area.includes("ui") || area.includes("api")) {
|
|
150
|
+
const typeErrors = run("pnpm tsc --noEmit 2>&1 | grep -c 'error TS' || echo '0'");
|
|
151
|
+
hasTypeErrors = parseInt(typeErrors, 10) > 0;
|
|
152
|
+
const testFiles = run("find tests -name '*.spec.ts' -maxdepth 4 2>/dev/null | head -20");
|
|
153
|
+
const failingTests = getTestFailures();
|
|
154
|
+
hasTestFailures = failingTests !== "all passing" && failingTests !== "no test report found";
|
|
155
|
+
sections.push(`## Test State\nType errors: ${typeErrors}\nFailing tests: ${failingTests}\nTest files:\n\`\`\`\n${testFiles || "none found"}\n\`\`\``);
|
|
156
|
+
}
|
|
157
|
+
// Workspace priorities
|
|
158
|
+
const workspaceDocs = findWorkspaceDocs();
|
|
159
|
+
const priorityDocs = Object.entries(workspaceDocs)
|
|
160
|
+
.filter(([n]) => /gap|roadmap|current|todo|changelog/i.test(n))
|
|
161
|
+
.slice(0, 3);
|
|
162
|
+
if (priorityDocs.length > 0) {
|
|
163
|
+
sections.push(`## Workspace Priorities\n${priorityDocs.map(([n, d]) => `### .claude/${n}\n\`\`\`\n${d.content}\n\`\`\``).join("\n\n")}`);
|
|
164
|
+
}
|
|
165
|
+
const signals = extractSignals(user_message, {
|
|
166
|
+
hasTypeErrors,
|
|
167
|
+
hasTestFailures,
|
|
168
|
+
hasDirtyFiles: dirtyCount > 0,
|
|
169
|
+
});
|
|
170
|
+
// Search for cross-project context
|
|
171
|
+
const crossProjectContext = await searchCrossProjectContext(user_message);
|
|
172
|
+
if (crossProjectContext.length > 0) {
|
|
173
|
+
sections.push(`## Related Project Context\n${crossProjectContext.map(c => `- ${c}`).join("\n")}`);
|
|
174
|
+
}
|
|
175
|
+
sections.push(`## Intent Signals\n${signals.map(s => `- ${s}`).join("\n")}`);
|
|
176
|
+
sections.push(`## Recommendation\n1. **Proceed with specifics** — state what you'll do and why\n2. **Ask ONE question** — if context doesn't disambiguate`);
|
|
177
|
+
return { content: [{ type: "text", text: sections.join("\n\n") }] };
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=clarify-intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clarify-intent.js","sourceRoot":"","sources":["../../src/tools/clarify-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC1G,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEtC,qFAAqF;AACrF,SAAS,eAAe;IACtB,6BAA6B;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,mBAAmB,EAAE,cAAc,CAAC,CAAC;IAC1E,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,CAAC,MAAa,EAAE,EAAE;gBAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC;oBACjC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;wBACrC,IAAI,IAAI,CAAC,EAAE,KAAK,KAAK;4BAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACnD,CAAC;oBACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClB,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,mCAAmC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,KAAK,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,EAAE,CAAC;QAC3D,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;gBACnD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW;oBAC7B,EAAE,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;oBAC3C,EAAE,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAClC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC3D,CAAC;YAAC,MAAM,CAAC;gBAAC,SAAS;YAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,6DAA6D;AAC7D,SAAS,cAAc,CAAC,GAAW,EAAE,OAAqF;IACxH,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAEhC,MAAM,QAAQ,GAA+B;QAC3C,CAAC,uDAAuD,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC,kDAAkD,EAAE,OAAO,EAAE,CAAC,CAAC;QAChE,CAAC,gDAAgD,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC,8CAA8C,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7D,CAAC,gDAAgD,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC/D,CAAC,gDAAgD,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC/D,CAAC,+CAA+C,EAAE,UAAU,EAAE,CAAC,CAAC;QAChE,CAAC,mCAAmC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClD,CAAC,mCAAmC,EAAE,cAAc,EAAE,CAAC,CAAC;KACzD,CAAC;IAEF,MAAM,OAAO,GAAsD,EAAE,CAAC;IACtE,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QAC3C,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,aAAa;YAAE,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QAC1F,IAAI,OAAO,CAAC,eAAe;YAAE,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;QAC9F,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,eAAe;YAAE,OAAO,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IACtH,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAC7G,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACnG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;IAClH,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;IACvH,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACnG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;IACpH,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACnG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,cAAc,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;IAEzH,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IAE7F,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gDAAgD;AAChD,KAAK,UAAU,yBAAyB,CAAC,WAAmB;IAC1D,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAC7C,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE5C,8DAA8D;IAC9D,MAAM,OAAO,GAAG;QACd,GAAG,WAAW,wBAAwB;QACtC,GAAG,WAAW,wBAAwB;QACtC,GAAG,WAAW,2BAA2B;QACzC,GAAG,WAAW,wBAAwB;KACvC,CAAC;IAEF,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE;gBAC1C,YAAY,EAAE,eAAe;gBAC7B,IAAI,EAAE,QAAQ,EAAE,wBAAwB;gBACxC,KAAK,EAAE,CAAC;aACT,CAAC,CAAC;YAEH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzE,YAAY,CAAC,IAAI,CAAC,UAAU,WAAW,OAAO,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC;YACxE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,+BAA+B;AAClE,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,wPAAwP,EACxP;QACE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QAClF,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;KACzG,EACD,KAAK,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE,EAAE,EAAE;QACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,aAAa,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1E,QAAQ,CAAC,IAAI,CAAC,yBAAyB,MAAM,kBAAkB,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,MAAM,UAAU,CAAC,CAAC,CAAC,oBAAoB,aAAa,MAAM,IAAI,SAAS,gCAAgC,aAAa,gDAAgD,WAAW,UAAU,CAAC,CAAC;QAE7R,uCAAuC;QACvC,MAAM,IAAI,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,eAAe,GAAG,KAAK,CAAC;QAE5B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1G,MAAM,UAAU,GAAG,GAAG,CAAC,yDAAyD,CAAC,CAAC;YAClF,aAAa,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;YAE7C,MAAM,SAAS,GAAG,GAAG,CAAC,iEAAiE,CAAC,CAAC;YACzF,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;YACvC,eAAe,GAAG,YAAY,KAAK,aAAa,IAAI,YAAY,KAAK,sBAAsB,CAAC;YAE5F,QAAQ,CAAC,IAAI,CAAC,+BAA+B,UAAU,oBAAoB,YAAY,0BAA0B,SAAS,IAAI,YAAY,UAAU,CAAC,CAAC;QACxJ,CAAC;QAED,uBAAuB;QACvB,MAAM,aAAa,GAAG,iBAAiB,EAAE,CAAC;QAC1C,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;aAC/C,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qCAAqC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aAC9D,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACf,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC,4BAA4B,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC3I,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,YAAY,EAAE;YAC3C,aAAa;YACb,eAAe;YACf,aAAa,EAAE,UAAU,GAAG,CAAC;SAC9B,CAAC,CAAC;QAEH,mCAAmC;QACnC,MAAM,mBAAmB,GAAG,MAAM,yBAAyB,CAAC,YAAY,CAAC,CAAC;QAC1E,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,+BAA+B,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpG,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,sBAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7E,QAAQ,CAAC,IAAI,CAAC,4IAA4I,CAAC,CAAC;QAE5J,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IAC/E,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { run, getDiffFiles } from "../lib/git.js";
|
|
3
|
+
import { PROJECT_DIR } from "../lib/files.js";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
/** Sanitize user input for safe use in shell commands */
|
|
7
|
+
function shellEscape(s) {
|
|
8
|
+
return s.replace(/[^a-zA-Z0-9_\-./]/g, "");
|
|
9
|
+
}
|
|
10
|
+
/** Detect package manager from lockfiles */
|
|
11
|
+
function detectPackageManager() {
|
|
12
|
+
if (existsSync(join(PROJECT_DIR, "pnpm-lock.yaml")))
|
|
13
|
+
return "pnpm";
|
|
14
|
+
if (existsSync(join(PROJECT_DIR, "yarn.lock")))
|
|
15
|
+
return "yarn";
|
|
16
|
+
if (existsSync(join(PROJECT_DIR, "bun.lockb")))
|
|
17
|
+
return "bun";
|
|
18
|
+
return "npm";
|
|
19
|
+
}
|
|
20
|
+
/** Find files in a target area using git-tracked files (project-agnostic) */
|
|
21
|
+
function findAreaFiles(area) {
|
|
22
|
+
if (!area)
|
|
23
|
+
return getDiffFiles("HEAD~3");
|
|
24
|
+
const safeArea = shellEscape(area);
|
|
25
|
+
// If area looks like a path, search directly
|
|
26
|
+
if (area.includes("/")) {
|
|
27
|
+
return run(`git ls-files -- '${safeArea}*' 2>/dev/null | head -20`);
|
|
28
|
+
}
|
|
29
|
+
// Search for area keyword in git-tracked file paths
|
|
30
|
+
const files = run(`git ls-files 2>/dev/null | grep -i '${safeArea}' | head -20`);
|
|
31
|
+
if (files && !files.startsWith("[command failed"))
|
|
32
|
+
return files;
|
|
33
|
+
// Fallback to recently changed files
|
|
34
|
+
return getDiffFiles("HEAD~3");
|
|
35
|
+
}
|
|
36
|
+
/** Find related test files for an area */
|
|
37
|
+
function findRelatedTests(area) {
|
|
38
|
+
if (!area)
|
|
39
|
+
return run("git ls-files 2>/dev/null | grep -E '\\.(spec|test)\\.(ts|tsx|js|jsx)$' | head -10");
|
|
40
|
+
const safeArea = shellEscape(area.split(/\s+/)[0]);
|
|
41
|
+
const tests = run(`git ls-files 2>/dev/null | grep -E '\\.(spec|test)\\.(ts|tsx|js|jsx)$' | grep -i '${safeArea}' | head -10`);
|
|
42
|
+
return tests || run("git ls-files 2>/dev/null | grep -E '\\.(spec|test)\\.(ts|tsx|js|jsx)$' | head -10");
|
|
43
|
+
}
|
|
44
|
+
/** Get an example pattern from the first matching file */
|
|
45
|
+
function getExamplePattern(files) {
|
|
46
|
+
const firstFile = files.split("\n").filter(Boolean)[0];
|
|
47
|
+
if (!firstFile)
|
|
48
|
+
return "no pattern available";
|
|
49
|
+
return run(`head -30 '${shellEscape(firstFile)}' 2>/dev/null || echo 'could not read file'`);
|
|
50
|
+
}
|
|
51
|
+
export function registerEnrichAgentTask(server) {
|
|
52
|
+
server.tool("enrich_agent_task", `Enrich a vague sub-agent task with project context. Call before spawning a Task/sub-agent to add file paths, patterns, scope boundaries, and done conditions.`, {
|
|
53
|
+
task_description: z.string().describe("The raw task for the sub-agent"),
|
|
54
|
+
target_area: z.string().optional().describe("Codebase area: directory path, keyword, or description like 'auth tests', 'api routes'"),
|
|
55
|
+
}, async ({ task_description, target_area }) => {
|
|
56
|
+
const area = target_area || "";
|
|
57
|
+
const pm = detectPackageManager();
|
|
58
|
+
const fileList = findAreaFiles(area);
|
|
59
|
+
const testFiles = findRelatedTests(area);
|
|
60
|
+
const pattern = getExamplePattern(area.includes("test") ? testFiles : fileList);
|
|
61
|
+
const fileSummary = fileList
|
|
62
|
+
? fileList.split("\n").filter(Boolean).slice(0, 5).join(", ")
|
|
63
|
+
: "Specify exact files";
|
|
64
|
+
const testSummary = testFiles
|
|
65
|
+
? testFiles.split("\n").filter(Boolean).slice(0, 3).join(", ")
|
|
66
|
+
: "Run relevant tests";
|
|
67
|
+
return {
|
|
68
|
+
content: [{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: `## Files in Target Area
|
|
71
|
+
\`\`\`
|
|
72
|
+
${fileList || "none found — specify a more precise area"}
|
|
73
|
+
\`\`\`
|
|
74
|
+
|
|
75
|
+
## Related Tests
|
|
76
|
+
\`\`\`
|
|
77
|
+
${testFiles || "none"}
|
|
78
|
+
\`\`\`
|
|
79
|
+
|
|
80
|
+
## Existing Pattern
|
|
81
|
+
\`\`\`typescript
|
|
82
|
+
${pattern}
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
## Enriched Task
|
|
86
|
+
Original: "${task_description}"
|
|
87
|
+
|
|
88
|
+
- **Files**: ${fileSummary}
|
|
89
|
+
- **Pattern**: Follow existing pattern above
|
|
90
|
+
- **Tests**: ${testSummary}
|
|
91
|
+
- **Scope**: Do NOT modify files outside target area
|
|
92
|
+
- **Done when**: All relevant tests pass + \`${pm} tsc --noEmit\` clean`,
|
|
93
|
+
}],
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=enrich-agent-task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrich-agent-task.js","sourceRoot":"","sources":["../../src/tools/enrich-agent-task.ts"],"names":[],"mappings":"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"}
|