@0xdevabir/enhance 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +173 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -602,7 +602,7 @@ function truncateLines(content, maxLines) {
|
|
|
602
602
|
}
|
|
603
603
|
|
|
604
604
|
// src/enhancer/injectors.ts
|
|
605
|
-
function
|
|
605
|
+
function getFallbackInjections(stack, intent, config) {
|
|
606
606
|
const rules = [];
|
|
607
607
|
if (stack.language === "typescript") {
|
|
608
608
|
rules.push("Use TypeScript throughout \u2014 no `any`, prefer `unknown` with type guards");
|
|
@@ -680,6 +680,31 @@ function getInjections(stack, intent, config) {
|
|
|
680
680
|
return rules;
|
|
681
681
|
}
|
|
682
682
|
|
|
683
|
+
// src/enhancer/angles.ts
|
|
684
|
+
var ANGLE_LABELS = {
|
|
685
|
+
completeness: "Completeness",
|
|
686
|
+
production: "Production Safety",
|
|
687
|
+
dx: "Developer Experience",
|
|
688
|
+
alternative: "Alternative Approach"
|
|
689
|
+
};
|
|
690
|
+
var ANGLE_ORDER = ["completeness", "production", "dx", "alternative"];
|
|
691
|
+
function getAngle(iteration) {
|
|
692
|
+
const idx = Math.min(iteration, ANGLE_ORDER.length - 1);
|
|
693
|
+
return ANGLE_ORDER[idx];
|
|
694
|
+
}
|
|
695
|
+
function getAngleFocus(angle) {
|
|
696
|
+
switch (angle) {
|
|
697
|
+
case "completeness":
|
|
698
|
+
return 'Cover every feature, sub-case, and edge case. Assume the reviewer will ask "what about X?" for every possible X. Nothing should be missing.';
|
|
699
|
+
case "production":
|
|
700
|
+
return "Focus on what breaks at 3am: failure modes, error handling, observability, security vulnerabilities, race conditions, data consistency, and retry semantics.";
|
|
701
|
+
case "dx":
|
|
702
|
+
return "Focus on implementation guidance: the correct step-by-step order, what confuses junior developers, integration pitfalls, what to verify first, and common mistakes.";
|
|
703
|
+
case "alternative":
|
|
704
|
+
return "Propose a meaningfully different architecture or pattern than the obvious approach. Explain the trade-off. Challenge the default solution.";
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
683
708
|
// src/enhancer/template.ts
|
|
684
709
|
function buildEnhancedPrompt(opts) {
|
|
685
710
|
const { intent } = opts;
|
|
@@ -692,9 +717,30 @@ function buildEnhancedPrompt(opts) {
|
|
|
692
717
|
return buildFeaturePrompt(opts);
|
|
693
718
|
}
|
|
694
719
|
}
|
|
720
|
+
function buildVersionHeader(opts) {
|
|
721
|
+
const { angle, iteration } = opts;
|
|
722
|
+
if (angle === void 0) return null;
|
|
723
|
+
const v = (iteration ?? 0) + 1;
|
|
724
|
+
const label = ANGLE_LABELS[angle];
|
|
725
|
+
return `\u{1F4CD} v${v} \u2014 ${label} angle`;
|
|
726
|
+
}
|
|
727
|
+
function buildAssumptionsSection(assumptions) {
|
|
728
|
+
if (!assumptions.length) return null;
|
|
729
|
+
return `## Assumptions
|
|
730
|
+
|
|
731
|
+
${assumptions.map((a) => `- ${a}`).join("\n")}`;
|
|
732
|
+
}
|
|
733
|
+
function buildGotchasSection(gotchas) {
|
|
734
|
+
if (!gotchas.length) return null;
|
|
735
|
+
return `## Watch out for
|
|
736
|
+
|
|
737
|
+
${gotchas.map((g) => `- ${g}`).join("\n")}`;
|
|
738
|
+
}
|
|
695
739
|
function buildSimplePrompt(opts) {
|
|
696
|
-
const { stack, intent, contextFiles, gitContext, injections, projectInstructions } = opts;
|
|
740
|
+
const { stack, intent, contextFiles, gitContext, injections, projectInstructions, assumptions = [], gotchas = [] } = opts;
|
|
697
741
|
const sections = [];
|
|
742
|
+
const versionHeader = buildVersionHeader(opts);
|
|
743
|
+
if (versionHeader) sections.push(versionHeader);
|
|
698
744
|
if (projectInstructions) {
|
|
699
745
|
sections.push(`## Project Instructions
|
|
700
746
|
|
|
@@ -710,6 +756,10 @@ ${buildTaskDescription(intent)}`);
|
|
|
710
756
|
sections.push(`## Requirements
|
|
711
757
|
|
|
712
758
|
${rules.map((r) => `- ${r}`).join("\n")}`);
|
|
759
|
+
const assumptionsSection = buildAssumptionsSection(assumptions);
|
|
760
|
+
if (assumptionsSection) sections.push(assumptionsSection);
|
|
761
|
+
const gotchasSection = buildGotchasSection(gotchas);
|
|
762
|
+
if (gotchasSection) sections.push(gotchasSection);
|
|
713
763
|
if (gitContext) {
|
|
714
764
|
sections.push(`## Recent Changes
|
|
715
765
|
|
|
@@ -726,8 +776,10 @@ ${buildOutputFormat(intent)}`);
|
|
|
726
776
|
return sections.join("\n\n---\n\n");
|
|
727
777
|
}
|
|
728
778
|
function buildFeaturePrompt(opts) {
|
|
729
|
-
const { stack, structure, intent, contextFiles, gitContext, injections, projectInstructions } = opts;
|
|
779
|
+
const { stack, structure, intent, contextFiles, gitContext, injections, projectInstructions, assumptions = [], gotchas = [] } = opts;
|
|
730
780
|
const sections = [];
|
|
781
|
+
const versionHeader = buildVersionHeader(opts);
|
|
782
|
+
if (versionHeader) sections.push(versionHeader);
|
|
731
783
|
if (projectInstructions) {
|
|
732
784
|
sections.push(`## Project Instructions
|
|
733
785
|
|
|
@@ -752,6 +804,10 @@ ${buildTaskDescription(intent)}`);
|
|
|
752
804
|
sections.push(`## Requirements
|
|
753
805
|
|
|
754
806
|
${requirementLines}`);
|
|
807
|
+
const assumptionsSection = buildAssumptionsSection(assumptions);
|
|
808
|
+
if (assumptionsSection) sections.push(assumptionsSection);
|
|
809
|
+
const gotchasSection = buildGotchasSection(gotchas);
|
|
810
|
+
if (gotchasSection) sections.push(gotchasSection);
|
|
755
811
|
if (gitContext) {
|
|
756
812
|
sections.push(`## Recent Changes
|
|
757
813
|
|
|
@@ -768,8 +824,10 @@ ${buildOutputFormat(intent)}`);
|
|
|
768
824
|
return sections.join("\n\n---\n\n");
|
|
769
825
|
}
|
|
770
826
|
function buildSystemPrompt(opts) {
|
|
771
|
-
const { stack, structure, intent, contextFiles, gitContext, injections, projectInstructions } = opts;
|
|
827
|
+
const { stack, structure, intent, contextFiles, gitContext, injections, projectInstructions, assumptions = [], gotchas = [] } = opts;
|
|
772
828
|
const sections = [];
|
|
829
|
+
const versionHeader = buildVersionHeader(opts);
|
|
830
|
+
if (versionHeader) sections.push(versionHeader);
|
|
773
831
|
if (projectInstructions) {
|
|
774
832
|
sections.push(`## Project Instructions
|
|
775
833
|
|
|
@@ -794,6 +852,10 @@ ${buildTaskDescription(intent)}
|
|
|
794
852
|
sections.push(`## Requirements
|
|
795
853
|
|
|
796
854
|
${requirementLines}`);
|
|
855
|
+
const assumptionsSection = buildAssumptionsSection(assumptions);
|
|
856
|
+
if (assumptionsSection) sections.push(assumptionsSection);
|
|
857
|
+
const gotchasSection = buildGotchasSection(gotchas);
|
|
858
|
+
if (gotchasSection) sections.push(gotchasSection);
|
|
797
859
|
if (gitContext) {
|
|
798
860
|
sections.push(`## Recent Changes
|
|
799
861
|
|
|
@@ -886,10 +948,97 @@ function capitalize(s) {
|
|
|
886
948
|
return map[s] ?? s.charAt(0).toUpperCase() + s.slice(1);
|
|
887
949
|
}
|
|
888
950
|
|
|
951
|
+
// src/enhancer/domain-requirements.ts
|
|
952
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
953
|
+
async function generateDomainEnhancements(rawPrompt, intent, stack, angle, apiKey) {
|
|
954
|
+
const client = new Anthropic({ apiKey });
|
|
955
|
+
const stackSummary = [
|
|
956
|
+
stack.language === "typescript" ? "TypeScript" : "JavaScript",
|
|
957
|
+
...stack.frameworks,
|
|
958
|
+
stack.orm ? `ORM:${stack.orm}` : null,
|
|
959
|
+
stack.uiLibrary ? `UI:${stack.uiLibrary}` : null
|
|
960
|
+
].filter(Boolean).join(", ");
|
|
961
|
+
const system = `You are a senior software engineer specializing in ${intent.feature} systems.
|
|
962
|
+
Generate implementation requirements, assumptions, and gotchas for a specific task.
|
|
963
|
+
|
|
964
|
+
CRITICAL RULES for requirements:
|
|
965
|
+
1. Every requirement must be SPECIFIC to this exact task \u2014 not generic boilerplate
|
|
966
|
+
2. Ask: "Would this sentence appear in a prompt about a completely different feature?" If yes \u2192 discard
|
|
967
|
+
3. Angle focus: ${getAngleFocus(angle)}
|
|
968
|
+
|
|
969
|
+
REJECTED examples (too generic \u2014 never include):
|
|
970
|
+
- "Use TypeScript throughout \u2014 no any"
|
|
971
|
+
- "Handle errors explicitly"
|
|
972
|
+
- "Keep components small and focused"
|
|
973
|
+
- "Follow best practices"
|
|
974
|
+
|
|
975
|
+
GOOD examples (specific, expert-level):
|
|
976
|
+
- "Stripe webhooks fire multiple times \u2014 use idempotency keys keyed on event.id to prevent double-processing"
|
|
977
|
+
- "Store payment_intent_id not charge_id \u2014 charge IDs change on retries"
|
|
978
|
+
- "JWT refresh tokens must be rotated on every use to prevent token theft via stolen refresh token reuse"
|
|
979
|
+
|
|
980
|
+
Return ONLY valid JSON \u2014 no markdown, no prose:
|
|
981
|
+
{
|
|
982
|
+
"requirements": ["...", "..."], // 10-13 specific items
|
|
983
|
+
"assumptions": ["Assumed ...", "Assumed ..."], // 3-5 items starting with "Assumed"
|
|
984
|
+
"gotchas": ["gotcha description", "..."] // 2-3 non-obvious things that WILL bite
|
|
985
|
+
}`;
|
|
986
|
+
const user = `Task: "${rawPrompt}"
|
|
987
|
+
Domain: ${intent.feature}
|
|
988
|
+
Stack: ${stackSummary}
|
|
989
|
+
Action: ${intent.action} | Entity: ${intent.entity}
|
|
990
|
+
|
|
991
|
+
Generate requirements, assumptions, and gotchas. JSON only.`;
|
|
992
|
+
const response = await client.messages.create({
|
|
993
|
+
model: "claude-haiku-4-5-20251001",
|
|
994
|
+
max_tokens: 1536,
|
|
995
|
+
system,
|
|
996
|
+
messages: [{ role: "user", content: user }]
|
|
997
|
+
});
|
|
998
|
+
const text = response.content[0]?.type === "text" ? response.content[0].text : "{}";
|
|
999
|
+
try {
|
|
1000
|
+
const parsed = JSON.parse(text);
|
|
1001
|
+
if (Array.isArray(parsed.requirements) && parsed.requirements.length > 0) {
|
|
1002
|
+
return {
|
|
1003
|
+
requirements: parsed.requirements,
|
|
1004
|
+
assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],
|
|
1005
|
+
gotchas: Array.isArray(parsed.gotchas) ? parsed.gotchas : []
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
throw new Error("empty requirements");
|
|
1009
|
+
} catch {
|
|
1010
|
+
const jsonMatch = text.match(/\{[\s\S]*\}/);
|
|
1011
|
+
if (jsonMatch) {
|
|
1012
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
1013
|
+
return {
|
|
1014
|
+
requirements: Array.isArray(parsed.requirements) ? parsed.requirements : [],
|
|
1015
|
+
assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],
|
|
1016
|
+
gotchas: Array.isArray(parsed.gotchas) ? parsed.gotchas : []
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
throw new Error("Failed to parse domain enhancements from AI response");
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
889
1023
|
// src/enhancer/index.ts
|
|
890
|
-
function enhance(rawPrompt, scan, contextFiles, projectInstructions = "", gitContext = "", intentOverride, config) {
|
|
1024
|
+
async function enhance(rawPrompt, scan, contextFiles, projectInstructions = "", gitContext = "", intentOverride, config, iteration = 0, _previousPrompt) {
|
|
891
1025
|
const intent = intentOverride ?? analyzeIntent(rawPrompt);
|
|
892
|
-
const
|
|
1026
|
+
const angle = getAngle(iteration);
|
|
1027
|
+
let injections;
|
|
1028
|
+
let assumptions = [];
|
|
1029
|
+
let gotchas = [];
|
|
1030
|
+
if (config?.apiKey) {
|
|
1031
|
+
try {
|
|
1032
|
+
const domain = await generateDomainEnhancements(rawPrompt, intent, scan.stack, angle, config.apiKey);
|
|
1033
|
+
injections = domain.requirements;
|
|
1034
|
+
assumptions = domain.assumptions;
|
|
1035
|
+
gotchas = domain.gotchas;
|
|
1036
|
+
} catch {
|
|
1037
|
+
injections = getFallbackInjections(scan.stack, intent, config);
|
|
1038
|
+
}
|
|
1039
|
+
} else {
|
|
1040
|
+
injections = getFallbackInjections(scan.stack, intent, config);
|
|
1041
|
+
}
|
|
893
1042
|
const enhanced = buildEnhancedPrompt({
|
|
894
1043
|
stack: scan.stack,
|
|
895
1044
|
structure: scan.structure,
|
|
@@ -897,15 +1046,19 @@ function enhance(rawPrompt, scan, contextFiles, projectInstructions = "", gitCon
|
|
|
897
1046
|
contextFiles,
|
|
898
1047
|
injections,
|
|
899
1048
|
projectInstructions,
|
|
900
|
-
gitContext
|
|
1049
|
+
gitContext,
|
|
1050
|
+
angle,
|
|
1051
|
+
assumptions,
|
|
1052
|
+
gotchas,
|
|
1053
|
+
iteration
|
|
901
1054
|
});
|
|
902
|
-
return { original: rawPrompt, enhanced, intent, stack: scan.stack };
|
|
1055
|
+
return { original: rawPrompt, enhanced, intent, stack: scan.stack, iteration, angle: ANGLE_LABELS[angle] };
|
|
903
1056
|
}
|
|
904
1057
|
|
|
905
1058
|
// src/enhancer/planner.ts
|
|
906
|
-
import
|
|
1059
|
+
import Anthropic2 from "@anthropic-ai/sdk";
|
|
907
1060
|
async function decomposeToPlan(rawPrompt, intent, stack, apiKey) {
|
|
908
|
-
const client = new
|
|
1061
|
+
const client = new Anthropic2({ apiKey });
|
|
909
1062
|
const stackSummary = `${stack.frameworks.join(", ")} / ${stack.language}`;
|
|
910
1063
|
const systemPrompt = `You are a software architect. Break complex development tasks into sequential, focused implementation steps.
|
|
911
1064
|
Each step should be small enough to implement in a single AI session.
|
|
@@ -952,7 +1105,7 @@ Rules:
|
|
|
952
1105
|
}
|
|
953
1106
|
|
|
954
1107
|
// src/providers/claude.ts
|
|
955
|
-
import
|
|
1108
|
+
import Anthropic3 from "@anthropic-ai/sdk";
|
|
956
1109
|
var MODEL_BY_COMPLEXITY = {
|
|
957
1110
|
simple: "claude-haiku-4-5-20251001",
|
|
958
1111
|
feature: "claude-sonnet-4-6",
|
|
@@ -969,7 +1122,7 @@ var ClaudeProvider = class {
|
|
|
969
1122
|
"ANTHROPIC_API_KEY environment variable is not set."
|
|
970
1123
|
);
|
|
971
1124
|
}
|
|
972
|
-
this.client = new
|
|
1125
|
+
this.client = new Anthropic3({ apiKey: config.apiKey });
|
|
973
1126
|
this.model = config.model;
|
|
974
1127
|
}
|
|
975
1128
|
async send(prompt, options) {
|
|
@@ -1230,7 +1383,7 @@ Examples:
|
|
|
1230
1383
|
enhance "fix the auth bug" --dry-run
|
|
1231
1384
|
enhance "create dashboard" --confirm --verbose
|
|
1232
1385
|
enhance "refactor user service" --provider codex
|
|
1233
|
-
enhance "add auth" --action add --feature auth`).option("-p, --provider <name>", "AI provider: claude | codex | opencode").option("--dry-run", "Print enhanced prompt without sending to AI").option("--print-prompt", "Print enhanced prompt before sending to AI").option("--preview", "Color-coded prompt preview with per-section token counts").option("--verbose", "Show detected stack, intent, and context stats").option("--confirm", "Show detected intent and ask for approval before enhancing").option("--plan", "Decompose complex task into sequential sub-prompts (uses AI)").option("--action <action>", "Override detected action (create|fix|refactor|explain|add|delete)").option("--entity <entity>", "Override detected entity (page|component|api|hook|util|config|style)").option("--feature <feature>", "Override detected feature (auth|payment|user|upload|...)").action(async (rawPrompt, opts) => {
|
|
1386
|
+
enhance "add auth" --action add --feature auth`).option("-p, --provider <name>", "AI provider: claude | codex | opencode").option("--dry-run", "Print enhanced prompt without sending to AI").option("--print-prompt", "Print enhanced prompt before sending to AI").option("--preview", "Color-coded prompt preview with per-section token counts").option("--verbose", "Show detected stack, intent, and context stats").option("--confirm", "Show detected intent and ask for approval before enhancing").option("--plan", "Decompose complex task into sequential sub-prompts (uses AI)").option("--iteration <n>", "Angle iteration: 0=completeness, 1=production, 2=dx, 3=alternative", "0").option("--action <action>", "Override detected action (create|fix|refactor|explain|add|delete)").option("--entity <entity>", "Override detected entity (page|component|api|hook|util|config|style)").option("--feature <feature>", "Override detected feature (auth|payment|user|upload|...)").action(async (rawPrompt, opts) => {
|
|
1234
1387
|
if (!rawPrompt) {
|
|
1235
1388
|
program.help();
|
|
1236
1389
|
return;
|
|
@@ -1301,8 +1454,14 @@ Examples:
|
|
|
1301
1454
|
spinner.start("Enhancing prompt...");
|
|
1302
1455
|
}
|
|
1303
1456
|
spinner.text = "Enhancing prompt...";
|
|
1304
|
-
const
|
|
1457
|
+
const iteration = Math.max(0, parseInt(opts.iteration ?? "0", 10) || 0);
|
|
1458
|
+
const enhanced = await enhance(rawPrompt, scan, contextFiles, projectInstructions, gitContext, intent, config, iteration);
|
|
1305
1459
|
spinner.stop();
|
|
1460
|
+
if (enhanced.angle) {
|
|
1461
|
+
console.log(chalk3.dim(`
|
|
1462
|
+
\u{1F4CD} v${iteration + 1} \u2014 ${enhanced.angle} angle
|
|
1463
|
+
`));
|
|
1464
|
+
}
|
|
1306
1465
|
if (opts.preview) {
|
|
1307
1466
|
printColoredPreview(enhanced.enhanced);
|
|
1308
1467
|
if (opts.dryRun) process.exit(0);
|