opencodekit 0.21.10 → 0.22.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 (156) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.opencode/AGENTS.md +116 -487
  3. package/dist/template/.opencode/README.md +1 -1
  4. package/dist/template/.opencode/agent/build.md +56 -396
  5. package/dist/template/.opencode/agent/explore.md +0 -1
  6. package/dist/template/.opencode/agent/review.md +0 -1
  7. package/dist/template/.opencode/agent/scout.md +0 -1
  8. package/dist/template/.opencode/agent/vision.md +0 -1
  9. package/dist/template/.opencode/command/clarify.md +48 -0
  10. package/dist/template/.opencode/command/commit.md +53 -0
  11. package/dist/template/.opencode/command/fix.md +56 -0
  12. package/dist/template/.opencode/command/improve-architecture.md +55 -0
  13. package/dist/template/.opencode/command/init.md +88 -68
  14. package/dist/template/.opencode/command/refactor.md +66 -0
  15. package/dist/template/.opencode/command/test.md +66 -0
  16. package/dist/template/.opencode/dcp.jsonc +13 -2
  17. package/dist/template/.opencode/memory/README.md +3 -5
  18. package/dist/template/.opencode/memory/_templates/adr.md +45 -0
  19. package/dist/template/.opencode/memory/project/gotchas.md +1 -1
  20. package/dist/template/.opencode/memory/session-context.md +1 -1
  21. package/dist/template/.opencode/plugin/README.md +1 -1
  22. package/dist/template/.opencode/plugin/guard.ts +62 -0
  23. package/dist/template/.opencode/plugin/{lib/memory-admin-tools.ts → memory/admin.ts} +4 -4
  24. package/dist/template/.opencode/plugin/{lib → memory}/capture.ts +1 -1
  25. package/dist/template/.opencode/plugin/{lib → memory}/compile.ts +2 -2
  26. package/dist/template/.opencode/plugin/{lib → memory}/context.ts +1 -1
  27. package/dist/template/.opencode/plugin/{lib → memory}/curator.ts +1 -1
  28. package/dist/template/.opencode/plugin/{lib → memory}/db/observations.ts +102 -3
  29. package/dist/template/.opencode/plugin/{lib → memory}/db/schema.ts +43 -1
  30. package/dist/template/.opencode/plugin/{lib → memory}/db/types.ts +22 -0
  31. package/dist/template/.opencode/plugin/{lib/memory-db.ts → memory/db.ts} +1 -1
  32. package/dist/template/.opencode/plugin/{lib → memory}/distill.ts +1 -1
  33. package/dist/template/.opencode/plugin/{lib/memory-helpers.ts → memory/helpers.ts} +5 -1
  34. package/dist/template/.opencode/plugin/{lib/memory-hooks.ts → memory/hooks.ts} +1 -1
  35. package/dist/template/.opencode/plugin/{lib → memory}/index-generator.ts +2 -2
  36. package/dist/template/.opencode/plugin/{lib → memory}/inject.ts +1 -1
  37. package/dist/template/.opencode/plugin/{lib → memory}/lint.ts +2 -2
  38. package/dist/template/.opencode/plugin/memory/tools.ts +322 -0
  39. package/dist/template/.opencode/plugin/{lib → memory}/validate.ts +2 -2
  40. package/dist/template/.opencode/plugin/memory.ts +7 -17
  41. package/dist/template/.opencode/plugin/srcwalk.ts +721 -0
  42. package/dist/template/.opencode/skill/agent-code-quality-gate/SKILL.md +98 -0
  43. package/dist/template/.opencode/skill/behavioral-kernel/SKILL.md +52 -0
  44. package/dist/template/.opencode/skill/browser-testing-with-devtools/SKILL.md +85 -0
  45. package/dist/template/.opencode/skill/code-cleanup/SKILL.md +114 -0
  46. package/dist/template/.opencode/skill/code-navigation/SKILL.md +142 -0
  47. package/dist/template/.opencode/skill/code-review-and-quality/SKILL.md +131 -0
  48. package/dist/template/.opencode/skill/debugging-and-error-recovery/SKILL.md +109 -0
  49. package/dist/template/.opencode/skill/deep-module-design/SKILL.md +207 -0
  50. package/dist/template/.opencode/skill/git-workflow-and-versioning/SKILL.md +77 -0
  51. package/dist/template/.opencode/skill/grill-me/SKILL.md +140 -0
  52. package/dist/template/.opencode/skill/memory-system/SKILL.md +9 -10
  53. package/dist/template/.opencode/skill/planning-and-task-breakdown/SKILL.md +116 -0
  54. package/dist/template/.opencode/skill/shipping-and-launch/SKILL.md +95 -0
  55. package/dist/template/.opencode/skill/source-driven-development/SKILL.md +103 -0
  56. package/dist/template/.opencode/skill/spec-driven-development/SKILL.md +121 -0
  57. package/dist/template/.opencode/skill/srcwalk/SKILL.md +161 -0
  58. package/dist/template/.opencode/skill/ubiquitous-language/SKILL.md +184 -0
  59. package/package.json +1 -1
  60. package/dist/template/.opencode/AGENT_ALIGNMENT.md +0 -564
  61. package/dist/template/.opencode/agent/painter.md +0 -83
  62. package/dist/template/.opencode/command/compound.md +0 -240
  63. package/dist/template/.opencode/command/curate.md +0 -299
  64. package/dist/template/.opencode/command/handoff.md +0 -149
  65. package/dist/template/.opencode/command/health.md +0 -356
  66. package/dist/template/.opencode/command/init-context.md +0 -297
  67. package/dist/template/.opencode/command/init-user.md +0 -125
  68. package/dist/template/.opencode/command/iterate.md +0 -200
  69. package/dist/template/.opencode/command/lfg.md +0 -173
  70. package/dist/template/.opencode/command/resume.md +0 -78
  71. package/dist/template/.opencode/command/status.md +0 -126
  72. package/dist/template/.opencode/command/ui-slop-check.md +0 -169
  73. package/dist/template/.opencode/plugin/lib/memory-tools.ts +0 -535
  74. package/dist/template/.opencode/skill/agent-evals/SKILL.md +0 -208
  75. package/dist/template/.opencode/skill/anti-ai-slop/SKILL.md +0 -76
  76. package/dist/template/.opencode/skill/augment-context-engine/SKILL.md +0 -122
  77. package/dist/template/.opencode/skill/augment-context-engine/mcp.json +0 -6
  78. package/dist/template/.opencode/skill/brand-asset-protocol/SKILL.md +0 -222
  79. package/dist/template/.opencode/skill/code-search-patterns/SKILL.md +0 -224
  80. package/dist/template/.opencode/skill/code-simplification/SKILL.md +0 -211
  81. package/dist/template/.opencode/skill/context-condensation/SKILL.md +0 -149
  82. package/dist/template/.opencode/skill/context-initialization/SKILL.md +0 -69
  83. package/dist/template/.opencode/skill/context-management/SKILL.md +0 -390
  84. package/dist/template/.opencode/skill/deep-research/SKILL.md +0 -384
  85. package/dist/template/.opencode/skill/design-direction-advisor/SKILL.md +0 -139
  86. package/dist/template/.opencode/skill/dispatching-parallel-agents/SKILL.md +0 -191
  87. package/dist/template/.opencode/skill/executing-plans/SKILL.md +0 -247
  88. package/dist/template/.opencode/skill/figma-go/SKILL.md +0 -65
  89. package/dist/template/.opencode/skill/finishing-a-development-branch/SKILL.md +0 -357
  90. package/dist/template/.opencode/skill/full-output-enforcement/SKILL.md +0 -62
  91. package/dist/template/.opencode/skill/gh-address-comments/SKILL.md +0 -29
  92. package/dist/template/.opencode/skill/gh-address-comments/scripts/fetch_comments.py +0 -237
  93. package/dist/template/.opencode/skill/gh-fix-ci/SKILL.md +0 -38
  94. package/dist/template/.opencode/skill/gh-fix-ci/scripts/inspect_pr_checks.py +0 -509
  95. package/dist/template/.opencode/skill/hi-fi-prototype-html/SKILL.md +0 -253
  96. package/dist/template/.opencode/skill/html-deck-export/SKILL.md +0 -189
  97. package/dist/template/.opencode/skill/index-knowledge/SKILL.md +0 -413
  98. package/dist/template/.opencode/skill/memory-grounding/SKILL.md +0 -68
  99. package/dist/template/.opencode/skill/playwriter/SKILL.md +0 -158
  100. package/dist/template/.opencode/skill/portless/SKILL.md +0 -109
  101. package/dist/template/.opencode/skill/prd/SKILL.md +0 -146
  102. package/dist/template/.opencode/skill/prd-task/SKILL.md +0 -182
  103. package/dist/template/.opencode/skill/prd-task/references/prd-schema.json +0 -124
  104. package/dist/template/.opencode/skill/prompt-leverage/SKILL.md +0 -90
  105. package/dist/template/.opencode/skill/prompt-leverage/references/framework.md +0 -91
  106. package/dist/template/.opencode/skill/prompt-leverage/scripts/augment_prompt.py +0 -157
  107. package/dist/template/.opencode/skill/receiving-code-review/SKILL.md +0 -263
  108. package/dist/template/.opencode/skill/reconcile/SKILL.md +0 -183
  109. package/dist/template/.opencode/skill/reflection-checkpoints/SKILL.md +0 -183
  110. package/dist/template/.opencode/skill/requesting-code-review/SKILL.md +0 -443
  111. package/dist/template/.opencode/skill/requesting-code-review/references/specialist-profiles.md +0 -108
  112. package/dist/template/.opencode/skill/requesting-code-review/review.md +0 -160
  113. package/dist/template/.opencode/skill/rtk-command-compression/SKILL.md +0 -134
  114. package/dist/template/.opencode/skill/screenshot/SKILL.md +0 -48
  115. package/dist/template/.opencode/skill/screenshot/scripts/ensure_macos_permissions.sh +0 -54
  116. package/dist/template/.opencode/skill/screenshot/scripts/macos_display_info.swift +0 -22
  117. package/dist/template/.opencode/skill/screenshot/scripts/macos_permissions.swift +0 -40
  118. package/dist/template/.opencode/skill/screenshot/scripts/macos_window_info.swift +0 -126
  119. package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.ps1 +0 -163
  120. package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.py +0 -585
  121. package/dist/template/.opencode/skill/security-threat-model/SKILL.md +0 -36
  122. package/dist/template/.opencode/skill/security-threat-model/references/prompt-template.md +0 -255
  123. package/dist/template/.opencode/skill/security-threat-model/references/security-controls-and-assets.md +0 -32
  124. package/dist/template/.opencode/skill/sharing-skills/SKILL.md +0 -214
  125. package/dist/template/.opencode/skill/skill-creator/SKILL.md +0 -181
  126. package/dist/template/.opencode/skill/skill-installer/SKILL.md +0 -58
  127. package/dist/template/.opencode/skill/skill-installer/scripts/github_utils.py +0 -21
  128. package/dist/template/.opencode/skill/skill-installer/scripts/install-skill-from-github.py +0 -313
  129. package/dist/template/.opencode/skill/skill-installer/scripts/list-skills.py +0 -106
  130. package/dist/template/.opencode/skill/swarm-coordination/SKILL.md +0 -244
  131. package/dist/template/.opencode/skill/swarm-coordination/references/architecture.md +0 -39
  132. package/dist/template/.opencode/skill/swarm-coordination/references/delegation-worker-protocol.md +0 -145
  133. package/dist/template/.opencode/skill/swarm-coordination/references/dependency-graph.md +0 -50
  134. package/dist/template/.opencode/skill/swarm-coordination/references/drift-check.md +0 -90
  135. package/dist/template/.opencode/skill/swarm-coordination/references/integration-beads.md +0 -20
  136. package/dist/template/.opencode/skill/swarm-coordination/references/launch-flow.md +0 -186
  137. package/dist/template/.opencode/skill/swarm-coordination/references/reconciler.md +0 -172
  138. package/dist/template/.opencode/skill/swarm-coordination/references/tier-enforcement.md +0 -78
  139. package/dist/template/.opencode/skill/swarm-coordination/references/tmux-integration.md +0 -134
  140. package/dist/template/.opencode/skill/systematic-debugging/SKILL.md +0 -402
  141. package/dist/template/.opencode/skill/terse-output-mode/SKILL.md +0 -95
  142. package/dist/template/.opencode/skill/think-in-code/SKILL.md +0 -136
  143. package/dist/template/.opencode/skill/ux-quality-gates/SKILL.md +0 -137
  144. package/dist/template/.opencode/skill/v1-run/SKILL.md +0 -175
  145. package/dist/template/.opencode/skill/v1-run/mcp.json +0 -6
  146. package/dist/template/.opencode/skill/verification-gates/SKILL.md +0 -63
  147. package/dist/template/.opencode/skill/visual-analysis/SKILL.md +0 -154
  148. package/dist/template/.opencode/skill/web-design-guidelines/SKILL.md +0 -46
  149. package/dist/template/.opencode/skill/workspace-setup/SKILL.md +0 -76
  150. package/dist/template/.opencode/skill/writing-plans/SKILL.md +0 -320
  151. /package/dist/template/.opencode/plugin/{lib → memory}/compact.ts +0 -0
  152. /package/dist/template/.opencode/plugin/{lib → memory}/db/graph.ts +0 -0
  153. /package/dist/template/.opencode/plugin/{lib → memory}/db/maintenance.ts +0 -0
  154. /package/dist/template/.opencode/plugin/{lib → memory}/db/pipeline.ts +0 -0
  155. /package/dist/template/.opencode/plugin/{lib → memory}/notify.ts +0 -0
  156. /package/dist/template/.opencode/plugin/{lib → memory}/operation-log.ts +0 -0
@@ -1,535 +0,0 @@
1
- /**
2
- * Memory Plugin — Core Tools
3
- *
4
- * observation, memory-search, memory-get, memory-read, memory-update, memory-timeline,
5
- * memory-graph-add, memory-graph-query, memory-graph-invalidate, memory-compact
6
- *
7
- * Uses factory pattern: createCoreTools(deps) returns tool definitions
8
- * that can be spread into plugin's tool:{} export.
9
- */
10
-
11
- import { readdir } from "node:fs/promises";
12
- import path from "node:path";
13
- import { tool } from "@opencode-ai/plugin/tool";
14
- import {
15
- addEntityTriple,
16
- type ConfidenceLevel,
17
- checkFTS5Available,
18
- getMemoryDB,
19
- getMemoryFile,
20
- getObservationsByIds,
21
- getTimelineAroundObservation,
22
- invalidateTriple,
23
- type ObservationSource,
24
- type ObservationType,
25
- queryEntity,
26
- searchDistillationsFTS,
27
- searchObservationsFTS,
28
- storeObservation,
29
- upsertMemoryFile,
30
- type HallType,
31
- VALID_HALLS,
32
- } from "./memory-db.js";
33
- import {
34
- autoDetectFiles,
35
- formatObservation,
36
- parseCSV,
37
- safeReadFile,
38
- TYPE_ICONS,
39
- VALID_TYPES,
40
- } from "./memory-helpers.js";
41
- import { validateObservation } from "./validate.js";
42
- import { compactObservations } from "./compact.js";
43
-
44
- /**
45
- * Wrap a memory tool execute function with DB error handling.
46
- * Returns a user-friendly error message instead of raw SQLite crashes.
47
- */
48
- function withDBErrorHandling<T extends Record<string, unknown>>(
49
- fn: (args: T) => Promise<string>,
50
- ): (args: T) => Promise<string> {
51
- return async (args: T) => {
52
- try {
53
- return await fn(args);
54
- } catch (err) {
55
- const message =
56
- err instanceof Error ? err.message : String(err);
57
- if (
58
- message.includes("database disk image is malformed") ||
59
- message.includes("SQLITE_CORRUPT") ||
60
- message.includes("integrity check failed")
61
- ) {
62
- return (
63
- `Error: Memory database is corrupted. ` +
64
- `Run \`memory-admin({ operation: "full" })\` to attempt repair, ` +
65
- `or delete .opencode/memory.db to start fresh. Details: ${message}`
66
- );
67
- }
68
- return `Error: Memory operation failed: ${message}`;
69
- }
70
- };
71
- }
72
-
73
- interface CoreToolDeps {
74
- handoffDir: string;
75
- }
76
-
77
- export function createCoreTools(deps: CoreToolDeps) {
78
- const { handoffDir } = deps;
79
-
80
- return {
81
- observation: tool({
82
- description: `Create a structured observation for future reference.\n\t\n\tPurpose:\n\t- Capture decisions, bugs, features, patterns, discoveries, learnings, or warnings\n\t- Auto-detects file references from content (file:line, \`path\`, src/, .opencode/)\n\t- Stores in SQLite with FTS5 index for fast search\n\t- Supports enhanced schema: facts, subtitle, files_read/files_modified\n\t\n\tConfidence guidance:\n\t- high: verified by tests, logs, or direct inspection (default)\n\t- medium: likely, but not fully verified\n\t- low: uncertain or speculative\n\t\n\tType-specific examples:\n\tdecision\n\tobservation({\n\t type: "decision",\n\t title: "Use JWT for auth",\n\t narrative: "Chose JWT for stateless auth across services.",\n\t facts: "stateless, scalable",\n\t concepts: "authentication, jwt",\n\t confidence: "high"\n\t})\n\t\n\tbugfix\n\tobservation({\n\t type: "bugfix",\n\t title: "Fix null pointer on login",\n\t narrative: "Guarded optional user in src/auth.ts:42 to prevent crash.",\n\t files_modified: "src/auth.ts",\n\t concepts: "auth, null-check",\n\t confidence: "high"\n\t})\n\t\n\tfeature\n\tobservation({\n\t type: "feature",\n\t title: "Add CLI --dry-run",\n\t narrative: "Introduce dry-run mode to show planned changes without writing.",\n\t files_modified: "src/commands/init.ts",\n\t concepts: "cli, ux",\n\t confidence: "medium"\n\t})\n\t\n\tpattern\n\tobservation({\n\t type: "pattern",\n\t title: "Use zod for input validation",\n\t narrative: "All command inputs validated with zod schemas before execute.",\n\t concepts: "validation, zod",\n\t confidence: "high"\n\t})\n\t\n\tdiscovery\n\tobservation({\n\t type: "discovery",\n\t title: "Build copies .opencode/ to dist/template/",\n\t narrative: "Found rsync step in build.ts that bundles .opencode/.",\n\t files_read: "build.ts",\n\t confidence: "high"\n\t})\n\t\n\tlearning\n\tobservation({\n\t type: "learning",\n\t title: "Bun test respects --watch",\n\t narrative: "Observed bun test --watch keeps runner active during edits.",\n\t confidence: "medium"\n\t})\n\t\n\twarning\n\tobservation({\n\t type: "warning",\n\t title: "Do not edit dist/ directly",\n\t narrative: "dist/ is built output and overwritten on build.",\n\t concepts: "build, generated",\n\t confidence: "high"\n\t})`,
83
- args: {
84
- type: tool.schema
85
- .string()
86
- .describe(
87
- "Observation type: decision, bugfix, feature, pattern, discovery, learning, warning",
88
- ),
89
- title: tool.schema.string().describe("Brief title"),
90
- subtitle: tool.schema.string().optional().describe("Optional subtitle"),
91
- facts: tool.schema
92
- .string()
93
- .optional()
94
- .describe("Comma-separated key facts"),
95
- narrative: tool.schema.string().optional().describe("Detailed content"),
96
- content: tool.schema
97
- .string()
98
- .optional()
99
- .describe("DEPRECATED: Use 'narrative'"),
100
- concepts: tool.schema
101
- .string()
102
- .optional()
103
- .describe("Comma-separated concept tags"),
104
- files_read: tool.schema
105
- .string()
106
- .optional()
107
- .describe("Comma-separated files read"),
108
- files_modified: tool.schema
109
- .string()
110
- .optional()
111
- .describe("Comma-separated files modified"),
112
- files: tool.schema
113
- .string()
114
- .optional()
115
- .describe("DEPRECATED: Use 'files_modified'"),
116
- bead_id: tool.schema.string().optional().describe("Related bead ID"),
117
- confidence: tool.schema
118
- .string()
119
- .optional()
120
- .describe("high, medium, low"),
121
- supersedes: tool.schema
122
- .string()
123
- .optional()
124
- .describe("ID this supersedes"),
125
- source: tool.schema
126
- .string()
127
- .optional()
128
- .describe("manual, curator, imported"),
129
- wing: tool.schema
130
- .string()
131
- .optional()
132
- .describe("Navigation wing (project or person name)"),
133
- hall: tool.schema
134
- .string()
135
- .optional()
136
- .describe("Navigation hall: facts, events, discoveries, preferences, advice"),
137
- room: tool.schema
138
- .string()
139
- .optional()
140
- .describe("Navigation room (topic name, e.g. auth-migration)"),
141
- raw_source: tool.schema
142
- .string()
143
- .optional()
144
- .describe("Verbatim source text to preserve losslessly alongside narrative"),
145
- },
146
- execute: withDBErrorHandling(async (args) => {
147
- const obsType = args.type as ObservationType;
148
- if (!VALID_TYPES.includes(obsType)) {
149
- return `Error: Invalid type "${args.type}". Valid: ${VALID_TYPES.join(", ")}`;
150
- }
151
-
152
- const confidence = (args.confidence ?? "high") as ConfidenceLevel;
153
- if (!["high", "medium", "low"].includes(confidence)) {
154
- return `Error: Invalid confidence "${args.confidence}". Valid: high, medium, low`;
155
- }
156
-
157
- const narrative = args.narrative ?? args.content;
158
- const filesModifiedRaw = args.files_modified ?? args.files;
159
- const facts = parseCSV(args.facts);
160
- const concepts = parseCSV(args.concepts);
161
- let filesRead = parseCSV(args.files_read);
162
- const filesModified = parseCSV(filesModifiedRaw);
163
-
164
- if (narrative) {
165
- const detected = autoDetectFiles(narrative);
166
- if (detected.length > 0) {
167
- const existing = new Set([
168
- ...(filesRead ?? []),
169
- ...(filesModified ?? []),
170
- ]);
171
- const newRefs = detected.filter((f) => !existing.has(f));
172
- if (newRefs.length > 0)
173
- filesRead = [...(filesRead ?? []), ...newRefs];
174
- }
175
- }
176
-
177
- let supersedes: number | undefined;
178
- if (args.supersedes) {
179
- const parsed = Number.parseInt(args.supersedes, 10);
180
- if (!Number.isNaN(parsed)) supersedes = parsed;
181
- }
182
-
183
- const source = (args.source ?? "manual") as ObservationSource;
184
- const hall = args.hall as HallType | undefined;
185
- if (hall && !VALID_HALLS.includes(hall)) {
186
- return `Error: Invalid hall "${args.hall}". Valid: ${VALID_HALLS.join(", ")}`;
187
- }
188
-
189
- // Validation gate: check for duplicates, contradictions, low quality
190
- const validation = validateObservation({
191
- type: obsType,
192
- title: args.title,
193
- subtitle: args.subtitle,
194
- facts,
195
- narrative,
196
- concepts,
197
- files_read: filesRead,
198
- files_modified: filesModified,
199
- confidence,
200
- bead_id: args.bead_id,
201
- supersedes,
202
- source,
203
- wing: args.wing,
204
- hall,
205
- room: args.room,
206
- });
207
-
208
- if (validation.verdict === "reject") {
209
- const reasons = validation.issues.map(i => i.message).join("; ");
210
- const dupHint = validation.duplicateOf
211
- ? ` Use \`observation({ supersedes: "${validation.duplicateOf}", ... })\` to update it.`
212
- : "";
213
- return `Rejected: ${reasons}.${dupHint}`;
214
- }
215
-
216
- const id = storeObservation({
217
- type: obsType,
218
- title: args.title,
219
- subtitle: args.subtitle,
220
- facts,
221
- narrative,
222
- raw_source: args.raw_source,
223
- concepts,
224
- files_read: filesRead,
225
- files_modified: filesModified,
226
- confidence,
227
- bead_id: args.bead_id,
228
- supersedes,
229
- source,
230
- wing: args.wing,
231
- hall,
232
- room: args.room,
233
- });
234
-
235
- const warnings = validation.issues.length > 0
236
- ? `\n⚠️ Warnings: ${validation.issues.map(i => i.message).join("; ")}`
237
- : "";
238
-
239
- return `${TYPE_ICONS[obsType] ?? "\uD83D\uDCCC"} Observation #${id} stored [${obsType}] "${args.title}" (confidence: ${confidence}, source: ${source})${warnings}`;
240
- }),
241
- }),
242
-
243
- "memory-search": tool({
244
- description: `Search memory across observations and markdown archives.\n\t\n\tPurpose:\n\t- Fast, ranked search across all observations in SQLite (when FTS5 is available)\n\t- Returns compact index (~50-100 tokens per result) for progressive disclosure\n\t- Use memory-get for full details after identifying relevant observations\n\t\n\tFTS5 availability:\n\t- Auto-detected at runtime; if unavailable, observation searches fall back to file scan\n\t\n\tSearch modes and hints:\n\t- "observations" (default): Best for decisions, bugs, learnings; uses FTS5 ranking when available\n\t- "handoffs": Use for past session handoffs and summaries\n\t- "research": Use for research notes and external findings\n\t- "templates": Use for memory templates and boilerplate references\n\t- "beads": Use for task artifacts in .beads/artifacts\n\t- "all": Use when you are unsure where info lives; searches SQLite + markdown + beads\n\t\n\tExample:\n\tmemory-search({ query: "authentication" })\n\tmemory-search({ query: "auth", type: "decision", limit: 5 })`,
245
- args: {
246
- query: tool.schema.string().describe("Search query"),
247
- type: tool.schema
248
- .string()
249
- .optional()
250
- .describe("Filter by type or scope"),
251
- limit: tool.schema
252
- .number()
253
- .optional()
254
- .describe("Max results (default: 10)"),
255
- },
256
- execute: withDBErrorHandling(async (args) => {
257
- const query = args.query.trim();
258
- if (!query) return "Error: Empty search query";
259
- const limit = args.limit ?? 10;
260
- const scope = args.type ?? "observations";
261
- const lines: string[] = [];
262
-
263
- if (
264
- scope === "observations" ||
265
- scope === "all" ||
266
- VALID_TYPES.includes(scope as ObservationType)
267
- ) {
268
- const typeFilter = VALID_TYPES.includes(scope as ObservationType)
269
- ? (scope as ObservationType)
270
- : undefined;
271
- if (checkFTS5Available()) {
272
- const results = searchObservationsFTS(query, {
273
- type: typeFilter,
274
- limit,
275
- });
276
- if (results.length > 0) {
277
- lines.push(`## Observations (${results.length} results)\n`);
278
- lines.push("| ID | Type | Title | Date |");
279
- lines.push("|---|---|---|---|");
280
- for (const r of results)
281
- lines.push(
282
- `| ${r.id} | ${r.type} | ${r.title} | ${r.created_at.slice(0, 10)} |`,
283
- );
284
- lines.push("");
285
- for (const r of results.slice(0, 3)) {
286
- if (r.snippet) lines.push(`**#${r.id}**: ${r.snippet}`);
287
- }
288
- lines.push(
289
- `\nUse \`memory-get({ ids: "${results
290
- .slice(0, 3)
291
- .map((r) => r.id)
292
- .join(",")}" })\` for full details.`,
293
- );
294
- } else {
295
- lines.push("No observation matches found.");
296
- }
297
- } else {
298
- lines.push("FTS5 not available. Use memory-admin to check status.");
299
- }
300
- }
301
-
302
- if (scope === "distillations" || scope === "all") {
303
- const distResults = searchDistillationsFTS(query, limit);
304
- if (distResults.length > 0) {
305
- lines.push(`\n## Distillations (${distResults.length} results)\n`);
306
- for (const d of distResults) {
307
- lines.push(
308
- `- **Session ${d.session_id.slice(0, 8)}** (${d.message_count} msgs): ${d.snippet}`,
309
- );
310
- }
311
- }
312
- }
313
-
314
- if (scope === "handoffs" || scope === "all") {
315
- try {
316
- const handoffFiles = await readdir(handoffDir);
317
- const matches: string[] = [];
318
- for (const f of handoffFiles.filter((n) => n.endsWith(".md"))) {
319
- const content = await safeReadFile(path.join(handoffDir, f));
320
- if (content.toLowerCase().includes(query.toLowerCase()))
321
- matches.push(f);
322
- }
323
- if (matches.length > 0) {
324
- lines.push(`\n## Handoffs (${matches.length} matches)\n`);
325
- for (const m of matches.slice(0, 5)) lines.push(`- ${m}`);
326
- }
327
- } catch {
328
- /* No handoffs directory */
329
- }
330
- }
331
-
332
- return lines.length > 0 ? lines.join("\n") : "No results found.";
333
- }),
334
- }),
335
-
336
- "memory-get": tool({
337
- description: `Get full observation details by ID.\n\t\n\tPurpose:\n\t- Progressive disclosure: fetch full details after identifying relevant observations via search\n\t- Get complete narrative, facts, and metadata\n\t- Supports multiple IDs for batch retrieval\n\t\n\tExample:\n\tmemory-get({ ids: "42" }) // Single observation\n\tmemory-get({ ids: "1,5,10" }) // Multiple observations`,
338
- args: {
339
- ids: tool.schema.string().describe("Comma-separated observation IDs"),
340
- },
341
- execute: withDBErrorHandling(async (args) => {
342
- const idList = args.ids
343
- .split(",")
344
- .map((s) => Number.parseInt(s.trim(), 10))
345
- .filter((n) => !Number.isNaN(n));
346
- if (idList.length === 0) return "Error: No valid IDs provided";
347
- const observations = getObservationsByIds(idList);
348
- if (observations.length === 0)
349
- return "No observations found for given IDs.";
350
- return observations
351
- .map((obs) => formatObservation(obs))
352
- .join("\n\n---\n\n");
353
- }),
354
- }),
355
-
356
- "memory-read": tool({
357
- description: `Read memory files for persistent cross-session context.\n\t\n\tPurpose:\n\t- Retrieve project state, learnings, and active tasks\n\t- Reads from SQLite database\n\t- Supports subdirectories: handoffs/, research/\n\t\n\tExample:\n\tmemory-read({ file: "handoffs/2024-01-20-phase-1" })\n\tmemory-read({ file: "research/2024-01-topic" })`,
358
- args: {
359
- file: tool.schema.string().optional().describe("Memory file path"),
360
- },
361
- execute: withDBErrorHandling(async (args) => {
362
- const filePath = (args.file ?? "").replace(/\.md$/, "");
363
- if (!filePath) return "Error: No file path provided";
364
- const row = getMemoryFile(filePath);
365
- return row ? row.content : `Memory file "${filePath}" not found.`;
366
- }),
367
- }),
368
-
369
- "memory-update": tool({
370
- description: `Update memory files with new learnings, progress, or context.\n\t\n\tPurpose:\n\t- Write or append to project memory in SQLite\n\t- Supports subdirectories (e.g., 'research/2024-01-topic')\n\t- Two modes: 'replace' (overwrite) or 'append' (add to end)\n\t\n\tExample:\n\tmemory-update({ file: "research/session-findings", content: "..." })\n\tmemory-update({ file: "handoffs/phase-2", content: "...", mode: "append" })`,
371
- args: {
372
- file: tool.schema.string().describe("Memory file to update"),
373
- content: tool.schema.string().describe("Content to write or append"),
374
- mode: tool.schema
375
- .string()
376
- .optional()
377
- .describe("replace (default) or append"),
378
- },
379
- execute: withDBErrorHandling(async (args) => {
380
- const filePath = args.file.replace(/\.md$/, "");
381
- const mode = (args.mode ?? "replace") as "replace" | "append";
382
- let finalContent = args.content;
383
- if (mode === "append") {
384
- finalContent = `\n---\n_Updated: ${new Date().toISOString()}_\n\n${args.content}`;
385
- }
386
- upsertMemoryFile(filePath, finalContent, mode);
387
- return `Memory file "${filePath}" updated (mode: ${mode}).`;
388
- }),
389
- }),
390
-
391
- "memory-timeline": tool({
392
- description: `Get chronological context around an observation.\n\t\n\tPurpose:\n\t- Progressive disclosure: see what was happening before/after a specific observation\n\t- Understand decision context over time\n\t- Navigate memory timeline\n\t\n\tExample:\n\tmemory-timeline({ anchor_id: 42, depth_before: 5, depth_after: 5 })`,
393
- args: {
394
- anchor_id: tool.schema.number().describe("ID of the observation"),
395
- depth_before: tool.schema
396
- .number()
397
- .optional()
398
- .describe("Earlier observations (default: 5)"),
399
- depth_after: tool.schema
400
- .number()
401
- .optional()
402
- .describe("Later observations (default: 5)"),
403
- },
404
- execute: withDBErrorHandling(async (args) => {
405
- const { anchor, before, after } = getTimelineAroundObservation(
406
- args.anchor_id,
407
- args.depth_before ?? 5,
408
- args.depth_after ?? 5,
409
- );
410
- if (!anchor) return `Observation #${args.anchor_id} not found.`;
411
- const lines: string[] = [];
412
- if (before.length > 0) {
413
- lines.push("### Earlier");
414
- for (const b of before)
415
- lines.push(
416
- ` ${b.id}: [${b.type}] ${b.title} (${b.created_at.slice(0, 10)})`,
417
- );
418
- }
419
- lines.push(
420
- `\n### ${TYPE_ICONS[anchor.type] ?? "\uD83D\uDCCC"} Current: #${anchor.id} [${anchor.type}] ${anchor.title}`,
421
- );
422
- if (anchor.narrative) lines.push(anchor.narrative.slice(0, 200));
423
- if (after.length > 0) {
424
- lines.push("\n### Later");
425
- for (const a of after)
426
- lines.push(
427
- ` ${a.id}: [${a.type}] ${a.title} (${a.created_at.slice(0, 10)})`,
428
- );
429
- }
430
- return lines.join("\n");
431
- }),
432
- }),
433
-
434
- "memory-graph-add": tool({
435
- description: `Add a triple to the entity knowledge graph.\n\nStores a subject-predicate-object relationship with optional temporal bounds and confidence.\nUse for structured facts like "project uses typescript" or "user prefers dark-mode".\n\nExample:\nmemory-graph-add({ subject: "project", predicate: "uses", object: "typescript" })\nmemory-graph-add({ subject: "auth", predicate: "depends-on", object: "jwt", confidence: 0.9, source_observation_id: 42 })`,
436
- args: {
437
- subject: tool.schema.string().describe("Entity subject"),
438
- predicate: tool.schema.string().describe("Relationship type (e.g. uses, depends-on, prefers)"),
439
- object: tool.schema.string().describe("Entity object"),
440
- valid_from: tool.schema.string().optional().describe("Start date (ISO, default: today)"),
441
- valid_to: tool.schema.string().optional().describe("End date (ISO, null = still active)"),
442
- confidence: tool.schema.number().optional().describe("Confidence 0.0-1.0 (default: 1.0)"),
443
- source_observation_id: tool.schema.number().optional().describe("Link to source observation"),
444
- },
445
- execute: withDBErrorHandling(async (args) => {
446
- if (!args.subject?.trim() || !args.predicate?.trim() || !args.object?.trim()) {
447
- return "Error: subject, predicate, and object are required.";
448
- }
449
- const id = addEntityTriple({
450
- subject: args.subject,
451
- predicate: args.predicate,
452
- object: args.object,
453
- valid_from: args.valid_from,
454
- valid_to: args.valid_to,
455
- confidence: args.confidence,
456
- source_observation_id: args.source_observation_id,
457
- });
458
- return `Triple #${id} added: ${args.subject} —[${args.predicate}]→ ${args.object}`;
459
- }),
460
- }),
461
-
462
- "memory-graph-query": tool({
463
- description: `Query the entity knowledge graph.\n\nFind relationships for an entity with optional time and direction filters.\nReturns triples where the entity appears as subject, object, or both.\n\nExample:\nmemory-graph-query({ entity: "typescript" })\nmemory-graph-query({ entity: "auth", direction: "out", active_only: true })\nmemory-graph-query({ entity: "project", as_of: "2025-06-01" })`,
464
- args: {
465
- entity: tool.schema.string().describe("Entity to query"),
466
- direction: tool.schema.string().optional().describe("out (subject), in (object), both (default)"),
467
- predicate: tool.schema.string().optional().describe("Filter by predicate"),
468
- as_of: tool.schema.string().optional().describe("ISO date for point-in-time query"),
469
- active_only: tool.schema.boolean().optional().describe("Only active triples (default: false)"),
470
- limit: tool.schema.number().optional().describe("Max results (default: 50)"),
471
- },
472
- execute: withDBErrorHandling(async (args) => {
473
- if (!args.entity?.trim()) return "Error: entity is required.";
474
- const results = queryEntity(args.entity, {
475
- direction: args.direction as "out" | "in" | "both" | undefined,
476
- predicate: args.predicate,
477
- as_of: args.as_of,
478
- activeOnly: args.active_only,
479
- limit: args.limit,
480
- });
481
- if (results.length === 0) return `No triples found for entity "${args.entity}".`;
482
- const lines: string[] = [
483
- `## Entity Graph: ${args.entity} (${results.length} triples)\n`,
484
- "| ID | Subject | Predicate | Object | Active | Confidence |",
485
- "|---|---|---|---|---|---|",
486
- ];
487
- for (const r of results) {
488
- lines.push(`| ${r.id} | ${r.subject} | ${r.predicate} | ${r.object} | ${r.is_active ? "\u2705" : "\u274C"} | ${(r.confidence * 100).toFixed(0)}% |`);
489
- }
490
- return lines.join("\n");
491
- }),
492
- }),
493
-
494
- "memory-graph-invalidate": tool({
495
- description: `Invalidate (close) entity triples in the knowledge graph.\n\nMarks active triples matching subject+predicate+object as no longer valid by setting valid_to.\nUse when a fact is no longer true (e.g. project stopped using a library).\n\nExample:\nmemory-graph-invalidate({ subject: "project", predicate: "uses", object: "moment.js" })`,
496
- args: {
497
- subject: tool.schema.string().describe("Entity subject"),
498
- predicate: tool.schema.string().describe("Relationship type"),
499
- object: tool.schema.string().describe("Entity object"),
500
- end_date: tool.schema.string().optional().describe("End date (ISO, default: today)"),
501
- },
502
- execute: withDBErrorHandling(async (args) => {
503
- if (!args.subject?.trim() || !args.predicate?.trim() || !args.object?.trim()) {
504
- return "Error: subject, predicate, and object are required.";
505
- }
506
- const count = invalidateTriple(args.subject, args.predicate, args.object, args.end_date);
507
- return count > 0
508
- ? `Invalidated ${count} triple(s): ${args.subject} —[${args.predicate}]→ ${args.object}`
509
- : `No active triples found matching ${args.subject} —[${args.predicate}]→ ${args.object}.`;
510
- }),
511
- }),
512
-
513
- "memory-compact": tool({
514
- description: `Compact observations into a dense, token-efficient format.\n\nUses AAAK-inspired pipe-separated compression achieving ~3-5x token reduction.\nUseful for injecting memory into prompts with minimal token cost.\n\nExample:\nmemory-compact({})\nmemory-compact({ limit: 20 })`,
515
- args: {
516
- limit: tool.schema.number().optional().describe("Max observations to compact (default: all)"),
517
- },
518
- execute: withDBErrorHandling(async (args) => {
519
- const db = getMemoryDB();
520
- const limitClause = args.limit ? `LIMIT ${Number(args.limit)}` : "";
521
- const observations = db.query(
522
- `SELECT id, type, title, narrative, concepts, wing, hall, room, confidence, created_at
523
- FROM observations
524
- WHERE superseded_by IS NULL
525
- ORDER BY created_at_epoch DESC ${limitClause}`
526
- ).all() as { id: number; type: string; title: string; narrative?: string | null; concepts?: string | null; wing?: string | null; hall?: string | null; room?: string | null; confidence?: string | null; created_at?: string | null }[];
527
- if (observations.length === 0) return "No observations to compact.";
528
- const result = compactObservations(observations);
529
- if (!result.compressed) return "No observations to compact.";
530
- const ratio = result.compression_ratio > 0 ? ` (${(result.compression_ratio * 100).toFixed(0)}% of original)` : "";
531
- return `## Compact Memory (${observations.length} observations, ~${result.token_estimate} tokens${ratio})\n\n${result.compressed}`;
532
- }),
533
- }),
534
- };
535
- }