opencodekit 0.14.6 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +100 -58
  3. package/dist/template/.opencode/.env.example +1 -0
  4. package/dist/template/.opencode/AGENTS.md +13 -24
  5. package/dist/template/.opencode/README.md +8 -119
  6. package/dist/template/.opencode/agent/explore.md +2 -3
  7. package/dist/template/.opencode/agent/general.md +56 -0
  8. package/dist/template/.opencode/agent/plan.md +54 -0
  9. package/dist/template/.opencode/agent/scout.md +15 -5
  10. package/dist/template/.opencode/command/analyze-project.md +2 -2
  11. package/dist/template/.opencode/command/brainstorm.md +1 -1
  12. package/dist/template/.opencode/command/design-audit.md +4 -5
  13. package/dist/template/.opencode/command/design.md +4 -13
  14. package/dist/template/.opencode/command/generate-pattern.md +2 -9
  15. package/dist/template/.opencode/command/implement.md +4 -4
  16. package/dist/template/.opencode/command/init.md +1 -1
  17. package/dist/template/.opencode/command/new-feature.md +2 -3
  18. package/dist/template/.opencode/command/plan.md +1 -1
  19. package/dist/template/.opencode/command/pr.md +0 -1
  20. package/dist/template/.opencode/command/research.md +20 -6
  21. package/dist/template/.opencode/command/restore-image.md +1 -9
  22. package/dist/template/.opencode/command/revert-feature.md +1 -1
  23. package/dist/template/.opencode/command/review-codebase.md +4 -4
  24. package/dist/template/.opencode/command/status.md +1 -2
  25. package/dist/template/.opencode/command/summarize.md +1 -2
  26. package/dist/template/.opencode/command/triage.md +4 -32
  27. package/dist/template/.opencode/dcp.jsonc +68 -68
  28. package/dist/template/.opencode/memory/_templates/README.md +35 -0
  29. package/dist/template/.opencode/memory/_templates/project/architecture.md +60 -0
  30. package/dist/template/.opencode/memory/_templates/project/commands.md +72 -0
  31. package/dist/template/.opencode/memory/_templates/project/conventions.md +68 -0
  32. package/dist/template/.opencode/memory/_templates/project/gotchas.md +41 -0
  33. package/dist/template/.opencode/memory/beads-workflow.md +30 -29
  34. package/dist/template/.opencode/memory/project/architecture.md +31 -50
  35. package/dist/template/.opencode/memory/project/commands.md +41 -22
  36. package/dist/template/.opencode/memory/project/conventions.md +39 -177
  37. package/dist/template/.opencode/memory/project/gotchas.md +21 -177
  38. package/dist/template/.opencode/memory/user.example.md +5 -0
  39. package/dist/template/.opencode/opencode.json +644 -579
  40. package/dist/template/.opencode/package.json +18 -21
  41. package/dist/template/.opencode/plugin/compaction.ts +79 -85
  42. package/dist/template/.opencode/plugin/env-ctx.ts +19 -19
  43. package/dist/template/.opencode/plugin/lib/notify.ts +41 -45
  44. package/dist/template/.opencode/plugin/lsp.ts +197 -200
  45. package/dist/template/.opencode/plugin/memory.ts +14 -112
  46. package/dist/template/.opencode/plugin/package.json +5 -5
  47. package/dist/template/.opencode/plugin/sessions.ts +1 -1
  48. package/dist/template/.opencode/plugin/skill-mcp.ts +486 -521
  49. package/dist/template/.opencode/plugin/truncator.ts +47 -50
  50. package/dist/template/.opencode/plugin/tsconfig.json +14 -14
  51. package/dist/template/.opencode/skill/chrome-devtools/mcp.json +17 -17
  52. package/dist/template/.opencode/skill/condition-based-waiting/SKILL.md +17 -12
  53. package/dist/template/.opencode/skill/condition-based-waiting/example.ts +63 -69
  54. package/dist/template/.opencode/skill/defense-in-depth/SKILL.md +14 -8
  55. package/dist/template/.opencode/skill/dispatching-parallel-agents/SKILL.md +14 -3
  56. package/dist/template/.opencode/skill/playwright/mcp.json +14 -14
  57. package/dist/template/.opencode/skill/receiving-code-review/SKILL.md +21 -8
  58. package/dist/template/.opencode/skill/requesting-code-review/review.md +14 -0
  59. package/dist/template/.opencode/skill/root-cause-tracing/SKILL.md +18 -4
  60. package/dist/template/.opencode/skill/source-code-research/SKILL.md +9 -7
  61. package/dist/template/.opencode/skill/test-driven-development/SKILL.md +49 -32
  62. package/dist/template/.opencode/skill/testing-anti-patterns/SKILL.md +40 -22
  63. package/dist/template/.opencode/skill/testing-skills-with-subagents/SKILL.md +46 -26
  64. package/dist/template/.opencode/skill/tool-priority/SKILL.md +117 -44
  65. package/dist/template/.opencode/skill/v0/SKILL.md +1 -7
  66. package/dist/template/.opencode/skill/verification-before-completion/SKILL.md +27 -19
  67. package/dist/template/.opencode/skill/writing-skills/anthropic-best-practices.md +171 -148
  68. package/dist/template/.opencode/skill/writing-skills/persuasion-principles.md +39 -6
  69. package/dist/template/.opencode/tool/memory-read.ts +44 -56
  70. package/dist/template/.opencode/tool/memory-search.ts +8 -291
  71. package/dist/template/.opencode/tool/memory-update.ts +47 -51
  72. package/dist/template/.opencode/tool/observation.ts +6 -180
  73. package/dist/template/.opencode/tsconfig.json +19 -19
  74. package/package.json +19 -15
  75. package/dist/template/.opencode/.background-tasks.json +0 -114
  76. package/dist/template/.opencode/.ralph-state.json +0 -12
  77. package/dist/template/.opencode/agent/build.md +0 -327
  78. package/dist/template/.opencode/agent/ninja.md +0 -351
  79. package/dist/template/.opencode/agent/planner.md +0 -281
  80. package/dist/template/.opencode/agent/rush.md +0 -223
  81. package/dist/template/.opencode/memory/handoffs/README.md +0 -83
  82. package/dist/template/.opencode/memory/observations/.gitkeep +0 -0
  83. package/dist/template/.opencode/memory/observations/2026-01-09-pattern-ampcode-mcp-json-includetools-pattern.md +0 -42
  84. package/dist/template/.opencode/memory/vector_db/memories.lance/_transactions/0-0d25ba80-ba3b-4209-9046-b45d6093b4da.txn +0 -0
  85. package/dist/template/.opencode/memory/vector_db/memories.lance/_versions/1.manifest +0 -0
  86. package/dist/template/.opencode/memory/vector_db/memories.lance/data/1111100101010101011010004a9ef34df6b29f36a9a53a2892.lance +0 -0
  87. package/dist/template/.opencode/tool/ast-grep.ts +0 -245
  88. package/dist/template/.opencode/tool/background.ts +0 -509
  89. package/dist/template/.opencode/tool/bd-inbox.ts +0 -110
  90. package/dist/template/.opencode/tool/bd-msg.ts +0 -62
  91. package/dist/template/.opencode/tool/bd-release.ts +0 -71
  92. package/dist/template/.opencode/tool/bd-reserve.ts +0 -121
  93. package/dist/template/.opencode/tool/memory-embed.ts +0 -183
  94. package/dist/template/.opencode/tool/memory-index.ts +0 -769
  95. package/dist/template/.opencode/tool/repo-map.ts +0 -451
@@ -9,142 +9,171 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
9
9
  ## The Seven Principles
10
10
 
11
11
  ### 1. Authority
12
+
12
13
  **What it is:** Deference to expertise, credentials, or official sources.
13
14
 
14
15
  **How it works in skills:**
16
+
15
17
  - Imperative language: "YOU MUST", "Never", "Always"
16
18
  - Non-negotiable framing: "No exceptions"
17
19
  - Eliminates decision fatigue and rationalization
18
20
 
19
21
  **When to use:**
22
+
20
23
  - Discipline-enforcing skills (TDD, verification requirements)
21
24
  - Safety-critical practices
22
25
  - Established best practices
23
26
 
24
27
  **Example:**
28
+
25
29
  ```markdown
26
30
  āœ… Write code before test? Delete it. Start over. No exceptions.
27
31
  āŒ Consider writing tests first when feasible.
28
32
  ```
29
33
 
30
34
  ### 2. Commitment
35
+
31
36
  **What it is:** Consistency with prior actions, statements, or public declarations.
32
37
 
33
38
  **How it works in skills:**
39
+
34
40
  - Require announcements: "Announce skill usage"
35
41
  - Force explicit choices: "Choose A, B, or C"
36
42
  - Use tracking: TodoWrite for checklists
37
43
 
38
44
  **When to use:**
45
+
39
46
  - Ensuring skills are actually followed
40
47
  - Multi-step processes
41
48
  - Accountability mechanisms
42
49
 
43
50
  **Example:**
51
+
44
52
  ```markdown
45
53
  āœ… When you find a skill, you MUST announce: "I'm using [Skill Name]"
46
54
  āŒ Consider letting your partner know which skill you're using.
47
55
  ```
48
56
 
49
57
  ### 3. Scarcity
58
+
50
59
  **What it is:** Urgency from time limits or limited availability.
51
60
 
52
61
  **How it works in skills:**
62
+
53
63
  - Time-bound requirements: "Before proceeding"
54
64
  - Sequential dependencies: "Immediately after X"
55
65
  - Prevents procrastination
56
66
 
57
67
  **When to use:**
68
+
58
69
  - Immediate verification requirements
59
70
  - Time-sensitive workflows
60
71
  - Preventing "I'll do it later"
61
72
 
62
73
  **Example:**
74
+
63
75
  ```markdown
64
76
  āœ… After completing a task, IMMEDIATELY request code review before proceeding.
65
77
  āŒ You can review code when convenient.
66
78
  ```
67
79
 
68
80
  ### 4. Social Proof
81
+
69
82
  **What it is:** Conformity to what others do or what's considered normal.
70
83
 
71
84
  **How it works in skills:**
85
+
72
86
  - Universal patterns: "Every time", "Always"
73
87
  - Failure modes: "X without Y = failure"
74
88
  - Establishes norms
75
89
 
76
90
  **When to use:**
91
+
77
92
  - Documenting universal practices
78
93
  - Warning about common failures
79
94
  - Reinforcing standards
80
95
 
81
96
  **Example:**
97
+
82
98
  ```markdown
83
99
  āœ… Checklists without TodoWrite tracking = steps get skipped. Every time.
84
100
  āŒ Some people find TodoWrite helpful for checklists.
85
101
  ```
86
102
 
87
103
  ### 5. Unity
104
+
88
105
  **What it is:** Shared identity, "we-ness", in-group belonging.
89
106
 
90
107
  **How it works in skills:**
108
+
91
109
  - Collaborative language: "our codebase", "we're colleagues"
92
110
  - Shared goals: "we both want quality"
93
111
 
94
112
  **When to use:**
113
+
95
114
  - Collaborative workflows
96
115
  - Establishing team culture
97
116
  - Non-hierarchical practices
98
117
 
99
118
  **Example:**
119
+
100
120
  ```markdown
101
121
  āœ… We're colleagues working together. I need your honest technical judgment.
102
122
  āŒ You should probably tell me if I'm wrong.
103
123
  ```
104
124
 
105
125
  ### 6. Reciprocity
126
+
106
127
  **What it is:** Obligation to return benefits received.
107
128
 
108
129
  **How it works:**
130
+
109
131
  - Use sparingly - can feel manipulative
110
132
  - Rarely needed in skills
111
133
 
112
134
  **When to avoid:**
135
+
113
136
  - Almost always (other principles more effective)
114
137
 
115
138
  ### 7. Liking
139
+
116
140
  **What it is:** Preference for cooperating with those we like.
117
141
 
118
142
  **How it works:**
143
+
119
144
  - **DON'T USE for compliance**
120
145
  - Conflicts with honest feedback culture
121
146
  - Creates sycophancy
122
147
 
123
148
  **When to avoid:**
149
+
124
150
  - Always for discipline enforcement
125
151
 
126
152
  ## Principle Combinations by Skill Type
127
153
 
128
- | Skill Type | Use | Avoid |
129
- |------------|-----|-------|
154
+ | Skill Type | Use | Avoid |
155
+ | -------------------- | ------------------------------------- | ------------------- |
130
156
  | Discipline-enforcing | Authority + Commitment + Social Proof | Liking, Reciprocity |
131
- | Guidance/technique | Moderate Authority + Unity | Heavy authority |
132
- | Collaborative | Unity + Commitment | Authority, Liking |
133
- | Reference | Clarity only | All persuasion |
157
+ | Guidance/technique | Moderate Authority + Unity | Heavy authority |
158
+ | Collaborative | Unity + Commitment | Authority, Liking |
159
+ | Reference | Clarity only | All persuasion |
134
160
 
135
161
  ## Why This Works: The Psychology
136
162
 
137
163
  **Bright-line rules reduce rationalization:**
164
+
138
165
  - "YOU MUST" removes decision fatigue
139
166
  - Absolute language eliminates "is this an exception?" questions
140
167
  - Explicit anti-rationalization counters close specific loopholes
141
168
 
142
169
  **Implementation intentions create automatic behavior:**
170
+
143
171
  - Clear triggers + required actions = automatic execution
144
172
  - "When X, do Y" more effective than "generally do Y"
145
173
  - Reduces cognitive load on compliance
146
174
 
147
175
  **LLMs are parahuman:**
176
+
148
177
  - Trained on human text containing these patterns
149
178
  - Authority language precedes compliance in training data
150
179
  - Commitment sequences (statement → action) frequently modeled
@@ -153,11 +182,13 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
153
182
  ## Ethical Use
154
183
 
155
184
  **Legitimate:**
185
+
156
186
  - Ensuring critical practices are followed
157
187
  - Creating effective documentation
158
188
  - Preventing predictable failures
159
189
 
160
190
  **Illegitimate:**
191
+
161
192
  - Manipulating for personal gain
162
193
  - Creating false urgency
163
194
  - Guilt-based compliance
@@ -166,11 +197,13 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
166
197
 
167
198
  ## Research Citations
168
199
 
169
- **Cialdini, R. B. (2021).** *Influence: The Psychology of Persuasion (New and Expanded).* Harper Business.
200
+ **Cialdini, R. B. (2021).** _Influence: The Psychology of Persuasion (New and Expanded)._ Harper Business.
201
+
170
202
  - Seven principles of persuasion
171
203
  - Empirical foundation for influence research
172
204
 
173
205
  **Meincke, L., Shapiro, D., Duckworth, A. L., Mollick, E., Mollick, L., & Cialdini, R. (2025).** Call Me A Jerk: Persuading AI to Comply with Objectionable Requests. University of Pennsylvania.
206
+
174
207
  - Tested 7 principles with N=28,000 LLM conversations
175
208
  - Compliance increased 33% → 72% with persuasion techniques
176
209
  - Authority, commitment, scarcity most effective
@@ -3,64 +3,52 @@ import path from "node:path";
3
3
  import { tool } from "@opencode-ai/plugin";
4
4
 
5
5
  export default tool({
6
- description:
7
- "Read memory files for persistent cross-session context. Returns current project state, learnings, and active tasks. Supports subdirectories (e.g., 'research/opencode-sessions').",
8
- args: {
9
- file: tool.schema
10
- .string()
11
- .optional()
12
- .describe(
13
- "Memory file to read: handoffs/YYYY-MM-DD-phase, research/YYYY-MM-DD-topic, _templates/task-prd, _templates/task-spec, _templates/task-review, _templates/research, _templates/handoff",
14
- ),
15
- },
16
- execute: async (args: { file?: string }) => {
17
- const fileName = args.file || "memory";
6
+ description:
7
+ "Read memory files for persistent cross-session context. Returns current project state, learnings, and active tasks. Supports subdirectories (e.g., 'research/opencode-sessions').",
8
+ args: {
9
+ file: tool.schema
10
+ .string()
11
+ .optional()
12
+ .describe(
13
+ "Memory file to read: handoffs/YYYY-MM-DD-phase, research/YYYY-MM-DD-topic, _templates/task-prd, _templates/task-spec, _templates/task-review, _templates/research, _templates/handoff",
14
+ ),
15
+ },
16
+ execute: async (args: { file?: string }) => {
17
+ const fileName = args.file || "memory";
18
18
 
19
- // Normalize: strip .md extension if present
20
- const normalizedFile = fileName.replace(/\.md$/i, "");
19
+ // Normalize: strip .md extension if present
20
+ const normalizedFile = fileName.replace(/\.md$/i, "");
21
21
 
22
- // Location priority: project > global > legacy
23
- const locations = [
24
- path.join(process.cwd(), ".opencode/memory", `${normalizedFile}.md`),
25
- path.join(
26
- process.env.HOME || "",
27
- ".config/opencode/memory",
28
- `${normalizedFile}.md`,
29
- ),
30
- path.join(
31
- process.cwd(),
32
- ".config/opencode/memory",
33
- `${normalizedFile}.md`,
34
- ),
35
- ];
22
+ // Location priority: project > global > legacy
23
+ const locations = [
24
+ path.join(process.cwd(), ".opencode/memory", `${normalizedFile}.md`),
25
+ path.join(process.env.HOME || "", ".config/opencode/memory", `${normalizedFile}.md`),
26
+ path.join(process.cwd(), ".config/opencode/memory", `${normalizedFile}.md`),
27
+ ];
36
28
 
37
- // Try each location in order
38
- for (const filePath of locations) {
39
- try {
40
- const content = await fs.readFile(filePath, "utf-8");
41
- const locationLabel = filePath.includes(".opencode/memory")
42
- ? "project"
43
- : filePath.includes(process.env.HOME || "")
44
- ? "global"
45
- : "legacy";
46
- return `[Read from ${locationLabel}: ${filePath}]\n\n${content}`;
47
- } catch (error) {
48
- // Continue to next location if file not found
49
- if (
50
- error instanceof Error &&
51
- "code" in error &&
52
- error.code === "ENOENT"
53
- ) {
54
- continue;
55
- }
56
- // Other errors should be reported
57
- if (error instanceof Error) {
58
- return `Error reading memory from ${filePath}: ${error.message}`;
59
- }
60
- }
61
- }
29
+ // Try each location in order
30
+ for (const filePath of locations) {
31
+ try {
32
+ const content = await fs.readFile(filePath, "utf-8");
33
+ const locationLabel = filePath.includes(".opencode/memory")
34
+ ? "project"
35
+ : filePath.includes(process.env.HOME || "")
36
+ ? "global"
37
+ : "legacy";
38
+ return `[Read from ${locationLabel}: ${filePath}]\n\n${content}`;
39
+ } catch (error) {
40
+ // Continue to next location if file not found
41
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
42
+ continue;
43
+ }
44
+ // Other errors should be reported
45
+ if (error instanceof Error) {
46
+ return `Error reading memory from ${filePath}: ${error.message}`;
47
+ }
48
+ }
49
+ }
62
50
 
63
- // No file found in any location
64
- return `Memory file '${normalizedFile}.md' not found in any location.\nSearched:\n- ${locations.join("\n- ")}\n\nStructure:\n- handoffs/YYYY-MM-DD-phase (phase transitions)\n- research/YYYY-MM-DD-topic (research findings)\n- _templates/ (prd, spec, review, research, handoff)`;
65
- },
51
+ // No file found in any location
52
+ return `Memory file '${normalizedFile}.md' not found in any location.\nSearched:\n- ${locations.join("\n- ")}\n\nStructure:\n- handoffs/YYYY-MM-DD-phase (phase transitions)\n- research/YYYY-MM-DD-topic (research findings)\n- _templates/ (prd, spec, review, research, handoff)`;
53
+ },
66
54
  });
@@ -1,82 +1,10 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { tool } from "@opencode-ai/plugin";
4
- import { searchVectorStore } from "./memory-index";
5
4
 
6
5
  interface SearchResult {
7
6
  file: string;
8
7
  matches: { line: number; content: string }[];
9
- score?: number;
10
- }
11
-
12
- interface SemanticResult {
13
- file: string;
14
- title: string;
15
- preview: string;
16
- type: string;
17
- score?: number;
18
- confidence?: string;
19
- age_days?: number;
20
- }
21
-
22
- // Confidence decay factor based on age (Graphiti-inspired)
23
- // Older observations with lower confidence rank lower
24
- function applyConfidenceDecay(
25
- results: SemanticResult[],
26
- contents: Map<string, string>,
27
- ): SemanticResult[] {
28
- const now = Date.now();
29
-
30
- return results.map((result) => {
31
- const content = contents.get(result.file) || "";
32
-
33
- // Extract metadata from YAML frontmatter
34
- const createdMatch = content.match(/created:\s*(.+)/);
35
- const confidenceMatch = content.match(/confidence:\s*(\w+)/);
36
- const validUntilMatch = content.match(/valid_until:\s*(.+)/);
37
- const supersededByMatch = content.match(/superseded_by:\s*(.+)/);
38
-
39
- // Check if superseded (should rank very low)
40
- if (supersededByMatch && supersededByMatch[1] !== "null") {
41
- return { ...result, score: (result.score || 1) * 0.1 };
42
- }
43
-
44
- // Check if expired
45
- if (validUntilMatch && validUntilMatch[1] !== "null") {
46
- const validUntil = new Date(validUntilMatch[1]).getTime();
47
- if (validUntil < now) {
48
- return { ...result, score: (result.score || 1) * 0.2 };
49
- }
50
- }
51
-
52
- // Calculate age in days
53
- let ageDays = 0;
54
- if (createdMatch) {
55
- const created = new Date(createdMatch[1]).getTime();
56
- ageDays = Math.floor((now - created) / (1000 * 60 * 60 * 24));
57
- }
58
-
59
- // Confidence multiplier
60
- const confidenceMultiplier: Record<string, number> = {
61
- high: 1.0,
62
- medium: 0.8,
63
- low: 0.6,
64
- };
65
- const confidence = confidenceMatch?.[1] || "high";
66
- const confMult = confidenceMultiplier[confidence] || 1.0;
67
-
68
- // Age decay: lose 5% per 30 days, minimum 50%
69
- const ageDecay = Math.max(0.5, 1 - (ageDays / 30) * 0.05);
70
-
71
- const finalScore = (result.score || 1) * confMult * ageDecay;
72
-
73
- return {
74
- ...result,
75
- score: finalScore,
76
- confidence,
77
- age_days: ageDays,
78
- };
79
- });
80
8
  }
81
9
 
82
10
  async function searchDirectory(
@@ -125,7 +53,7 @@ async function searchDirectory(
125
53
  async function keywordSearch(
126
54
  query: string,
127
55
  type: string | undefined,
128
- limit: number,
56
+ _limit: number,
129
57
  ): Promise<SearchResult[]> {
130
58
  const memoryDir = path.join(process.cwd(), ".opencode/memory");
131
59
  const beadsDir = path.join(process.cwd(), ".beads/artifacts");
@@ -171,58 +99,16 @@ async function keywordSearch(
171
99
  return results;
172
100
  }
173
101
 
174
- async function semanticSearch(
175
- query: string,
176
- type: string | undefined,
177
- limit: number,
178
- ): Promise<SemanticResult[]> {
179
- const typeMap: Record<string, string> = {
180
- handoffs: "handoff",
181
- observations: "observation",
182
- beads: "bead",
183
- project: "project",
184
- templates: "template",
185
- };
186
-
187
- const fileType = type && type !== "all" ? typeMap[type] : undefined;
188
- const docs = await searchVectorStore(query, limit * 2, fileType); // Fetch extra for decay filtering
189
-
190
- // Build content map for decay calculation
191
- const contents = new Map<string, string>();
192
- for (const doc of docs) {
193
- try {
194
- const content = await fs.readFile(doc.file_path, "utf-8");
195
- contents.set(doc.file_path, content);
196
- } catch {
197
- // File not found, skip
198
- }
199
- }
200
-
201
- const results: SemanticResult[] = docs.map((doc) => ({
202
- file: doc.file_path,
203
- title: doc.title,
204
- preview: doc.content_preview,
205
- type: doc.file_type,
206
- score: 1.0,
207
- }));
208
-
209
- // Apply confidence decay and re-sort
210
- const decayedResults = applyConfidenceDecay(results, contents);
211
- decayedResults.sort((a, b) => (b.score || 0) - (a.score || 0));
212
-
213
- return decayedResults.slice(0, limit);
214
- }
215
-
216
102
  function formatKeywordResults(
217
103
  query: string,
218
104
  results: SearchResult[],
219
105
  limit: number,
220
106
  ): string {
221
107
  if (results.length === 0) {
222
- return `No keyword matches found for "${query}".\n\nTip: Try 'mode: semantic' for conceptual search, or run 'vector-store rebuild' first.`;
108
+ return `No matches found for "${query}".`;
223
109
  }
224
110
 
225
- let output = `# Keyword Search: "${query}"\n\n`;
111
+ let output = `# Search: "${query}"\n\n`;
226
112
  output += `Found ${results.length} file(s) with matches.\n\n`;
227
113
 
228
114
  for (const result of results) {
@@ -234,138 +120,6 @@ function formatKeywordResults(
234
120
  if (result.matches.length > limit) {
235
121
  output += `- ... and ${result.matches.length - limit} more matches\n`;
236
122
  }
237
- // Add LSP navigation hint for code files
238
- if (
239
- result.file.endsWith(".ts") ||
240
- result.file.endsWith(".tsx") ||
241
- result.file.endsWith(".js") ||
242
- result.file.endsWith(".jsx") ||
243
- result.file.endsWith(".py") ||
244
- result.file.endsWith(".go") ||
245
- result.file.endsWith(".rs")
246
- ) {
247
- const lineNum = result.matches[0]?.line;
248
- if (lineNum) {
249
- output += "\nšŸ” **LSP Nudge:**\n";
250
- output += ` \`lsp_lsp_goto_definition({ filePath: "${result.file}", line: ${lineNum}, character: 1 })\`\n`;
251
- }
252
- }
253
- output += "\n";
254
- }
255
-
256
- return output;
257
- }
258
-
259
- function formatSemanticResults(
260
- query: string,
261
- results: SemanticResult[],
262
- ): string {
263
- if (results.length === 0) {
264
- return `No semantic matches found for "${query}".\n\nTip: Run 'vector-store rebuild' to index memory files first.`;
265
- }
266
-
267
- let output = `# Semantic Search: "${query}"\n\n`;
268
- output += `Found ${results.length} similar document(s).\n\n`;
269
-
270
- const confidenceIcons: Record<string, string> = {
271
- high: "🟢",
272
- medium: "🟔",
273
- low: "šŸ”“",
274
- };
275
-
276
- for (const result of results) {
277
- output += `## ${result.title}\n\n`;
278
- output += `**File:** \`${result.file}\`\n`;
279
- output += `**Type:** ${result.type}`;
280
- if (result.confidence) {
281
- const icon = confidenceIcons[result.confidence] || "";
282
- output += ` | **Confidence:** ${icon} ${result.confidence}`;
283
- }
284
- if (result.age_days !== undefined && result.age_days > 0) {
285
- output += ` | **Age:** ${result.age_days}d`;
286
- }
287
- output += "\n\n";
288
- output += `${result.preview}...\n\n`;
289
-
290
- // Add LSP navigation for code files
291
- if (
292
- result.file.endsWith(".ts") ||
293
- result.file.endsWith(".tsx") ||
294
- result.file.endsWith(".js") ||
295
- result.file.endsWith(".jsx") ||
296
- result.file.endsWith(".py") ||
297
- result.file.endsWith(".go") ||
298
- result.file.endsWith(".rs")
299
- ) {
300
- output += "\nšŸ” **LSP Nudge:**\n";
301
- output += ` Get symbols: \`lsp_lsp_document_symbols({ filePath: "${result.file}" })\`\n`;
302
- output += ` Find references: \`lsp_lsp_find_references({ filePath: "${result.file}", line: 1, character: 1 })\`\n`;
303
- }
304
-
305
- output += "---\n\n";
306
- }
307
-
308
- return output;
309
- }
310
-
311
- function formatHybridResults(
312
- query: string,
313
- keywordResults: SearchResult[],
314
- semanticResults: SemanticResult[],
315
- limit: number,
316
- ): string {
317
- let output = `# Hybrid Search: "${query}"\n\n`;
318
-
319
- // Semantic results first (conceptual matches)
320
- output += `## Semantic Matches (${semanticResults.length})\n\n`;
321
- if (semanticResults.length === 0) {
322
- output += `_No semantic matches. Run 'vector-store rebuild' to enable._\n\n`;
323
- } else {
324
- for (const result of semanticResults.slice(0, limit)) {
325
- output += `- **${result.title}** (\`${result.file}\`)\n`;
326
- output += ` ${result.preview.substring(0, 100)}...\n`;
327
- // Add LSP hint for code files
328
- if (
329
- result.file.endsWith(".ts") ||
330
- result.file.endsWith(".tsx") ||
331
- result.file.endsWith(".js") ||
332
- result.file.endsWith(".jsx") ||
333
- result.file.endsWith(".py") ||
334
- result.file.endsWith(".go") ||
335
- result.file.endsWith(".rs")
336
- ) {
337
- output += ` šŸ” **LSP Nudge:** \`lsp_lsp_document_symbols({ filePath: "${result.file}" })\`\n`;
338
- }
339
- }
340
- output += "\n";
341
- }
342
-
343
- // Keyword results (exact matches)
344
- output += `## Keyword Matches (${keywordResults.length})\n\n`;
345
- if (keywordResults.length === 0) {
346
- output += "_No exact keyword matches._\n\n";
347
- } else {
348
- for (const result of keywordResults.slice(0, limit)) {
349
- output += `- **${result.file}**\n`;
350
- for (const match of result.matches.slice(0, 2)) {
351
- output += ` - Line ${match.line}: ${match.content.substring(0, 80)}...\n`;
352
- }
353
- // Add LSP hint for code files
354
- if (
355
- result.file.endsWith(".ts") ||
356
- result.file.endsWith(".tsx") ||
357
- result.file.endsWith(".js") ||
358
- result.file.endsWith(".jsx") ||
359
- result.file.endsWith(".py") ||
360
- result.file.endsWith(".go") ||
361
- result.file.endsWith(".rs")
362
- ) {
363
- const lineNum = result.matches[0]?.line;
364
- if (lineNum) {
365
- output += ` šŸ” **LSP Nudge:** \`lsp_lsp_goto_definition({ filePath: "${result.file}", line: ${lineNum}, character: 1 })\`\n`;
366
- }
367
- }
368
- }
369
123
  output += "\n";
370
124
  }
371
125
 
@@ -374,19 +128,11 @@ function formatHybridResults(
374
128
 
375
129
  export default tool({
376
130
  description:
377
- "Search across all memory files using keywords, semantic similarity, or hybrid mode. Returns matching files with context. Useful for finding past decisions, research, or handoffs.",
131
+ "Search across all memory files using keywords. Returns matching files with context. Useful for finding past decisions, research, or handoffs.",
378
132
  args: {
379
133
  query: tool.schema
380
134
  .string()
381
- .describe(
382
- "Search query: keywords, regex pattern, or natural language for semantic search",
383
- ),
384
- mode: tool.schema
385
- .enum(["keyword", "semantic", "hybrid"])
386
- .optional()
387
- .describe(
388
- "Search mode: 'keyword' (default, regex matching), 'semantic' (vector similarity), 'hybrid' (both)",
389
- ),
135
+ .describe("Search query: keywords or regex pattern"),
390
136
  type: tool.schema
391
137
  .string()
392
138
  .optional()
@@ -395,38 +141,9 @@ export default tool({
395
141
  ),
396
142
  limit: tool.schema.number().optional().describe("Max results (default: 5)"),
397
143
  },
398
- execute: async (args: {
399
- query: string;
400
- mode?: "keyword" | "semantic" | "hybrid";
401
- type?: string;
402
- limit?: number;
403
- }) => {
404
- const mode = args.mode || "keyword";
144
+ execute: async (args: { query: string; type?: string; limit?: number }) => {
405
145
  const limit = args.limit || 5;
406
-
407
- if (mode === "keyword") {
408
- const results = await keywordSearch(args.query, args.type, limit);
409
- return formatKeywordResults(args.query, results, limit);
410
- }
411
-
412
- if (mode === "semantic") {
413
- const results = await semanticSearch(args.query, args.type, limit);
414
- return formatSemanticResults(args.query, results);
415
- }
416
-
417
- if (mode === "hybrid") {
418
- const [keywordResults, semanticResults] = await Promise.all([
419
- keywordSearch(args.query, args.type, limit),
420
- semanticSearch(args.query, args.type, limit),
421
- ]);
422
- return formatHybridResults(
423
- args.query,
424
- keywordResults,
425
- semanticResults,
426
- limit,
427
- );
428
- }
429
-
430
- return "Unknown search mode";
146
+ const results = await keywordSearch(args.query, args.type, limit);
147
+ return formatKeywordResults(args.query, results, limit);
431
148
  },
432
149
  });