@triedotdev/mcp 1.0.140 → 1.0.142
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 +42 -7
- package/dist/{chunk-GXF6JOCN.js → chunk-4PAAGLKO.js} +7 -7
- package/dist/{chunk-OQ4A3RDY.js → chunk-N2EDZTKG.js} +6 -359
- package/dist/chunk-N2EDZTKG.js.map +1 -0
- package/dist/{chunk-75ADWWUF.js → chunk-T6PS3MXJ.js} +2 -2
- package/dist/{chunk-AF2APASP.js → chunk-V7AY2EJO.js} +4 -4
- package/dist/{chunk-UOSTOLU7.js → chunk-WMDFK7LI.js} +365 -10
- package/dist/chunk-WMDFK7LI.js.map +1 -0
- package/dist/{chunk-4O2KRHK4.js → chunk-Y2LYDCJD.js} +19 -19
- package/dist/cli/main.js +669 -441
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +9 -9
- package/dist/{codebase-index-5SEOESWM.js → codebase-index-FMIULFZQ.js} +3 -3
- package/dist/{fast-analyzer-AYLZB5TW.js → fast-analyzer-MWKCDRGD.js} +5 -5
- package/dist/{goal-validator-HNXXUCPW.js → goal-validator-DA3JQ6JN.js} +2 -2
- package/dist/index.js +91 -31
- package/dist/index.js.map +1 -1
- package/dist/{trie-agent-M6PHM6UD.js → trie-agent-6A7YBNTQ.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-OQ4A3RDY.js.map +0 -1
- package/dist/chunk-UOSTOLU7.js.map +0 -1
- /package/dist/{chunk-GXF6JOCN.js.map → chunk-4PAAGLKO.js.map} +0 -0
- /package/dist/{chunk-75ADWWUF.js.map → chunk-T6PS3MXJ.js.map} +0 -0
- /package/dist/{chunk-AF2APASP.js.map → chunk-V7AY2EJO.js.map} +0 -0
- /package/dist/{chunk-4O2KRHK4.js.map → chunk-Y2LYDCJD.js.map} +0 -0
- /package/dist/{codebase-index-5SEOESWM.js.map → codebase-index-FMIULFZQ.js.map} +0 -0
- /package/dist/{fast-analyzer-AYLZB5TW.js.map → fast-analyzer-MWKCDRGD.js.map} +0 -0
- /package/dist/{goal-validator-HNXXUCPW.js.map → goal-validator-DA3JQ6JN.js.map} +0 -0
- /package/dist/{trie-agent-M6PHM6UD.js.map → trie-agent-6A7YBNTQ.js.map} +0 -0
package/dist/cli/main.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
isTrieInitialized,
|
|
22
22
|
perceiveCurrentChanges,
|
|
23
23
|
reasonAboutChangesHumanReadable
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-4PAAGLKO.js";
|
|
25
25
|
import {
|
|
26
26
|
loadConfig,
|
|
27
27
|
saveConfig
|
|
@@ -32,22 +32,36 @@ import {
|
|
|
32
32
|
import "../chunk-ZV2K6M7T.js";
|
|
33
33
|
import {
|
|
34
34
|
GotchaPredictor,
|
|
35
|
+
SlackIntegration,
|
|
35
36
|
findCrossProjectPatterns,
|
|
36
37
|
getGlobalMemoryStats,
|
|
37
38
|
listTrackedProjects,
|
|
38
39
|
searchGlobalPatterns,
|
|
39
40
|
updateGlobalMemoryMd
|
|
40
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-WMDFK7LI.js";
|
|
41
42
|
import {
|
|
42
43
|
ContextGraph
|
|
43
44
|
} from "../chunk-FH335WL5.js";
|
|
44
45
|
import {
|
|
45
46
|
measureInitialGoalValue
|
|
46
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-T6PS3MXJ.js";
|
|
47
48
|
import "../chunk-FPEMP54L.js";
|
|
48
49
|
import {
|
|
49
50
|
getProjectState
|
|
50
51
|
} from "../chunk-LT6VUZG2.js";
|
|
52
|
+
import "../chunk-F4NJ4CBP.js";
|
|
53
|
+
import "../chunk-IXO4G4D3.js";
|
|
54
|
+
import "../chunk-6NLHFIYA.js";
|
|
55
|
+
import {
|
|
56
|
+
getStorage
|
|
57
|
+
} from "../chunk-FG467PDD.js";
|
|
58
|
+
import {
|
|
59
|
+
getAutonomyConfig,
|
|
60
|
+
recordBypass,
|
|
61
|
+
shouldAutoFix,
|
|
62
|
+
shouldBlockPush,
|
|
63
|
+
trackIssueOccurrence
|
|
64
|
+
} from "../chunk-5KJ4UJOY.js";
|
|
51
65
|
import {
|
|
52
66
|
compressOldBlocks,
|
|
53
67
|
deleteAllBlocks,
|
|
@@ -78,19 +92,6 @@ import {
|
|
|
78
92
|
} from "../chunk-62POBLFC.js";
|
|
79
93
|
import "../chunk-4MJ52WBH.js";
|
|
80
94
|
import "../chunk-43X6JBEM.js";
|
|
81
|
-
import "../chunk-F4NJ4CBP.js";
|
|
82
|
-
import "../chunk-IXO4G4D3.js";
|
|
83
|
-
import "../chunk-6NLHFIYA.js";
|
|
84
|
-
import {
|
|
85
|
-
getStorage
|
|
86
|
-
} from "../chunk-FG467PDD.js";
|
|
87
|
-
import {
|
|
88
|
-
getAutonomyConfig,
|
|
89
|
-
recordBypass,
|
|
90
|
-
shouldAutoFix,
|
|
91
|
-
shouldBlockPush,
|
|
92
|
-
trackIssueOccurrence
|
|
93
|
-
} from "../chunk-5KJ4UJOY.js";
|
|
94
95
|
import {
|
|
95
96
|
getTrieDirectory,
|
|
96
97
|
getWorkingDirectory
|
|
@@ -101,10 +102,10 @@ import {
|
|
|
101
102
|
} from "../chunk-DGUM43GV.js";
|
|
102
103
|
|
|
103
104
|
// src/cli/main.ts
|
|
104
|
-
import { resolve, join as
|
|
105
|
-
import { readFileSync, realpathSync } from "fs";
|
|
106
|
-
import { fileURLToPath } from "url";
|
|
107
|
-
import
|
|
105
|
+
import { resolve as resolve2, join as join5, dirname as dirname2 } from "path";
|
|
106
|
+
import { readFileSync as readFileSync2, realpathSync } from "fs";
|
|
107
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
108
|
+
import pc9 from "picocolors";
|
|
108
109
|
|
|
109
110
|
// src/hooks/install.ts
|
|
110
111
|
import fs from "fs";
|
|
@@ -879,18 +880,371 @@ function collectIssuesForBlocking(reasoning) {
|
|
|
879
880
|
return issues;
|
|
880
881
|
}
|
|
881
882
|
|
|
883
|
+
// src/cli/hooks.ts
|
|
884
|
+
import { writeFile, mkdir, chmod } from "fs/promises";
|
|
885
|
+
import { join } from "path";
|
|
886
|
+
import { existsSync } from "fs";
|
|
887
|
+
import pc2 from "picocolors";
|
|
888
|
+
import { resolve, dirname } from "path";
|
|
889
|
+
import { fileURLToPath } from "url";
|
|
890
|
+
async function installGitHooks2() {
|
|
891
|
+
const workDir = getWorkingDirectory(void 0, true);
|
|
892
|
+
const isRepo = await isGitRepo(workDir);
|
|
893
|
+
if (!isRepo) {
|
|
894
|
+
console.log(pc2.yellow("\u26A0 Not a git repository. Git hooks not installed."));
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
const hooksDir = join(workDir, ".git", "hooks");
|
|
898
|
+
if (!existsSync(hooksDir)) {
|
|
899
|
+
await mkdir(hooksDir, { recursive: true });
|
|
900
|
+
}
|
|
901
|
+
const prePushHook = `#!/bin/sh
|
|
902
|
+
# Auto-sync ledger to shared storage before push
|
|
903
|
+
|
|
904
|
+
# Only run if trie is initialized
|
|
905
|
+
if [ ! -d ".trie" ]; then
|
|
906
|
+
exit 0
|
|
907
|
+
fi
|
|
908
|
+
|
|
909
|
+
# Check if trie command is available
|
|
910
|
+
if ! command -v trie >/dev/null 2>&1; then
|
|
911
|
+
echo "Warning: trie command not found, skipping ledger sync"
|
|
912
|
+
exit 0
|
|
913
|
+
fi
|
|
914
|
+
|
|
915
|
+
# Sync ledger to shared storage
|
|
916
|
+
echo "Syncing ledger to shared storage..."
|
|
917
|
+
trie sync push 2>/dev/null || true
|
|
918
|
+
|
|
919
|
+
exit 0
|
|
920
|
+
`;
|
|
921
|
+
const postMergeHook = `#!/bin/sh
|
|
922
|
+
# Auto-sync ledger from shared storage after merge
|
|
923
|
+
|
|
924
|
+
# Only run if trie is initialized
|
|
925
|
+
if [ ! -d ".trie" ]; then
|
|
926
|
+
exit 0
|
|
927
|
+
fi
|
|
928
|
+
|
|
929
|
+
# Check if trie command is available
|
|
930
|
+
if ! command -v trie >/dev/null 2>&1; then
|
|
931
|
+
exit 0
|
|
932
|
+
fi
|
|
933
|
+
|
|
934
|
+
# Sync ledger from shared storage
|
|
935
|
+
echo "Syncing ledger from shared storage..."
|
|
936
|
+
trie sync pull 2>/dev/null || true
|
|
937
|
+
|
|
938
|
+
exit 0
|
|
939
|
+
`;
|
|
940
|
+
const prePushPath = join(hooksDir, "pre-push");
|
|
941
|
+
const postMergePath = join(hooksDir, "post-merge");
|
|
942
|
+
await writeFile(prePushPath, prePushHook);
|
|
943
|
+
await writeFile(postMergePath, postMergeHook);
|
|
944
|
+
await chmod(prePushPath, 493);
|
|
945
|
+
await chmod(postMergePath, 493);
|
|
946
|
+
console.log(pc2.green("\u2713 Git hooks installed successfully"));
|
|
947
|
+
console.log(pc2.dim(" pre-push: Syncs ledger to shared storage"));
|
|
948
|
+
console.log(pc2.dim(" post-merge: Syncs ledger from shared storage"));
|
|
949
|
+
}
|
|
950
|
+
async function checkGitHooks() {
|
|
951
|
+
const workDir = getWorkingDirectory(void 0, true);
|
|
952
|
+
const isRepo = await isGitRepo(workDir);
|
|
953
|
+
if (!isRepo) {
|
|
954
|
+
return {
|
|
955
|
+
isGitRepo: false,
|
|
956
|
+
prePushInstalled: false,
|
|
957
|
+
postMergeInstalled: false
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
const hooksDir = join(workDir, ".git", "hooks");
|
|
961
|
+
const prePushPath = join(hooksDir, "pre-push");
|
|
962
|
+
const postMergePath = join(hooksDir, "post-merge");
|
|
963
|
+
return {
|
|
964
|
+
isGitRepo: true,
|
|
965
|
+
prePushInstalled: existsSync(prePushPath),
|
|
966
|
+
postMergeInstalled: existsSync(postMergePath)
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
970
|
+
var __dirname2 = dirname(__filename2);
|
|
971
|
+
async function handlePreCommitCommand(_args) {
|
|
972
|
+
console.log(pc2.cyan("\u{1F50D} Running pre-commit hook..."));
|
|
973
|
+
try {
|
|
974
|
+
const { spawn } = await import("child_process");
|
|
975
|
+
let daemonPath;
|
|
976
|
+
if (__filename2.endsWith(".ts")) {
|
|
977
|
+
daemonPath = resolve(__dirname2, "yolo-daemon.ts");
|
|
978
|
+
} else {
|
|
979
|
+
daemonPath = resolve(__dirname2, "yolo-daemon.js");
|
|
980
|
+
}
|
|
981
|
+
const daemonArgs = ["--once", "--staged-only", "--fail-on", "critical"];
|
|
982
|
+
const executor = daemonPath.endsWith(".ts") ? "npx" : "node";
|
|
983
|
+
const execArgs = daemonPath.endsWith(".ts") ? ["tsx", daemonPath, ...daemonArgs] : [daemonPath, ...daemonArgs];
|
|
984
|
+
const child = spawn(executor, execArgs, {
|
|
985
|
+
stdio: "inherit",
|
|
986
|
+
env: process.env
|
|
987
|
+
});
|
|
988
|
+
child.on("close", (code) => {
|
|
989
|
+
if (code === 0) {
|
|
990
|
+
console.log(pc2.green("\u2713 Pre-commit hook completed successfully"));
|
|
991
|
+
} else {
|
|
992
|
+
console.log(pc2.red("\u2717 Pre-commit hook found critical issues"));
|
|
993
|
+
console.log(pc2.dim(" Commit blocked. Fix issues and try again."));
|
|
994
|
+
}
|
|
995
|
+
process.exit(code || 0);
|
|
996
|
+
});
|
|
997
|
+
} catch (error) {
|
|
998
|
+
console.error(pc2.red("Error in pre-commit hook:"), error);
|
|
999
|
+
process.exit(0);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
async function handlePostCommitCommand(_args) {
|
|
1003
|
+
console.log(pc2.cyan("\u{1F4DD} Running post-commit hook..."));
|
|
1004
|
+
try {
|
|
1005
|
+
const workDir = getWorkingDirectory(void 0, true);
|
|
1006
|
+
const { spawn } = await import("child_process");
|
|
1007
|
+
const updateProcess = spawn("node", [
|
|
1008
|
+
"-e",
|
|
1009
|
+
`
|
|
1010
|
+
const { updateContextAfterCommit } = require('./context.js');
|
|
1011
|
+
updateContextAfterCommit('${workDir}').catch(console.error);
|
|
1012
|
+
`
|
|
1013
|
+
], {
|
|
1014
|
+
stdio: "pipe",
|
|
1015
|
+
env: process.env
|
|
1016
|
+
});
|
|
1017
|
+
updateProcess.on("close", (code) => {
|
|
1018
|
+
if (code === 0) {
|
|
1019
|
+
console.log(pc2.green("\u2713 Post-commit hook completed - context updated"));
|
|
1020
|
+
} else {
|
|
1021
|
+
console.log(pc2.yellow("\u26A0 Post-commit hook completed with warnings"));
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
updateProcess.unref();
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
console.error(pc2.yellow("Warning in post-commit hook:"), error);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/cli/setup.ts
|
|
1031
|
+
import pc3 from "picocolors";
|
|
1032
|
+
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
1033
|
+
import { join as join2 } from "path";
|
|
1034
|
+
async function handleSetupCommand(args) {
|
|
1035
|
+
const subcommand = args[0]?.toLowerCase();
|
|
1036
|
+
if (subcommand === "slack") {
|
|
1037
|
+
await setupSlackIntegration(args.slice(1));
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
if (subcommand === "test-slack") {
|
|
1041
|
+
await testSlackIntegration();
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
showSetup();
|
|
1045
|
+
}
|
|
1046
|
+
async function setupSlackIntegration(args) {
|
|
1047
|
+
const webhookUrl = args[0];
|
|
1048
|
+
if (!webhookUrl) {
|
|
1049
|
+
console.log(`
|
|
1050
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
1051
|
+
\u2551 Slack Integration Setup \u2551
|
|
1052
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
1053
|
+
|
|
1054
|
+
STEP 1: Create a Slack Webhook
|
|
1055
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1056
|
+
1. Go to https://api.slack.com/apps
|
|
1057
|
+
2. Click "Create New App" > "From scratch"
|
|
1058
|
+
3. Name your app (e.g. "Trie Security Bot")
|
|
1059
|
+
4. Choose your workspace
|
|
1060
|
+
5. Go to "Incoming Webhooks" in the sidebar
|
|
1061
|
+
6. Toggle "Activate Incoming Webhooks" to On
|
|
1062
|
+
7. Click "Add New Webhook to Workspace"
|
|
1063
|
+
8. Choose a channel (e.g. #security, #alerts)
|
|
1064
|
+
9. Copy the webhook URL
|
|
1065
|
+
|
|
1066
|
+
STEP 2: Configure Trie
|
|
1067
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1068
|
+
Run: trie setup slack <webhook-url> [channel]
|
|
1069
|
+
|
|
1070
|
+
EXAMPLES:
|
|
1071
|
+
trie setup slack https://hooks.slack.com/services/T.../B.../... #security
|
|
1072
|
+
trie setup slack https://hooks.slack.com/services/T.../B.../...
|
|
1073
|
+
|
|
1074
|
+
STEP 3: Test the Integration
|
|
1075
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1076
|
+
Run: trie setup test-slack
|
|
1077
|
+
|
|
1078
|
+
WHAT TRIE SENDS TO SLACK:
|
|
1079
|
+
\u2022 Decision extractions from incidents
|
|
1080
|
+
\u2022 Active blockers and risk predictions
|
|
1081
|
+
\u2022 Daily/weekly team summaries
|
|
1082
|
+
\u2022 Critical security findings
|
|
1083
|
+
\u2022 Auto-escalation notifications
|
|
1084
|
+
`);
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const channel = args[1];
|
|
1088
|
+
try {
|
|
1089
|
+
if (!webhookUrl.startsWith("https://hooks.slack.com/services/")) {
|
|
1090
|
+
console.error(pc3.red("Error:"), "Invalid Slack webhook URL format");
|
|
1091
|
+
console.error("Expected: https://hooks.slack.com/services/...");
|
|
1092
|
+
process.exit(1);
|
|
1093
|
+
}
|
|
1094
|
+
const config = await loadConfig();
|
|
1095
|
+
const updatedConfig = {
|
|
1096
|
+
...config,
|
|
1097
|
+
integrations: {
|
|
1098
|
+
...config.integrations,
|
|
1099
|
+
slack: {
|
|
1100
|
+
enabled: true,
|
|
1101
|
+
webhook: webhookUrl,
|
|
1102
|
+
channel: channel || void 0
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
await saveConfig(updatedConfig);
|
|
1107
|
+
console.log(pc3.green("\u2713"), "Slack integration configured successfully!");
|
|
1108
|
+
if (channel) {
|
|
1109
|
+
console.log(pc3.dim(` Channel: ${channel}`));
|
|
1110
|
+
}
|
|
1111
|
+
console.log(pc3.dim(` Webhook: ${webhookUrl.substring(0, 50)}...`));
|
|
1112
|
+
console.log(`
|
|
1113
|
+
${pc3.bold("Next steps:")}
|
|
1114
|
+
1. Test the integration: ${pc3.cyan("trie setup test-slack")}
|
|
1115
|
+
2. Configure auto-escalation (optional):
|
|
1116
|
+
${pc3.dim("Add to .trie/config.json:")}
|
|
1117
|
+
${pc3.dim(`{
|
|
1118
|
+
"autoEscalation": {
|
|
1119
|
+
"enabled": true,
|
|
1120
|
+
"webhookUrl": "${webhookUrl}",
|
|
1121
|
+
"quietHours": { "start": "21:00", "end": "08:00" }
|
|
1122
|
+
}
|
|
1123
|
+
}`)}
|
|
1124
|
+
3. Notifications will be sent for:
|
|
1125
|
+
\u2022 Critical security issues
|
|
1126
|
+
\u2022 Team assignments and escalations
|
|
1127
|
+
\u2022 Daily/weekly summaries
|
|
1128
|
+
`);
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
console.error(pc3.red("Error configuring Slack integration:"), error);
|
|
1131
|
+
process.exit(1);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
async function testSlackIntegration() {
|
|
1135
|
+
try {
|
|
1136
|
+
const config = await loadConfig();
|
|
1137
|
+
if (!config.integrations?.slack?.enabled || !config.integrations.slack.webhook) {
|
|
1138
|
+
console.error(pc3.red("Error:"), "Slack integration not configured");
|
|
1139
|
+
console.error("Run:", pc3.cyan("trie setup slack <webhook-url>"));
|
|
1140
|
+
process.exit(1);
|
|
1141
|
+
}
|
|
1142
|
+
console.log(pc3.cyan("\u{1F50D}"), "Testing Slack integration...");
|
|
1143
|
+
const slack = new SlackIntegration({
|
|
1144
|
+
webhookUrl: config.integrations.slack.webhook,
|
|
1145
|
+
channel: config.integrations.slack.channel
|
|
1146
|
+
});
|
|
1147
|
+
const success = await slack.testConnection();
|
|
1148
|
+
if (success) {
|
|
1149
|
+
console.log(pc3.green("\u2713"), "Slack integration test successful!");
|
|
1150
|
+
console.log(pc3.dim(" Check your Slack channel for the test message"));
|
|
1151
|
+
} else {
|
|
1152
|
+
console.log(pc3.red("\u2717"), "Slack integration test failed");
|
|
1153
|
+
console.log(pc3.dim(" Check your webhook URL and network connection"));
|
|
1154
|
+
process.exit(1);
|
|
1155
|
+
}
|
|
1156
|
+
} catch (error) {
|
|
1157
|
+
console.error(pc3.red("Error testing Slack integration:"), error);
|
|
1158
|
+
process.exit(1);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
function showSetup() {
|
|
1162
|
+
const config = getCurrentConfig();
|
|
1163
|
+
const hasSlack = config?.integrations?.slack?.enabled;
|
|
1164
|
+
const hasGitHub = config?.apiKeys?.github;
|
|
1165
|
+
const hasLinear = config?.apiKeys?.linear;
|
|
1166
|
+
console.log(`
|
|
1167
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
1168
|
+
\u2551 Trie Agent Setup \u2551
|
|
1169
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
1170
|
+
|
|
1171
|
+
STEP 1: API Keys
|
|
1172
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1173
|
+
Trie can work offline, but performs best with these keys:
|
|
1174
|
+
|
|
1175
|
+
1. ANTHROPIC_API_KEY (Required for AI analysis)
|
|
1176
|
+
Get it: https://console.anthropic.com/
|
|
1177
|
+
|
|
1178
|
+
2. LINEAR_API_KEY (Required for JIT defect prediction)
|
|
1179
|
+
Get it: https://linear.app/settings/api
|
|
1180
|
+
|
|
1181
|
+
3. GITHUB_TOKEN (Optional for GitHub integration)
|
|
1182
|
+
Get it: https://github.com/settings/tokens
|
|
1183
|
+
|
|
1184
|
+
Set them in your environment (~/.zshrc) or .trie/config.json:
|
|
1185
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
1186
|
+
export LINEAR_API_KEY=lin_api_...
|
|
1187
|
+
export GITHUB_TOKEN=ghp_...
|
|
1188
|
+
|
|
1189
|
+
STEP 2: Team Integrations
|
|
1190
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1191
|
+
${hasSlack ? pc3.green("\u2713") : pc3.red("\u2717")} Slack: ${hasSlack ? "Configured" : "trie setup slack <webhook>"}
|
|
1192
|
+
${hasGitHub ? pc3.green("\u2713") : pc3.red("\u2717")} GitHub: ${hasGitHub ? "Configured" : "Set GITHUB_TOKEN"}
|
|
1193
|
+
${hasLinear ? pc3.green("\u2713") : pc3.red("\u2717")} Linear: ${hasLinear ? "Configured" : "Set LINEAR_API_KEY"}
|
|
1194
|
+
|
|
1195
|
+
SLACK SETUP:
|
|
1196
|
+
trie setup slack # Show Slack setup guide
|
|
1197
|
+
trie setup slack <webhook> [channel] # Configure Slack webhook
|
|
1198
|
+
trie setup test-slack # Test Slack integration
|
|
1199
|
+
|
|
1200
|
+
STEP 3: Configure for your AI tool
|
|
1201
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1202
|
+
|
|
1203
|
+
For CLAUDE CODE:
|
|
1204
|
+
claude mcp add Trie -- npx @triedotdev/mcp
|
|
1205
|
+
|
|
1206
|
+
For CURSOR (~/.cursor/mcp.json):
|
|
1207
|
+
{
|
|
1208
|
+
"mcpServers": {
|
|
1209
|
+
"Trie": {
|
|
1210
|
+
"command": "npx",
|
|
1211
|
+
"args": ["-y", "@triedotdev/mcp"],
|
|
1212
|
+
"env": {
|
|
1213
|
+
"ANTHROPIC_API_KEY": "your-key-here",
|
|
1214
|
+
"LINEAR_API_KEY": "your-key-here"
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
STEP 4: Start scanning!
|
|
1221
|
+
${pc3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
1222
|
+
Ask your AI assistant: "Scan this with Trie" or "Use trie_scan"
|
|
1223
|
+
`);
|
|
1224
|
+
}
|
|
1225
|
+
function getCurrentConfig() {
|
|
1226
|
+
try {
|
|
1227
|
+
const configPath = join2(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
1228
|
+
if (existsSync2(configPath)) {
|
|
1229
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
1230
|
+
}
|
|
1231
|
+
} catch {
|
|
1232
|
+
}
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
882
1236
|
// src/cli/auto-fix.ts
|
|
883
1237
|
import { readFile as readFile2 } from "fs/promises";
|
|
884
|
-
import { existsSync as
|
|
1238
|
+
import { existsSync as existsSync4 } from "fs";
|
|
885
1239
|
import { createInterface } from "readline";
|
|
886
|
-
import
|
|
1240
|
+
import pc4 from "picocolors";
|
|
887
1241
|
|
|
888
1242
|
// src/utils/auto-fix-apply.ts
|
|
889
|
-
import { readFile, writeFile } from "fs/promises";
|
|
890
|
-
import { existsSync } from "fs";
|
|
1243
|
+
import { readFile, writeFile as writeFile2 } from "fs/promises";
|
|
1244
|
+
import { existsSync as existsSync3 } from "fs";
|
|
891
1245
|
async function applyAutoFix(fix) {
|
|
892
1246
|
try {
|
|
893
|
-
if (!
|
|
1247
|
+
if (!existsSync3(fix.file)) {
|
|
894
1248
|
return false;
|
|
895
1249
|
}
|
|
896
1250
|
const content = await readFile(fix.file, "utf-8");
|
|
@@ -913,7 +1267,7 @@ async function applyAutoFix(fix) {
|
|
|
913
1267
|
} else {
|
|
914
1268
|
return false;
|
|
915
1269
|
}
|
|
916
|
-
await
|
|
1270
|
+
await writeFile2(fix.file, newContent);
|
|
917
1271
|
return true;
|
|
918
1272
|
} catch {
|
|
919
1273
|
return false;
|
|
@@ -968,34 +1322,34 @@ async function promptUser(question) {
|
|
|
968
1322
|
input: process.stdin,
|
|
969
1323
|
output: process.stderr
|
|
970
1324
|
});
|
|
971
|
-
return new Promise((
|
|
1325
|
+
return new Promise((resolve3) => {
|
|
972
1326
|
rl.question(question, (answer) => {
|
|
973
1327
|
rl.close();
|
|
974
|
-
|
|
1328
|
+
resolve3(answer.toLowerCase().trim());
|
|
975
1329
|
});
|
|
976
1330
|
});
|
|
977
1331
|
}
|
|
978
1332
|
function displayFixPreview(fix, index, total) {
|
|
979
1333
|
console.error("");
|
|
980
|
-
console.error(
|
|
981
|
-
console.error(
|
|
982
|
-
console.error(
|
|
983
|
-
console.error(
|
|
1334
|
+
console.error(pc4.cyan(`\u2501\u2501\u2501 Fix ${index + 1}/${total} \u2501\u2501\u2501`));
|
|
1335
|
+
console.error(pc4.dim(`File: ${fix.file}${fix.line ? `:${fix.line}` : ""}`));
|
|
1336
|
+
console.error(pc4.dim(`Type: ${fix.type}`));
|
|
1337
|
+
console.error(pc4.yellow(`Description: ${fix.description}`));
|
|
984
1338
|
console.error("");
|
|
985
1339
|
if (fix.original) {
|
|
986
|
-
console.error(
|
|
1340
|
+
console.error(pc4.red("- " + fix.original));
|
|
987
1341
|
}
|
|
988
1342
|
if (fix.fixed) {
|
|
989
|
-
console.error(
|
|
1343
|
+
console.error(pc4.green("+ " + fix.fixed));
|
|
990
1344
|
} else if (fix.original) {
|
|
991
|
-
console.error(
|
|
1345
|
+
console.error(pc4.dim(" (line will be removed)"));
|
|
992
1346
|
}
|
|
993
1347
|
console.error("");
|
|
994
1348
|
}
|
|
995
1349
|
async function loadFixContent(fixes) {
|
|
996
1350
|
const enrichedFixes = [];
|
|
997
1351
|
for (const fix of fixes) {
|
|
998
|
-
if (!fix.line || !
|
|
1352
|
+
if (!fix.line || !existsSync4(fix.file)) {
|
|
999
1353
|
continue;
|
|
1000
1354
|
}
|
|
1001
1355
|
try {
|
|
@@ -1017,39 +1371,39 @@ async function handleAutoFixCommand(args, issues) {
|
|
|
1017
1371
|
const projectPath = getWorkingDirectory(void 0, true);
|
|
1018
1372
|
const config = await getAutonomyConfig(projectPath);
|
|
1019
1373
|
if (!config.autoFix.enabled) {
|
|
1020
|
-
console.error(
|
|
1021
|
-
console.error(
|
|
1374
|
+
console.error(pc4.yellow("Auto-fix is disabled in config."));
|
|
1375
|
+
console.error(pc4.dim("Enable it with: trie config set autoFix.enabled true"));
|
|
1022
1376
|
return;
|
|
1023
1377
|
}
|
|
1024
1378
|
const dryRun = args.includes("--dry-run");
|
|
1025
1379
|
const skipConfirm = args.includes("--yes") || args.includes("-y");
|
|
1026
1380
|
if (!issues || issues.length === 0) {
|
|
1027
|
-
console.error(
|
|
1028
|
-
console.error(
|
|
1381
|
+
console.error(pc4.yellow("No issues provided. Run a scan first:"));
|
|
1382
|
+
console.error(pc4.dim(" trie scan --fix"));
|
|
1029
1383
|
return;
|
|
1030
1384
|
}
|
|
1031
1385
|
let fixes = detectAutoFixes(issues);
|
|
1032
1386
|
if (fixes.length === 0) {
|
|
1033
|
-
console.error(
|
|
1387
|
+
console.error(pc4.green("\u2713 No auto-fixable issues found."));
|
|
1034
1388
|
return;
|
|
1035
1389
|
}
|
|
1036
1390
|
fixes = fixes.filter((fix) => shouldAutoFix(fix, config));
|
|
1037
1391
|
if (fixes.length === 0) {
|
|
1038
|
-
console.error(
|
|
1039
|
-
console.error(
|
|
1392
|
+
console.error(pc4.yellow("Found fixable issues but they are not in allowed categories."));
|
|
1393
|
+
console.error(pc4.dim("Allowed categories: " + config.autoFix.categories.join(", ")));
|
|
1040
1394
|
return;
|
|
1041
1395
|
}
|
|
1042
1396
|
fixes = await loadFixContent(fixes);
|
|
1043
1397
|
if (fixes.length === 0) {
|
|
1044
|
-
console.error(
|
|
1398
|
+
console.error(pc4.yellow("Could not load fix content from files."));
|
|
1045
1399
|
return;
|
|
1046
1400
|
}
|
|
1047
1401
|
console.error("");
|
|
1048
|
-
console.error(
|
|
1049
|
-
console.error(
|
|
1050
|
-
console.error(
|
|
1402
|
+
console.error(pc4.cyan("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
1403
|
+
console.error(pc4.bold("Auto-Fix: Human-in-the-Loop"));
|
|
1404
|
+
console.error(pc4.cyan("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
1051
1405
|
console.error("");
|
|
1052
|
-
console.error(`Found ${
|
|
1406
|
+
console.error(`Found ${pc4.bold(fixes.length.toString())} auto-fixable issues:`);
|
|
1053
1407
|
const byCategory = /* @__PURE__ */ new Map();
|
|
1054
1408
|
for (const fix of fixes) {
|
|
1055
1409
|
byCategory.set(fix.category, (byCategory.get(fix.category) || 0) + 1);
|
|
@@ -1059,7 +1413,7 @@ async function handleAutoFixCommand(args, issues) {
|
|
|
1059
1413
|
}
|
|
1060
1414
|
console.error("");
|
|
1061
1415
|
if (dryRun) {
|
|
1062
|
-
console.error(
|
|
1416
|
+
console.error(pc4.yellow("[DRY RUN] No changes will be made."));
|
|
1063
1417
|
console.error("");
|
|
1064
1418
|
for (let i = 0; i < fixes.length; i++) {
|
|
1065
1419
|
displayFixPreview(fixes[i], i, fixes.length);
|
|
@@ -1067,13 +1421,13 @@ async function handleAutoFixCommand(args, issues) {
|
|
|
1067
1421
|
return;
|
|
1068
1422
|
}
|
|
1069
1423
|
if (config.autoFix.askFirst && !skipConfirm) {
|
|
1070
|
-
console.error(
|
|
1424
|
+
console.error(pc4.yellow("Trie will ask before applying each fix."));
|
|
1071
1425
|
console.error("");
|
|
1072
1426
|
const response = await promptUser(
|
|
1073
1427
|
`Apply all ${fixes.length} fixes? (y)es / (n)o / (r)eview each: `
|
|
1074
1428
|
);
|
|
1075
1429
|
if (response === "n" || response === "no") {
|
|
1076
|
-
console.error(
|
|
1430
|
+
console.error(pc4.dim("Cancelled."));
|
|
1077
1431
|
return;
|
|
1078
1432
|
}
|
|
1079
1433
|
if (response === "r" || response === "review") {
|
|
@@ -1084,54 +1438,54 @@ async function handleAutoFixCommand(args, issues) {
|
|
|
1084
1438
|
displayFixPreview(fix, i, fixes.length);
|
|
1085
1439
|
const answer = await promptUser("Apply this fix? (y/n/q): ");
|
|
1086
1440
|
if (answer === "q" || answer === "quit") {
|
|
1087
|
-
console.error(
|
|
1441
|
+
console.error(pc4.dim("Stopped."));
|
|
1088
1442
|
break;
|
|
1089
1443
|
}
|
|
1090
1444
|
if (answer === "y" || answer === "yes") {
|
|
1091
1445
|
const success = await applyAutoFix(fix);
|
|
1092
1446
|
if (success) {
|
|
1093
|
-
console.error(
|
|
1447
|
+
console.error(pc4.green(`\u2713 Applied fix to ${fix.file}:${fix.line}`));
|
|
1094
1448
|
applied2++;
|
|
1095
1449
|
} else {
|
|
1096
|
-
console.error(
|
|
1450
|
+
console.error(pc4.red(`\u2717 Failed to apply fix`));
|
|
1097
1451
|
}
|
|
1098
1452
|
} else {
|
|
1099
|
-
console.error(
|
|
1453
|
+
console.error(pc4.dim("Skipped."));
|
|
1100
1454
|
skipped++;
|
|
1101
1455
|
}
|
|
1102
1456
|
}
|
|
1103
1457
|
console.error("");
|
|
1104
|
-
console.error(
|
|
1105
|
-
console.error(`Applied: ${
|
|
1106
|
-
console.error(`Skipped: ${
|
|
1458
|
+
console.error(pc4.cyan("\u2501\u2501\u2501 Summary \u2501\u2501\u2501"));
|
|
1459
|
+
console.error(`Applied: ${pc4.green(applied2.toString())}`);
|
|
1460
|
+
console.error(`Skipped: ${pc4.dim(skipped.toString())}`);
|
|
1107
1461
|
return;
|
|
1108
1462
|
}
|
|
1109
1463
|
}
|
|
1110
1464
|
console.error("");
|
|
1111
|
-
console.error(
|
|
1465
|
+
console.error(pc4.cyan("Applying fixes..."));
|
|
1112
1466
|
console.error("");
|
|
1113
1467
|
let applied = 0;
|
|
1114
1468
|
let failed = 0;
|
|
1115
1469
|
for (const fix of fixes) {
|
|
1116
1470
|
const success = await applyAutoFix(fix);
|
|
1117
1471
|
if (success) {
|
|
1118
|
-
console.error(
|
|
1472
|
+
console.error(pc4.green(`\u2713 Applied fix to ${fix.file}:${fix.line}`));
|
|
1119
1473
|
applied++;
|
|
1120
1474
|
} else {
|
|
1121
|
-
console.error(
|
|
1475
|
+
console.error(pc4.red(`\u2717 Failed to apply fix to ${fix.file}:${fix.line}`));
|
|
1122
1476
|
failed++;
|
|
1123
1477
|
}
|
|
1124
1478
|
}
|
|
1125
1479
|
console.error("");
|
|
1126
|
-
console.error(
|
|
1127
|
-
console.error(`Applied: ${
|
|
1480
|
+
console.error(pc4.cyan("\u2501\u2501\u2501 Complete \u2501\u2501\u2501"));
|
|
1481
|
+
console.error(`Applied: ${pc4.green(applied.toString())}`);
|
|
1128
1482
|
if (failed > 0) {
|
|
1129
|
-
console.error(`Failed: ${
|
|
1483
|
+
console.error(`Failed: ${pc4.red(failed.toString())}`);
|
|
1130
1484
|
}
|
|
1131
1485
|
}
|
|
1132
1486
|
|
|
1133
1487
|
// src/cli/goal.ts
|
|
1134
|
-
import
|
|
1488
|
+
import pc5 from "picocolors";
|
|
1135
1489
|
async function handleGoalCommand(args) {
|
|
1136
1490
|
const projectPath = getWorkingDirectory(void 0, true);
|
|
1137
1491
|
const projectState = getProjectState(projectPath);
|
|
@@ -1166,8 +1520,8 @@ async function handleGoalCommand(args) {
|
|
|
1166
1520
|
async function addGoal(projectState, args) {
|
|
1167
1521
|
const description = args.join(" ").replace(/^["']|["']$/g, "");
|
|
1168
1522
|
if (!description) {
|
|
1169
|
-
console.error(
|
|
1170
|
-
console.error(
|
|
1523
|
+
console.error(pc5.red("Please provide a goal description."));
|
|
1524
|
+
console.error(pc5.dim('Example: trie goal add "Reduce auth issues by 50%"'));
|
|
1171
1525
|
return;
|
|
1172
1526
|
}
|
|
1173
1527
|
const categoryMatch = description.match(/--category[=\s](\w+)/);
|
|
@@ -1224,51 +1578,51 @@ async function addGoal(projectState, args) {
|
|
|
1224
1578
|
};
|
|
1225
1579
|
await projectState.addGoal(goal);
|
|
1226
1580
|
console.error("");
|
|
1227
|
-
console.error(
|
|
1581
|
+
console.error(pc5.green("\u2713 Goal created"));
|
|
1228
1582
|
console.error("");
|
|
1229
|
-
console.error(
|
|
1230
|
-
console.error(
|
|
1231
|
-
console.error(
|
|
1583
|
+
console.error(pc5.bold(cleanDesc));
|
|
1584
|
+
console.error(pc5.dim(`ID: ${goal.id}`));
|
|
1585
|
+
console.error(pc5.dim(`Type: ${goalType} | Target: ${target} | Category: ${category}`));
|
|
1232
1586
|
if (initialValue > 0) {
|
|
1233
|
-
console.error(
|
|
1587
|
+
console.error(pc5.dim(`Starting value: ${initialValue} issues found`));
|
|
1234
1588
|
}
|
|
1235
|
-
console.error(
|
|
1589
|
+
console.error(pc5.dim(`Deadline: ${deadline.toLocaleDateString()}`));
|
|
1236
1590
|
console.error("");
|
|
1237
|
-
console.error(
|
|
1591
|
+
console.error(pc5.cyan("Progress will be tracked and you'll be notified when you achieve it!"));
|
|
1238
1592
|
}
|
|
1239
1593
|
async function listGoals(projectState) {
|
|
1240
1594
|
const goals = projectState.getAllGoals();
|
|
1241
1595
|
if (goals.length === 0) {
|
|
1242
|
-
console.error(
|
|
1243
|
-
console.error(
|
|
1596
|
+
console.error(pc5.dim("No goals yet."));
|
|
1597
|
+
console.error(pc5.dim('Create one: trie goal add "Reduce auth issues by 50%"'));
|
|
1244
1598
|
return;
|
|
1245
1599
|
}
|
|
1246
1600
|
console.error("");
|
|
1247
|
-
console.error(
|
|
1601
|
+
console.error(pc5.bold("Goals"));
|
|
1248
1602
|
console.error("");
|
|
1249
1603
|
const active = goals.filter((g) => g.status === "active");
|
|
1250
1604
|
const achieved = goals.filter((g) => g.status === "achieved");
|
|
1251
1605
|
const other = goals.filter((g) => g.status !== "active" && g.status !== "achieved");
|
|
1252
1606
|
if (active.length > 0) {
|
|
1253
|
-
console.error(
|
|
1607
|
+
console.error(pc5.cyan("Active:"));
|
|
1254
1608
|
for (const goal of active) {
|
|
1255
1609
|
const progress = calculateGoalProgress(goal);
|
|
1256
1610
|
const bar = renderProgressBar(progress);
|
|
1257
|
-
const source = goal.autoGenerated ?
|
|
1611
|
+
const source = goal.autoGenerated ? pc5.dim("[auto]") : pc5.dim("[manual]");
|
|
1258
1612
|
console.error(` ${bar} ${goal.description} ${source}`);
|
|
1259
|
-
console.error(
|
|
1613
|
+
console.error(pc5.dim(` ID: ${goal.id} | ${progress}% complete`));
|
|
1260
1614
|
}
|
|
1261
1615
|
console.error("");
|
|
1262
1616
|
}
|
|
1263
1617
|
if (achieved.length > 0) {
|
|
1264
|
-
console.error(
|
|
1618
|
+
console.error(pc5.green("Achieved:"));
|
|
1265
1619
|
for (const goal of achieved) {
|
|
1266
1620
|
console.error(` [+] ${goal.description}`);
|
|
1267
1621
|
}
|
|
1268
1622
|
console.error("");
|
|
1269
1623
|
}
|
|
1270
1624
|
if (other.length > 0) {
|
|
1271
|
-
console.error(
|
|
1625
|
+
console.error(pc5.dim("Other:"));
|
|
1272
1626
|
for (const goal of other) {
|
|
1273
1627
|
const icon = goal.status === "failed" ? "[X]" : goal.status === "paused" ? "[P]" : "\u2022";
|
|
1274
1628
|
console.error(` ${icon} ${goal.description} (${goal.status})`);
|
|
@@ -1277,14 +1631,14 @@ async function listGoals(projectState) {
|
|
|
1277
1631
|
}
|
|
1278
1632
|
async function completeGoal(projectState, goalId) {
|
|
1279
1633
|
if (!goalId) {
|
|
1280
|
-
console.error(
|
|
1281
|
-
console.error(
|
|
1634
|
+
console.error(pc5.red("Please provide a goal ID."));
|
|
1635
|
+
console.error(pc5.dim('Run "trie goal list" to see IDs.'));
|
|
1282
1636
|
return;
|
|
1283
1637
|
}
|
|
1284
1638
|
const goals = projectState.getAllGoals();
|
|
1285
1639
|
const goal = goals.find((g) => g.id === goalId || g.id.startsWith(goalId));
|
|
1286
1640
|
if (!goal) {
|
|
1287
|
-
console.error(
|
|
1641
|
+
console.error(pc5.red(`Goal not found: ${goalId}`));
|
|
1288
1642
|
return;
|
|
1289
1643
|
}
|
|
1290
1644
|
await projectState.updateGoal(goal.id, {
|
|
@@ -1293,23 +1647,23 @@ async function completeGoal(projectState, goalId) {
|
|
|
1293
1647
|
achievedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1294
1648
|
});
|
|
1295
1649
|
console.error("");
|
|
1296
|
-
console.error(
|
|
1297
|
-
console.error(
|
|
1650
|
+
console.error(pc5.green("Goal achieved!"));
|
|
1651
|
+
console.error(pc5.bold(goal.description));
|
|
1298
1652
|
console.error("");
|
|
1299
1653
|
}
|
|
1300
1654
|
async function deleteGoal(projectState, goalId) {
|
|
1301
1655
|
if (!goalId) {
|
|
1302
|
-
console.error(
|
|
1656
|
+
console.error(pc5.red("Please provide a goal ID."));
|
|
1303
1657
|
return;
|
|
1304
1658
|
}
|
|
1305
1659
|
const goals = projectState.getAllGoals();
|
|
1306
1660
|
const goal = goals.find((g) => g.id === goalId || g.id.startsWith(goalId));
|
|
1307
1661
|
if (!goal) {
|
|
1308
|
-
console.error(
|
|
1662
|
+
console.error(pc5.red(`Goal not found: ${goalId}`));
|
|
1309
1663
|
return;
|
|
1310
1664
|
}
|
|
1311
1665
|
await projectState.updateGoal(goal.id, { status: "rejected" });
|
|
1312
|
-
console.error(
|
|
1666
|
+
console.error(pc5.dim(`Removed goal: ${goal.description}`));
|
|
1313
1667
|
}
|
|
1314
1668
|
function calculateGoalProgress(goal) {
|
|
1315
1669
|
if (goal.target <= 0) return 0;
|
|
@@ -1327,7 +1681,7 @@ function renderProgressBar(percent) {
|
|
|
1327
1681
|
const clamped = Math.max(0, Math.min(100, percent));
|
|
1328
1682
|
const filled = Math.round(clamped / 100 * width);
|
|
1329
1683
|
const empty = width - filled;
|
|
1330
|
-
return `[${
|
|
1684
|
+
return `[${pc5.green("\u2588".repeat(filled))}${pc5.gray("\u2591".repeat(empty))}]`;
|
|
1331
1685
|
}
|
|
1332
1686
|
function detectCategory(description) {
|
|
1333
1687
|
const lower = description.toLowerCase();
|
|
@@ -1339,20 +1693,20 @@ function detectCategory(description) {
|
|
|
1339
1693
|
}
|
|
1340
1694
|
function printGoalHelp() {
|
|
1341
1695
|
console.error("");
|
|
1342
|
-
console.error(
|
|
1696
|
+
console.error(pc5.bold("trie goal - Manage guardian goals"));
|
|
1343
1697
|
console.error("");
|
|
1344
|
-
console.error(
|
|
1698
|
+
console.error(pc5.cyan("Usage:"));
|
|
1345
1699
|
console.error(' trie goal add "Reduce auth issues by 50%"');
|
|
1346
1700
|
console.error(" trie goal list");
|
|
1347
1701
|
console.error(" trie goal complete <id>");
|
|
1348
1702
|
console.error(" trie goal delete <id>");
|
|
1349
1703
|
console.error("");
|
|
1350
|
-
console.error(
|
|
1704
|
+
console.error(pc5.cyan("Options for add:"));
|
|
1351
1705
|
console.error(" --category=security|quality|performance|coverage|general");
|
|
1352
1706
|
console.error(" --target=<number>");
|
|
1353
1707
|
console.error(" --deadline=<days>");
|
|
1354
1708
|
console.error("");
|
|
1355
|
-
console.error(
|
|
1709
|
+
console.error(pc5.cyan("Examples:"));
|
|
1356
1710
|
console.error(' trie goal add "Eliminate all critical security issues"');
|
|
1357
1711
|
console.error(' trie goal add "7 days streak of clean builds"');
|
|
1358
1712
|
console.error(' trie goal add "Reduce test flakiness by 80%" --category=quality');
|
|
@@ -1394,8 +1748,8 @@ async function handleHypothesisCommand(args) {
|
|
|
1394
1748
|
async function addHypothesis(projectState, args) {
|
|
1395
1749
|
const statement = args.join(" ").replace(/^["']|["']$/g, "");
|
|
1396
1750
|
if (!statement) {
|
|
1397
|
-
console.error(
|
|
1398
|
-
console.error(
|
|
1751
|
+
console.error(pc5.red("Please provide a hypothesis statement."));
|
|
1752
|
+
console.error(pc5.dim('Example: trie hypothesis add "Mondays have more bugs than Fridays"'));
|
|
1399
1753
|
return;
|
|
1400
1754
|
}
|
|
1401
1755
|
const categoryMatch = statement.match(/--category[=\s](\w+)/);
|
|
@@ -1418,47 +1772,47 @@ async function addHypothesis(projectState, args) {
|
|
|
1418
1772
|
};
|
|
1419
1773
|
await projectState.addHypothesis(hypothesis);
|
|
1420
1774
|
console.error("");
|
|
1421
|
-
console.error(
|
|
1775
|
+
console.error(pc5.green("\u2713 Hypothesis created"));
|
|
1422
1776
|
console.error("");
|
|
1423
|
-
console.error(
|
|
1424
|
-
console.error(
|
|
1425
|
-
console.error(
|
|
1777
|
+
console.error(pc5.bold(`"${cleanStatement}"`));
|
|
1778
|
+
console.error(pc5.dim(`ID: ${hypothesis.id}`));
|
|
1779
|
+
console.error(pc5.dim(`Status: testing | Confidence: untested | Category: ${category}`));
|
|
1426
1780
|
console.error("");
|
|
1427
|
-
console.error(
|
|
1428
|
-
console.error(
|
|
1781
|
+
console.error(pc5.cyan("The agent will collect evidence and update confidence over time."));
|
|
1782
|
+
console.error(pc5.dim(`Test criteria: ${testCriteria}`));
|
|
1429
1783
|
}
|
|
1430
1784
|
async function listHypotheses(projectState) {
|
|
1431
1785
|
const hypotheses = projectState.getAllHypotheses();
|
|
1432
1786
|
if (hypotheses.length === 0) {
|
|
1433
|
-
console.error(
|
|
1434
|
-
console.error(
|
|
1787
|
+
console.error(pc5.dim("No hypotheses yet."));
|
|
1788
|
+
console.error(pc5.dim('Create one: trie hypothesis add "Mondays have more bugs"'));
|
|
1435
1789
|
return;
|
|
1436
1790
|
}
|
|
1437
1791
|
console.error("");
|
|
1438
|
-
console.error(
|
|
1792
|
+
console.error(pc5.bold("Hypotheses"));
|
|
1439
1793
|
console.error("");
|
|
1440
1794
|
const testing = hypotheses.filter((h) => h.status === "testing");
|
|
1441
1795
|
const validated = hypotheses.filter((h) => h.status === "validated");
|
|
1442
1796
|
const invalidated = hypotheses.filter((h) => h.status === "invalidated");
|
|
1443
1797
|
if (testing.length > 0) {
|
|
1444
|
-
console.error(
|
|
1798
|
+
console.error(pc5.cyan("Testing:"));
|
|
1445
1799
|
for (const hypo of testing) {
|
|
1446
1800
|
const conf = Math.round(hypo.confidence * 100);
|
|
1447
|
-
const confColor = conf >= 70 ?
|
|
1801
|
+
const confColor = conf >= 70 ? pc5.green : conf >= 40 ? pc5.yellow : pc5.red;
|
|
1448
1802
|
console.error(` [?] "${hypo.statement}" ${confColor(`(${conf}% confidence)`)}`);
|
|
1449
|
-
console.error(
|
|
1803
|
+
console.error(pc5.dim(` ID: ${hypo.id} | Evidence: ${hypo.evidence.length} points`));
|
|
1450
1804
|
}
|
|
1451
1805
|
console.error("");
|
|
1452
1806
|
}
|
|
1453
1807
|
if (validated.length > 0) {
|
|
1454
|
-
console.error(
|
|
1808
|
+
console.error(pc5.green("Validated:"));
|
|
1455
1809
|
for (const hypo of validated) {
|
|
1456
1810
|
console.error(` [+] "${hypo.statement}" (${Math.round(hypo.confidence * 100)}%)`);
|
|
1457
1811
|
}
|
|
1458
1812
|
console.error("");
|
|
1459
1813
|
}
|
|
1460
1814
|
if (invalidated.length > 0) {
|
|
1461
|
-
console.error(
|
|
1815
|
+
console.error(pc5.red("Invalidated:"));
|
|
1462
1816
|
for (const hypo of invalidated) {
|
|
1463
1817
|
console.error(` [X] "${hypo.statement}"`);
|
|
1464
1818
|
}
|
|
@@ -1466,13 +1820,13 @@ async function listHypotheses(projectState) {
|
|
|
1466
1820
|
}
|
|
1467
1821
|
async function validateHypothesis(projectState, hypoId) {
|
|
1468
1822
|
if (!hypoId) {
|
|
1469
|
-
console.error(
|
|
1823
|
+
console.error(pc5.red("Please provide a hypothesis ID."));
|
|
1470
1824
|
return;
|
|
1471
1825
|
}
|
|
1472
1826
|
const hypotheses = projectState.getAllHypotheses();
|
|
1473
1827
|
const hypo = hypotheses.find((h) => h.id === hypoId || h.id.startsWith(hypoId));
|
|
1474
1828
|
if (!hypo) {
|
|
1475
|
-
console.error(
|
|
1829
|
+
console.error(pc5.red(`Hypothesis not found: ${hypoId}`));
|
|
1476
1830
|
return;
|
|
1477
1831
|
}
|
|
1478
1832
|
await projectState.updateHypothesis(hypo.id, {
|
|
@@ -1480,38 +1834,38 @@ async function validateHypothesis(projectState, hypoId) {
|
|
|
1480
1834
|
confidence: 0.9,
|
|
1481
1835
|
validatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1482
1836
|
});
|
|
1483
|
-
console.error(
|
|
1837
|
+
console.error(pc5.green(`Hypothesis validated: "${hypo.statement}"`));
|
|
1484
1838
|
}
|
|
1485
1839
|
async function invalidateHypothesis(projectState, hypoId) {
|
|
1486
1840
|
if (!hypoId) {
|
|
1487
|
-
console.error(
|
|
1841
|
+
console.error(pc5.red("Please provide a hypothesis ID."));
|
|
1488
1842
|
return;
|
|
1489
1843
|
}
|
|
1490
1844
|
const hypotheses = projectState.getAllHypotheses();
|
|
1491
1845
|
const hypo = hypotheses.find((h) => h.id === hypoId || h.id.startsWith(hypoId));
|
|
1492
1846
|
if (!hypo) {
|
|
1493
|
-
console.error(
|
|
1847
|
+
console.error(pc5.red(`Hypothesis not found: ${hypoId}`));
|
|
1494
1848
|
return;
|
|
1495
1849
|
}
|
|
1496
1850
|
await projectState.updateHypothesis(hypo.id, {
|
|
1497
1851
|
status: "invalidated",
|
|
1498
1852
|
confidence: 0.1
|
|
1499
1853
|
});
|
|
1500
|
-
console.error(
|
|
1854
|
+
console.error(pc5.red(`Hypothesis invalidated: "${hypo.statement}"`));
|
|
1501
1855
|
}
|
|
1502
1856
|
async function deleteHypothesis(projectState, hypoId) {
|
|
1503
1857
|
if (!hypoId) {
|
|
1504
|
-
console.error(
|
|
1858
|
+
console.error(pc5.red("Please provide a hypothesis ID."));
|
|
1505
1859
|
return;
|
|
1506
1860
|
}
|
|
1507
1861
|
const hypotheses = projectState.getAllHypotheses();
|
|
1508
1862
|
const hypo = hypotheses.find((h) => h.id === hypoId || h.id.startsWith(hypoId));
|
|
1509
1863
|
if (!hypo) {
|
|
1510
|
-
console.error(
|
|
1864
|
+
console.error(pc5.red(`Hypothesis not found: ${hypoId}`));
|
|
1511
1865
|
return;
|
|
1512
1866
|
}
|
|
1513
1867
|
await projectState.updateHypothesis(hypo.id, { status: "retired" });
|
|
1514
|
-
console.error(
|
|
1868
|
+
console.error(pc5.dim(`Removed hypothesis: "${hypo.statement}"`));
|
|
1515
1869
|
}
|
|
1516
1870
|
function detectHypothesisCategory(statement) {
|
|
1517
1871
|
const lower = statement.toLowerCase();
|
|
@@ -1539,20 +1893,20 @@ function generateTestCriteria(statement) {
|
|
|
1539
1893
|
}
|
|
1540
1894
|
function printHypothesisHelp() {
|
|
1541
1895
|
console.error("");
|
|
1542
|
-
console.error(
|
|
1896
|
+
console.error(pc5.bold("trie hypothesis - Manage project hypotheses"));
|
|
1543
1897
|
console.error("");
|
|
1544
|
-
console.error(
|
|
1898
|
+
console.error(pc5.cyan("Usage:"));
|
|
1545
1899
|
console.error(' trie hypothesis add "Mondays have more bugs than Fridays"');
|
|
1546
1900
|
console.error(" trie hypothesis list");
|
|
1547
1901
|
console.error(" trie hypothesis validate <id>");
|
|
1548
1902
|
console.error(" trie hypothesis invalidate <id>");
|
|
1549
1903
|
console.error(" trie hypothesis delete <id>");
|
|
1550
1904
|
console.error("");
|
|
1551
|
-
console.error(
|
|
1905
|
+
console.error(pc5.cyan("Options for add:"));
|
|
1552
1906
|
console.error(" --category=timing|pattern|team|code|general");
|
|
1553
1907
|
console.error(' --test="<test criteria>"');
|
|
1554
1908
|
console.error("");
|
|
1555
|
-
console.error(
|
|
1909
|
+
console.error(pc5.cyan("Examples:"));
|
|
1556
1910
|
console.error(' trie hypothesis add "Code reviews reduce bug rate"');
|
|
1557
1911
|
console.error(' trie hypothesis add "Auth module has highest churn"');
|
|
1558
1912
|
console.error(' trie hypothesis add "Deploy Fridays cause weekend incidents"');
|
|
@@ -1677,9 +2031,9 @@ async function handleQuietCommand() {
|
|
|
1677
2031
|
}
|
|
1678
2032
|
|
|
1679
2033
|
// src/cli/ci.ts
|
|
1680
|
-
import { writeFileSync, existsSync as
|
|
1681
|
-
import { join } from "path";
|
|
1682
|
-
import
|
|
2034
|
+
import { writeFileSync, existsSync as existsSync5, mkdirSync } from "fs";
|
|
2035
|
+
import { join as join3 } from "path";
|
|
2036
|
+
import pc6 from "picocolors";
|
|
1683
2037
|
var WORKFLOW_TEMPLATE = `# Trie Security Scan with Memory Persistence
|
|
1684
2038
|
# Generated by: trie ci
|
|
1685
2039
|
#
|
|
@@ -1769,84 +2123,84 @@ jobs:
|
|
|
1769
2123
|
`;
|
|
1770
2124
|
function handleCISetupCommand(args) {
|
|
1771
2125
|
const workDir = getWorkingDirectory(void 0, true);
|
|
1772
|
-
const workflowsDir =
|
|
1773
|
-
const workflowPath =
|
|
2126
|
+
const workflowsDir = join3(workDir, ".github", "workflows");
|
|
2127
|
+
const workflowPath = join3(workflowsDir, "trie-scan.yml");
|
|
1774
2128
|
const isMinimal = args.includes("--minimal") || args.includes("-m");
|
|
1775
2129
|
const isDryRun = args.includes("--dry-run") || args.includes("-n");
|
|
1776
2130
|
const showHelp3 = args.includes("--help") || args.includes("-h");
|
|
1777
2131
|
if (showHelp3) {
|
|
1778
2132
|
console.log(`
|
|
1779
|
-
${
|
|
2133
|
+
${pc6.bold("trie ci")} - Generate GitHub Actions workflow with memory caching
|
|
1780
2134
|
|
|
1781
|
-
${
|
|
2135
|
+
${pc6.bold("USAGE:")}
|
|
1782
2136
|
trie ci [options]
|
|
1783
2137
|
|
|
1784
|
-
${
|
|
2138
|
+
${pc6.bold("OPTIONS:")}
|
|
1785
2139
|
--minimal, -m Generate minimal workflow (simpler, fewer features)
|
|
1786
2140
|
--dry-run, -n Preview workflow without creating files
|
|
1787
2141
|
--help, -h Show this help
|
|
1788
2142
|
|
|
1789
|
-
${
|
|
2143
|
+
${pc6.bold("WHAT IT DOES:")}
|
|
1790
2144
|
Creates .github/workflows/trie-scan.yml that:
|
|
1791
2145
|
|
|
1792
|
-
1. ${
|
|
1793
|
-
2. ${
|
|
1794
|
-
3. ${
|
|
1795
|
-
4. ${
|
|
2146
|
+
1. ${pc6.green("Caches Trie memory")} - Patterns and fixes persist across runs
|
|
2147
|
+
2. ${pc6.green("Enables learning")} - Trie remembers issues from previous PRs
|
|
2148
|
+
3. ${pc6.green("Tracks patterns")} - Detects recurring issues across your codebase
|
|
2149
|
+
4. ${pc6.green("SARIF upload")} - Results appear in GitHub Security tab
|
|
1796
2150
|
|
|
1797
|
-
${
|
|
2151
|
+
${pc6.bold("MEMORY BENEFITS:")}
|
|
1798
2152
|
\u2022 "This issue was introduced 3 PRs ago"
|
|
1799
2153
|
\u2022 "Similar issue was fixed in PR #42"
|
|
1800
2154
|
\u2022 "This pattern keeps recurring in auth code"
|
|
1801
2155
|
\u2022 Trend tracking: improving, stable, or declining
|
|
1802
2156
|
|
|
1803
|
-
${
|
|
2157
|
+
${pc6.bold("EXAMPLES:")}
|
|
1804
2158
|
trie ci # Generate full workflow
|
|
1805
2159
|
trie ci --minimal # Generate simple workflow
|
|
1806
2160
|
trie ci --dry-run # Preview without writing
|
|
1807
2161
|
|
|
1808
|
-
${
|
|
2162
|
+
${pc6.bold("REQUIRED SECRETS:")}
|
|
1809
2163
|
ANTHROPIC_API_KEY Your Anthropic API key (add in GitHub repo settings)
|
|
1810
2164
|
`);
|
|
1811
2165
|
return;
|
|
1812
2166
|
}
|
|
1813
2167
|
const template = isMinimal ? WORKFLOW_MINIMAL : WORKFLOW_TEMPLATE;
|
|
1814
2168
|
if (isDryRun) {
|
|
1815
|
-
console.log(
|
|
1816
|
-
console.log(
|
|
2169
|
+
console.log(pc6.bold("\nWorkflow Preview:\n"));
|
|
2170
|
+
console.log(pc6.dim("\u2500".repeat(60)));
|
|
1817
2171
|
console.log(template);
|
|
1818
|
-
console.log(
|
|
1819
|
-
console.log(
|
|
2172
|
+
console.log(pc6.dim("\u2500".repeat(60)));
|
|
2173
|
+
console.log(pc6.dim("\nRun without --dry-run to create the file."));
|
|
1820
2174
|
return;
|
|
1821
2175
|
}
|
|
1822
|
-
if (
|
|
1823
|
-
console.log(
|
|
1824
|
-
console.log(
|
|
1825
|
-
console.log(
|
|
2176
|
+
if (existsSync5(workflowPath)) {
|
|
2177
|
+
console.log(pc6.yellow("Workflow already exists: .github/workflows/trie-scan.yml"));
|
|
2178
|
+
console.log(pc6.dim(" Run with --dry-run to preview what would be written."));
|
|
2179
|
+
console.log(pc6.dim(" Delete the existing file to regenerate."));
|
|
1826
2180
|
return;
|
|
1827
2181
|
}
|
|
1828
|
-
if (!
|
|
2182
|
+
if (!existsSync5(workflowsDir)) {
|
|
1829
2183
|
mkdirSync(workflowsDir, { recursive: true });
|
|
1830
2184
|
}
|
|
1831
2185
|
writeFileSync(workflowPath, template);
|
|
1832
|
-
console.log(
|
|
2186
|
+
console.log(pc6.green("\u2713") + " Created .github/workflows/trie-scan.yml");
|
|
1833
2187
|
console.log("");
|
|
1834
|
-
console.log(
|
|
2188
|
+
console.log(pc6.bold("Next steps:"));
|
|
1835
2189
|
console.log("");
|
|
1836
2190
|
console.log(" 1. Add your Anthropic API key to GitHub Secrets:");
|
|
1837
|
-
console.log(
|
|
1838
|
-
console.log(
|
|
2191
|
+
console.log(pc6.dim(" Settings \u2192 Secrets \u2192 Actions \u2192 New repository secret"));
|
|
2192
|
+
console.log(pc6.dim(" Name: ANTHROPIC_API_KEY"));
|
|
1839
2193
|
console.log("");
|
|
1840
2194
|
console.log(" 2. Commit and push:");
|
|
1841
|
-
console.log(
|
|
1842
|
-
console.log(
|
|
1843
|
-
console.log(
|
|
2195
|
+
console.log(pc6.dim(" git add .github/workflows/trie-scan.yml"));
|
|
2196
|
+
console.log(pc6.dim(' git commit -m "Add Trie security scan with memory"'));
|
|
2197
|
+
console.log(pc6.dim(" git push"));
|
|
1844
2198
|
console.log("");
|
|
1845
|
-
console.log(
|
|
1846
|
-
console.log(
|
|
1847
|
-
console.log(
|
|
1848
|
-
console.log(
|
|
1849
|
-
console.log(
|
|
2199
|
+
console.log(pc6.bold("Memory caching benefits:"));
|
|
2200
|
+
console.log(pc6.dim(" \u2022 Trie learns from past scans"));
|
|
2201
|
+
console.log(pc6.dim(" \u2022 Tracks issue trends over time"));
|
|
2202
|
+
console.log(pc6.dim(" \u2022 Remembers when issues were introduced"));
|
|
2203
|
+
console.log(pc6.dim(" \u2022 Recognizes recurring patterns"));
|
|
1850
2204
|
}
|
|
1851
2205
|
|
|
1852
2206
|
// src/cli/audit.ts
|
|
@@ -2091,20 +2445,20 @@ async function handleLearnCommand(args) {
|
|
|
2091
2445
|
}
|
|
2092
2446
|
|
|
2093
2447
|
// src/cli/patterns.ts
|
|
2094
|
-
import { readFile as readFile4, writeFile as
|
|
2095
|
-
import { existsSync as
|
|
2448
|
+
import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
2449
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2096
2450
|
import { basename as basename2 } from "path";
|
|
2097
2451
|
import picocolors3 from "picocolors";
|
|
2098
2452
|
|
|
2099
2453
|
// src/patterns/saved-patterns.ts
|
|
2100
2454
|
import { createHash } from "crypto";
|
|
2101
|
-
import { readFile as readFile3, writeFile as
|
|
2102
|
-
import { existsSync as
|
|
2103
|
-
import { join as
|
|
2455
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
2456
|
+
import { existsSync as existsSync6 } from "fs";
|
|
2457
|
+
import { join as join4, basename } from "path";
|
|
2104
2458
|
async function loadSavedPatterns(workDir) {
|
|
2105
|
-
const patternsPath =
|
|
2459
|
+
const patternsPath = join4(getTrieDirectory(workDir), "saved-patterns.json");
|
|
2106
2460
|
try {
|
|
2107
|
-
if (
|
|
2461
|
+
if (existsSync6(patternsPath)) {
|
|
2108
2462
|
const content = await readFile3(patternsPath, "utf-8");
|
|
2109
2463
|
return JSON.parse(content);
|
|
2110
2464
|
}
|
|
@@ -2114,9 +2468,9 @@ async function loadSavedPatterns(workDir) {
|
|
|
2114
2468
|
}
|
|
2115
2469
|
async function savePatternsToProject(patterns, workDir) {
|
|
2116
2470
|
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
2117
|
-
const patternsPath =
|
|
2471
|
+
const patternsPath = join4(getTrieDirectory(workDir), "saved-patterns.json");
|
|
2118
2472
|
await mkdir2(getTrieDirectory(workDir), { recursive: true });
|
|
2119
|
-
await
|
|
2473
|
+
await writeFile3(patternsPath, JSON.stringify(patterns, null, 2));
|
|
2120
2474
|
}
|
|
2121
2475
|
async function savePatternToProject(pattern, workDir) {
|
|
2122
2476
|
const patterns = await loadSavedPatterns(workDir);
|
|
@@ -2151,8 +2505,8 @@ function detectPatternType(target, workDir) {
|
|
|
2151
2505
|
if (scoutNames.includes(target.toLowerCase())) {
|
|
2152
2506
|
return "detection-rule";
|
|
2153
2507
|
}
|
|
2154
|
-
const fullPath =
|
|
2155
|
-
if (
|
|
2508
|
+
const fullPath = join4(workDir, target);
|
|
2509
|
+
if (existsSync6(fullPath) || target.includes("/") || target.includes("*") || target.endsWith(".ts") || target.endsWith(".js")) {
|
|
2156
2510
|
return "file-structure";
|
|
2157
2511
|
}
|
|
2158
2512
|
return "code-pattern";
|
|
@@ -2310,7 +2664,7 @@ async function handleExportPatterns(args, workDir) {
|
|
|
2310
2664
|
exportedFrom: basename2(workDir),
|
|
2311
2665
|
patterns
|
|
2312
2666
|
};
|
|
2313
|
-
await
|
|
2667
|
+
await writeFile4(outputPath, JSON.stringify(exportData, null, 2));
|
|
2314
2668
|
console.log(picocolors3.green(`\u2713 Exported ${patterns.length} patterns to ${outputPath}`));
|
|
2315
2669
|
console.log(picocolors3.dim(` Import to another project with: trie patterns import ${outputPath}`));
|
|
2316
2670
|
}
|
|
@@ -2320,7 +2674,7 @@ async function handleImportPatterns(args, workDir) {
|
|
|
2320
2674
|
console.error(picocolors3.red("Usage: trie patterns import <path-to-patterns.json>"));
|
|
2321
2675
|
process.exit(1);
|
|
2322
2676
|
}
|
|
2323
|
-
if (!
|
|
2677
|
+
if (!existsSync7(inputPath)) {
|
|
2324
2678
|
console.error(picocolors3.red(`File not found: ${inputPath}`));
|
|
2325
2679
|
process.exit(1);
|
|
2326
2680
|
}
|
|
@@ -2417,95 +2771,8 @@ ${picocolors3.dim("Patterns are saved in .trie/saved-patterns.json")}
|
|
|
2417
2771
|
}
|
|
2418
2772
|
|
|
2419
2773
|
// src/cli/sync.ts
|
|
2420
|
-
import
|
|
2774
|
+
import pc7 from "picocolors";
|
|
2421
2775
|
import { Command } from "commander";
|
|
2422
|
-
|
|
2423
|
-
// src/cli/hooks.ts
|
|
2424
|
-
import { writeFile as writeFile4, mkdir, chmod } from "fs/promises";
|
|
2425
|
-
import { join as join3 } from "path";
|
|
2426
|
-
import { existsSync as existsSync6 } from "fs";
|
|
2427
|
-
import pc5 from "picocolors";
|
|
2428
|
-
async function installGitHooks2() {
|
|
2429
|
-
const workDir = getWorkingDirectory(void 0, true);
|
|
2430
|
-
const isRepo = await isGitRepo(workDir);
|
|
2431
|
-
if (!isRepo) {
|
|
2432
|
-
console.log(pc5.yellow("\u26A0 Not a git repository. Git hooks not installed."));
|
|
2433
|
-
return;
|
|
2434
|
-
}
|
|
2435
|
-
const hooksDir = join3(workDir, ".git", "hooks");
|
|
2436
|
-
if (!existsSync6(hooksDir)) {
|
|
2437
|
-
await mkdir(hooksDir, { recursive: true });
|
|
2438
|
-
}
|
|
2439
|
-
const prePushHook = `#!/bin/sh
|
|
2440
|
-
# Auto-sync ledger to shared storage before push
|
|
2441
|
-
|
|
2442
|
-
# Only run if trie is initialized
|
|
2443
|
-
if [ ! -d ".trie" ]; then
|
|
2444
|
-
exit 0
|
|
2445
|
-
fi
|
|
2446
|
-
|
|
2447
|
-
# Check if trie command is available
|
|
2448
|
-
if ! command -v trie >/dev/null 2>&1; then
|
|
2449
|
-
echo "Warning: trie command not found, skipping ledger sync"
|
|
2450
|
-
exit 0
|
|
2451
|
-
fi
|
|
2452
|
-
|
|
2453
|
-
# Sync ledger to shared storage
|
|
2454
|
-
echo "Syncing ledger to shared storage..."
|
|
2455
|
-
trie sync push 2>/dev/null || true
|
|
2456
|
-
|
|
2457
|
-
exit 0
|
|
2458
|
-
`;
|
|
2459
|
-
const postMergeHook = `#!/bin/sh
|
|
2460
|
-
# Auto-sync ledger from shared storage after merge
|
|
2461
|
-
|
|
2462
|
-
# Only run if trie is initialized
|
|
2463
|
-
if [ ! -d ".trie" ]; then
|
|
2464
|
-
exit 0
|
|
2465
|
-
fi
|
|
2466
|
-
|
|
2467
|
-
# Check if trie command is available
|
|
2468
|
-
if ! command -v trie >/dev/null 2>&1; then
|
|
2469
|
-
exit 0
|
|
2470
|
-
fi
|
|
2471
|
-
|
|
2472
|
-
# Sync ledger from shared storage
|
|
2473
|
-
echo "Syncing ledger from shared storage..."
|
|
2474
|
-
trie sync pull 2>/dev/null || true
|
|
2475
|
-
|
|
2476
|
-
exit 0
|
|
2477
|
-
`;
|
|
2478
|
-
const prePushPath = join3(hooksDir, "pre-push");
|
|
2479
|
-
const postMergePath = join3(hooksDir, "post-merge");
|
|
2480
|
-
await writeFile4(prePushPath, prePushHook);
|
|
2481
|
-
await writeFile4(postMergePath, postMergeHook);
|
|
2482
|
-
await chmod(prePushPath, 493);
|
|
2483
|
-
await chmod(postMergePath, 493);
|
|
2484
|
-
console.log(pc5.green("\u2713 Git hooks installed successfully"));
|
|
2485
|
-
console.log(pc5.dim(" pre-push: Syncs ledger to shared storage"));
|
|
2486
|
-
console.log(pc5.dim(" post-merge: Syncs ledger from shared storage"));
|
|
2487
|
-
}
|
|
2488
|
-
async function checkGitHooks() {
|
|
2489
|
-
const workDir = getWorkingDirectory(void 0, true);
|
|
2490
|
-
const isRepo = await isGitRepo(workDir);
|
|
2491
|
-
if (!isRepo) {
|
|
2492
|
-
return {
|
|
2493
|
-
isGitRepo: false,
|
|
2494
|
-
prePushInstalled: false,
|
|
2495
|
-
postMergeInstalled: false
|
|
2496
|
-
};
|
|
2497
|
-
}
|
|
2498
|
-
const hooksDir = join3(workDir, ".git", "hooks");
|
|
2499
|
-
const prePushPath = join3(hooksDir, "pre-push");
|
|
2500
|
-
const postMergePath = join3(hooksDir, "post-merge");
|
|
2501
|
-
return {
|
|
2502
|
-
isGitRepo: true,
|
|
2503
|
-
prePushInstalled: existsSync6(prePushPath),
|
|
2504
|
-
postMergeInstalled: existsSync6(postMergePath)
|
|
2505
|
-
};
|
|
2506
|
-
}
|
|
2507
|
-
|
|
2508
|
-
// src/cli/sync.ts
|
|
2509
2776
|
function createSyncCommand() {
|
|
2510
2777
|
const sync = new Command("sync").description("Sync ledger with shared storage");
|
|
2511
2778
|
sync.command("init").description("Initialize shared ledger storage").action(async () => {
|
|
@@ -2513,9 +2780,9 @@ function createSyncCommand() {
|
|
|
2513
2780
|
const workDir = getWorkingDirectory(void 0, true);
|
|
2514
2781
|
console.log(`Initializing shared ledger in ${workDir}...`);
|
|
2515
2782
|
await initializeSharedLedger();
|
|
2516
|
-
console.log(
|
|
2783
|
+
console.log(pc7.green("\u2713 Shared ledger initialized successfully"));
|
|
2517
2784
|
} catch (error) {
|
|
2518
|
-
console.error(
|
|
2785
|
+
console.error(pc7.red("Failed to initialize shared ledger:"), error);
|
|
2519
2786
|
process.exit(1);
|
|
2520
2787
|
}
|
|
2521
2788
|
});
|
|
@@ -2528,17 +2795,17 @@ function createSyncCommand() {
|
|
|
2528
2795
|
await migrateLegacyLedger();
|
|
2529
2796
|
}
|
|
2530
2797
|
const result = await syncLedgerFromShared();
|
|
2531
|
-
console.log(
|
|
2798
|
+
console.log(pc7.green("\u2713 Sync completed"));
|
|
2532
2799
|
console.log(`Merged ${result.stats.mergedBlocks} blocks`);
|
|
2533
2800
|
if (result.conflicts.length > 0) {
|
|
2534
|
-
console.log(
|
|
2801
|
+
console.log(pc7.yellow(`\u26A0 ${result.conflicts.length} conflicts detected`));
|
|
2535
2802
|
console.log('Run "trie sync status" to see details');
|
|
2536
2803
|
}
|
|
2537
2804
|
if (result.stats.duplicatesRemoved > 0) {
|
|
2538
2805
|
console.log(`Removed ${result.stats.duplicatesRemoved} duplicate entries`);
|
|
2539
2806
|
}
|
|
2540
2807
|
} catch (error) {
|
|
2541
|
-
console.error(
|
|
2808
|
+
console.error(pc7.red("Failed to sync from shared ledger:"), error);
|
|
2542
2809
|
process.exit(1);
|
|
2543
2810
|
}
|
|
2544
2811
|
});
|
|
@@ -2551,45 +2818,45 @@ function createSyncCommand() {
|
|
|
2551
2818
|
await migrateLegacyLedger();
|
|
2552
2819
|
}
|
|
2553
2820
|
await pushLedgerToShared();
|
|
2554
|
-
console.log(
|
|
2821
|
+
console.log(pc7.green("\u2713 Push completed"));
|
|
2555
2822
|
} catch (error) {
|
|
2556
|
-
console.error(
|
|
2823
|
+
console.error(pc7.red("Failed to push to shared ledger:"), error);
|
|
2557
2824
|
process.exit(1);
|
|
2558
2825
|
}
|
|
2559
2826
|
});
|
|
2560
2827
|
sync.command("status").description("Show ledger sync status").action(async () => {
|
|
2561
2828
|
try {
|
|
2562
2829
|
const status = await getLedgerSyncStatus();
|
|
2563
|
-
console.log(
|
|
2830
|
+
console.log(pc7.bold("Ledger Sync Status\n"));
|
|
2564
2831
|
if (!status.isInitialized) {
|
|
2565
|
-
console.log(
|
|
2832
|
+
console.log(pc7.yellow('\u26A0 Shared ledger not initialized. Run "trie sync init" first.'));
|
|
2566
2833
|
return;
|
|
2567
2834
|
}
|
|
2568
2835
|
if (status.hasLegacyLedger) {
|
|
2569
|
-
console.log(
|
|
2836
|
+
console.log(pc7.yellow('\u26A0 Legacy ledger detected. Run "trie sync pull" to migrate.'));
|
|
2570
2837
|
}
|
|
2571
|
-
console.log(`Local blocks: ${
|
|
2572
|
-
console.log(`Shared blocks: ${
|
|
2838
|
+
console.log(`Local blocks: ${pc7.cyan(status.localBlocks.toString())}`);
|
|
2839
|
+
console.log(`Shared blocks: ${pc7.cyan(status.sharedBlocks.toString())}`);
|
|
2573
2840
|
if (status.syncState) {
|
|
2574
2841
|
const lastSync = new Date(status.syncState.lastSyncTimestamp);
|
|
2575
|
-
console.log(`Last sync: ${
|
|
2842
|
+
console.log(`Last sync: ${pc7.dim(lastSync.toLocaleString())}`);
|
|
2576
2843
|
if (status.conflicts > 0) {
|
|
2577
|
-
console.log(
|
|
2844
|
+
console.log(pc7.yellow(`Conflicts: ${status.conflicts}`));
|
|
2578
2845
|
console.log("\nConflicts:");
|
|
2579
2846
|
for (const conflict of status.syncState.conflicts) {
|
|
2580
2847
|
console.log(` \u2022 ${conflict.type}: ${conflict.description}`);
|
|
2581
2848
|
}
|
|
2582
2849
|
} else {
|
|
2583
|
-
console.log(
|
|
2850
|
+
console.log(pc7.green("\u2713 No conflicts"));
|
|
2584
2851
|
}
|
|
2585
2852
|
}
|
|
2586
2853
|
if (status.manifest) {
|
|
2587
2854
|
console.log(`
|
|
2588
|
-
Total entries: ${
|
|
2589
|
-
console.log(`Compression: ${status.manifest.compressionConfig.enabled ?
|
|
2855
|
+
Total entries: ${pc7.cyan(status.manifest.totalEntries.toString())}`);
|
|
2856
|
+
console.log(`Compression: ${status.manifest.compressionConfig.enabled ? pc7.green("enabled") : pc7.red("disabled")}`);
|
|
2590
2857
|
}
|
|
2591
2858
|
} catch (error) {
|
|
2592
|
-
console.error(
|
|
2859
|
+
console.error(pc7.red("Failed to get sync status:"), error);
|
|
2593
2860
|
process.exit(1);
|
|
2594
2861
|
}
|
|
2595
2862
|
});
|
|
@@ -2597,19 +2864,19 @@ Total entries: ${pc6.cyan(status.manifest.totalEntries.toString())}`);
|
|
|
2597
2864
|
try {
|
|
2598
2865
|
const hasLegacy = await detectLegacyLedger();
|
|
2599
2866
|
if (!hasLegacy) {
|
|
2600
|
-
console.log(
|
|
2867
|
+
console.log(pc7.yellow("No legacy ledger found to migrate"));
|
|
2601
2868
|
return;
|
|
2602
2869
|
}
|
|
2603
2870
|
console.log("Migrating legacy ledger...");
|
|
2604
2871
|
const success = await migrateLegacyLedger();
|
|
2605
2872
|
if (success) {
|
|
2606
|
-
console.log(
|
|
2873
|
+
console.log(pc7.green("\u2713 Migration completed successfully"));
|
|
2607
2874
|
} else {
|
|
2608
|
-
console.log(
|
|
2875
|
+
console.log(pc7.red("Migration failed"));
|
|
2609
2876
|
process.exit(1);
|
|
2610
2877
|
}
|
|
2611
2878
|
} catch (error) {
|
|
2612
|
-
console.error(
|
|
2879
|
+
console.error(pc7.red("Failed to migrate legacy ledger:"), error);
|
|
2613
2880
|
process.exit(1);
|
|
2614
2881
|
}
|
|
2615
2882
|
});
|
|
@@ -2621,18 +2888,18 @@ Total entries: ${pc6.cyan(status.manifest.totalEntries.toString())}`);
|
|
|
2621
2888
|
}
|
|
2622
2889
|
const status = await checkGitHooks();
|
|
2623
2890
|
if (!status.isGitRepo) {
|
|
2624
|
-
console.log(
|
|
2891
|
+
console.log(pc7.yellow("Not a git repository"));
|
|
2625
2892
|
return;
|
|
2626
2893
|
}
|
|
2627
|
-
console.log(
|
|
2628
|
-
console.log(`Pre-push hook: ${status.prePushInstalled ?
|
|
2629
|
-
console.log(`Post-merge hook: ${status.postMergeInstalled ?
|
|
2894
|
+
console.log(pc7.bold("Git Hooks Status\n"));
|
|
2895
|
+
console.log(`Pre-push hook: ${status.prePushInstalled ? pc7.green("\u2713 installed") : pc7.red("\u2717 not installed")}`);
|
|
2896
|
+
console.log(`Post-merge hook: ${status.postMergeInstalled ? pc7.green("\u2713 installed") : pc7.red("\u2717 not installed")}`);
|
|
2630
2897
|
if (!status.prePushInstalled || !status.postMergeInstalled) {
|
|
2631
2898
|
console.log(`
|
|
2632
|
-
${
|
|
2899
|
+
${pc7.yellow("\u{1F4A1} Tip:")} Run ${pc7.bold("trie sync hooks --install")} to install missing hooks`);
|
|
2633
2900
|
}
|
|
2634
2901
|
} catch (error) {
|
|
2635
|
-
console.error(
|
|
2902
|
+
console.error(pc7.red("Failed to manage git hooks:"), error);
|
|
2636
2903
|
process.exit(1);
|
|
2637
2904
|
}
|
|
2638
2905
|
});
|
|
@@ -2640,7 +2907,7 @@ ${pc6.yellow("\u{1F4A1} Tip:")} Run ${pc6.bold("trie sync hooks --install")} to
|
|
|
2640
2907
|
}
|
|
2641
2908
|
|
|
2642
2909
|
// src/cli/ledger.ts
|
|
2643
|
-
import
|
|
2910
|
+
import pc8 from "picocolors";
|
|
2644
2911
|
import { Command as Command2 } from "commander";
|
|
2645
2912
|
function createLedgerCommand() {
|
|
2646
2913
|
const ledger = new Command2("ledger").description("Manage and inspect the ledger");
|
|
@@ -2649,13 +2916,13 @@ function createLedgerCommand() {
|
|
|
2649
2916
|
console.log("Verifying ledger chain...");
|
|
2650
2917
|
const result = await verifyLedger();
|
|
2651
2918
|
if (result.valid) {
|
|
2652
|
-
console.log(
|
|
2919
|
+
console.log(pc8.green("\u2713 Ledger chain is valid"));
|
|
2653
2920
|
} else {
|
|
2654
|
-
console.log(
|
|
2921
|
+
console.log(pc8.red(`\u2717 Ledger chain is invalid: ${result.error}`));
|
|
2655
2922
|
process.exit(1);
|
|
2656
2923
|
}
|
|
2657
2924
|
} catch (error) {
|
|
2658
|
-
console.error(
|
|
2925
|
+
console.error(pc8.red("Failed to verify ledger:"), error);
|
|
2659
2926
|
process.exit(1);
|
|
2660
2927
|
}
|
|
2661
2928
|
});
|
|
@@ -2667,20 +2934,20 @@ function createLedgerCommand() {
|
|
|
2667
2934
|
console.log("No ledger blocks found");
|
|
2668
2935
|
return;
|
|
2669
2936
|
}
|
|
2670
|
-
console.log(
|
|
2937
|
+
console.log(pc8.bold(`Ledger History (last ${Math.min(limit, blocks.length)} blocks)
|
|
2671
2938
|
`));
|
|
2672
2939
|
const recentBlocks = blocks.slice(-limit).reverse();
|
|
2673
2940
|
for (const block of recentBlocks) {
|
|
2674
2941
|
const syncableBlock = block;
|
|
2675
|
-
console.log(
|
|
2942
|
+
console.log(pc8.bold(pc8.cyan(`Block ${block.date}`)));
|
|
2676
2943
|
if (syncableBlock.author) {
|
|
2677
|
-
console.log(`Author: ${
|
|
2944
|
+
console.log(`Author: ${pc8.dim(syncableBlock.author)}`);
|
|
2678
2945
|
}
|
|
2679
2946
|
if (syncableBlock.gitCommit) {
|
|
2680
|
-
console.log(`Git: ${
|
|
2947
|
+
console.log(`Git: ${pc8.dim(syncableBlock.gitCommit.slice(0, 8))}`);
|
|
2681
2948
|
}
|
|
2682
2949
|
console.log(`Entries: ${block.entries.length}`);
|
|
2683
|
-
console.log(`Hash: ${
|
|
2950
|
+
console.log(`Hash: ${pc8.dim(block.blockHash.slice(0, 16))}...`);
|
|
2684
2951
|
if (block.entries.length > 0) {
|
|
2685
2952
|
console.log("Issues:");
|
|
2686
2953
|
for (const entry of block.entries) {
|
|
@@ -2690,7 +2957,7 @@ function createLedgerCommand() {
|
|
|
2690
2957
|
console.log("");
|
|
2691
2958
|
}
|
|
2692
2959
|
} catch (error) {
|
|
2693
|
-
console.error(
|
|
2960
|
+
console.error(pc8.red("Failed to show ledger history:"), error);
|
|
2694
2961
|
process.exit(1);
|
|
2695
2962
|
}
|
|
2696
2963
|
});
|
|
@@ -2698,22 +2965,22 @@ function createLedgerCommand() {
|
|
|
2698
2965
|
try {
|
|
2699
2966
|
const status = await getLedgerSyncStatus();
|
|
2700
2967
|
const blocks = await getLedgerBlocks();
|
|
2701
|
-
console.log(
|
|
2702
|
-
console.log(`Total blocks: ${
|
|
2968
|
+
console.log(pc8.bold("Ledger Statistics\n"));
|
|
2969
|
+
console.log(`Total blocks: ${pc8.cyan(blocks.length.toString())}`);
|
|
2703
2970
|
if (status.manifest) {
|
|
2704
|
-
console.log(`Total entries: ${
|
|
2705
|
-
console.log(`Active blocks: ${
|
|
2706
|
-
console.log(`Archived blocks: ${
|
|
2971
|
+
console.log(`Total entries: ${pc8.cyan(status.manifest.totalEntries.toString())}`);
|
|
2972
|
+
console.log(`Active blocks: ${pc8.cyan(status.manifest.activeBlocks.length.toString())}`);
|
|
2973
|
+
console.log(`Archived blocks: ${pc8.cyan(status.manifest.archivedBlocks.length.toString())}`);
|
|
2707
2974
|
if (status.manifest.compressionConfig.enabled) {
|
|
2708
2975
|
const hotSize = Math.round(status.manifest.compressionConfig.maxHotStorageSize / 1024 / 1024);
|
|
2709
|
-
console.log(`Hot storage limit: ${
|
|
2710
|
-
console.log(`Archive after: ${
|
|
2976
|
+
console.log(`Hot storage limit: ${pc8.cyan(`${hotSize}MB`)}`);
|
|
2977
|
+
console.log(`Archive after: ${pc8.cyan(`${status.manifest.compressionConfig.archiveAfterDays} days`)}`);
|
|
2711
2978
|
}
|
|
2712
2979
|
}
|
|
2713
2980
|
if (blocks.length > 0) {
|
|
2714
2981
|
const firstBlock = blocks[0];
|
|
2715
2982
|
const lastBlock = blocks[blocks.length - 1];
|
|
2716
|
-
console.log(`Date range: ${
|
|
2983
|
+
console.log(`Date range: ${pc8.dim(`${firstBlock.date} to ${lastBlock.date}`)}`);
|
|
2717
2984
|
}
|
|
2718
2985
|
const authorCounts = /* @__PURE__ */ new Map();
|
|
2719
2986
|
for (const block of blocks) {
|
|
@@ -2726,7 +2993,7 @@ function createLedgerCommand() {
|
|
|
2726
2993
|
console.log("\nBlocks by author:");
|
|
2727
2994
|
const sortedAuthors = Array.from(authorCounts.entries()).sort((a, b) => b[1] - a[1]);
|
|
2728
2995
|
for (const [author, count] of sortedAuthors.slice(0, 10)) {
|
|
2729
|
-
console.log(` ${author}: ${
|
|
2996
|
+
console.log(` ${author}: ${pc8.cyan(count.toString())}`);
|
|
2730
2997
|
}
|
|
2731
2998
|
}
|
|
2732
2999
|
const severityCounts = /* @__PURE__ */ new Map();
|
|
@@ -2741,39 +3008,39 @@ function createLedgerCommand() {
|
|
|
2741
3008
|
for (const severity of severityOrder) {
|
|
2742
3009
|
const count = severityCounts.get(severity);
|
|
2743
3010
|
if (count) {
|
|
2744
|
-
const color = severity === "critical" ?
|
|
2745
|
-
console.log(` ${color(severity)}: ${
|
|
3011
|
+
const color = severity === "critical" ? pc8.red : severity === "high" ? pc8.yellow : severity === "medium" ? pc8.blue : pc8.gray;
|
|
3012
|
+
console.log(` ${color(severity)}: ${pc8.cyan(count.toString())}`);
|
|
2746
3013
|
}
|
|
2747
3014
|
}
|
|
2748
3015
|
}
|
|
2749
3016
|
} catch (error) {
|
|
2750
|
-
console.error(
|
|
3017
|
+
console.error(pc8.red("Failed to show ledger stats:"), error);
|
|
2751
3018
|
process.exit(1);
|
|
2752
3019
|
}
|
|
2753
3020
|
});
|
|
2754
3021
|
ledger.command("diff").description("Compare local and shared ledger state").action(async () => {
|
|
2755
3022
|
try {
|
|
2756
3023
|
const status = await getLedgerSyncStatus();
|
|
2757
|
-
console.log(
|
|
3024
|
+
console.log(pc8.bold("Ledger Diff\n"));
|
|
2758
3025
|
if (!status.isInitialized) {
|
|
2759
|
-
console.log(
|
|
3026
|
+
console.log(pc8.yellow("Shared ledger not initialized"));
|
|
2760
3027
|
return;
|
|
2761
3028
|
}
|
|
2762
|
-
console.log(`Local blocks: ${
|
|
2763
|
-
console.log(`Shared blocks: ${
|
|
3029
|
+
console.log(`Local blocks: ${pc8.cyan(status.localBlocks.toString())}`);
|
|
3030
|
+
console.log(`Shared blocks: ${pc8.cyan(status.sharedBlocks.toString())}`);
|
|
2764
3031
|
const diff = status.sharedBlocks - status.localBlocks;
|
|
2765
3032
|
if (diff > 0) {
|
|
2766
|
-
console.log(
|
|
3033
|
+
console.log(pc8.green(`\u2193 ${diff} blocks available to pull`));
|
|
2767
3034
|
} else if (diff < 0) {
|
|
2768
|
-
console.log(
|
|
3035
|
+
console.log(pc8.blue(`\u2191 ${-diff} local blocks not yet pushed`));
|
|
2769
3036
|
} else {
|
|
2770
|
-
console.log(
|
|
3037
|
+
console.log(pc8.green("\u2713 Local and shared ledgers are in sync"));
|
|
2771
3038
|
}
|
|
2772
3039
|
if (status.conflicts > 0) {
|
|
2773
|
-
console.log(
|
|
3040
|
+
console.log(pc8.red(`\u26A0 ${status.conflicts} conflicts detected`));
|
|
2774
3041
|
}
|
|
2775
3042
|
} catch (error) {
|
|
2776
|
-
console.error(
|
|
3043
|
+
console.error(pc8.red("Failed to diff ledgers:"), error);
|
|
2777
3044
|
process.exit(1);
|
|
2778
3045
|
}
|
|
2779
3046
|
});
|
|
@@ -2787,42 +3054,42 @@ function createLedgerCommand() {
|
|
|
2787
3054
|
console.log("Compressing old ledger blocks...");
|
|
2788
3055
|
const result = await compressOldBlocks();
|
|
2789
3056
|
if (result.archived > 0) {
|
|
2790
|
-
console.log(
|
|
3057
|
+
console.log(pc8.green(`\u2713 Compressed ${result.archived} blocks`));
|
|
2791
3058
|
console.log(`Space saved: ${result.sizeReduction}%`);
|
|
2792
3059
|
} else {
|
|
2793
3060
|
console.log("No blocks were archived");
|
|
2794
3061
|
}
|
|
2795
3062
|
} catch (error) {
|
|
2796
|
-
console.error(
|
|
3063
|
+
console.error(pc8.red("Failed to compress blocks:"), error);
|
|
2797
3064
|
process.exit(1);
|
|
2798
3065
|
}
|
|
2799
3066
|
});
|
|
2800
3067
|
ledger.command("storage").description("Show detailed storage statistics").action(async () => {
|
|
2801
3068
|
try {
|
|
2802
3069
|
const stats = await getStorageStats();
|
|
2803
|
-
console.log(
|
|
2804
|
-
console.log(
|
|
2805
|
-
console.log(` Active blocks: ${
|
|
2806
|
-
console.log(` Archived blocks: ${
|
|
2807
|
-
console.log(
|
|
3070
|
+
console.log(pc8.bold("Ledger Storage Statistics\n"));
|
|
3071
|
+
console.log(pc8.bold("Block Storage:"));
|
|
3072
|
+
console.log(` Active blocks: ${pc8.cyan(stats.activeBlocks.toString())}`);
|
|
3073
|
+
console.log(` Archived blocks: ${pc8.cyan(stats.archivedBlocks.toString())}`);
|
|
3074
|
+
console.log(pc8.bold("\nStorage Usage:"));
|
|
2808
3075
|
const activeMB = (stats.activeSize / 1024 / 1024).toFixed(2);
|
|
2809
3076
|
const archivedMB = (stats.archivedSize / 1024 / 1024).toFixed(2);
|
|
2810
3077
|
const totalMB = (Number(activeMB) + Number(archivedMB)).toFixed(2);
|
|
2811
|
-
console.log(` Active storage: ${
|
|
2812
|
-
console.log(` Archived storage: ${
|
|
2813
|
-
console.log(` Total storage: ${
|
|
3078
|
+
console.log(` Active storage: ${pc8.cyan(`${activeMB} MB`)}`);
|
|
3079
|
+
console.log(` Archived storage: ${pc8.cyan(`${archivedMB} MB`)}`);
|
|
3080
|
+
console.log(` Total storage: ${pc8.bold(pc8.cyan(`${totalMB} MB`))}`);
|
|
2814
3081
|
if (stats.compressionRatio > 0) {
|
|
2815
|
-
console.log(` Compression ratio: ${
|
|
3082
|
+
console.log(` Compression ratio: ${pc8.green(`${stats.compressionRatio}%`)}`);
|
|
2816
3083
|
}
|
|
2817
|
-
console.log(
|
|
2818
|
-
console.log(` Total entries: ${
|
|
3084
|
+
console.log(pc8.bold("\nData:"));
|
|
3085
|
+
console.log(` Total entries: ${pc8.cyan(stats.totalEntries.toString())}`);
|
|
2819
3086
|
const needsCompression = await shouldCompress();
|
|
2820
3087
|
if (needsCompression) {
|
|
2821
3088
|
console.log(`
|
|
2822
|
-
${
|
|
3089
|
+
${pc8.yellow("\u{1F4A1} Tip:")} Run ${pc8.bold("trie ledger compress")} to archive old blocks`);
|
|
2823
3090
|
}
|
|
2824
3091
|
} catch (error) {
|
|
2825
|
-
console.error(
|
|
3092
|
+
console.error(pc8.red("Failed to get storage stats:"), error);
|
|
2826
3093
|
process.exit(1);
|
|
2827
3094
|
}
|
|
2828
3095
|
});
|
|
@@ -2831,69 +3098,69 @@ ${pc7.yellow("\u{1F4A1} Tip:")} Run ${pc7.bold("trie ledger compress")} to archi
|
|
|
2831
3098
|
const datePattern = /^\d{4}-\d{2}-\d{2}$/;
|
|
2832
3099
|
const invalidDates = dates.filter((date) => !datePattern.test(date));
|
|
2833
3100
|
if (invalidDates.length > 0) {
|
|
2834
|
-
console.error(
|
|
3101
|
+
console.error(pc8.red("Invalid date format(s):"), invalidDates.join(", "));
|
|
2835
3102
|
console.error("Please use YYYY-MM-DD format");
|
|
2836
3103
|
process.exit(1);
|
|
2837
3104
|
}
|
|
2838
3105
|
if (!options.confirm) {
|
|
2839
|
-
console.log(
|
|
3106
|
+
console.log(pc8.bold(pc8.red("\u26A0\uFE0F DANGER: PERMANENT DELETION")));
|
|
2840
3107
|
console.log("");
|
|
2841
3108
|
console.log(`You are about to permanently delete ${dates.length} block(s):`);
|
|
2842
3109
|
for (const date of dates) {
|
|
2843
|
-
console.log(` \u2022 ${
|
|
3110
|
+
console.log(` \u2022 ${pc8.cyan(date)}`);
|
|
2844
3111
|
}
|
|
2845
3112
|
console.log("");
|
|
2846
|
-
console.log(
|
|
2847
|
-
console.log(
|
|
3113
|
+
console.log(pc8.red("This operation cannot be undone and will permanently remove"));
|
|
3114
|
+
console.log(pc8.red("all issues and data from these blocks."));
|
|
2848
3115
|
console.log("");
|
|
2849
|
-
console.log(`To proceed, add the ${
|
|
2850
|
-
console.log(` ${
|
|
3116
|
+
console.log(`To proceed, add the ${pc8.bold("--confirm")} flag:`);
|
|
3117
|
+
console.log(` ${pc8.dim("trie ledger delete " + dates.join(" ") + " --confirm")}`);
|
|
2851
3118
|
return;
|
|
2852
3119
|
}
|
|
2853
|
-
console.log(
|
|
3120
|
+
console.log(pc8.yellow("\u{1F5D1}\uFE0F Deleting blocks..."));
|
|
2854
3121
|
const result = await deleteBlocks(dates, void 0, true);
|
|
2855
3122
|
if (result.success) {
|
|
2856
|
-
console.log(
|
|
3123
|
+
console.log(pc8.green(`\u2713 Successfully deleted ${result.deletedBlocks} block(s)`));
|
|
2857
3124
|
if (result.warning) {
|
|
2858
|
-
console.log(
|
|
3125
|
+
console.log(pc8.yellow(`\u26A0\uFE0F ${result.warning}`));
|
|
2859
3126
|
}
|
|
2860
3127
|
} else {
|
|
2861
|
-
console.error(
|
|
3128
|
+
console.error(pc8.red("\u2717 Deletion failed:"), result.error);
|
|
2862
3129
|
process.exit(1);
|
|
2863
3130
|
}
|
|
2864
3131
|
} catch (error) {
|
|
2865
|
-
console.error(
|
|
3132
|
+
console.error(pc8.red("Failed to delete blocks:"), error);
|
|
2866
3133
|
process.exit(1);
|
|
2867
3134
|
}
|
|
2868
3135
|
});
|
|
2869
3136
|
ledger.command("clear").description("Delete ALL blocks from the ledger (PERMANENT)").option("--confirm", "Confirm the permanent deletion of all blocks").action(async (options) => {
|
|
2870
3137
|
try {
|
|
2871
3138
|
if (!options.confirm) {
|
|
2872
|
-
console.log(
|
|
3139
|
+
console.log(pc8.bold(pc8.red("\u{1F6A8} DANGER: COMPLETE LEDGER DELETION")));
|
|
2873
3140
|
console.log("");
|
|
2874
|
-
console.log(
|
|
2875
|
-
console.log(
|
|
3141
|
+
console.log(pc8.red("You are about to permanently delete ALL blocks in the ledger."));
|
|
3142
|
+
console.log(pc8.red("This will completely erase the entire ledger history."));
|
|
2876
3143
|
console.log("");
|
|
2877
|
-
console.log(
|
|
2878
|
-
console.log(
|
|
3144
|
+
console.log(pc8.red("This operation cannot be undone and will permanently remove"));
|
|
3145
|
+
console.log(pc8.red("ALL issues and historical data."));
|
|
2879
3146
|
console.log("");
|
|
2880
|
-
console.log(`To proceed, add the ${
|
|
2881
|
-
console.log(` ${
|
|
3147
|
+
console.log(`To proceed, add the ${pc8.bold("--confirm")} flag:`);
|
|
3148
|
+
console.log(` ${pc8.dim("trie ledger clear --confirm")}`);
|
|
2882
3149
|
return;
|
|
2883
3150
|
}
|
|
2884
|
-
console.log(
|
|
3151
|
+
console.log(pc8.yellow("\u{1F5D1}\uFE0F Clearing entire ledger..."));
|
|
2885
3152
|
const result = await deleteAllBlocks(void 0, true);
|
|
2886
3153
|
if (result.success) {
|
|
2887
|
-
console.log(
|
|
3154
|
+
console.log(pc8.green(`\u2713 Successfully deleted ${result.deletedBlocks} block(s)`));
|
|
2888
3155
|
if (result.warning) {
|
|
2889
|
-
console.log(
|
|
3156
|
+
console.log(pc8.yellow(`\u26A0\uFE0F ${result.warning}`));
|
|
2890
3157
|
}
|
|
2891
3158
|
} else {
|
|
2892
|
-
console.error(
|
|
3159
|
+
console.error(pc8.red("\u2717 Clear operation failed:"), result.error);
|
|
2893
3160
|
process.exit(1);
|
|
2894
3161
|
}
|
|
2895
3162
|
} catch (error) {
|
|
2896
|
-
console.error(
|
|
3163
|
+
console.error(pc8.red("Failed to clear ledger:"), error);
|
|
2897
3164
|
process.exit(1);
|
|
2898
3165
|
}
|
|
2899
3166
|
});
|
|
@@ -2901,13 +3168,13 @@ ${pc7.yellow("\u{1F4A1} Tip:")} Run ${pc7.bold("trie ledger compress")} to archi
|
|
|
2901
3168
|
}
|
|
2902
3169
|
|
|
2903
3170
|
// src/cli/main.ts
|
|
2904
|
-
var
|
|
2905
|
-
var
|
|
3171
|
+
var __filename3 = fileURLToPath2(import.meta.url);
|
|
3172
|
+
var __dirname3 = dirname2(__filename3);
|
|
2906
3173
|
var DEFAULT_VERSION = "0.0.0";
|
|
2907
3174
|
function getCliVersion() {
|
|
2908
3175
|
try {
|
|
2909
|
-
const pkgPath =
|
|
2910
|
-
const pkg = JSON.parse(
|
|
3176
|
+
const pkgPath = resolve2(__dirname3, "..", "..", "package.json");
|
|
3177
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
2911
3178
|
return typeof pkg.version === "string" && pkg.version.trim() ? pkg.version.trim() : DEFAULT_VERSION;
|
|
2912
3179
|
} catch {
|
|
2913
3180
|
return DEFAULT_VERSION;
|
|
@@ -2996,51 +3263,6 @@ MCP TOOLS (use via Cursor/Claude Desktop):
|
|
|
2996
3263
|
trie_explain Explain code, issues, or changes
|
|
2997
3264
|
trie_watch Watch mode for autonomous reporting
|
|
2998
3265
|
|
|
2999
|
-
`);
|
|
3000
|
-
}
|
|
3001
|
-
function showSetup() {
|
|
3002
|
-
console.log(`
|
|
3003
|
-
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
3004
|
-
\u2551 Trie Agent Setup \u2551
|
|
3005
|
-
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
3006
|
-
|
|
3007
|
-
STEP 1: API Keys
|
|
3008
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3009
|
-
Trie can work offline, but performs best with these keys:
|
|
3010
|
-
|
|
3011
|
-
1. ANTHROPIC_API_KEY (Required for AI analysis)
|
|
3012
|
-
Get it: https://console.anthropic.com/
|
|
3013
|
-
|
|
3014
|
-
2. LINEAR_API_KEY (Required for JIT defect prediction)
|
|
3015
|
-
Get it: https://linear.app/settings/api
|
|
3016
|
-
|
|
3017
|
-
Set them in your environment (~/.zshrc) or MCP config:
|
|
3018
|
-
export ANTHROPIC_API_KEY=sk-ant-...
|
|
3019
|
-
export LINEAR_API_KEY=lin_api_...
|
|
3020
|
-
|
|
3021
|
-
STEP 2: Configure for your AI tool
|
|
3022
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3023
|
-
|
|
3024
|
-
For CLAUDE CODE:
|
|
3025
|
-
claude mcp add Trie -- npx @triedotdev/mcp
|
|
3026
|
-
|
|
3027
|
-
For CURSOR (~/.cursor/mcp.json):
|
|
3028
|
-
{
|
|
3029
|
-
"mcpServers": {
|
|
3030
|
-
"Trie": {
|
|
3031
|
-
"command": "npx",
|
|
3032
|
-
"args": ["-y", "@triedotdev/mcp"],
|
|
3033
|
-
"env": {
|
|
3034
|
-
"ANTHROPIC_API_KEY": "your-key-here",
|
|
3035
|
-
"LINEAR_API_KEY": "your-key-here"
|
|
3036
|
-
}
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
|
|
3041
|
-
STEP 3: Start scanning!
|
|
3042
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3043
|
-
Ask your AI assistant: "Scan this with Trie" or "Use trie_scan"
|
|
3044
3266
|
`);
|
|
3045
3267
|
}
|
|
3046
3268
|
function showVersion() {
|
|
@@ -3059,47 +3281,47 @@ async function handleStatusCommand() {
|
|
|
3059
3281
|
const lastScanDate = new Date(state.lastScan.timestamp);
|
|
3060
3282
|
const daysAgo = Math.floor((Date.now() - lastScanDate.getTime()) / (1e3 * 60 * 60 * 24));
|
|
3061
3283
|
console.log(`
|
|
3062
|
-
${
|
|
3063
|
-
console.log(
|
|
3064
|
-
console.log(
|
|
3284
|
+
${pc9.bold("Last Scan:")} ${lastScanDate.toLocaleDateString()} (${daysAgo === 0 ? "today" : daysAgo === 1 ? "yesterday" : `${daysAgo} days ago`})`);
|
|
3285
|
+
console.log(pc9.dim(` Files scanned: ${state.lastScan.filesScanned}`));
|
|
3286
|
+
console.log(pc9.dim(` Issues found: ${state.lastScan.issues.total} (${state.lastScan.issues.critical} critical, ${state.lastScan.issues.serious} serious)`));
|
|
3065
3287
|
} else {
|
|
3066
3288
|
console.log(`
|
|
3067
|
-
${
|
|
3289
|
+
${pc9.bold("Last Scan:")} Never ${pc9.dim("(run `trie scan` to get started)")}`);
|
|
3068
3290
|
}
|
|
3069
3291
|
console.log(`
|
|
3070
|
-
${
|
|
3071
|
-
console.log(
|
|
3072
|
-
console.log(
|
|
3073
|
-
console.log(
|
|
3292
|
+
${pc9.bold("Memory Stats:")}`);
|
|
3293
|
+
console.log(pc9.dim(` Active Issues: ${memoryStats.activeIssues}`));
|
|
3294
|
+
console.log(pc9.dim(` Resolved: ${memoryStats.resolvedCount}`));
|
|
3295
|
+
console.log(pc9.dim(` Total (all-time): ${memoryStats.totalIssues}`));
|
|
3074
3296
|
const cap = memoryStats.capacityInfo;
|
|
3075
|
-
const capIndicator = cap.isAtCap ?
|
|
3076
|
-
console.log(` ${capIndicator} Memory Usage: ${
|
|
3297
|
+
const capIndicator = cap.isAtCap ? pc9.red("\u25CB") : cap.percentFull >= 80 ? pc9.yellow("\u25C9") : pc9.green("\u25CF");
|
|
3298
|
+
console.log(` ${capIndicator} Memory Usage: ${pc9.bold(cap.percentFull + "%")} ${pc9.dim(`(${cap.current}/${cap.max})`)}`);
|
|
3077
3299
|
if (memoryStats.activeIssues > 0) {
|
|
3078
3300
|
console.log(`
|
|
3079
|
-
${
|
|
3301
|
+
${pc9.bold("Active Issues by Severity:")}`);
|
|
3080
3302
|
const severityOrder = ["critical", "serious", "moderate", "low", "info"];
|
|
3081
3303
|
for (const severity of severityOrder) {
|
|
3082
3304
|
const count = memoryStats.activeIssuesBySeverity[severity] || 0;
|
|
3083
3305
|
if (count > 0) {
|
|
3084
|
-
console.log(
|
|
3306
|
+
console.log(pc9.dim(` ${severity}: ${count}`));
|
|
3085
3307
|
}
|
|
3086
3308
|
}
|
|
3087
3309
|
} else if (memoryStats.totalIssues > 0) {
|
|
3088
3310
|
console.log(`
|
|
3089
|
-
${
|
|
3311
|
+
${pc9.green("\u25CF")} All issues have been resolved`);
|
|
3090
3312
|
}
|
|
3091
3313
|
if (cap.isAtCap) {
|
|
3092
3314
|
console.log(`
|
|
3093
|
-
${
|
|
3315
|
+
${pc9.yellow("\u2B22 Warning:")} Memory at capacity - consider running: ${pc9.bold("trie memory purge smart")}`);
|
|
3094
3316
|
} else if (cap.percentFull >= 80) {
|
|
3095
3317
|
console.log(`
|
|
3096
|
-
${
|
|
3318
|
+
${pc9.yellow("\u2B22 Notice:")} Memory usage high - consider running: ${pc9.bold("trie memory purge smart")}`);
|
|
3097
3319
|
}
|
|
3098
3320
|
console.log(`
|
|
3099
|
-
${
|
|
3100
|
-
console.log(
|
|
3101
|
-
console.log(
|
|
3102
|
-
console.log(
|
|
3321
|
+
${pc9.bold("Quick Commands:")}`);
|
|
3322
|
+
console.log(pc9.dim(" trie scan - Scan codebase now"));
|
|
3323
|
+
console.log(pc9.dim(" trie memory stats - Detailed memory statistics"));
|
|
3324
|
+
console.log(pc9.dim(" trie project - View project information"));
|
|
3103
3325
|
console.log("");
|
|
3104
3326
|
} catch (error) {
|
|
3105
3327
|
console.error("Error loading status:", error);
|
|
@@ -3117,7 +3339,7 @@ async function handleProject(args) {
|
|
|
3117
3339
|
\u2551 PROJECT.md Created \u2551
|
|
3118
3340
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
3119
3341
|
|
|
3120
|
-
${
|
|
3342
|
+
${pc9.bold("Path:")} ${result.path}
|
|
3121
3343
|
|
|
3122
3344
|
A template has been created with sections for:
|
|
3123
3345
|
\u2022 Project Overview
|
|
@@ -3142,7 +3364,7 @@ Next steps:
|
|
|
3142
3364
|
}
|
|
3143
3365
|
if (subcommand === "edit") {
|
|
3144
3366
|
const editor = process.env.EDITOR || process.env.VISUAL || "nano";
|
|
3145
|
-
const projectPath =
|
|
3367
|
+
const projectPath = join5(getTrieDirectory(workDir), "PROJECT.md");
|
|
3146
3368
|
if (!projectInfoExists(workDir)) {
|
|
3147
3369
|
console.log("No PROJECT.md found. Creating one first...");
|
|
3148
3370
|
await initProjectInfo(workDir);
|
|
@@ -3160,7 +3382,7 @@ Next steps:
|
|
|
3160
3382
|
\u2551 Project Information \u2551
|
|
3161
3383
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
3162
3384
|
|
|
3163
|
-
${
|
|
3385
|
+
${pc9.bold("No PROJECT.md found in this project.")}
|
|
3164
3386
|
|
|
3165
3387
|
COMMANDS:
|
|
3166
3388
|
trie project init Create PROJECT.md from template
|
|
@@ -3188,7 +3410,7 @@ This info is available via trie://project MCP resource.
|
|
|
3188
3410
|
\u2551 Project Information \u2551
|
|
3189
3411
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
3190
3412
|
|
|
3191
|
-
${
|
|
3413
|
+
${pc9.bold("Path:")} ${join5(getTrieDirectory(workDir), "PROJECT.md")}
|
|
3192
3414
|
|
|
3193
3415
|
${"-".repeat(68)}
|
|
3194
3416
|
`);
|
|
@@ -3197,10 +3419,10 @@ ${"-".repeat(68)}
|
|
|
3197
3419
|
async function runScan(args) {
|
|
3198
3420
|
const { spawn } = await import("child_process");
|
|
3199
3421
|
let daemonPath;
|
|
3200
|
-
if (
|
|
3201
|
-
daemonPath =
|
|
3422
|
+
if (__filename3.endsWith(".ts")) {
|
|
3423
|
+
daemonPath = resolve2(__dirname3, "yolo-daemon.ts");
|
|
3202
3424
|
} else {
|
|
3203
|
-
daemonPath =
|
|
3425
|
+
daemonPath = resolve2(__dirname3, "yolo-daemon.js");
|
|
3204
3426
|
}
|
|
3205
3427
|
const daemonArgs = ["--once", ...args];
|
|
3206
3428
|
const executor = daemonPath.endsWith(".ts") ? "npx" : "node";
|
|
@@ -3216,10 +3438,10 @@ async function runScan(args) {
|
|
|
3216
3438
|
async function runWatch(args) {
|
|
3217
3439
|
const { spawn } = await import("child_process");
|
|
3218
3440
|
let daemonPath;
|
|
3219
|
-
if (
|
|
3220
|
-
daemonPath =
|
|
3441
|
+
if (__filename3.endsWith(".ts")) {
|
|
3442
|
+
daemonPath = resolve2(__dirname3, "yolo-daemon.ts");
|
|
3221
3443
|
} else {
|
|
3222
|
-
daemonPath =
|
|
3444
|
+
daemonPath = resolve2(__dirname3, "yolo-daemon.js");
|
|
3223
3445
|
}
|
|
3224
3446
|
const executor = daemonPath.endsWith(".ts") ? "npx" : "node";
|
|
3225
3447
|
const execArgs = daemonPath.endsWith(".ts") ? ["tsx", daemonPath, ...args] : [daemonPath, ...args];
|
|
@@ -3252,7 +3474,7 @@ async function main() {
|
|
|
3252
3474
|
case "setup":
|
|
3253
3475
|
case "config":
|
|
3254
3476
|
case "configure":
|
|
3255
|
-
|
|
3477
|
+
await handleSetupCommand(restArgs);
|
|
3256
3478
|
break;
|
|
3257
3479
|
case "init":
|
|
3258
3480
|
case "bootstrap":
|
|
@@ -3296,6 +3518,12 @@ async function main() {
|
|
|
3296
3518
|
case "pre-push":
|
|
3297
3519
|
handlePrePushCommand(restArgs);
|
|
3298
3520
|
break;
|
|
3521
|
+
case "pre-commit":
|
|
3522
|
+
handlePreCommitCommand(restArgs);
|
|
3523
|
+
break;
|
|
3524
|
+
case "post-commit":
|
|
3525
|
+
handlePostCommitCommand(restArgs);
|
|
3526
|
+
break;
|
|
3299
3527
|
case "fix":
|
|
3300
3528
|
case "auto-fix":
|
|
3301
3529
|
case "autofix":
|
|
@@ -3362,7 +3590,7 @@ async function main() {
|
|
|
3362
3590
|
default:
|
|
3363
3591
|
if (command.startsWith("-")) {
|
|
3364
3592
|
const { spawn } = __require("child_process");
|
|
3365
|
-
const daemonPath =
|
|
3593
|
+
const daemonPath = resolve2(__dirname3, "yolo-daemon.js");
|
|
3366
3594
|
const child = spawn("node", [daemonPath, ...args], {
|
|
3367
3595
|
stdio: "inherit",
|
|
3368
3596
|
env: process.env
|
|
@@ -3382,7 +3610,7 @@ var isEntryPoint = (() => {
|
|
|
3382
3610
|
if (!entry) return false;
|
|
3383
3611
|
try {
|
|
3384
3612
|
const realEntry = realpathSync(entry);
|
|
3385
|
-
const realThis =
|
|
3613
|
+
const realThis = fileURLToPath2(import.meta.url);
|
|
3386
3614
|
return realEntry === realThis;
|
|
3387
3615
|
} catch {
|
|
3388
3616
|
return !process.env.VITEST && !process.env.VITEST_WORKER_ID;
|