@agentbridge1/cli 0.0.10 → 0.0.11
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/build-info.json +3 -3
- package/dist/commands/watch.js +116 -9
- package/dist/contract-intelligence.js +45 -18
- package/dist/contract-verdict.js +9 -2
- package/dist/domain-keywords.js +119 -0
- package/dist/index.js +4 -0
- package/dist/intent-parser.js +8 -20
- package/dist/mcp/agentbridge-mcp.js +124 -26
- package/dist/mcp/agentbridge-mcp.js.map +4 -4
- package/dist/proof-parser.js +24 -25
- package/dist/test-runner.js +134 -46
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"builtAt": "2026-06-
|
|
3
|
-
"gitHead": "
|
|
4
|
-
"sourceLatestMtime": "2026-06-
|
|
2
|
+
"builtAt": "2026-06-21T02:05:47.707Z",
|
|
3
|
+
"gitHead": "09300d7",
|
|
4
|
+
"sourceLatestMtime": "2026-06-21T01:45:03.790Z",
|
|
5
5
|
"sourceLatestFile": "src/commands/watch.ts"
|
|
6
6
|
}
|
package/dist/commands/watch.js
CHANGED
|
@@ -648,9 +648,12 @@ async function buildAutoVerifyIssueForFiles(files, options) {
|
|
|
648
648
|
? `\nNote: ${coherence.suspiciousFiles.length} file(s) may not match your declared intent ("${options.intent}"). Check: ${coherence.suspiciousFiles.slice(0, 3).join(", ")}`
|
|
649
649
|
: "";
|
|
650
650
|
if (testResult.passed) {
|
|
651
|
+
const fallbackNote = testResult.fallbackUsed
|
|
652
|
+
? "\nScoped test selection could not run cleanly; AgentBridge fell back to the full verify command."
|
|
653
|
+
: "";
|
|
651
654
|
return {
|
|
652
655
|
errorCode: "AUTO_VERIFIED",
|
|
653
|
-
whatHappened: `AgentBridge ran tests and they passed (${testResult.command}).` + driftWarning,
|
|
656
|
+
whatHappened: `AgentBridge ran tests and they passed (${testResult.command}).` + fallbackNote + driftWarning,
|
|
654
657
|
whyItMatters: coherence.verdict === "drift"
|
|
655
658
|
? "Tests passed, but some changed files look unrelated to your stated intent — review the scope."
|
|
656
659
|
: "Automated verification confirms the changes are safe.",
|
|
@@ -664,18 +667,94 @@ async function buildAutoVerifyIssueForFiles(files, options) {
|
|
|
664
667
|
coherence,
|
|
665
668
|
};
|
|
666
669
|
}
|
|
670
|
+
const failureType = testResult.failureType ?? "test_failures";
|
|
667
671
|
const failedNames = (0, test_runner_1.extractFailedTestNames)(testResult.stdout + "\n" + testResult.stderr);
|
|
668
672
|
const failureSummary = failedNames.length > 0
|
|
669
673
|
? `Failing: ${failedNames.slice(0, 3).join(", ")}${failedNames.length > 3 ? ` (+${failedNames.length - 3} more)` : ""}`
|
|
670
|
-
: "Check
|
|
674
|
+
: "Check verification output for details.";
|
|
675
|
+
const firstErrorLine = (testResult.stderr.split("\n").find((line) => line.trim().length > 0) ??
|
|
676
|
+
testResult.stdout.split("\n").find((line) => line.trim().length > 0) ??
|
|
677
|
+
"No diagnostic output captured.").trim();
|
|
678
|
+
const fallbackHint = testResult.fallbackUsed
|
|
679
|
+
? "AgentBridge retried with the broader verify command after scoped verification failed."
|
|
680
|
+
: "";
|
|
681
|
+
if (failureType === "command_invalid") {
|
|
682
|
+
return {
|
|
683
|
+
errorCode: "TEST_COMMAND_INVALID",
|
|
684
|
+
whatHappened: `AgentBridge could not run verification command due to an invalid flag/argument (${testResult.command}).` +
|
|
685
|
+
driftWarning,
|
|
686
|
+
whyItMatters: "This is a verification command configuration issue, so test pass/fail status is unknown.",
|
|
687
|
+
files: uniqueFiles,
|
|
688
|
+
suggestedPrompt: [
|
|
689
|
+
"AgentBridge could not execute verification because the command arguments are invalid.",
|
|
690
|
+
`Diagnostic: ${firstErrorLine}`,
|
|
691
|
+
fallbackHint,
|
|
692
|
+
options.intent ? `Your declared intent: "${options.intent}"` : "",
|
|
693
|
+
"Fix the verification command/config and rerun AgentBridge watch.",
|
|
694
|
+
`Files changed: ${summarizeWatchPromptFiles(uniqueFiles)}`,
|
|
695
|
+
]
|
|
696
|
+
.filter(Boolean)
|
|
697
|
+
.join("\n"),
|
|
698
|
+
nextAction: "Fix verification command flags/options, then rerun: agentbridge watch",
|
|
699
|
+
testResult,
|
|
700
|
+
intent: options.intent,
|
|
701
|
+
coherence,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
if (failureType === "tooling_missing") {
|
|
705
|
+
return {
|
|
706
|
+
errorCode: "TEST_TOOLING_MISSING",
|
|
707
|
+
whatHappened: `AgentBridge could not run verification because required test tooling is missing (${testResult.command}).` +
|
|
708
|
+
driftWarning,
|
|
709
|
+
whyItMatters: "Without test tooling, AgentBridge cannot produce reliable verification evidence for this change.",
|
|
710
|
+
files: uniqueFiles,
|
|
711
|
+
suggestedPrompt: [
|
|
712
|
+
"AgentBridge could not execute verification because test tooling is missing.",
|
|
713
|
+
`Diagnostic: ${firstErrorLine}`,
|
|
714
|
+
fallbackHint,
|
|
715
|
+
options.intent ? `Your declared intent: "${options.intent}"` : "",
|
|
716
|
+
"Install/restore required tooling and rerun AgentBridge watch.",
|
|
717
|
+
`Files changed: ${summarizeWatchPromptFiles(uniqueFiles)}`,
|
|
718
|
+
]
|
|
719
|
+
.filter(Boolean)
|
|
720
|
+
.join("\n"),
|
|
721
|
+
nextAction: "Install missing test tooling/dependencies, then rerun: agentbridge watch",
|
|
722
|
+
testResult,
|
|
723
|
+
intent: options.intent,
|
|
724
|
+
coherence,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
if (failureType === "timeout") {
|
|
728
|
+
return {
|
|
729
|
+
errorCode: "TEST_TIMEOUT",
|
|
730
|
+
whatHappened: `AgentBridge verification timed out (${testResult.command}).` + driftWarning,
|
|
731
|
+
whyItMatters: "Timed-out verification provides no reliable proof for these changes.",
|
|
732
|
+
files: uniqueFiles,
|
|
733
|
+
suggestedPrompt: [
|
|
734
|
+
"AgentBridge verification timed out before tests completed.",
|
|
735
|
+
`Diagnostic: ${firstErrorLine}`,
|
|
736
|
+
fallbackHint,
|
|
737
|
+
options.intent ? `Your declared intent: "${options.intent}"` : "",
|
|
738
|
+
"Narrow the test scope or increase verify timeout, then rerun AgentBridge watch.",
|
|
739
|
+
`Files changed: ${summarizeWatchPromptFiles(uniqueFiles)}`,
|
|
740
|
+
]
|
|
741
|
+
.filter(Boolean)
|
|
742
|
+
.join("\n"),
|
|
743
|
+
nextAction: "Reduce scope or increase verify timeout, then rerun: agentbridge watch",
|
|
744
|
+
testResult,
|
|
745
|
+
intent: options.intent,
|
|
746
|
+
coherence,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
671
749
|
return {
|
|
672
750
|
errorCode: "TEST_FAILED",
|
|
673
|
-
whatHappened: `AgentBridge ran \`${testResult.command}\` and
|
|
751
|
+
whatHappened: `AgentBridge ran \`${testResult.command}\` and tests failed.` +
|
|
674
752
|
driftWarning,
|
|
675
753
|
whyItMatters: "These test failures must be fixed before the changes can be trusted.",
|
|
676
754
|
files: uniqueFiles,
|
|
677
755
|
suggestedPrompt: [
|
|
678
756
|
"AgentBridge ran tests and found failures.",
|
|
757
|
+
fallbackHint,
|
|
679
758
|
failureSummary,
|
|
680
759
|
options.intent ? `Your declared intent: "${options.intent}"` : "",
|
|
681
760
|
"Fix the failing tests, then rerun AgentBridge watch.",
|
|
@@ -875,19 +954,44 @@ function renderWatchBlockingIssue(issue) {
|
|
|
875
954
|
].join("\n");
|
|
876
955
|
}
|
|
877
956
|
// ── Test run failed ───────────────────────────────────────────────────────
|
|
878
|
-
if (issue.errorCode === "TEST_FAILED"
|
|
957
|
+
if ((issue.errorCode === "TEST_FAILED" ||
|
|
958
|
+
issue.errorCode === "TEST_TIMEOUT" ||
|
|
959
|
+
issue.errorCode === "TEST_COMMAND_INVALID" ||
|
|
960
|
+
issue.errorCode === "TEST_TOOLING_MISSING") &&
|
|
961
|
+
issue.testResult) {
|
|
879
962
|
const dur = (issue.testResult.durationMs / 1000).toFixed(1);
|
|
880
963
|
const failedNames = (0, test_runner_1.extractFailedTestNames)(issue.testResult.stdout + "\n" + issue.testResult.stderr);
|
|
964
|
+
const firstDiagnosticLine = (issue.testResult.stderr.split("\n").find((line) => line.trim().length > 0) ??
|
|
965
|
+
issue.testResult.stdout.split("\n").find((line) => line.trim().length > 0) ??
|
|
966
|
+
"No diagnostic output captured.").trim();
|
|
881
967
|
const failureLines = failedNames.length > 0
|
|
882
968
|
? failedNames.slice(0, 5).map((n) => ` ✗ ${n}`).join("\n")
|
|
883
|
-
:
|
|
969
|
+
: issue.errorCode === "TEST_COMMAND_INVALID" ||
|
|
970
|
+
issue.errorCode === "TEST_TOOLING_MISSING" ||
|
|
971
|
+
issue.errorCode === "TEST_TIMEOUT"
|
|
972
|
+
? ` ${firstDiagnosticLine}`
|
|
973
|
+
: " (check test output above for details)";
|
|
884
974
|
const moreFailures = failedNames.length > 5 ? `\n (+${failedNames.length - 5} more)` : "";
|
|
885
975
|
const hasDrift = issue.coherence?.verdict === "drift";
|
|
886
976
|
const fileList = issue.files.slice(0, 8).join("\n ");
|
|
887
977
|
const moreFiles = issue.files.length > 8 ? `\n (+${issue.files.length - 8} more)` : "";
|
|
888
|
-
const timedOutNote = issue.testResult.
|
|
978
|
+
const timedOutNote = issue.testResult.failureType === "timeout"
|
|
889
979
|
? `\n ⚠ Timed out after ${(issue.testResult.durationMs / 1000).toFixed(0)}s — increase verify.timeoutMs in .agentbridge.json`
|
|
890
980
|
: "";
|
|
981
|
+
const outcomeLabel = issue.errorCode === "TEST_COMMAND_INVALID"
|
|
982
|
+
? "⚠ Verification command invalid"
|
|
983
|
+
: issue.errorCode === "TEST_TOOLING_MISSING"
|
|
984
|
+
? "⚠ Verification tooling missing"
|
|
985
|
+
: issue.errorCode === "TEST_TIMEOUT"
|
|
986
|
+
? "✗ Verification timed out"
|
|
987
|
+
: "✗ Tests failed";
|
|
988
|
+
const stepOne = issue.errorCode === "TEST_COMMAND_INVALID"
|
|
989
|
+
? " 1. Fix the verification command flags/options shown above."
|
|
990
|
+
: issue.errorCode === "TEST_TOOLING_MISSING"
|
|
991
|
+
? " 1. Install/fix required test tooling for the verification command."
|
|
992
|
+
: issue.errorCode === "TEST_TIMEOUT"
|
|
993
|
+
? " 1. Narrow test scope or increase verification timeout."
|
|
994
|
+
: " 1. Fix the failing tests listed above.";
|
|
891
995
|
return [
|
|
892
996
|
sep,
|
|
893
997
|
" AgentBridge Verification Report",
|
|
@@ -908,14 +1012,14 @@ function renderWatchBlockingIssue(issue) {
|
|
|
908
1012
|
"🔬 WHAT WE RAN",
|
|
909
1013
|
` Command : ${issue.testResult.command}`,
|
|
910
1014
|
` Duration: ${dur}s${timedOutNote}`,
|
|
911
|
-
` Outcome :
|
|
1015
|
+
` Outcome : ${outcomeLabel}`,
|
|
912
1016
|
"",
|
|
913
1017
|
"❌ WHAT WE FOUND",
|
|
914
1018
|
failureLines + moreFailures,
|
|
915
1019
|
...(hasDrift ? ["", ` Scope note: ${issue.whyItMatters}`] : []),
|
|
916
1020
|
"",
|
|
917
1021
|
"➡ NEXT STEPS",
|
|
918
|
-
|
|
1022
|
+
stepOne,
|
|
919
1023
|
...(hasDrift ? [" 2. Review the out-of-scope files — are they intentional?"] : []),
|
|
920
1024
|
` ${hasDrift ? "3" : "2"}. Re-run: agentbridge watch`,
|
|
921
1025
|
"",
|
|
@@ -2552,7 +2656,10 @@ async function runWatch(options = {}) {
|
|
|
2552
2656
|
nextAction: onceModeVerificationIssue.nextAction,
|
|
2553
2657
|
};
|
|
2554
2658
|
}
|
|
2555
|
-
else if (onceModeVerificationIssue?.errorCode === "TEST_FAILED"
|
|
2659
|
+
else if (onceModeVerificationIssue?.errorCode === "TEST_FAILED" ||
|
|
2660
|
+
onceModeVerificationIssue?.errorCode === "TEST_TIMEOUT" ||
|
|
2661
|
+
onceModeVerificationIssue?.errorCode === "TEST_COMMAND_INVALID" ||
|
|
2662
|
+
onceModeVerificationIssue?.errorCode === "TEST_TOOLING_MISSING") {
|
|
2556
2663
|
supervision = {
|
|
2557
2664
|
...supervision,
|
|
2558
2665
|
decision: "failed",
|
|
@@ -15,6 +15,7 @@ const intent_parser_1 = require("./intent-parser");
|
|
|
15
15
|
const proof_parser_1 = require("./proof-parser");
|
|
16
16
|
const diff_reader_1 = require("./diff-reader");
|
|
17
17
|
const session_state_1 = require("./session-state");
|
|
18
|
+
const domain_keywords_1 = require("./domain-keywords");
|
|
18
19
|
const MCP_RULE_PROFILE = "mcp_rules_config_install";
|
|
19
20
|
const AUTH_PROFILE = "auth_login_session";
|
|
20
21
|
const DB_PROFILE = "database_schema_migration";
|
|
@@ -26,32 +27,30 @@ const GENERIC_PROFILE = "generic";
|
|
|
26
27
|
function unique(values) {
|
|
27
28
|
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return keywords.some((keyword) => lower.includes(keyword));
|
|
32
|
-
}
|
|
30
|
+
const MCP_ENTITY_KEYWORDS = ["mcp", "agentbridge", "cursor"];
|
|
31
|
+
const MCP_ACTION_KEYWORDS = ["rule", "rules", "install", "setup", "config", "configuration"];
|
|
33
32
|
function detectProfiles(intent) {
|
|
34
33
|
const profiles = [];
|
|
35
|
-
if (
|
|
36
|
-
|
|
34
|
+
if ((0, domain_keywords_1.matchesAnyKeywordBoundary)(intent, MCP_ENTITY_KEYWORDS) &&
|
|
35
|
+
(0, domain_keywords_1.matchesAnyKeywordBoundary)(intent, MCP_ACTION_KEYWORDS)) {
|
|
37
36
|
profiles.push(MCP_RULE_PROFILE);
|
|
38
37
|
}
|
|
39
|
-
if (
|
|
38
|
+
if ((0, domain_keywords_1.matchesDomainKeywords)(intent, "auth")) {
|
|
40
39
|
profiles.push(AUTH_PROFILE);
|
|
41
40
|
}
|
|
42
|
-
if (
|
|
41
|
+
if ((0, domain_keywords_1.matchesDomainKeywords)(intent, "database")) {
|
|
43
42
|
profiles.push(DB_PROFILE);
|
|
44
43
|
}
|
|
45
|
-
if (
|
|
44
|
+
if ((0, domain_keywords_1.matchesDomainKeywords)(intent, "ui")) {
|
|
46
45
|
profiles.push(UI_PROFILE);
|
|
47
46
|
}
|
|
48
|
-
if (
|
|
47
|
+
if ((0, domain_keywords_1.matchesDomainKeywords)(intent, "api")) {
|
|
49
48
|
profiles.push(API_PROFILE);
|
|
50
49
|
}
|
|
51
|
-
if (
|
|
50
|
+
if ((0, domain_keywords_1.matchesDomainKeywords)(intent, "tests")) {
|
|
52
51
|
profiles.push(TEST_PROFILE);
|
|
53
52
|
}
|
|
54
|
-
if (
|
|
53
|
+
if ((0, domain_keywords_1.matchesDomainKeywords)(intent, "payments")) {
|
|
55
54
|
profiles.push(PAYMENTS_PROFILE);
|
|
56
55
|
}
|
|
57
56
|
return profiles.length > 0 ? profiles : [GENERIC_PROFILE];
|
|
@@ -229,6 +228,31 @@ function fileMatchesArea(file, area) {
|
|
|
229
228
|
const normalizedArea = area.replaceAll("\\", "/").trim();
|
|
230
229
|
if (!normalizedArea || normalizedArea === "**")
|
|
231
230
|
return true;
|
|
231
|
+
// Infix glob: src/**/auth/** — prefix path + directory segment(s), not substring hacks
|
|
232
|
+
if (normalizedArea.includes("**/")) {
|
|
233
|
+
const segments = normalizedArea.split("/**/");
|
|
234
|
+
if (segments.length >= 2) {
|
|
235
|
+
const prefix = segments[0].replace(/\/$/, "");
|
|
236
|
+
if (prefix && normalizedFile !== prefix && !normalizedFile.startsWith(`${prefix}/`)) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
const infixPattern = segments
|
|
240
|
+
.slice(1)
|
|
241
|
+
.join("/")
|
|
242
|
+
.replace(/\/\*\*$/, "")
|
|
243
|
+
.replace(/^\*\//, "");
|
|
244
|
+
if (!infixPattern || infixPattern === "*")
|
|
245
|
+
return true;
|
|
246
|
+
const infixParts = infixPattern.split("/").filter((part) => part && part !== "*");
|
|
247
|
+
for (const part of infixParts) {
|
|
248
|
+
const asDir = `/${part}/`;
|
|
249
|
+
const atEnd = normalizedFile.endsWith(`/${part}`);
|
|
250
|
+
if (!normalizedFile.includes(asDir) && !atEnd)
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
232
256
|
if (normalizedArea.endsWith("/**")) {
|
|
233
257
|
const prefix = normalizedArea.slice(0, -3);
|
|
234
258
|
return normalizedFile === prefix || normalizedFile.startsWith(`${prefix}/`);
|
|
@@ -495,20 +519,23 @@ function evaluateCompletionCriteria(params) {
|
|
|
495
519
|
});
|
|
496
520
|
}
|
|
497
521
|
function nextStepFromCriteria(evaluations, proofNeeded) {
|
|
498
|
-
const
|
|
499
|
-
|
|
522
|
+
const unproven = evaluations.filter((item) => item.status === "no_evidence" ||
|
|
523
|
+
item.status === "partial_evidence" ||
|
|
524
|
+
item.status === "cannot_verify");
|
|
525
|
+
if (unproven.length === 0) {
|
|
500
526
|
return "All tracked criteria are evidenced. Confirm final proof and commit when ready.";
|
|
501
527
|
}
|
|
502
528
|
// Prioritise idempotency if it is anywhere in the unproven list
|
|
503
|
-
const idempotency =
|
|
529
|
+
const idempotency = unproven.find((item) => item.criterion.toLowerCase().includes("idempotent"));
|
|
504
530
|
if (idempotency) {
|
|
505
531
|
return "Run setup/configuration twice in a clean repo and record output proving idempotency.";
|
|
506
532
|
}
|
|
507
|
-
const
|
|
508
|
-
if (
|
|
533
|
+
const proofGap = unproven.find((item) => item.criterion.toLowerCase().includes("proof"));
|
|
534
|
+
if (proofGap) {
|
|
509
535
|
return proofNeeded[0] ?? "Run a relevant test/manual proof command and record output.";
|
|
510
536
|
}
|
|
511
|
-
|
|
537
|
+
const firstUnproven = unproven[0];
|
|
538
|
+
return `${firstUnproven?.criterion ?? "Missing evidence"} — capture concrete proof before closing this contract.`;
|
|
512
539
|
}
|
|
513
540
|
function renderLiveExpectationSummary(contract) {
|
|
514
541
|
const lines = ["AgentBridge expects evidence for:"];
|
package/dist/contract-verdict.js
CHANGED
|
@@ -207,7 +207,9 @@ function renderContractVerdict(session, changedFiles, proofRun, domains = []) {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
const stillUnproven = criteriaEvals
|
|
210
|
-
? criteriaEvals.filter((e) => e.status === "no_evidence"
|
|
210
|
+
? criteriaEvals.filter((e) => e.status === "no_evidence" ||
|
|
211
|
+
e.status === "partial_evidence" ||
|
|
212
|
+
e.status === "cannot_verify")
|
|
211
213
|
: [];
|
|
212
214
|
lines.push("", "Here's what is still unproven:");
|
|
213
215
|
if (stillUnproven.length === 0 && (!criteriaEvals || criteriaEvals.length === 0)) {
|
|
@@ -218,7 +220,12 @@ function renderContractVerdict(session, changedFiles, proofRun, domains = []) {
|
|
|
218
220
|
}
|
|
219
221
|
else {
|
|
220
222
|
for (const e of stillUnproven) {
|
|
221
|
-
|
|
223
|
+
const prefix = e.status === "partial_evidence"
|
|
224
|
+
? "~"
|
|
225
|
+
: e.status === "cannot_verify"
|
|
226
|
+
? "?"
|
|
227
|
+
: "✗";
|
|
228
|
+
lines.push(` ${prefix} [${e.status}] ${e.criterion}`);
|
|
222
229
|
lines.push(` ${e.evidence}`);
|
|
223
230
|
}
|
|
224
231
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DOMAIN_KEYWORDS = void 0;
|
|
4
|
+
exports.matchesKeywordBoundary = matchesKeywordBoundary;
|
|
5
|
+
exports.matchesAnyKeywordBoundary = matchesAnyKeywordBoundary;
|
|
6
|
+
exports.matchesDomainKeywords = matchesDomainKeywords;
|
|
7
|
+
exports.detectDomainFromKeywords = detectDomainFromKeywords;
|
|
8
|
+
exports.DOMAIN_KEYWORDS = {
|
|
9
|
+
auth: [
|
|
10
|
+
"auth",
|
|
11
|
+
"login",
|
|
12
|
+
"logout",
|
|
13
|
+
"session",
|
|
14
|
+
"token",
|
|
15
|
+
"oauth",
|
|
16
|
+
"jwt",
|
|
17
|
+
"password",
|
|
18
|
+
"signin",
|
|
19
|
+
"sign-in",
|
|
20
|
+
"signup",
|
|
21
|
+
"sign-up",
|
|
22
|
+
"register",
|
|
23
|
+
"registration",
|
|
24
|
+
"credential",
|
|
25
|
+
"credentials",
|
|
26
|
+
"permission",
|
|
27
|
+
"permissions",
|
|
28
|
+
"role",
|
|
29
|
+
"roles",
|
|
30
|
+
"unauthorized",
|
|
31
|
+
"unauthenticated",
|
|
32
|
+
"authenticate",
|
|
33
|
+
"authentication",
|
|
34
|
+
"authorize",
|
|
35
|
+
"authorization",
|
|
36
|
+
],
|
|
37
|
+
database: [
|
|
38
|
+
"database",
|
|
39
|
+
"db",
|
|
40
|
+
"schema",
|
|
41
|
+
"migration",
|
|
42
|
+
"migrate",
|
|
43
|
+
"prisma",
|
|
44
|
+
"sql",
|
|
45
|
+
"query",
|
|
46
|
+
"table",
|
|
47
|
+
"column",
|
|
48
|
+
"index",
|
|
49
|
+
"model",
|
|
50
|
+
"entity",
|
|
51
|
+
"seed",
|
|
52
|
+
"orm",
|
|
53
|
+
],
|
|
54
|
+
payments: [
|
|
55
|
+
"payment",
|
|
56
|
+
"payments",
|
|
57
|
+
"billing",
|
|
58
|
+
"stripe",
|
|
59
|
+
"invoice",
|
|
60
|
+
"subscription",
|
|
61
|
+
"checkout",
|
|
62
|
+
"webhook",
|
|
63
|
+
"charge",
|
|
64
|
+
],
|
|
65
|
+
api: ["api", "endpoint", "route", "handler", "controller", "request", "response", "rest", "graphql"],
|
|
66
|
+
ui: [
|
|
67
|
+
"ui",
|
|
68
|
+
"style",
|
|
69
|
+
"css",
|
|
70
|
+
"component",
|
|
71
|
+
"page",
|
|
72
|
+
"layout",
|
|
73
|
+
"copy",
|
|
74
|
+
"design",
|
|
75
|
+
"render",
|
|
76
|
+
"display",
|
|
77
|
+
"view",
|
|
78
|
+
"frontend",
|
|
79
|
+
"html",
|
|
80
|
+
"template",
|
|
81
|
+
"dashboard",
|
|
82
|
+
"button",
|
|
83
|
+
"theme",
|
|
84
|
+
],
|
|
85
|
+
mcp: ["mcp", "agentbridge", "cursor", "rules", "configuration", "config", "setup", "install"],
|
|
86
|
+
tests: ["test", "tests", "spec", "vitest", "jest", "coverage", "proof"],
|
|
87
|
+
};
|
|
88
|
+
const BOUNDARY_ALNUM = "a-z0-9";
|
|
89
|
+
const REGEX_CACHE = new Map();
|
|
90
|
+
function escapeRegex(value) {
|
|
91
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
92
|
+
}
|
|
93
|
+
function keywordRegex(keyword) {
|
|
94
|
+
const normalized = keyword.trim().toLowerCase();
|
|
95
|
+
const cached = REGEX_CACHE.get(normalized);
|
|
96
|
+
if (cached)
|
|
97
|
+
return cached;
|
|
98
|
+
const pattern = `(^|[^${BOUNDARY_ALNUM}])${escapeRegex(normalized)}([^${BOUNDARY_ALNUM}]|$)`;
|
|
99
|
+
const compiled = new RegExp(pattern);
|
|
100
|
+
REGEX_CACHE.set(normalized, compiled);
|
|
101
|
+
return compiled;
|
|
102
|
+
}
|
|
103
|
+
function matchesKeywordBoundary(text, keyword) {
|
|
104
|
+
const normalizedText = text.toLowerCase();
|
|
105
|
+
return keywordRegex(keyword).test(normalizedText);
|
|
106
|
+
}
|
|
107
|
+
function matchesAnyKeywordBoundary(text, keywords) {
|
|
108
|
+
return keywords.some((keyword) => matchesKeywordBoundary(text, keyword));
|
|
109
|
+
}
|
|
110
|
+
function matchesDomainKeywords(text, domain) {
|
|
111
|
+
return matchesAnyKeywordBoundary(text, exports.DOMAIN_KEYWORDS[domain]);
|
|
112
|
+
}
|
|
113
|
+
function detectDomainFromKeywords(text, domainOrder = ["auth", "database", "payments", "api", "ui", "mcp", "tests"]) {
|
|
114
|
+
for (const domain of domainOrder) {
|
|
115
|
+
if (matchesDomainKeywords(text, domain))
|
|
116
|
+
return domain;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -262,6 +262,10 @@ async function main() {
|
|
|
262
262
|
if (command === "--help" || command === "help") {
|
|
263
263
|
usage(undefined, { exitCode: 0, stream: "stdout" });
|
|
264
264
|
}
|
|
265
|
+
if (command === "--version" || command === "-V" || command === "-v") {
|
|
266
|
+
(0, version_1.runVersion)();
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
265
269
|
// --help on any subcommand
|
|
266
270
|
if (flags["--help"] === "true") {
|
|
267
271
|
usage(command, { exitCode: 0, stream: "stdout" });
|
package/dist/intent-parser.js
CHANGED
|
@@ -1,28 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseIntent = parseIntent;
|
|
4
|
+
exports.buildTaskSpecificCriteria = buildTaskSpecificCriteria;
|
|
2
5
|
/**
|
|
3
6
|
* Intent parser — extracts structured task specification from a raw intent string.
|
|
4
7
|
* All logic is deterministic: no LLM, no external calls.
|
|
5
8
|
*/
|
|
6
|
-
|
|
7
|
-
exports.parseIntent = parseIntent;
|
|
8
|
-
exports.buildTaskSpecificCriteria = buildTaskSpecificCriteria;
|
|
9
|
+
const domain_keywords_1 = require("./domain-keywords");
|
|
9
10
|
const ACTIONS = ["fix", "add", "update", "refactor", "remove", "migrate", "rename", "revert", "delete", "implement", "improve", "patch"];
|
|
10
|
-
const DOMAIN_KEYWORD_MAP = {
|
|
11
|
-
auth: ["auth", "login", "logout", "session", "token", "oauth", "jwt", "password", "signin", "signup", "sign-in", "sign-up", "register", "credential", "permission", "role"],
|
|
12
|
-
database: ["database", "db", "schema", "migration", "migrate", "prisma", "sql", "query", "table", "column", "index", "model", "seed", "orm"],
|
|
13
|
-
payments: ["payment", "payments", "billing", "stripe", "invoice", "subscription", "checkout", "webhook"],
|
|
14
|
-
api: ["api", "endpoint", "route", "handler", "controller", "request", "response", "rest", "graphql"],
|
|
15
|
-
ui: ["ui", "style", "css", "component", "page", "layout", "copy", "design", "render", "display", "view", "frontend", "html", "template"],
|
|
16
|
-
mcp: ["mcp", "agentbridge", "cursor", "rules"],
|
|
17
|
-
tests: ["test", "tests", "spec", "vitest", "jest", "coverage", "proof"],
|
|
18
|
-
};
|
|
19
11
|
const SYMPTOMS = {
|
|
20
12
|
"401": ["401", "unauthorized", "unauthenticated"],
|
|
21
13
|
"403": ["403", "forbidden"],
|
|
22
14
|
"404": ["404", "not found", "notfound"],
|
|
23
15
|
"500": ["500", "internal server error", "server error"],
|
|
24
16
|
"null": ["null", "undefined", "nan", "nil"],
|
|
25
|
-
"crash": ["crash", "crashes", "crashed", "exception", "throws", "throw"],
|
|
17
|
+
"crash": ["crash", "crashes", "crashed", "crashing", "exception", "throws", "throw"],
|
|
26
18
|
"loop": ["loop", "infinite loop", "recursion"],
|
|
27
19
|
"hang": ["hang", "hangs", "timeout", "deadlock"],
|
|
28
20
|
"slow": ["slow", "performance", "latency", "memory leak", "memory"],
|
|
@@ -40,22 +32,18 @@ const CAMEL_FN_RE = /\b([a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)+)\b/g;
|
|
|
40
32
|
// Quoted phrase
|
|
41
33
|
const QUOTED_RE = /"([^"]+)"|'([^']+)'/g;
|
|
42
34
|
function detectDomain(lower) {
|
|
43
|
-
|
|
44
|
-
if (keywords.some((kw) => lower.includes(kw)))
|
|
45
|
-
return domain;
|
|
46
|
-
}
|
|
47
|
-
return null;
|
|
35
|
+
return (0, domain_keywords_1.detectDomainFromKeywords)(lower);
|
|
48
36
|
}
|
|
49
37
|
function detectAction(lower) {
|
|
50
38
|
for (const action of ACTIONS) {
|
|
51
|
-
if (
|
|
39
|
+
if ((0, domain_keywords_1.matchesKeywordBoundary)(lower, action))
|
|
52
40
|
return action;
|
|
53
41
|
}
|
|
54
42
|
return null;
|
|
55
43
|
}
|
|
56
44
|
function detectSymptom(lower) {
|
|
57
45
|
for (const [symptom, patterns] of Object.entries(SYMPTOMS)) {
|
|
58
|
-
if (
|
|
46
|
+
if ((0, domain_keywords_1.matchesAnyKeywordBoundary)(lower, patterns))
|
|
59
47
|
return symptom;
|
|
60
48
|
}
|
|
61
49
|
return null;
|