@triedotdev/mcp 1.0.87 → 1.0.89
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 +96 -12
- package/dist/{agent-smith-MCKGNWPL.js → agent-smith-KIFP2XG3.js} +4 -4
- package/dist/{agent-smith-runner-GP5HLL7E.js → agent-smith-runner-Z73W5DR5.js} +4 -4
- package/dist/{chunk-4U3DNRUA.js → chunk-3HTPH3P2.js} +213 -12
- package/dist/chunk-3HTPH3P2.js.map +1 -0
- package/dist/{chunk-KERQ4JXR.js → chunk-A44W6SZJ.js} +50 -17
- package/dist/chunk-A44W6SZJ.js.map +1 -0
- package/dist/{chunk-Z6JP2QQU.js → chunk-BBEFK56U.js} +27 -26
- package/dist/chunk-BBEFK56U.js.map +1 -0
- package/dist/{chunk-X3E6ISEG.js → chunk-CFE7FZU7.js} +7 -4
- package/dist/chunk-CFE7FZU7.js.map +1 -0
- package/dist/{chunk-KGVKUMFO.js → chunk-D35TI7NY.js} +2 -2
- package/dist/{chunk-CM7EHNQK.js → chunk-D5VEUZLP.js} +33 -2
- package/dist/chunk-D5VEUZLP.js.map +1 -0
- package/dist/{chunk-TBRU735C.js → chunk-F3WW4FY2.js} +6 -3
- package/dist/chunk-F3WW4FY2.js.map +1 -0
- package/dist/{chunk-DXBYHIA7.js → chunk-G4DUCCMT.js} +8 -8
- package/dist/{chunk-DCJKNE2L.js → chunk-GMKPXL4Q.js} +4 -3
- package/dist/chunk-GMKPXL4Q.js.map +1 -0
- package/dist/{chunk-7UPNCM66.js → chunk-JG2TAVAO.js} +14 -13
- package/dist/chunk-JG2TAVAO.js.map +1 -0
- package/dist/{chunk-THJKXIMJ.js → chunk-OXZKSR6J.js} +7 -4
- package/dist/chunk-OXZKSR6J.js.map +1 -0
- package/dist/{chunk-TDWPEV3N.js → chunk-PFWGEHIA.js} +8 -5
- package/dist/chunk-PFWGEHIA.js.map +1 -0
- package/dist/{chunk-PH4HZEAM.js → chunk-QH5XB4K6.js} +6 -5
- package/dist/chunk-QH5XB4K6.js.map +1 -0
- package/dist/{chunk-4UVTFL2T.js → chunk-TBL3FWWG.js} +22 -21
- package/dist/chunk-TBL3FWWG.js.map +1 -0
- package/dist/cli/create-agent.js +2 -2
- package/dist/cli/main.js +241 -18
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +12 -12
- package/dist/{goal-manager-JTM6MOZG.js → goal-manager-7D3GUJVV.js} +5 -5
- package/dist/guardian-agent-QBYV2JLR.js +21 -0
- package/dist/index.js +23 -22
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-AZ3D4LOG.js → issue-store-WTXCQZEA.js} +3 -3
- package/dist/workers/agent-worker.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-4U3DNRUA.js.map +0 -1
- package/dist/chunk-4UVTFL2T.js.map +0 -1
- package/dist/chunk-7UPNCM66.js.map +0 -1
- package/dist/chunk-CM7EHNQK.js.map +0 -1
- package/dist/chunk-DCJKNE2L.js.map +0 -1
- package/dist/chunk-KERQ4JXR.js.map +0 -1
- package/dist/chunk-PH4HZEAM.js.map +0 -1
- package/dist/chunk-TBRU735C.js.map +0 -1
- package/dist/chunk-TDWPEV3N.js.map +0 -1
- package/dist/chunk-THJKXIMJ.js.map +0 -1
- package/dist/chunk-X3E6ISEG.js.map +0 -1
- package/dist/chunk-Z6JP2QQU.js.map +0 -1
- package/dist/guardian-agent-RIF7XBFL.js +0 -21
- /package/dist/{agent-smith-MCKGNWPL.js.map → agent-smith-KIFP2XG3.js.map} +0 -0
- /package/dist/{agent-smith-runner-GP5HLL7E.js.map → agent-smith-runner-Z73W5DR5.js.map} +0 -0
- /package/dist/{chunk-KGVKUMFO.js.map → chunk-D35TI7NY.js.map} +0 -0
- /package/dist/{chunk-DXBYHIA7.js.map → chunk-G4DUCCMT.js.map} +0 -0
- /package/dist/{goal-manager-JTM6MOZG.js.map → goal-manager-7D3GUJVV.js.map} +0 -0
- /package/dist/{guardian-agent-RIF7XBFL.js.map → guardian-agent-QBYV2JLR.js.map} +0 -0
- /package/dist/{issue-store-AZ3D4LOG.js.map → issue-store-WTXCQZEA.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,29 +1,26 @@
|
|
|
1
1
|
# Trie: Trainable AI Agent for Maintaining AI-Generated Codebases
|
|
2
2
|
|
|
3
|
-
A trainable AI agent that watches all of your codebases, learns from your incidents, and prevents repeat bugs before they ship
|
|
3
|
+
**A trainable AI agent that watches all of your codebases, learns from your incidents, and prevents repeat bugs before they ship.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
<a href="https://www.trie.dev"><img alt="Download Workspace" src="https://img.shields.io/badge/Download_Workspace-0b0f14?style=for-the-badge&logo=vercel&logoColor=white"></a>
|
|
7
|
-
<a href="https://x.com/louiskishfy"><img alt="Follow on X" src="https://img.shields.io/badge/Follow_on_X-000000?style=for-the-badge&logo=x&logoColor=white"></a>
|
|
8
|
-
</p>
|
|
5
|
+
[](https://www.trie.dev) [](https://x.com/louiskishfy)
|
|
9
6
|
|
|
10
7
|
## What Trie Does
|
|
11
8
|
|
|
12
|
-
- Central skill repository
|
|
13
|
-
- Sets and tracks goals
|
|
14
|
-
- Tests your theories
|
|
15
|
-
- Learns from your incidents
|
|
16
|
-
- Predicts "Gotchas" proactively
|
|
9
|
+
- **Central skill repository**: One place for all your skills — carry context and rules across Cursor, Claude, VS Code, CLI, and CI/CD. Unlike running skills with Claude Code, Trie will check for anything malicious before you run them.
|
|
10
|
+
- **Sets and tracks goals**: "Reduce login bugs by 50%" then actually measures progress and celebrates wins
|
|
11
|
+
- **Tests your theories**: "Mondays have more bugs" — Trie validates with real data and builds confidence over time
|
|
12
|
+
- **Learns from your incidents**: Train it on your specific patterns, not generic rules that don't fit your prompting
|
|
13
|
+
- **Predicts "Gotchas" proactively**: Ingests Linear tickets and correlates them with past failures to warn you before you even push code
|
|
17
14
|
|
|
18
15
|
## Goal
|
|
19
16
|
|
|
20
|
-
Trie exists so you can maintain multiple codebases as one person without losing your mind.
|
|
17
|
+
Trie exists so you can maintain multiple codebases as one person without losing your mind.
|
|
21
18
|
|
|
22
19
|
Every bug you fix teaches Trie a pattern that protects all your projects. Every incident you report becomes institutional knowledge that travels with your code. Every decision you make—and the tradeoffs you considered—gets remembered across Cursor, Claude, VS Code, CLI, and CI/CD.
|
|
23
20
|
|
|
24
21
|
Instead of burning tokens on the same questions across different repos or forgetting why you architected something a certain way six months ago, Trie remembers for you. Instead of losing track of edge cases and tradeoffs as you switch between tools, Trie maintains system coherence. The result is faster development with fewer production fires, because your personal AI agent gets smarter every time something breaks instead of starting from zero in every conversation.
|
|
25
22
|
|
|
26
|
-
Your thinking and planning keep up with code generation. Your decisions persist across tools. Your edge cases don't get forgotten
|
|
23
|
+
**Your thinking and planning keep up with code generation. Your decisions persist across tools. Your edge cases don't get forgotten.**
|
|
27
24
|
|
|
28
25
|
## Quick Start
|
|
29
26
|
|
|
@@ -151,6 +148,22 @@ When you switch from Cursor to Claude Code to terminal, Trie remembers. Your thi
|
|
|
151
148
|
|
|
152
149
|
## Core Workflow
|
|
153
150
|
|
|
151
|
+
### 0. Planning Phase
|
|
152
|
+
|
|
153
|
+
**Start every complex task by checking Trie first.** Just like starting in plan mode helps Claude 1-shot implementation, checking Trie before coding helps you avoid known pitfalls:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Before starting work on a feature, check what broke before
|
|
157
|
+
trie gotcha # Predict risks for current changes
|
|
158
|
+
trie memory search "auth" # See past incidents in this area
|
|
159
|
+
trie status # Check overall project health
|
|
160
|
+
|
|
161
|
+
# Review past decisions and tradeoffs
|
|
162
|
+
# Trie's Context Graph remembers why you made choices and what happened
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Pro tip:** The moment something goes sideways, check Trie again. Don't keep pushing—re-plan with historical context. Trie shows you what broke before, what decisions were made, and what edge cases caused issues. Use that knowledge to inform your plan, then let your AI tools implement it.
|
|
166
|
+
|
|
154
167
|
### 1. Teaching Phase
|
|
155
168
|
|
|
156
169
|
```bash
|
|
@@ -485,6 +498,38 @@ git push --no-verify # Skip all hooks
|
|
|
485
498
|
TRIE_BYPASS=1 git push # Skip Trie but log bypass
|
|
486
499
|
```
|
|
487
500
|
|
|
501
|
+
### Slack Integration
|
|
502
|
+
|
|
503
|
+
Trie sends notifications to Slack for team collaboration:
|
|
504
|
+
|
|
505
|
+
**Setup:**
|
|
506
|
+
1. Create a Slack webhook: https://api.slack.com/apps
|
|
507
|
+
2. Add to `.trie/config.json`:
|
|
508
|
+
|
|
509
|
+
```json
|
|
510
|
+
{
|
|
511
|
+
"integrations": {
|
|
512
|
+
"slack": {
|
|
513
|
+
"enabled": true,
|
|
514
|
+
"webhook": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
|
|
515
|
+
"channel": "#security" // Optional: default channel
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
"autoEscalation": {
|
|
519
|
+
"enabled": true,
|
|
520
|
+
"webhookUrl": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
|
|
521
|
+
"quietHours": { "start": "21:00", "end": "08:00" }
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
**What Trie sends to Slack:**
|
|
527
|
+
- Scan completion notifications with issue counts
|
|
528
|
+
- Critical security alerts (immediate)
|
|
529
|
+
- Daily/weekly team summaries
|
|
530
|
+
- Escalation notifications for overdue issues
|
|
531
|
+
- Bulk fix notifications
|
|
532
|
+
|
|
488
533
|
## CI/CD Integration
|
|
489
534
|
|
|
490
535
|
### GitHub Actions
|
|
@@ -1037,6 +1082,37 @@ trie learn # Learn from your git history
|
|
|
1037
1082
|
trie pause # Disable warnings for 1 hour
|
|
1038
1083
|
```
|
|
1039
1084
|
|
|
1085
|
+
### Pattern Sharing
|
|
1086
|
+
Save, validate, and share patterns that worked well across projects:
|
|
1087
|
+
|
|
1088
|
+
```bash
|
|
1089
|
+
# Save patterns (auto-detects type: file structure, code pattern, or detection rule)
|
|
1090
|
+
trie patterns save "auth/login.ts" "This error handling prevented 3 bugs"
|
|
1091
|
+
trie patterns save "auth/*" "This folder structure worked well"
|
|
1092
|
+
trie patterns save security "This scout caught issues early"
|
|
1093
|
+
|
|
1094
|
+
# List saved patterns
|
|
1095
|
+
trie patterns list
|
|
1096
|
+
trie patterns list --validated # Only validated patterns
|
|
1097
|
+
|
|
1098
|
+
# Validate a pattern (mark as "worked great")
|
|
1099
|
+
trie patterns validate pattern-abc123 "Worked great in production"
|
|
1100
|
+
|
|
1101
|
+
# Export patterns to share
|
|
1102
|
+
trie patterns export my-patterns.json --validated
|
|
1103
|
+
|
|
1104
|
+
# Import patterns into another project
|
|
1105
|
+
cd ../another-project
|
|
1106
|
+
trie patterns import ../source-project/patterns.json
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
**Smart Pattern Detection:**
|
|
1110
|
+
- **File structure patterns** - Architecture decisions (`path/*`, `*.ts`)
|
|
1111
|
+
- **Code patterns** - Specific fixes/approaches that worked (`path/to/file.ts`)
|
|
1112
|
+
- **Detection rules** - Scout configurations that caught issues (`security`, `privacy`)
|
|
1113
|
+
|
|
1114
|
+
Saved patterns are automatically applied during `trie scan` and `trie watch` runs.
|
|
1115
|
+
|
|
1040
1116
|
### Watch Mode
|
|
1041
1117
|
```bash
|
|
1042
1118
|
trie watch # Start interactive monitoring dashboard
|
|
@@ -1112,6 +1188,14 @@ Global patterns stored in `~/.trie/memory/`:
|
|
|
1112
1188
|
- Skill effectiveness data
|
|
1113
1189
|
- Your personal coding patterns
|
|
1114
1190
|
|
|
1191
|
+
### Git Worktrees
|
|
1192
|
+
Trie is worktree-aware and shares a single `.trie/` across linked worktrees by default.
|
|
1193
|
+
|
|
1194
|
+
If you want isolated memory per worktree, set:
|
|
1195
|
+
```
|
|
1196
|
+
TRIE_WORKTREE_MODE=isolated
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1115
1199
|
### Memory Management
|
|
1116
1200
|
```bash
|
|
1117
1201
|
# View capacity (default: 10,000 issues)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentSmithSkill,
|
|
3
3
|
PATTERN_HUNTER_CONFIGS
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-F3WW4FY2.js";
|
|
5
|
+
import "./chunk-GMKPXL4Q.js";
|
|
6
|
+
import "./chunk-D5VEUZLP.js";
|
|
7
7
|
import "./chunk-MIL54SAF.js";
|
|
8
8
|
import "./chunk-DGUM43GV.js";
|
|
9
9
|
export {
|
|
@@ -11,4 +11,4 @@ export {
|
|
|
11
11
|
AgentSmithSkill,
|
|
12
12
|
PATTERN_HUNTER_CONFIGS
|
|
13
13
|
};
|
|
14
|
-
//# sourceMappingURL=agent-smith-
|
|
14
|
+
//# sourceMappingURL=agent-smith-KIFP2XG3.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentSmithSkill
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-F3WW4FY2.js";
|
|
4
4
|
import {
|
|
5
5
|
getAIStatusMessage,
|
|
6
6
|
isAIAvailable,
|
|
7
7
|
runAIAnalysis
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GMKPXL4Q.js";
|
|
9
9
|
import {
|
|
10
10
|
getWorkingDirectory
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-D5VEUZLP.js";
|
|
12
12
|
import {
|
|
13
13
|
isInteractiveMode
|
|
14
14
|
} from "./chunk-MIL54SAF.js";
|
|
@@ -570,4 +570,4 @@ ${getAIStatusMessage()}`);
|
|
|
570
570
|
export {
|
|
571
571
|
runAgentSmith
|
|
572
572
|
};
|
|
573
|
-
//# sourceMappingURL=agent-smith-runner-
|
|
573
|
+
//# sourceMappingURL=agent-smith-runner-Z73W5DR5.js.map
|
|
@@ -3,18 +3,20 @@ import {
|
|
|
3
3
|
getSkillRegistry,
|
|
4
4
|
loadContextState,
|
|
5
5
|
runExecFile
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BBEFK56U.js";
|
|
7
7
|
import {
|
|
8
8
|
getGlobalMemoryStats
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-D35TI7NY.js";
|
|
10
10
|
import {
|
|
11
11
|
getHistoricalInsights,
|
|
12
12
|
getMemoryStats,
|
|
13
|
-
getRecentIssues
|
|
14
|
-
|
|
13
|
+
getRecentIssues,
|
|
14
|
+
searchIssues
|
|
15
|
+
} from "./chunk-JG2TAVAO.js";
|
|
15
16
|
import {
|
|
17
|
+
getTrieDirectory,
|
|
16
18
|
getWorkingDirectory
|
|
17
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-D5VEUZLP.js";
|
|
18
20
|
import {
|
|
19
21
|
isInteractiveMode
|
|
20
22
|
} from "./chunk-MIL54SAF.js";
|
|
@@ -35,7 +37,7 @@ var INIT_MARKERS = [
|
|
|
35
37
|
];
|
|
36
38
|
function isTrieInitialized(workDir) {
|
|
37
39
|
const dir = workDir || getWorkingDirectory(void 0, true);
|
|
38
|
-
const trieDir =
|
|
40
|
+
const trieDir = getTrieDirectory(dir);
|
|
39
41
|
return INIT_MARKERS.some((marker) => existsSync(join(trieDir, marker)));
|
|
40
42
|
}
|
|
41
43
|
|
|
@@ -183,7 +185,7 @@ var ConfigValidator = class {
|
|
|
183
185
|
let anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
184
186
|
if (!anthropicKey) {
|
|
185
187
|
try {
|
|
186
|
-
const configPath = join2(getWorkingDirectory(void 0, true), "
|
|
188
|
+
const configPath = join2(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
187
189
|
if (existsSync2(configPath)) {
|
|
188
190
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
189
191
|
anthropicKey = config.apiKeys?.anthropic;
|
|
@@ -419,7 +421,7 @@ var DEFAULT_CONFIG = {
|
|
|
419
421
|
// src/config/loader.ts
|
|
420
422
|
async function loadConfig() {
|
|
421
423
|
const validator = new ConfigValidator();
|
|
422
|
-
const configPath = join3(getWorkingDirectory(void 0, true), "
|
|
424
|
+
const configPath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
423
425
|
try {
|
|
424
426
|
if (!existsSync3(configPath)) {
|
|
425
427
|
return DEFAULT_CONFIG;
|
|
@@ -455,7 +457,7 @@ async function loadConfig() {
|
|
|
455
457
|
}
|
|
456
458
|
}
|
|
457
459
|
async function saveConfig(config) {
|
|
458
|
-
const configPath = join3(getWorkingDirectory(void 0, true), "
|
|
460
|
+
const configPath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
|
|
459
461
|
const dir = dirname(configPath);
|
|
460
462
|
if (!existsSync3(dir)) {
|
|
461
463
|
await mkdir(dir, { recursive: true });
|
|
@@ -1413,7 +1415,7 @@ var CacheManager = class {
|
|
|
1413
1415
|
// 24 hours
|
|
1414
1416
|
MAX_ENTRIES = 1e3;
|
|
1415
1417
|
constructor(baseDir) {
|
|
1416
|
-
this.cacheDir = join4(baseDir, "
|
|
1418
|
+
this.cacheDir = join4(getTrieDirectory(baseDir), "cache");
|
|
1417
1419
|
this.indexPath = join4(this.cacheDir, "index.json");
|
|
1418
1420
|
}
|
|
1419
1421
|
/**
|
|
@@ -2227,6 +2229,199 @@ function getSkillCategories() {
|
|
|
2227
2229
|
}));
|
|
2228
2230
|
}
|
|
2229
2231
|
|
|
2232
|
+
// src/patterns/saved-patterns.ts
|
|
2233
|
+
import { createHash as createHash2 } from "crypto";
|
|
2234
|
+
import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
2235
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2236
|
+
import { join as join6, basename } from "path";
|
|
2237
|
+
async function loadSavedPatterns(workDir) {
|
|
2238
|
+
const patternsPath = join6(getTrieDirectory(workDir), "saved-patterns.json");
|
|
2239
|
+
try {
|
|
2240
|
+
if (existsSync7(patternsPath)) {
|
|
2241
|
+
const content = await readFile4(patternsPath, "utf-8");
|
|
2242
|
+
return JSON.parse(content);
|
|
2243
|
+
}
|
|
2244
|
+
} catch {
|
|
2245
|
+
}
|
|
2246
|
+
return [];
|
|
2247
|
+
}
|
|
2248
|
+
async function savePatternsToProject(patterns, workDir) {
|
|
2249
|
+
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
2250
|
+
const patternsPath = join6(getTrieDirectory(workDir), "saved-patterns.json");
|
|
2251
|
+
await mkdir3(getTrieDirectory(workDir), { recursive: true });
|
|
2252
|
+
await writeFile3(patternsPath, JSON.stringify(patterns, null, 2));
|
|
2253
|
+
}
|
|
2254
|
+
async function savePatternToProject(pattern, workDir) {
|
|
2255
|
+
const patterns = await loadSavedPatterns(workDir);
|
|
2256
|
+
const existing = patterns.findIndex((p) => p.id === pattern.id);
|
|
2257
|
+
if (existing >= 0) {
|
|
2258
|
+
patterns[existing] = {
|
|
2259
|
+
...patterns[existing],
|
|
2260
|
+
...pattern,
|
|
2261
|
+
occurrences: patterns[existing].occurrences + 1
|
|
2262
|
+
};
|
|
2263
|
+
} else {
|
|
2264
|
+
patterns.push(pattern);
|
|
2265
|
+
}
|
|
2266
|
+
await savePatternsToProject(patterns, workDir);
|
|
2267
|
+
}
|
|
2268
|
+
function detectPatternType(target, workDir) {
|
|
2269
|
+
const scoutNames = [
|
|
2270
|
+
"security",
|
|
2271
|
+
"privacy",
|
|
2272
|
+
"legal",
|
|
2273
|
+
"accessibility",
|
|
2274
|
+
"bug-finding",
|
|
2275
|
+
"architecture",
|
|
2276
|
+
"types",
|
|
2277
|
+
"clean",
|
|
2278
|
+
"devops",
|
|
2279
|
+
"performance",
|
|
2280
|
+
"ux",
|
|
2281
|
+
"design",
|
|
2282
|
+
"production-ready",
|
|
2283
|
+
"agent-smith"
|
|
2284
|
+
];
|
|
2285
|
+
if (scoutNames.includes(target.toLowerCase())) {
|
|
2286
|
+
return "detection-rule";
|
|
2287
|
+
}
|
|
2288
|
+
const fullPath = join6(workDir, target);
|
|
2289
|
+
if (existsSync7(fullPath) || target.includes("/") || target.includes("*") || target.endsWith(".ts") || target.endsWith(".js")) {
|
|
2290
|
+
return "file-structure";
|
|
2291
|
+
}
|
|
2292
|
+
return "code-pattern";
|
|
2293
|
+
}
|
|
2294
|
+
function generatePatternId(target, type) {
|
|
2295
|
+
const hash = createHash2("sha256").update(`${type}:${target}`).digest("hex").slice(0, 12);
|
|
2296
|
+
return `${type}-${hash}`;
|
|
2297
|
+
}
|
|
2298
|
+
function getDetectionRuleAgents(patterns) {
|
|
2299
|
+
return patterns.filter((p) => p.type === "detection-rule").map((p) => p.detectionRule?.agent || p.name).filter(Boolean);
|
|
2300
|
+
}
|
|
2301
|
+
async function createSavedPattern(target, note, workDir) {
|
|
2302
|
+
const projectName = basename(workDir);
|
|
2303
|
+
const patternType = detectPatternType(target, workDir);
|
|
2304
|
+
const savedPattern = {
|
|
2305
|
+
id: generatePatternId(target, patternType),
|
|
2306
|
+
type: patternType,
|
|
2307
|
+
name: target,
|
|
2308
|
+
description: note || `Pattern saved from ${projectName}`,
|
|
2309
|
+
validated: false,
|
|
2310
|
+
projects: [projectName],
|
|
2311
|
+
occurrences: 1,
|
|
2312
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2313
|
+
savedBy: projectName
|
|
2314
|
+
};
|
|
2315
|
+
if (patternType === "file-structure") {
|
|
2316
|
+
savedPattern.filePatterns = [target];
|
|
2317
|
+
savedPattern.architecture = {
|
|
2318
|
+
structure: `Files matching ${target}`,
|
|
2319
|
+
rationale: note || "File structure pattern that worked well"
|
|
2320
|
+
};
|
|
2321
|
+
} else if (patternType === "code-pattern") {
|
|
2322
|
+
const issues = await searchIssues(target, { limit: 5 });
|
|
2323
|
+
if (issues.length > 0) {
|
|
2324
|
+
const latestIssue = issues[0];
|
|
2325
|
+
savedPattern.codePattern = {
|
|
2326
|
+
pattern: latestIssue?.issue.issue || target,
|
|
2327
|
+
fix: latestIssue?.issue.fix || "Review and apply similar fix",
|
|
2328
|
+
context: note || "Code pattern that worked well"
|
|
2329
|
+
};
|
|
2330
|
+
} else {
|
|
2331
|
+
savedPattern.codePattern = {
|
|
2332
|
+
pattern: target,
|
|
2333
|
+
fix: "Review and apply similar fix",
|
|
2334
|
+
context: note || "Code pattern that worked well"
|
|
2335
|
+
};
|
|
2336
|
+
}
|
|
2337
|
+
} else if (patternType === "detection-rule") {
|
|
2338
|
+
savedPattern.detectionRule = {
|
|
2339
|
+
agent: target,
|
|
2340
|
+
rule: `Detection rules from ${target} scout`,
|
|
2341
|
+
severity: "moderate"
|
|
2342
|
+
};
|
|
2343
|
+
}
|
|
2344
|
+
return savedPattern;
|
|
2345
|
+
}
|
|
2346
|
+
async function buildSavedPatternIssues(patterns, files, readFileContent) {
|
|
2347
|
+
const issues = [];
|
|
2348
|
+
for (const pattern of patterns) {
|
|
2349
|
+
if (pattern.type === "detection-rule") continue;
|
|
2350
|
+
const targetFiles = filterFilesForPattern(files, pattern);
|
|
2351
|
+
if (targetFiles.length === 0) continue;
|
|
2352
|
+
if (pattern.type === "file-structure") {
|
|
2353
|
+
for (const file of targetFiles) {
|
|
2354
|
+
issues.push(createPatternIssue(pattern, file, void 0));
|
|
2355
|
+
}
|
|
2356
|
+
continue;
|
|
2357
|
+
}
|
|
2358
|
+
if (pattern.type === "code-pattern" && pattern.codePattern) {
|
|
2359
|
+
for (const file of targetFiles) {
|
|
2360
|
+
const content = await readFileContent(file);
|
|
2361
|
+
const match = findPatternMatch(content, pattern.codePattern.pattern);
|
|
2362
|
+
if (match) {
|
|
2363
|
+
issues.push(createPatternIssue(pattern, file, match.line));
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
return issues;
|
|
2369
|
+
}
|
|
2370
|
+
function filterFilesForPattern(files, pattern) {
|
|
2371
|
+
if (pattern.type === "file-structure" && pattern.filePatterns) {
|
|
2372
|
+
return files.filter((file) => pattern.filePatterns.some((p) => matchesFilePattern(file, p)));
|
|
2373
|
+
}
|
|
2374
|
+
if (pattern.type === "code-pattern") {
|
|
2375
|
+
return files;
|
|
2376
|
+
}
|
|
2377
|
+
return [];
|
|
2378
|
+
}
|
|
2379
|
+
function matchesFilePattern(filePath, pattern) {
|
|
2380
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
2381
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "___DOUBLESTAR___").replace(/\*/g, "[^/]*").replace(/___DOUBLESTAR___/g, ".*");
|
|
2382
|
+
const regex = new RegExp(`^${escaped}$`, "i");
|
|
2383
|
+
return regex.test(normalized) || normalized.includes(pattern.replace(/\*+/g, ""));
|
|
2384
|
+
}
|
|
2385
|
+
function findPatternMatch(content, pattern) {
|
|
2386
|
+
try {
|
|
2387
|
+
const regex = new RegExp(pattern, "i");
|
|
2388
|
+
const match = regex.exec(content);
|
|
2389
|
+
if (!match || match.index === void 0) return null;
|
|
2390
|
+
const line = getLineNumber(content, match.index);
|
|
2391
|
+
return { line };
|
|
2392
|
+
} catch {
|
|
2393
|
+
const index = content.toLowerCase().indexOf(pattern.toLowerCase());
|
|
2394
|
+
if (index === -1) return null;
|
|
2395
|
+
const line = getLineNumber(content, index);
|
|
2396
|
+
return { line };
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
function getLineNumber(content, index) {
|
|
2400
|
+
return content.slice(0, index).split("\n").length;
|
|
2401
|
+
}
|
|
2402
|
+
function createPatternIssue(pattern, file, line) {
|
|
2403
|
+
const description = pattern.description || `Saved pattern: ${pattern.name}`;
|
|
2404
|
+
const fix = pattern.codePattern?.fix || "Apply the saved pattern from your other project.";
|
|
2405
|
+
const issue = {
|
|
2406
|
+
id: `saved-${pattern.id}-${hashFile(file)}`,
|
|
2407
|
+
severity: "low",
|
|
2408
|
+
issue: `Saved pattern suggestion: ${description}`,
|
|
2409
|
+
fix,
|
|
2410
|
+
file,
|
|
2411
|
+
confidence: 0.6,
|
|
2412
|
+
autoFixable: false,
|
|
2413
|
+
agent: "saved-patterns",
|
|
2414
|
+
category: "pattern-sharing"
|
|
2415
|
+
};
|
|
2416
|
+
if (line !== void 0) {
|
|
2417
|
+
issue.line = line;
|
|
2418
|
+
}
|
|
2419
|
+
return issue;
|
|
2420
|
+
}
|
|
2421
|
+
function hashFile(file) {
|
|
2422
|
+
return createHash2("sha256").update(file).digest("hex").slice(0, 8);
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2230
2425
|
export {
|
|
2231
2426
|
loadConfig,
|
|
2232
2427
|
saveConfig,
|
|
@@ -2243,6 +2438,12 @@ export {
|
|
|
2243
2438
|
SKILL_CATEGORIES,
|
|
2244
2439
|
detectStack,
|
|
2245
2440
|
getSkillsByCategory,
|
|
2246
|
-
getSkillCategories
|
|
2441
|
+
getSkillCategories,
|
|
2442
|
+
loadSavedPatterns,
|
|
2443
|
+
savePatternsToProject,
|
|
2444
|
+
savePatternToProject,
|
|
2445
|
+
getDetectionRuleAgents,
|
|
2446
|
+
createSavedPattern,
|
|
2447
|
+
buildSavedPatternIssues
|
|
2247
2448
|
};
|
|
2248
|
-
//# sourceMappingURL=chunk-
|
|
2449
|
+
//# sourceMappingURL=chunk-3HTPH3P2.js.map
|