opencodekit 0.16.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +64 -3
- package/dist/template/.opencode/command/create.md +34 -0
- package/dist/template/.opencode/command/design.md +35 -0
- package/dist/template/.opencode/command/handoff.md +15 -0
- package/dist/template/.opencode/command/init.md +40 -47
- package/dist/template/.opencode/command/plan.md +1 -0
- package/dist/template/.opencode/command/pr.md +15 -0
- package/dist/template/.opencode/command/research.md +3 -0
- package/dist/template/.opencode/command/resume.md +1 -0
- package/dist/template/.opencode/command/review-codebase.md +30 -0
- package/dist/template/.opencode/command/ship.md +43 -0
- package/dist/template/.opencode/command/start.md +1 -0
- package/dist/template/.opencode/command/status.md +24 -1
- package/dist/template/.opencode/command/ui-review.md +31 -0
- package/dist/template/.opencode/command/verify.md +35 -7
- package/dist/template/.opencode/memory/project/tech-stack.md +25 -22
- package/dist/template/.opencode/memory.db +0 -0
- package/dist/template/.opencode/memory.db-shm +0 -0
- package/dist/template/.opencode/memory.db-wal +0 -0
- package/dist/template/.opencode/opencode.json +817 -916
- package/dist/template/.opencode/package.json +1 -0
- package/dist/template/.opencode/plans/1770006237537-mighty-otter.md +418 -0
- package/dist/template/.opencode/plans/1770006913647-glowing-forest.md +170 -0
- package/dist/template/.opencode/plans/1770013678126-witty-planet.md +278 -0
- package/dist/template/.opencode/plugin/lib/memory-db.ts +828 -0
- package/dist/template/.opencode/plugin/memory.ts +38 -1
- package/dist/template/.opencode/skill/index-knowledge/SKILL.md +76 -31
- package/dist/template/.opencode/skill/memory-system/SKILL.md +110 -55
- package/dist/template/.opencode/tool/memory-get.ts +143 -0
- package/dist/template/.opencode/tool/memory-maintain.ts +167 -0
- package/dist/template/.opencode/tool/memory-migrate.ts +319 -0
- package/dist/template/.opencode/tool/memory-read.ts +17 -46
- package/dist/template/.opencode/tool/memory-search.ts +131 -28
- package/dist/template/.opencode/tool/memory-timeline.ts +105 -0
- package/dist/template/.opencode/tool/memory-update.ts +21 -26
- package/dist/template/.opencode/tool/observation.ts +112 -100
- package/dist/template/.opencode/tsconfig.json +19 -19
- package/package.json +1 -1
- package/dist/template/.opencode/memory/_templates/README.md +0 -73
- package/dist/template/.opencode/memory/_templates/observation.md +0 -39
- package/dist/template/.opencode/memory/_templates/prompt-engineering.md +0 -333
- package/dist/template/.opencode/memory/observations/2026-01-22-decision-agents-md-prompt-engineering-improvement.md +0 -29
- package/dist/template/.opencode/memory/observations/2026-01-25-decision-agent-roles-build-orchestrates-general-e.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-01-25-decision-simplified-swarm-helper-tool-to-fix-type.md +0 -20
- package/dist/template/.opencode/memory/observations/2026-01-25-decision-use-beads-as-swarm-board-source-of-truth.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-01-25-learning-user-wants-real-swarm-coordination-guida.md +0 -15
- package/dist/template/.opencode/memory/observations/2026-01-28-decision-created-deep-research-skill-for-thorough.md +0 -29
- package/dist/template/.opencode/memory/observations/2026-01-28-decision-gh-grep-mcp-wrapper-vs-native-grep-searc.md +0 -21
- package/dist/template/.opencode/memory/observations/2026-01-28-decision-oracle-tool-optimal-usage-patterns.md +0 -32
- package/dist/template/.opencode/memory/observations/2026-01-28-learning-ampcode-deep-mode-research-integration-w.md +0 -42
- package/dist/template/.opencode/memory/observations/2026-01-28-pattern-research-delegation-pattern-explore-for-.md +0 -32
- package/dist/template/.opencode/memory/observations/2026-01-29-decision-copilot-auth-plugin-rate-limit-handling.md +0 -27
- package/dist/template/.opencode/memory/observations/2026-01-29-decision-spec-driven-approach-for-opencodekit.md +0 -21
- package/dist/template/.opencode/memory/observations/2026-01-29-learning-karpathy-llm-coding-insights-dec-2025.md +0 -44
- package/dist/template/.opencode/memory/observations/2026-01-30-decision-github-copilot-claude-routing-keep-disab.md +0 -32
- package/dist/template/.opencode/memory/observations/2026-01-30-discovery-context-management-research-critical-gap.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-01-30-discovery-kimi-k2-5-agent-swarm-architecture-patte.md +0 -45
- package/dist/template/.opencode/memory/observations/2026-01-30-pattern-swarm-tools-architecture.md +0 -28
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-copilot-auth-plugin-updated-with-baseurl.md +0 -63
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-created-dedicated-worker-agent-for-swarm.md +0 -20
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-rollback-to-v1-1-47-for-copilot-claude-r.md +0 -21
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-simplified-swarm-to-task-tool-pattern.md +0 -44
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-swarm-architecture-task-tool-over-tmux.md +0 -33
- package/dist/template/.opencode/memory/observations/2026-01-31-decision-worker-skills-defined-for-swarm-delegati.md +0 -30
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-gpt-reasoning-config-for-github-copilot.md +0 -51
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-opencode-copilot-auth-comparison-finding.md +0 -61
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-opencode-copilot-reasoning-architecture-.md +0 -66
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-opencode-custom-tools-api.md +0 -48
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-opencode-v1-1-48-skills-as-slash-command.md +0 -21
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-swarm-system-simplified-removed-mailbox-.md +0 -30
- package/dist/template/.opencode/memory/observations/2026-01-31-learning-v1-1-48-native-copilot-reasoning-via-pr-.md +0 -45
- package/dist/template/.opencode/memory/observations/2026-01-31-warning-cannot-add-custom-config-to-opencode-jso.md +0 -18
- package/dist/template/.opencode/memory/observations/2026-01-31-warning-copilot-claude-v1-endpoint-returns-404-c.md +0 -48
- package/dist/template/.opencode/memory/observations/2026-01-31-warning-opencode-v1-1-48-claude-thinking-block-s.md +0 -51
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-add-skills-vs-commands-to-global-agents-.md +0 -15
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-build-agent-auto-loads-skills-contextual.md +0 -31
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-fixed-agent-configuration-for-opencodeki.md +0 -25
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-focused-agents-md-upgrade-for-opencode-k.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-implement-tier-1-permission-upgrades.md +0 -15
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-instructions-config-explicit-paths-not-w.md +0 -40
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-merged-context-into-memory-project-singl.md +0 -42
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-oracle-tool-should-use-review-agent-not-.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-plan-agent-auto-loads-skills-contextuall.md +0 -31
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-plan-phased-oracle-command-merge-into-ne.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-prd-workflow-uses-prd-and-prd-task-skill.md +0 -23
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-prefer-review-agent-via-opencode-cli-ove.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-remove-oracle-tool-add-ship-command-with.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-remove-oracle-tool-and-add-ship-command-.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-remove-oracle-tool-and-add-ship-command.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-remove-skills-vs-commands-section-from-a.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-replace-oracle-tool-with-ship-command-fl.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-replace-oracle-with-ship-command-workflo.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-replace-proxypal-oracle-with-cli-review-.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-simplified-dist-template-only-tech-stack.md +0 -50
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-simplified-templates-only-tech-stack-md.md +0 -26
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-subagents-load-minimal-skills-stay-lean.md +0 -29
- package/dist/template/.opencode/memory/observations/2026-02-01-decision-user-approved-permission-upgrades-in-ope.md +0 -15
- package/dist/template/.opencode/memory/observations/2026-02-01-discovery-verify-command-already-implemented.md +0 -28
- package/dist/template/.opencode/memory/observations/2026-02-01-feature-openspec-phase-b-complete-template-upgra.md +0 -43
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-build-agent-should-use-dynamic-lsp-not-f.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-kimi-k2-5-model-requires-temperature-1-0.md +0 -22
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-opencode-context-injection-already-imple.md +0 -27
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-opencode-context-injection-uses-instruct.md +0 -35
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-update-build-agent-prompt-to-use-context.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-upgrade-agents-md-using-opencode-expert-.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-upgrade-agents-md-with-opencode-expert-g.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-upgrade-agents-md-with-opencode-expert-r.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-user-prefers-copilot-gpt-5-2-codex-mediu.md +0 -14
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-user-wants-general-agent-prompt-contextu.md +0 -15
- package/dist/template/.opencode/memory/observations/2026-02-01-learning-user-wants-general-agent-prompt-reviewed.md +0 -15
- package/dist/template/.opencode/memory/project/architecture.md +0 -60
- package/dist/template/.opencode/memory/project/command-rules.md +0 -122
- package/dist/template/.opencode/memory/project/commands.md +0 -72
- package/dist/template/.opencode/memory/project/conventions.md +0 -68
- package/dist/template/.opencode/memory/project/gotchas.md +0 -41
- /package/dist/template/.opencode/memory/_templates/{project/tech-stack.md → tech-stack.md} +0 -0
- /package/dist/template/.opencode/memory/{user.example.md → _templates/user.md} +0 -0
- /package/dist/template/.opencode/memory/{user.md → project/user.md} +0 -0
|
@@ -1,8 +1,15 @@
|
|
|
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 {
|
|
5
|
+
type ObservationType,
|
|
6
|
+
type SearchIndexResult,
|
|
7
|
+
checkFTS5Available,
|
|
8
|
+
searchObservationsFTS,
|
|
9
|
+
} from "../plugin/lib/memory-db";
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
// Fallback file-based search for non-SQLite content
|
|
12
|
+
interface FileSearchResult {
|
|
6
13
|
file: string;
|
|
7
14
|
matches: { line: number; content: string }[];
|
|
8
15
|
}
|
|
@@ -10,7 +17,7 @@ interface SearchResult {
|
|
|
10
17
|
async function searchDirectory(
|
|
11
18
|
dir: string,
|
|
12
19
|
pattern: RegExp,
|
|
13
|
-
results:
|
|
20
|
+
results: FileSearchResult[],
|
|
14
21
|
baseDir: string,
|
|
15
22
|
): Promise<void> {
|
|
16
23
|
try {
|
|
@@ -30,14 +37,15 @@ async function searchDirectory(
|
|
|
30
37
|
const lines = content.split("\n");
|
|
31
38
|
const matches: { line: number; content: string }[] = [];
|
|
32
39
|
|
|
33
|
-
lines.
|
|
40
|
+
for (let index = 0; index < lines.length; index++) {
|
|
41
|
+
const line = lines[index];
|
|
34
42
|
if (pattern.test(line)) {
|
|
35
43
|
matches.push({
|
|
36
44
|
line: index + 1,
|
|
37
45
|
content: line.trim().substring(0, 150),
|
|
38
46
|
});
|
|
39
47
|
}
|
|
40
|
-
}
|
|
48
|
+
}
|
|
41
49
|
|
|
42
50
|
if (matches.length > 0) {
|
|
43
51
|
const relativePath = path.relative(baseDir, fullPath);
|
|
@@ -50,11 +58,11 @@ async function searchDirectory(
|
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
async function
|
|
61
|
+
async function fallbackKeywordSearch(
|
|
54
62
|
query: string,
|
|
55
63
|
type: string | undefined,
|
|
56
|
-
|
|
57
|
-
): Promise<
|
|
64
|
+
limit: number,
|
|
65
|
+
): Promise<FileSearchResult[]> {
|
|
58
66
|
const memoryDir = path.join(process.cwd(), ".opencode/memory");
|
|
59
67
|
const beadsDir = path.join(process.cwd(), ".beads/artifacts");
|
|
60
68
|
const globalMemoryDir = path.join(
|
|
@@ -72,17 +80,16 @@ async function keywordSearch(
|
|
|
72
80
|
pattern = new RegExp(escaped, "i");
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
const results:
|
|
83
|
+
const results: FileSearchResult[] = [];
|
|
76
84
|
|
|
77
85
|
// Handle type filtering
|
|
78
86
|
if (type === "beads") {
|
|
79
87
|
await searchDirectory(beadsDir, pattern, results, beadsDir);
|
|
80
|
-
} else if (type && type !== "all") {
|
|
88
|
+
} else if (type && type !== "all" && type !== "observations") {
|
|
81
89
|
const typeMap: Record<string, string> = {
|
|
82
90
|
handoffs: "handoffs",
|
|
83
91
|
research: "research",
|
|
84
92
|
templates: "_templates",
|
|
85
|
-
observations: "observations",
|
|
86
93
|
};
|
|
87
94
|
const subdir = typeMap[type];
|
|
88
95
|
if (subdir) {
|
|
@@ -96,19 +103,73 @@ async function keywordSearch(
|
|
|
96
103
|
await searchDirectory(globalMemoryDir, pattern, results, globalMemoryDir);
|
|
97
104
|
}
|
|
98
105
|
|
|
99
|
-
return results;
|
|
106
|
+
return results.slice(0, limit);
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
|
|
109
|
+
const TYPE_ICONS: Record<string, string> = {
|
|
110
|
+
decision: "🎯",
|
|
111
|
+
bugfix: "🐛",
|
|
112
|
+
feature: "✨",
|
|
113
|
+
pattern: "🔄",
|
|
114
|
+
discovery: "💡",
|
|
115
|
+
learning: "📚",
|
|
116
|
+
warning: "⚠️",
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
function formatCompactIndex(
|
|
120
|
+
results: SearchIndexResult[],
|
|
103
121
|
query: string,
|
|
104
|
-
|
|
122
|
+
): string {
|
|
123
|
+
if (results.length === 0) {
|
|
124
|
+
return `No observations found for "${query}".\n\nTip: Use memory-search without query to see recent observations.`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let output = `# Search Results: "${query}"\n\n`;
|
|
128
|
+
output += `Found **${results.length}** observation(s). Use \`memory-get\` for full details.\n\n`;
|
|
129
|
+
output += "| ID | Type | Title | Date |\n";
|
|
130
|
+
output += "|---|---|---|---|\n";
|
|
131
|
+
|
|
132
|
+
for (const result of results) {
|
|
133
|
+
const icon = TYPE_ICONS[result.type] || "📝";
|
|
134
|
+
const date = result.created_at.split("T")[0];
|
|
135
|
+
const title =
|
|
136
|
+
result.title.length > 50
|
|
137
|
+
? `${result.title.substring(0, 47)}...`
|
|
138
|
+
: result.title;
|
|
139
|
+
output += `| #${result.id} | ${icon} ${result.type} | ${title} | ${date} |\n`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
output += "\n## Snippets\n\n";
|
|
143
|
+
for (const result of results) {
|
|
144
|
+
const icon = TYPE_ICONS[result.type] || "📝";
|
|
145
|
+
output += `**#${result.id}** ${icon} ${result.title}\n`;
|
|
146
|
+
if (result.snippet) {
|
|
147
|
+
output += `> ${result.snippet}...\n`;
|
|
148
|
+
}
|
|
149
|
+
output += "\n";
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
output += "\n---\n";
|
|
153
|
+
output += `💡 **Next steps:**\n`;
|
|
154
|
+
output += `- \`memory-get({ ids: "${results
|
|
155
|
+
.map((r) => r.id)
|
|
156
|
+
.slice(0, 3)
|
|
157
|
+
.join(",")}" })\` - Get full details\n`;
|
|
158
|
+
output += `- \`memory-timeline({ anchor_id: ${results[0].id} })\` - See chronological context\n`;
|
|
159
|
+
|
|
160
|
+
return output;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function formatFallbackResults(
|
|
164
|
+
query: string,
|
|
165
|
+
results: FileSearchResult[],
|
|
105
166
|
limit: number,
|
|
106
167
|
): string {
|
|
107
168
|
if (results.length === 0) {
|
|
108
|
-
return `No matches found for "${query}".`;
|
|
169
|
+
return `No matches found for "${query}" in non-observation files.`;
|
|
109
170
|
}
|
|
110
171
|
|
|
111
|
-
let output = `# Search: "${query}"\n\n`;
|
|
172
|
+
let output = `# File Search: "${query}"\n\n`;
|
|
112
173
|
output += `Found ${results.length} file(s) with matches.\n\n`;
|
|
113
174
|
|
|
114
175
|
for (const result of results) {
|
|
@@ -127,30 +188,72 @@ function formatKeywordResults(
|
|
|
127
188
|
}
|
|
128
189
|
|
|
129
190
|
export default tool({
|
|
130
|
-
description: `Search
|
|
191
|
+
description: `Search observations using FTS5 full-text search.
|
|
131
192
|
|
|
132
193
|
Purpose:
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
194
|
+
- Fast, ranked search across all observations in SQLite
|
|
195
|
+
- Returns compact index (~50-100 tokens per result) for progressive disclosure
|
|
196
|
+
- Use memory-get for full details after identifying relevant observations
|
|
197
|
+
|
|
198
|
+
Search modes:
|
|
199
|
+
- "observations" (default): Search SQLite with FTS5 ranking
|
|
200
|
+
- "handoffs", "research", "templates": Search specific markdown directories
|
|
201
|
+
- "beads": Search .beads/artifacts
|
|
202
|
+
- "all": Search everything (SQLite + markdown files)
|
|
136
203
|
|
|
137
204
|
Example:
|
|
138
|
-
memory-search({ query: "authentication"
|
|
205
|
+
memory-search({ query: "authentication" })
|
|
206
|
+
memory-search({ query: "auth", type: "decision", limit: 5 })`,
|
|
139
207
|
args: {
|
|
140
|
-
query: tool.schema
|
|
141
|
-
.string()
|
|
142
|
-
.describe("Search query: keywords or regex pattern"),
|
|
208
|
+
query: tool.schema.string().describe("Search query: keywords or phrase"),
|
|
143
209
|
type: tool.schema
|
|
144
210
|
.string()
|
|
145
211
|
.optional()
|
|
146
212
|
.describe(
|
|
147
|
-
"Filter by type
|
|
213
|
+
"Filter by observation type (decision, bugfix, feature, pattern, discovery, learning, warning) or search scope (observations, handoffs, research, templates, beads, all)",
|
|
148
214
|
),
|
|
149
|
-
limit: tool.schema
|
|
215
|
+
limit: tool.schema
|
|
216
|
+
.number()
|
|
217
|
+
.optional()
|
|
218
|
+
.describe("Max results (default: 10)"),
|
|
150
219
|
},
|
|
151
220
|
execute: async (args: { query: string; type?: string; limit?: number }) => {
|
|
152
|
-
const limit = args.limit ||
|
|
153
|
-
|
|
154
|
-
|
|
221
|
+
const limit = args.limit || 10;
|
|
222
|
+
|
|
223
|
+
// Determine if we should use SQLite FTS5 or fallback
|
|
224
|
+
const observationTypes = [
|
|
225
|
+
"decision",
|
|
226
|
+
"bugfix",
|
|
227
|
+
"feature",
|
|
228
|
+
"pattern",
|
|
229
|
+
"discovery",
|
|
230
|
+
"learning",
|
|
231
|
+
"warning",
|
|
232
|
+
];
|
|
233
|
+
const isObservationType =
|
|
234
|
+
args.type && observationTypes.includes(args.type.toLowerCase());
|
|
235
|
+
const isObservationsScope =
|
|
236
|
+
!args.type || args.type === "observations" || isObservationType;
|
|
237
|
+
|
|
238
|
+
// Try SQLite FTS5 for observations
|
|
239
|
+
if (isObservationsScope && checkFTS5Available()) {
|
|
240
|
+
try {
|
|
241
|
+
const obsType = isObservationType
|
|
242
|
+
? (args.type?.toLowerCase() as ObservationType)
|
|
243
|
+
: undefined;
|
|
244
|
+
const results = searchObservationsFTS(args.query, {
|
|
245
|
+
type: obsType,
|
|
246
|
+
limit,
|
|
247
|
+
});
|
|
248
|
+
return formatCompactIndex(results, args.query);
|
|
249
|
+
} catch {
|
|
250
|
+
// FTS5 failed, fall through to file search
|
|
251
|
+
// Silently fall back to file-based search
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Fallback to file-based search for non-observation types or FTS5 failure
|
|
256
|
+
const results = await fallbackKeywordSearch(args.query, args.type, limit);
|
|
257
|
+
return formatFallbackResults(args.query, results, limit);
|
|
155
258
|
},
|
|
156
259
|
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import {
|
|
3
|
+
type SearchIndexResult,
|
|
4
|
+
getTimelineAroundObservation,
|
|
5
|
+
} from "../plugin/lib/memory-db";
|
|
6
|
+
|
|
7
|
+
const TYPE_ICONS: Record<string, string> = {
|
|
8
|
+
decision: "🎯",
|
|
9
|
+
bugfix: "🐛",
|
|
10
|
+
feature: "✨",
|
|
11
|
+
pattern: "🔄",
|
|
12
|
+
discovery: "💡",
|
|
13
|
+
learning: "📚",
|
|
14
|
+
warning: "⚠️",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function formatTimelineResult(
|
|
18
|
+
anchor: {
|
|
19
|
+
id: number;
|
|
20
|
+
type: string;
|
|
21
|
+
title: string;
|
|
22
|
+
created_at: string;
|
|
23
|
+
} | null,
|
|
24
|
+
before: SearchIndexResult[],
|
|
25
|
+
after: SearchIndexResult[],
|
|
26
|
+
): string {
|
|
27
|
+
if (!anchor) {
|
|
28
|
+
return "Anchor observation not found.";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let output = "# Timeline Context\n\n";
|
|
32
|
+
|
|
33
|
+
// Before (older observations)
|
|
34
|
+
if (before.length > 0) {
|
|
35
|
+
output += "## Earlier Observations\n\n";
|
|
36
|
+
for (const obs of before) {
|
|
37
|
+
const icon = TYPE_ICONS[obs.type] || "📝";
|
|
38
|
+
const date = obs.created_at.split("T")[0];
|
|
39
|
+
output += `- **#${obs.id}** ${icon} ${obs.title} _(${date})_\n`;
|
|
40
|
+
if (obs.snippet) {
|
|
41
|
+
output += ` ${obs.snippet.substring(0, 80)}...\n`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
output += "\n";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Anchor
|
|
48
|
+
const anchorIcon = TYPE_ICONS[anchor.type] || "📝";
|
|
49
|
+
const anchorDate = anchor.created_at.split("T")[0];
|
|
50
|
+
output += `## ▶ Current: #${anchor.id}\n\n`;
|
|
51
|
+
output += `${anchorIcon} **${anchor.title}** _(${anchorDate})_\n\n`;
|
|
52
|
+
|
|
53
|
+
// After (newer observations)
|
|
54
|
+
if (after.length > 0) {
|
|
55
|
+
output += "## Later Observations\n\n";
|
|
56
|
+
for (const obs of after) {
|
|
57
|
+
const icon = TYPE_ICONS[obs.type] || "📝";
|
|
58
|
+
const date = obs.created_at.split("T")[0];
|
|
59
|
+
output += `- **#${obs.id}** ${icon} ${obs.title} _(${date})_\n`;
|
|
60
|
+
if (obs.snippet) {
|
|
61
|
+
output += ` ${obs.snippet.substring(0, 80)}...\n`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return output;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default tool({
|
|
70
|
+
description: `Get chronological context around an observation.
|
|
71
|
+
|
|
72
|
+
Purpose:
|
|
73
|
+
- Progressive disclosure: see what was happening before/after a specific observation
|
|
74
|
+
- Understand decision context over time
|
|
75
|
+
- Navigate memory timeline
|
|
76
|
+
|
|
77
|
+
Example:
|
|
78
|
+
memory-timeline({ anchor_id: 42, depth_before: 5, depth_after: 5 })`,
|
|
79
|
+
args: {
|
|
80
|
+
anchor_id: tool.schema
|
|
81
|
+
.number()
|
|
82
|
+
.describe("ID of the observation to get context around"),
|
|
83
|
+
depth_before: tool.schema
|
|
84
|
+
.number()
|
|
85
|
+
.optional()
|
|
86
|
+
.describe("Number of earlier observations to include (default: 5)"),
|
|
87
|
+
depth_after: tool.schema
|
|
88
|
+
.number()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe("Number of later observations to include (default: 5)"),
|
|
91
|
+
},
|
|
92
|
+
execute: async (args: {
|
|
93
|
+
anchor_id: number;
|
|
94
|
+
depth_before?: number;
|
|
95
|
+
depth_after?: number;
|
|
96
|
+
}) => {
|
|
97
|
+
const { anchor, before, after } = getTimelineAroundObservation(
|
|
98
|
+
args.anchor_id,
|
|
99
|
+
args.depth_before ?? 5,
|
|
100
|
+
args.depth_after ?? 5,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return formatTimelineResult(anchor, before, after);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { upsertMemoryFile } from "../plugin/lib/memory-db.js";
|
|
4
3
|
|
|
5
4
|
export default tool({
|
|
6
5
|
description: `Update memory files with new learnings, progress, or context.
|
|
7
6
|
|
|
8
7
|
Purpose:
|
|
9
|
-
- Write or append to project memory in
|
|
8
|
+
- Write or append to project memory in SQLite
|
|
10
9
|
- Supports subdirectories (e.g., 'research/2024-01-topic')
|
|
11
10
|
- Two modes: 'replace' (overwrite) or 'append' (add to end)
|
|
12
11
|
|
|
@@ -17,7 +16,7 @@ export default tool({
|
|
|
17
16
|
file: tool.schema
|
|
18
17
|
.string()
|
|
19
18
|
.describe(
|
|
20
|
-
"Memory file to update: handoffs/YYYY-MM-DD-phase, research/YYYY-MM-DD-topic
|
|
19
|
+
"Memory file to update: handoffs/YYYY-MM-DD-phase, research/YYYY-MM-DD-topic",
|
|
21
20
|
),
|
|
22
21
|
content: tool.schema
|
|
23
22
|
.string()
|
|
@@ -31,33 +30,29 @@ export default tool({
|
|
|
31
30
|
),
|
|
32
31
|
},
|
|
33
32
|
execute: async (args: { file: string; content: string; mode?: string }) => {
|
|
34
|
-
//
|
|
35
|
-
const
|
|
33
|
+
// Normalize file path: strip existing .md extension
|
|
34
|
+
const normalizedFile = args.file.replace(/\.md$/i, "");
|
|
35
|
+
const mode = (args.mode || "replace") as "replace" | "append";
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const filePath = path.join(memoryDir, `${normalizedFile}.md`);
|
|
40
|
-
const mode = args.mode || "replace";
|
|
37
|
+
const timestamp = new Date().toISOString();
|
|
38
|
+
let finalContent: string;
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (mode === "append") {
|
|
48
|
-
const timestamp = new Date().toISOString();
|
|
49
|
-
const appendContent = `\n\n---\n**Updated:** ${timestamp}\n\n${args.content}`;
|
|
50
|
-
await fs.appendFile(filePath, appendContent, "utf-8");
|
|
51
|
-
return `Successfully appended to ${normalizedFile}.md\n[Written to: ${filePath}]`;
|
|
52
|
-
}
|
|
53
|
-
// Replace mode - update timestamp
|
|
54
|
-
const timestamp = new Date().toISOString();
|
|
55
|
-
const updatedContent = args.content.replace(
|
|
40
|
+
if (mode === "append") {
|
|
41
|
+
finalContent = `\n\n---\n**Updated:** ${timestamp}\n\n${args.content}`;
|
|
42
|
+
} else {
|
|
43
|
+
// Replace mode - update timestamp placeholder if present
|
|
44
|
+
finalContent = args.content.replace(
|
|
56
45
|
/\*\*Last Updated:\*\* \[Timestamp\]/,
|
|
57
46
|
`**Last Updated:** ${timestamp}`,
|
|
58
47
|
);
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// Store in SQLite (single source of truth)
|
|
52
|
+
upsertMemoryFile(normalizedFile, finalContent, mode);
|
|
53
|
+
|
|
54
|
+
const action = mode === "append" ? "Appended to" : "Updated";
|
|
55
|
+
return `✓ ${action} ${normalizedFile}`;
|
|
61
56
|
} catch (error) {
|
|
62
57
|
if (error instanceof Error) {
|
|
63
58
|
return `Error updating memory: ${error.message}`;
|